blob: 9b70e52b67d27180ffd3d52a73859b35b186037c [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Test case generation functions
30
31@fixme Update the following
32The following components are generated.
33
34test_common.[ch]: A collection of common code for tests. Currently
35this includes the ability to set the scalar members of an object with
36incrementing values and then similarly verify those values
37
38test_scalar_acc.c: Instantiate each type of object, then set and get
39scalar values in the objects.
40
41test_list.c: Instantiate each type of list, add an element of each
42type the list supports, setting scalar values of the elements.
43
44test_match.c: Various tests for match objects
45
46test_msg.c: Instantiate top level messages
47
48These will move towards unified tests that do the following:
49
50Create or init an object.
51Populate the object with incrementing values.
52Possibly transform the object in some way (e.g., run the underlying
53wire buffer through a parse routine).
54Verify that the members all have the appropriate value
55
56Through out, checking the consistency of memory and memory operations
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +090057is done with mcheck (if available).
Rich Lanea06d0c32013-03-25 08:52:03 -070058
59"""
60
61import sys
Andreas Wundsam76db0062013-11-15 13:34:41 -080062import c_gen.of_g_legacy as of_g
Andreas Wundsam542a13c2013-11-15 13:28:55 -080063import c_gen.match as match
64import c_gen.flags as flags
Rich Lanea06d0c32013-03-25 08:52:03 -070065from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080066import c_gen.type_maps as type_maps
67import c_gen.loxi_utils_legacy as loxi_utils
68import c_gen.identifiers as identifiers
Rich Laneccae0312013-07-21 23:34:13 -070069import util
70import test_data
Rich Lane79c87192014-03-04 10:56:59 -080071import loxi_globals
72from loxi_ir import *
Rich Lanea06d0c32013-03-25 08:52:03 -070073
74def var_name_map(m_type):
75 """
76 Map a type to a generic variable name for the type.
77 @param m_type The data type
78
79 Used mostly in test code generation, but also for the dup functions.
80 """
81 _var_name_map= dict(
82 uint8_t="val8",
83 uint16_t="val16",
84 uint32_t="val32",
85 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070086 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_port_no_t="port_no",
88 of_fm_cmd_t="fm_cmd",
89 of_wc_bmap_t="wc_bmap",
90 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070091 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070092 of_table_name_t="table_name",
93 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070094 of_serial_num_t="ser_num",
Rich Lanef8a3d002014-03-19 13:33:52 -070095 of_str64_t="str64",
Andreas Wundsam53256162013-05-02 14:05:53 -070096 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070097 of_ipv6_t="ipv6",
98 # Non-scalars; more TBD
99 of_octets_t="octets",
100 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700101 of_match_t="match",
Rich Lane90020b42014-04-07 12:05:45 -0700102 of_oxm_header_t="oxm",
Wilson Ngd6181882014-04-14 16:28:35 -0700103 of_bsn_vport_header_t="bsn_vport",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700104 # BSN extensions
105 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700106 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800107 of_checksum_128_t="checksum_128",
Praseed Balakrishnanf78068b2014-09-04 10:30:40 -0700108 #Circuit extensions
109 oxm_of_och_sig_id_t="sig_id",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700110 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700111
112 if m_type.find("of_list_") == 0:
113 return "list"
114 if m_type in of_g.of_mixed_types:
115 return of_g.of_mixed_types[m_type]["short_name"]
116 return _var_name_map[m_type]
117
118integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
119 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700120 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700121string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700122 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700123 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
124 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700125
126scalar_types = integer_types[:]
127scalar_types.extend(string_types)
128
129def ignore_member(cls, version, m_name, m_type):
130 """
131 Filter out names or types that either don't have accessors
132 or those that should not be messed with
133 or whose types we're not ready to deal with yet.
134 """
Rich Lane79c87192014-03-04 10:56:59 -0800135
136 uclass = loxi_globals.unified.class_by_name(cls)
137 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700138 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800139
Rich Lane79c87192014-03-04 10:56:59 -0800140 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800141 return True
Rich Lane79c87192014-03-04 10:56:59 -0800142
Rich Lanea06d0c32013-03-25 08:52:03 -0700143 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
144
145def gen_fill_string(out):
146 out.write("""
147
148/**
149 * The increment to use on values inside a string
150 */
151#define OF_TEST_STR_INCR 3
152
153/**
154 * Fill in a buffer with incrementing values starting
155 * at the given offset with the given value
156 * @param buf The buffer to fill
157 * @param value The value to use for data
158 * @param len The number of bytes to fill
159 */
160
161void
162of_test_str_fill(uint8_t *buf, int value, int len)
163{
164 int i;
165
166 for (i = 0; i < len; i++) {
167 *buf = value;
168 value += OF_TEST_STR_INCR;
169 buf++;
170 }
171}
172
173/**
174 * Given a buffer, verify that it's filled as above
175 * @param buf The buffer to check
176 * @param value The value to use for data
177 * @param len The number of bytes to fill
178 * @return Boolean True on equality (success)
179 */
180
181int
182of_test_str_check(uint8_t *buf, int value, int len)
183{
184 int i;
185 uint8_t val8;
186
187 val8 = value;
188
189 for (i = 0; i < len; i++) {
190 if (*buf != val8) {
191 return 0;
192 }
193 val8 += OF_TEST_STR_INCR;
194 buf++;
195 }
196
197 return 1;
198}
199
200/**
201 * Global that determines how octets should be populated
202 * -1 means use value % MAX (below) to determine length
203 * 0, 1, ... means used that fixed length
204 *
205 * Note: Was 16K, but that made objects too big. May add flexibility
206 * to call populate with a max parameter for length
207 */
208int octets_pop_style = -1;
209#define OCTETS_MAX_VALUE (128) /* 16K was too big */
210#define OCTETS_MULTIPLIER 6367 /* A prime */
211
212int
213of_octets_populate(of_octets_t *octets, int value)
214{
215 if (octets_pop_style < 0) {
216 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
217 } else {
218 octets->bytes = octets_pop_style;
219 }
220
221 if (octets->bytes != 0) {
222 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
223 return 0;
224 }
225 of_test_str_fill(octets->data, value, octets->bytes);
226 value += 1;
227 }
228
229 return value;
230}
231
232int
233of_octets_check(of_octets_t *octets, int value)
234{
235 int len;
236
237 if (octets_pop_style < 0) {
238 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
239 TEST_ASSERT(octets->bytes == len);
240 } else {
241 TEST_ASSERT(octets->bytes == octets_pop_style);
242 }
243
244 if (octets->bytes != 0) {
245 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
246 == 1);
247 value += 1;
248 }
249
250 return value;
251}
252
253int
254of_match_populate(of_match_t *match, of_version_t version, int value)
255{
256 MEMSET(match, 0, sizeof(*match));
257 match->version = version;
258""")
259
Rich Laned56f8d22014-05-06 14:52:55 -0700260 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700261 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700262 if (version == %d) {\
263""" % wire_version)
264 for key in keys:
265 entry = match.of_match_members[key]
266 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700267 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
268 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
269 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700270""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
271 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700272 }
273
Rich Laned56f8d22014-05-06 14:52:55 -0700274""")
275
Rich Laneb4a63a52014-05-22 14:41:57 -0700276 for wire_version, match_keys in match.match_keys.items():
277 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700278
279 out.write("""
280 if (value % 2) {
281 /* Sometimes set ipv4 addr masks to non-exact */
282 match->masks.ipv4_src = 0xffff0000;
283 match->masks.ipv4_dst = 0xfffff800;
284 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700285
286 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700287 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700288 return value;
289}
290
291int
292of_match_check(of_match_t *match, of_version_t version, int value)
293{
294 of_match_t check;
295
296 value = of_match_populate(&check, match->version, value);
297 TEST_ASSERT(value != 0);
298 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
299
300 return value;
301}
302""")
303
304def gen_common_test_header(out, name):
305 loxi_utils.gen_c_copy_license(out)
306 out.write("""
307/*
308 * Test header file
309 *
310 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
311 */
312
313#if !defined(_TEST_COMMON_H_)
314#define _TEST_COMMON_H_
315
316#define DISABLE_WARN_UNUSED_RESULT
317#include <loci/loci.h>
318#include <locitest/of_dup.h>
319#include <locitest/unittest.h>
320
321extern int global_error;
322extern int exit_on_error;
323
324/* @todo Make option for -k to continue tests if errors */
325#define RUN_TEST(test) do { \\
326 int rv; \\
327 TESTCASE(test, rv); \\
328 if (rv != TEST_PASS) { \\
329 global_error=1; \\
330 if (exit_on_error) return(1); \\
331 } \\
332 } while(0)
333
334#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
335#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
336
337/*
338 * Declarations of functions to populate scalar values in a a class
339 */
340
341extern void of_test_str_fill(uint8_t *buf, int value, int len);
342extern int of_test_str_check(uint8_t *buf, int value, int len);
343
344
345extern int of_octets_populate(of_octets_t *octets, int value);
346extern int of_octets_check(of_octets_t *octets, int value);
347extern int of_match_populate(of_match_t *match, of_version_t version,
348 int value);
349extern int of_match_check(of_match_t *match, of_version_t version, int value);
350extern int test_ident_macros(void);
351extern int test_dump_objs(void);
352
353/* In test_match_utils.c */
354extern int test_match_utils(void);
355
356extern int run_unified_accessor_tests(void);
357extern int run_match_tests(void);
358extern int run_utility_tests(void);
359
360extern int run_scalar_acc_tests(void);
361extern int run_list_tests(void);
362extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700363
364extern int run_validator_tests(void);
365
366extern int run_list_limits_tests(void);
367
368extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700369extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700370
371""")
372
373 for version in of_g.of_version_range:
374 for cls in of_g.standard_class_order:
375 if not loxi_utils.class_in_version(cls, version):
376 continue
377 if cls in type_maps.inheritance_map:
378 continue
379 out.write("""
380extern int %(cls)s_%(v_name)s_populate(
381 %(cls)s_t *obj, int value);
382extern int %(cls)s_%(v_name)s_check(
383 %(cls)s_t *obj, int value);
384extern int %(cls)s_%(v_name)s_populate_scalars(
385 %(cls)s_t *obj, int value);
386extern int %(cls)s_%(v_name)s_check_scalars(
387 %(cls)s_t *obj, int value);
388""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
389
390 out.write("""
391/*
392 * Declarations for list population and check primitives
393 */
394""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700395
Rich Lanea06d0c32013-03-25 08:52:03 -0700396 for version in of_g.of_version_range:
397 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700398 if version in of_g.unified[cls]:
399 out.write("""
400extern int
401 list_setup_%(cls)s_%(v_name)s(
402 %(cls)s_t *list, int value);
403extern int
404 list_check_%(cls)s_%(v_name)s(
405 %(cls)s_t *list, int value);
406""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
407
408 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
409
410def gen_common_test(out, name):
411 """
412 Generate common test content including main
413 """
414 loxi_utils.gen_c_copy_license(out)
415 out.write("""
416/*
417 * Common test code for LOCI
418 *
419 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
420 */
421
422#define DISABLE_WARN_UNUSED_RESULT
423#include "loci_log.h"
424#include <loci/loci_obj_dump.h>
425#include <locitest/unittest.h>
426#include <locitest/test_common.h>
427
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900428/* mcheck is a glibc extension */
429#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700430#include <mcheck.h>
431#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900432#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700433#define MCHECK_INIT do { } while (0)
434#endif
435
436/**
437 * Exit on error if set to 1
438 */
439int exit_on_error = 1;
440
441/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700442 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700443 */
444int global_error = 0;
445
446extern int run_unified_accessor_tests(void);
447extern int run_match_tests(void);
448extern int run_utility_tests(void);
449
450extern int run_scalar_acc_tests(void);
451extern int run_list_tests(void);
452extern int run_message_tests(void);
453
454/**
455 * Macros for initializing and checking scalar types
456 *
457 * @param var The variable being initialized or checked
458 * @param val The integer value to set/check against, see below
459 *
460 * Note that equality means something special for strings. Each byte
461 * is initialized to an incrementing value. So check is done against that.
462 *
463 */
464
465""")
466 for t in scalar_types:
467 if t in integer_types:
468 out.write("""
469#define VAR_%s_INIT(var, val) var = (%s)(val)
470#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
471""" % (t.upper(), t, t.upper(), t))
472 else:
473 out.write("""
474#define VAR_%s_INIT(var, val) \\
475 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
476#define VAR_%s_CHECK(var, val) \\
477 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
478""" % (t.upper(), t.upper()))
479
480 gen_fill_string(out)
481 gen_scalar_set_check_funs(out)
482 gen_list_set_check_funs(out)
483 gen_unified_accessor_funs(out)
484
485 gen_ident_tests(out)
486 gen_log_test(out)
487
488def gen_message_scalar_test(out, name):
489 """
490 Generate test cases for message objects, scalar accessors
491 """
492
493 loxi_utils.gen_c_copy_license(out)
494 out.write("""
495/**
496 *
497 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
498 *
499 * Message-scalar tests for all versions
500 */
501
502#include <locitest/test_common.h>
503""")
504 for version in of_g.of_version_range:
505 v_name = loxi_utils.version_to_name(version)
506 out.write("""
507/**
508 * Message-scalar tests for version %s
509 */
510""" % v_name)
511 for cls in of_g.standard_class_order:
512 if cls in type_maps.inheritance_map:
513 continue
514 if version in of_g.unified[cls]:
515 message_scalar_test(out, version, cls)
516
517 out.write("""
518int
519run_scalar_acc_tests(void)
520{
521""")
522 for version in of_g.of_version_range:
523 v_name = loxi_utils.version_to_name(version)
524 for cls in of_g.standard_class_order:
525 if cls in type_maps.inheritance_map:
526 continue
527 if version in of_g.unified[cls]:
528 test_name = "%s_%s" % (cls, v_name)
529 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
530
531 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700532
Rich Lanea06d0c32013-03-25 08:52:03 -0700533def message_scalar_test(out, version, cls):
534 """
535 Generate one test case for the given version and class
536 """
537
538 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700539 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700540 v_name = loxi_utils.version_to_name(version)
541
542 out.write("""
543static int
544test_%(cls)s_%(v_name)s_scalar(void)
545{
546 %(cls)s_t *obj;
547
548 obj = %(cls)s_new(%(v_name)s);
549 TEST_ASSERT(obj != NULL);
550 TEST_ASSERT(obj->version == %(v_name)s);
551 TEST_ASSERT(obj->length == %(length)d);
552 TEST_ASSERT(obj->parent == NULL);
553 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700554""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700555 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700556
557 # If this class is a concrete member of an inheritance hierarchy,
558 # run the hierarchy's root wire type parser and assert it returns
559 # the expected object id.
560 ofclass = loxi_globals.unified.class_by_name(cls)
561 if ofclass and not ofclass.virtual:
562 root = ofclass
563 while root.superclass:
564 root = root.superclass
565 if root.virtual:
566 out.write("""
567 {
568 of_object_id_t object_id;
569 %(root_cls)s_wire_object_id_get(obj, &object_id);
570 TEST_ASSERT(object_id == %(u_cls)s);
571 }
572""" % dict(root_cls=root.name, u_cls=cls.upper()))
573
Rich Lanea06d0c32013-03-25 08:52:03 -0700574 if not type_maps.class_is_virtual(cls):
575 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700576 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700577 int length;
578
Rich Lanedc46fe22014-04-03 15:10:38 -0700579 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 TEST_ASSERT(length == %(length)d);
581 }
582
583 /* Set up incrementing values for scalar members */
584 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
585
586 /* Check values just set */
587 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700588""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700589 v_name=v_name, length=length, version=version))
590
591 out.write("""
592 %(cls)s_delete(obj);
593
594 /* To do: Check memory */
595 return TEST_PASS;
596}
597""" % dict(cls=cls))
598
599# Get the members and list of scalar types for members of a given class
600def scalar_member_types_get(cls, version):
601 member_types = []
602
603 if not version in of_g.unified[cls]:
604 return ([], [])
605
606 if "use_version" in of_g.unified[cls][version]:
607 v = of_g.unified[cls][version]["use_version"]
608 members = of_g.unified[cls][v]["members"]
609 else:
610 members = of_g.unified[cls][version]["members"]
611 # Accumulate variables that are supported
612 for member in members:
613 m_type = member["m_type"]
614 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700615 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700616 ignore_member(cls, version, m_name, m_type)):
617 continue
618 if not m_type in member_types:
619 member_types.append(m_type)
620
621 return (members, member_types)
622
623def scalar_funs_instance(out, cls, version, members, member_types):
624 """
625 Generate one instance of scalar set/check functions
626 """
627 out.write("""
628/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700629 * Populate the scalar values in obj of type %(cls)s,
630 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700631 * @param obj Pointer to an object to populate
632 * @param value The seed value to use in populating the object
633 * @returns The value after increments for this object's values
634 */
635int %(cls)s_%(v_name)s_populate_scalars(
636 %(cls)s_t *obj, int value) {
637""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
638 # Declare string types
639 for t in member_types:
640 out.write(" %s %s;\n" % (t, var_name_map(t)))
641 for member in members:
642 m_type = member["m_type"]
643 m_name = member["name"]
644 if (not loxi_utils.type_is_scalar(m_type) or
645 ignore_member(cls, version, m_name, m_type)):
646 continue
647 v_name = var_name_map(m_type);
648 out.write("""
649 VAR_%(u_type)s_INIT(%(v_name)s, value);
650 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
651 value += 1;
652""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
653 out.write("""
654 return value;
655}
656""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700657
Rich Lanea06d0c32013-03-25 08:52:03 -0700658 out.write("""
659/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700660 * Check scalar values in obj of type %(cls)s,
661 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700662 * @param obj Pointer to an object to check
663 * @param value Starting value for checking
664 * @returns The value after increments for this object's values
665 */
666int %(cls)s_%(v_name)s_check_scalars(
667 %(cls)s_t *obj, int value) {
668""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
669
670 for t in member_types:
671 out.write(" %s %s;\n" % (t, var_name_map(t)))
672 for member in members:
673 m_type = member["m_type"]
674 m_name = member["name"]
675 if (not loxi_utils.type_is_scalar(m_type) or
676 ignore_member(cls, version, m_name, m_type)):
677 continue
678 v_name = var_name_map(m_type);
679 out.write("""
680 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
681 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
682 value += 1;
683""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
684
685 out.write("""
686 return value;
687}
688
689""")
690
691def gen_scalar_set_check_funs(out):
692 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700693 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700694 set and check their values
695 """
696 for version in of_g.of_version_range:
697 for cls in of_g.standard_class_order:
698 (members, member_types) = scalar_member_types_get(cls, version)
699 scalar_funs_instance(out, cls, version, members, member_types)
700
701
702# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700703def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700704 base_type = loxi_utils.list_to_entry_type(cls)
705 setup_template = """
706 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700707 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700708 (%(base_type)s_t *)%(inst)s);
709 value = %(subcls)s_%(v_name)s_populate(
710 %(inst)s, value);
711 cur_len += %(inst)s->length;
712 TEST_ASSERT(list->length == cur_len);
713"""
714 out.write("""
715 /* Append two instances of type %s */
716""" % subcls)
717 for i in range(2):
718 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700719 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700720 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700721 version=version))
722
Rich Lane9afc3b92014-04-09 22:55:53 -0700723def check_instance(out, cls, subcls, instance, v_name, version, last):
724 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700725 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
726 value = %(subcls)s_%(v_name)s_check(
727 %(inst)s, value);
728 TEST_ASSERT(value != 0);
729"""
730 out.write("\n /* Check two instances of type %s */" % instance)
731
Andreas Wundsam53256162013-05-02 14:05:53 -0700732 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700733 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700734 inst=instance, subcls=subcls,
735 v_name=loxi_utils.version_to_name(version)))
736 out.write("""\
737 TEST_OK(%(cls)s_next(list, &elt));
738""" % dict(cls=cls))
739
Andreas Wundsam53256162013-05-02 14:05:53 -0700740 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700741 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700742 inst=instance, subcls=subcls,
743 v_name=loxi_utils.version_to_name(version)))
744 if last:
745 out.write("""\
746 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
747""" % dict(cls=cls))
748 else:
749 out.write("""\
750 TEST_OK(%(cls)s_next(list, &elt));
751""" % dict(cls=cls))
752
753def setup_list_fn(out, version, cls):
754 """
755 Generate a helper function that populates a list with two
756 of each type of subclass it supports
757 """
758 out.write("""
759/**
760 * Set up a list of type %(cls)s with two of each type of subclass
761 */
762int
763list_setup_%(cls)s_%(v_name)s(
764 %(cls)s_t *list, int value)
765{
766""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
767 base_type = loxi_utils.list_to_entry_type(cls)
768 out.write("""
769 %(base_type)s_t elt;
770 int cur_len = 0;
771""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700772
Rich Lanea06d0c32013-03-25 08:52:03 -0700773 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700774 sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700775 v_name = loxi_utils.version_to_name(version)
776
777 if len(sub_classes) == 0:
778 out.write(" /* No subclasses for %s */\n"% base_type)
779 out.write(" %s_t *elt_p;\n" % base_type)
780 out.write("\n elt_p = &elt;\n")
781 else:
782 out.write(" /* Declare pointers for each subclass */\n")
783 for instance, subcls in sub_classes:
784 out.write(" %s_t *%s;\n" % (subcls, instance))
785 out.write("\n /* Instantiate pointers for each subclass */\n")
786 for instance, subcls in sub_classes:
787 out.write(" %s = &elt.%s;\n" % (instance, instance))
788
789 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700790 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700791 else:
792 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700793 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700794 out.write("""
795
796 return value;
797}
798""")
799
800def check_list_fn(out, version, cls):
801 """
802 Generate a helper function that checks a list populated by above fn
803 """
804 out.write("""
805/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700806 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700807 * list_setup_%(cls)s_%(v_name)s
808 */
809int
810list_check_%(cls)s_%(v_name)s(
811 %(cls)s_t *list, int value)
812{
813""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
814 base_type = loxi_utils.list_to_entry_type(cls)
815 out.write("""
816 %(base_type)s_t elt;
817""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700818
Rich Lanea06d0c32013-03-25 08:52:03 -0700819 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700820 sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700821 v_name = loxi_utils.version_to_name(version)
822
823 if len(sub_classes) == 0:
824 out.write(" /* No subclasses for %s */\n"% base_type)
825 out.write(" %s_t *elt_p;\n" % base_type)
826 out.write("\n elt_p = &elt;\n")
827 else:
828 out.write(" /* Declare pointers for each subclass */\n")
829 for instance, subcls in sub_classes:
830 out.write(" %s_t *%s;\n" % (subcls, instance))
831 out.write("\n /* Instantiate pointers for each subclass */\n")
832 for instance, subcls in sub_classes:
833 out.write(" %s = &elt.%s;\n" % (instance, instance))
834
835 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
836 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700837 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700838 else:
839 count = 0
840 for instance, subcls in sub_classes:
841 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700842 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700843 version, count==len(sub_classes))
844
845 out.write("""
846 return value;
847}
848""" % dict(base_type=base_type))
849
850def gen_list_set_check_funs(out):
851 for version in of_g.of_version_range:
852 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700853 if version in of_g.unified[cls]:
854 setup_list_fn(out, version, cls)
855 check_list_fn(out, version, cls)
856
857# Maybe: Get a map from list class to parent, mem_name of container
858
859def list_test(out, version, cls):
860 out.write("""
861static int
862test_%(cls)s_%(v_name)s(void)
863{
864""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
865 base_type = loxi_utils.list_to_entry_type(cls)
866
867 out.write(""" %(cls)s_t *list;
868 int value = 1;
869""" % dict(cls=cls, base_type=base_type))
870
871 out.write("""
872 list = %(cls)s_new(%(v_name)s);
873 TEST_ASSERT(list != NULL);
874 TEST_ASSERT(list->version == %(v_name)s);
875 TEST_ASSERT(list->length == 0);
876 TEST_ASSERT(list->parent == NULL);
877 TEST_ASSERT(list->object_id == %(enum_cls)s);
878
879 value = list_setup_%(cls)s_%(v_name)s(list, value);
880 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700881""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700882 enum_cls=loxi_utils.enum_name(cls)))
883
884 out.write("""
885 /* Now check values */
886 value = 1;
887 value = list_check_%(cls)s_%(v_name)s(list, value);
888 TEST_ASSERT(value != 0);
889""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
890
891 out.write("""
892 %(cls)s_delete(list);
893
894 return TEST_PASS;
895}
896""" % dict(cls=cls))
897
898def gen_list_test(out, name):
899 """
900 Generate base line test cases for lists
901 @param out The file handle to write to
902 """
903
904 loxi_utils.gen_c_copy_license(out)
905 out.write("""
906/**
907 *
908 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
909 *
910 * Message-scalar tests for all versions
911 */
912
913#include <locitest/test_common.h>
914""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700915
Rich Lanea06d0c32013-03-25 08:52:03 -0700916 for version in of_g.of_version_range:
917 v_name = loxi_utils.version_to_name(version)
918 out.write("""
919/**
920 * Baseline list tests for version %s
921 */
922""" % v_name)
923 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700924 if version in of_g.unified[cls]:
925 list_test(out, version, cls)
926
927 out.write("""
928int
929run_list_tests(void)
930{
931""")
932 for version in of_g.of_version_range:
933 v_name = loxi_utils.version_to_name(version)
934 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700935 if version in of_g.unified[cls]:
936 test_name = "%s_%s" % (cls, v_name)
937 out.write(" RUN_TEST(%s);\n" % test_name)
938
939 out.write("\n return TEST_PASS;\n}\n");
940
941def gen_match_test(out, name):
942 """
943 Generate baseline tests for match functions
944 """
945
946 loxi_utils.gen_c_copy_license(out)
947 out.write("""\
948/**
949 *
950 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
951 *
952 * Message-scalar tests for all versions
953 * @fixme These are mostly hard coded now.
954 */
955
956#include <locitest/test_common.h>
957
958static int
959test_match_1(void)
960{
961 of_match_v1_t *m_v1;
962 of_match_v2_t *m_v2;
963 of_match_v3_t *m_v3;
964 of_match_v4_t *m_v4;
965 of_match_t match;
966 int value = 1;
967 int idx;
968 uint32_t exp_value;
969
970 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700971 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700972 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
973 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
974 if (idx < 32) {
975 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
976 }
977 }
978""")
979
980 for version in of_g.of_version_range:
981 out.write("""
982 /* Create/populate/convert and delete for version %(v_name)s */
983 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
984 TEST_ASSERT(m_v%(version)d != NULL);
985 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
986 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
987 of_match_v%(version)d_delete(m_v%(version)d);
988""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
989
990 out.write("""
991 return TEST_PASS;
992}
993""")
994
995 out.write("""
996static int
997test_match_2(void)
998{
999 of_match_v1_t *m_v1;
1000 of_match_v2_t *m_v2;
1001 of_match_v3_t *m_v3;
1002 of_match_v3_t *m_v4;
1003 of_match_t match1;
1004 of_match_t match2;
1005 int value = 1;
1006""")
1007
1008 for version in of_g.of_version_range:
1009 out.write("""
1010 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1011 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1012 TEST_ASSERT(m_v%(version)d != NULL);
1013 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1014 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1015 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1016 of_match_v%(version)d_delete(m_v%(version)d);
1017""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1018
1019 out.write("""
1020 return TEST_PASS;
1021}
1022""")
1023
1024 out.write("""
1025static int
1026test_match_3(void)
1027{
1028 of_match_t match1;
1029 of_match_t match2;
1030 int value = 1;
1031 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001032 of_object_storage_t storage;
1033 memset(&storage, 0, sizeof(storage));
1034 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001035""")
1036 for version in of_g.of_version_range:
1037 out.write("""
1038 /* Serialize to version %(v_name)s */
1039 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001040 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001041 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001042 storage.obj.wbuf->buf = octets.data;
1043 storage.obj.wbuf->alloc_bytes = octets.bytes;
1044 storage.obj.wbuf->current_bytes = octets.bytes;
1045 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001046 OF_ERROR_NONE);
1047 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1048 FREE(octets.data);
1049""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1050
1051 out.write("""
1052 return TEST_PASS;
1053}
1054""")
1055
1056 out.write("""
1057int run_match_tests(void)
1058{
1059 RUN_TEST(match_1);
1060 RUN_TEST(match_2);
1061 RUN_TEST(match_3);
1062 RUN_TEST(match_utils);
1063
1064 return TEST_PASS;
1065}
1066""")
1067
1068def gen_msg_test(out, name):
1069 loxi_utils.gen_c_copy_license(out)
1070 out.write("""
1071/**
1072 *
1073 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1074 *
1075 * Message-scalar tests for all versions
1076 */
1077
1078#include <locitest/test_common.h>
1079""")
1080 for version in of_g.of_version_range:
1081 for cls in of_g.ordered_messages:
1082 if not (cls, version) in of_g.base_length:
1083 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001084 if type_maps.class_is_virtual(cls):
1085 continue
Rich Lanef70be942013-07-18 13:33:14 -07001086 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001087 out.write("""
1088static int
1089test_%(cls)s_create_%(v_name)s(void)
1090{
1091 %(cls)s_t *obj;
1092 uint8_t *msg_buf;
1093 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001094 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001095 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001096
1097 obj = %(cls)s_new(%(v_name)s);
1098 TEST_ASSERT(obj != NULL);
1099 TEST_ASSERT(obj->version == %(v_name)s);
1100 TEST_ASSERT(obj->length == %(bytes)d);
1101 TEST_ASSERT(obj->parent == NULL);
1102 TEST_ASSERT(obj->object_id == %(enum)s);
1103
Rich Lanea4b68302014-03-12 15:17:58 -07001104 of_header_wire_object_id_get(obj, &object_id);
1105 TEST_ASSERT(object_id == %(enum)s);
1106
Rich Lanea06d0c32013-03-25 08:52:03 -07001107 /* Set up incrementing values for scalar members */
1108 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1109 TEST_ASSERT(value != 0);
1110
Rich Lanebb8f17c2014-06-12 13:14:09 -07001111 len = obj->length;
1112
Rich Lanea06d0c32013-03-25 08:52:03 -07001113 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001114 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1115 TEST_ASSERT(msg_buf != NULL);
1116 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001117 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001118
1119 TEST_ASSERT(obj != NULL);
1120
1121 /* @fixme Set up all message objects (recursively?) */
1122
1123 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1124 TEST_ASSERT(value != 0);
1125
1126 %(cls)s_delete(obj);
1127
1128 return TEST_PASS;
1129}
1130""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1131 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1132
1133 out.write("""
1134int
1135run_message_tests(void)
1136{
1137""")
1138 for version in of_g.of_version_range:
1139 for cls in of_g.ordered_messages:
1140 if not (cls, version) in of_g.base_length:
1141 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001142 if type_maps.class_is_virtual(cls):
1143 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001144 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1145 out.write(" RUN_TEST(%s);\n" % test_name)
1146
1147 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001148
Rich Lanea06d0c32013-03-25 08:52:03 -07001149
1150def gen_list_setup_check(out, cls, version):
1151 """
1152 Generate functions that populate and check a list with two
1153 of each type of subclass it supports
1154 """
1155 out.write("""
1156/**
1157 * Populate a list of type %(cls)s with two of each type of subclass
1158 * @param list Pointer to the list to be populated
1159 * @param value The seed value to use in populating the list
1160 * @returns The value after increments for this object's values
1161 */
1162int
1163%(cls)s_%(v_name)s_populate(
1164 %(cls)s_t *list, int value)
1165{
1166""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1167 base_type = loxi_utils.list_to_entry_type(cls)
1168 out.write("""
1169 %(base_type)s_t elt;
1170 int cur_len = 0;
1171""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001172
Rich Lanea06d0c32013-03-25 08:52:03 -07001173 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001174 sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001175 v_name = loxi_utils.version_to_name(version)
1176
1177 if len(sub_classes) == 0:
1178 out.write(" /* No subclasses for %s */\n"% base_type)
1179 out.write(" %s_t *elt_p;\n" % base_type)
1180 out.write("\n elt_p = &elt;\n")
1181 else:
1182 out.write(" /* Declare pointers for each subclass */\n")
1183 for instance, subcls in sub_classes:
1184 out.write(" %s_t *%s;\n" % (subcls, instance))
1185 out.write("\n /* Instantiate pointers for each subclass */\n")
1186 for instance, subcls in sub_classes:
1187 out.write(" %s = &elt.%s;\n" % (instance, instance))
1188
Rich Lanea06d0c32013-03-25 08:52:03 -07001189 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001190 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001191 else:
1192 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001193 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001194 out.write("""
1195 return value;
1196}
1197""")
1198 out.write("""
1199/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001200 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001201 * %(cls)s_%(v_name)s_populate
1202 * @param list Pointer to the list that was populated
1203 * @param value Starting value for checking
1204 * @returns The value after increments for this object's values
1205 */
1206int
1207%(cls)s_%(v_name)s_check(
1208 %(cls)s_t *list, int value)
1209{
1210""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1211 base_type = loxi_utils.list_to_entry_type(cls)
1212 out.write("""
1213 %(base_type)s_t elt;
1214 int count = 0;
1215 int rv;
1216""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001217
Rich Lanea06d0c32013-03-25 08:52:03 -07001218
1219 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001220 sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001221 v_name = loxi_utils.version_to_name(version)
1222
1223 if len(sub_classes) == 0:
1224 entry_count = 2
1225 out.write(" /* No subclasses for %s */\n"% base_type)
1226 out.write(" %s_t *elt_p;\n" % base_type)
1227 out.write("\n elt_p = &elt;\n")
1228 else:
1229 entry_count = 2 * len(sub_classes) # Two of each type appended
1230 out.write(" /* Declare pointers for each subclass */\n")
1231 for instance, subcls in sub_classes:
1232 out.write(" %s_t *%s;\n" % (subcls, instance))
1233 out.write("\n /* Instantiate pointers for each subclass */\n")
1234 for instance, subcls in sub_classes:
1235 out.write(" %s = &elt.%s;\n" % (instance, instance))
1236
1237 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1238 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001239 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001240 version, True)
1241 else:
1242 count = 0
1243 for instance, subcls in sub_classes:
1244 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001245 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001246 version, count==len(sub_classes))
1247 out.write("""
1248""" % dict(base_type=base_type))
1249
1250 out.write("""
1251 /* Do an iterate to test the iterator */
1252 %(u_cls)s_ITER(list, &elt, rv) {
1253 count += 1;
1254 }
1255
1256 TEST_ASSERT(rv == OF_ERROR_RANGE);
1257 TEST_ASSERT(count == %(entry_count)d);
1258
1259 /* We shoehorn a test of the dup functions here */
1260 {
1261 %(cls)s_t *dup;
1262
1263 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1264 TEST_ASSERT(dup->length == list->length);
1265 TEST_ASSERT(dup->object_id == list->object_id);
1266 TEST_ASSERT(dup->version == list->version);
1267 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1268 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1269 of_object_delete((of_object_t *)dup);
1270
1271 /* And now for the generic dup function */
1272 TEST_ASSERT((dup = (%(cls)s_t *)
1273 of_object_dup(list)) != NULL);
1274 TEST_ASSERT(dup->length == list->length);
1275 TEST_ASSERT(dup->object_id == list->object_id);
1276 TEST_ASSERT(dup->version == list->version);
1277 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1278 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1279 of_object_delete((of_object_t *)dup);
1280 }
1281
1282 return value;
1283}
1284""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1285
1286
1287def gen_class_setup_check(out, cls, version):
1288 out.write("""
1289/**
1290 * Populate all members of an object of type %(cls)s
1291 * with incrementing values
1292 * @param obj Pointer to an object to populate
1293 * @param value The seed value to use in populating the object
1294 * @returns The value after increments for this object's values
1295 */
1296
1297int
1298%(cls)s_%(v_name)s_populate(
1299 %(cls)s_t *obj, int value)
1300{
1301""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1302 members, member_types = loxi_utils.all_member_types_get(cls, version)
1303 for m_type in member_types:
1304 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1305 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001306 elif m_type == "of_bsn_vport_header_t":
1307 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001308 else:
1309 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1310 out.write("""
1311 /* Run thru accessors after new to ensure okay */
1312""")
1313 for member in members:
1314 m_type = member["m_type"]
1315 m_name = member["name"]
1316 if loxi_utils.skip_member_name(m_name):
1317 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001318 if m_type == "of_bsn_vport_header_t":
1319 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001320 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1321 out.write("""\
1322 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1323""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1324 else:
1325 sub_cls = m_type[:-2] # Trim _t
1326 out.write("""\
1327 {
1328 %(sub_cls)s_t sub_cls;
1329
1330 /* Test bind */
1331 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1332 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001333""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001334 m_name=m_name, sub_cls=sub_cls,
1335 v_name=loxi_utils.version_to_name(version)))
1336
1337 out.write("""
1338 value = %(cls)s_%(v_name)s_populate_scalars(
1339 obj, value);
1340 TEST_ASSERT(value != 0);
1341""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1342
1343 for member in members:
1344 m_type = member["m_type"]
1345 m_name = member["name"]
1346 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1347 continue
1348 if loxi_utils.skip_member_name(m_name):
1349 continue
1350 if m_type == "of_match_t":
1351 out.write("""\
1352 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1353 TEST_ASSERT(value != 0);
1354 %(cls)s_%(m_name)s_set(
1355 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001356""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001357 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1358 elif m_type == "of_octets_t":
1359 out.write("""\
1360 value = of_octets_populate(&%(var_name)s, value);
1361 TEST_ASSERT(value != 0);
1362 %(cls)s_%(m_name)s_set(
1363 obj, &%(var_name)s);
1364 if (octets.bytes) {
1365 FREE(octets.data);
1366 }
1367""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001368 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1369 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001370 out.write("""\
1371 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1372 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001373 value = %(sub_cls)s_%(v_name)s_populate(
1374 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001375 TEST_ASSERT(value != 0);
1376 %(cls)s_%(m_name)s_set(
1377 obj, %(var_name)s);
1378 %(sub_cls)s_delete(%(var_name)s);
1379""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1380 var_name=var_name_map(m_type),
1381 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001382 else:
1383 sub_cls = m_type[:-2] # Trim _t
1384 out.write("""
1385 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1386 TEST_ASSERT(%(var_name)s != NULL);
1387 value = %(sub_cls)s_%(v_name)s_populate(
1388 %(var_name)s, value);
1389 TEST_ASSERT(value != 0);
1390 %(cls)s_%(m_name)s_set(
1391 obj, %(var_name)s);
1392 %(sub_cls)s_delete(%(var_name)s);
1393""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1394 var_name=var_name_map(m_type),
1395 v_name=loxi_utils.version_to_name(version)))
1396
1397 out.write("""
1398 return value;
1399}
1400""")
1401
1402 out.write("""
1403/**
1404 * Check all members of an object of type %(cls)s
1405 * populated by the above function
1406 * @param obj Pointer to an object to check
1407 * @param value Starting value for checking
1408 * @returns The value after increments for this object's values
1409 */
1410
1411int
1412%(cls)s_%(v_name)s_check(
1413 %(cls)s_t *obj, int value)
1414{
1415""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1416 members, member_types = loxi_utils.all_member_types_get(cls, version)
1417 for m_type in member_types:
1418 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1419 continue
1420 if loxi_utils.type_is_of_object(m_type):
1421 continue
1422 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1423 out.write("""
1424 value = %(cls)s_%(v_name)s_check_scalars(
1425 obj, value);
1426 TEST_ASSERT(value != 0);
1427""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1428
1429 for member in members:
1430 m_type = member["m_type"]
1431 m_name = member["name"]
1432 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1433 continue
1434 if loxi_utils.skip_member_name(m_name):
1435 continue
1436 if m_type == "of_match_t":
1437 out.write("""\
1438 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1439 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1440""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1441 v_name=loxi_utils.version_to_name(version)))
1442 elif m_type == "of_octets_t":
1443 out.write("""\
1444 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1445 value = of_octets_check(&%(var_name)s, value);
1446""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1447 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001448 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1449 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001450 out.write("""
1451 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001452 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001453
1454 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1455 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001456 value = %(sub_cls)s_%(v_name)s_check(
1457 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001458 TEST_ASSERT(value != 0);
1459 %(sub_cls)s_delete(%(m_name)s_ptr);
1460 }
1461""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1462 var_name=var_name_map(m_type),
1463 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001464 else:
1465 sub_cls = m_type[:-2] # Trim _t
1466 out.write("""
1467 { /* Use get/delete to access on check */
1468 %(m_type)s *%(m_name)s_ptr;
1469
1470 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1471 TEST_ASSERT(%(m_name)s_ptr != NULL);
1472 value = %(sub_cls)s_%(v_name)s_check(
1473 %(m_name)s_ptr, value);
1474 TEST_ASSERT(value != 0);
1475 %(sub_cls)s_delete(%(m_name)s_ptr);
1476 }
1477""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1478 var_name=var_name_map(m_type),
1479 v_name=loxi_utils.version_to_name(version)))
1480
1481 out.write("""
1482 /* We shoehorn a test of the dup functions here */
1483 {
1484 %(cls)s_t *dup;
1485
1486 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1487 TEST_ASSERT(dup->length == obj->length);
1488 TEST_ASSERT(dup->object_id == obj->object_id);
1489 TEST_ASSERT(dup->version == obj->version);
1490 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1491 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1492 of_object_delete((of_object_t *)dup);
1493
1494 /* And now for the generic dup function */
1495 TEST_ASSERT((dup = (%(cls)s_t *)
1496 of_object_dup(obj)) != NULL);
1497 TEST_ASSERT(dup->length == obj->length);
1498 TEST_ASSERT(dup->object_id == obj->object_id);
1499 TEST_ASSERT(dup->version == obj->version);
1500 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1501 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1502 of_object_delete((of_object_t *)dup);
1503 }
1504
1505 return value;
1506}
1507""" % dict(cls=cls))
1508
1509def unified_accessor_test_case(out, cls, version):
1510 """
1511 Generate one test case for the given version and class
1512 """
1513
1514 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001515 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001516 v_name = loxi_utils.version_to_name(version)
1517
1518 out.write("""
1519static int
1520test_%(cls)s_%(v_name)s(void)
1521{
1522 %(cls)s_t *obj;
1523 obj = %(cls)s_new(%(v_name)s);
1524 TEST_ASSERT(obj != NULL);
1525 TEST_ASSERT(obj->version == %(v_name)s);
1526 TEST_ASSERT(obj->length == %(length)d);
1527 TEST_ASSERT(obj->parent == NULL);
1528 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001529""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001530 v_name=v_name, length=length, version=version))
1531 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1532 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001533 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001534 int length;
1535
Rich Lanedc46fe22014-04-03 15:10:38 -07001536 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001537 TEST_ASSERT(length == %(length)d);
1538 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001539 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001540 of_object_id_t obj_id;
1541
Rich Lanedc46fe22014-04-03 15:10:38 -07001542 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001543 TEST_ASSERT(obj_id == %(u_cls)s);
1544 }
1545
1546 /* Set up incrementing values for members */
1547 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1548 obj, 1) != 0);
1549
1550 /* Check values just set */
1551 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1552 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001553""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001554 v_name=v_name, length=length, version=version))
1555
1556 out.write("""
1557 %(cls)s_delete(obj);
1558
1559 /* To do: Check memory */
1560 return TEST_PASS;
1561}
1562""" % dict(cls=cls))
1563
1564
1565def gen_unified_accessor_funs(out):
1566 for version in of_g.of_version_range:
1567 for cls in of_g.standard_class_order:
1568 if not loxi_utils.class_in_version(cls, version):
1569 continue
1570 if cls in type_maps.inheritance_map:
1571 continue
1572 elif loxi_utils.class_is_list(cls):
1573 gen_list_setup_check(out, cls, version)
1574 else:
1575 gen_class_setup_check(out, cls, version)
1576
1577def gen_unified_accessor_tests(out, name):
1578 loxi_utils.gen_c_copy_license(out)
1579 out.write("""
1580/**
1581 *
1582 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1583 *
1584 * Unified simple class instantiation tests for all versions
1585 */
1586
1587#include <locitest/test_common.h>
1588""")
1589 for version in of_g.of_version_range:
1590 for cls in of_g.standard_class_order:
1591 if not loxi_utils.class_in_version(cls, version):
1592 continue
1593 if cls in type_maps.inheritance_map:
1594 continue
1595 unified_accessor_test_case(out, cls, version)
1596
1597 out.write("""
1598int
1599run_unified_accessor_tests(void)
1600{
1601""")
1602 for version in of_g.of_version_range:
1603 v_name = loxi_utils.version_to_name(version)
1604 for cls in of_g.standard_class_order:
1605 if not loxi_utils.class_in_version(cls, version):
1606 continue
1607 if cls in type_maps.inheritance_map:
1608 continue
1609 test_name = "%s_%s" % (cls, v_name)
1610 out.write(" RUN_TEST(%s);\n" % test_name)
1611
1612 out.write(" return TEST_PASS;\n}\n");
1613
1614
1615
1616################################################################
1617#
1618# Object duplication functions
1619#
1620# These exercise the accessors to create duplicate objects.
1621# They are used in the LOCI test shim which sits in an OF
1622# protocol stream.
1623#
1624# TODO
1625# Resolve version stuff
1626# Complete list dup
1627
1628def gen_dup_list(out, cls, version):
1629 ver_name = loxi_utils.version_to_name(version)
1630 elt_type = loxi_utils.list_to_entry_type(cls)
1631 out.write("""
1632/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001633 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001634 * using accessor functions
1635 * @param src Pointer to object to be duplicated
1636 * @returns A new object of type %(cls)s.
1637 *
1638 * The caller is responsible for deleting the returned value
1639 */
1640%(cls)s_t *
1641%(cls)s_%(ver_name)s_dup(
1642 %(cls)s_t *src)
1643{
1644 %(elt_type)s_t src_elt;
1645 %(elt_type)s_t *dst_elt;
1646 int rv;
1647 %(cls)s_t *dst;
1648
1649 if ((dst = %(cls)s_new(src->version)) == NULL) {
1650 return NULL;
1651 }
1652""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1653
1654 out.write("""
1655 %(u_cls)s_ITER(src, &src_elt, rv) {
1656 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1657 of_object_delete((of_object_t *)dst);
1658 return NULL;
1659 }
1660 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1661 dst, NULL);
1662 of_object_delete((of_object_t *)dst_elt);
1663 }
1664
1665 return dst;
1666}
1667""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1668
1669
1670def gen_dup_inheritance(out, cls, version):
1671 ver_name = loxi_utils.version_to_name(version)
1672 out.write("""
1673/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001674 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001675 * @param src Pointer to object to be duplicated
1676 * @returns A new object of type %(cls)s.
1677 *
1678 * The caller is responsible for deleting the returned value
1679 */
1680%(cls)s_t *
1681%(cls)s_%(ver_name)s_dup(
1682 %(cls)s_t *src)
1683{
1684""" % dict(cls=cls, ver_name=ver_name))
1685
1686 # For each subclass, check if this is an instance of that subclass
1687 version_classes = type_maps.inheritance_data[cls][version]
1688 for sub_cls in version_classes:
1689 sub_enum = (cls + "_" + sub_cls).upper()
1690 out.write("""
1691 if (src->header.object_id == %(sub_enum)s) {
1692 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1693 &src->%(sub_cls)s);
1694 }
1695""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1696
1697 out.write("""
1698 return NULL;
1699}
1700""")
1701
1702
1703def gen_dup_cls(out, cls, version):
1704 """
1705 Generate duplication routine for class cls
1706 """
1707 ver_name = loxi_utils.version_to_name(version)
1708
1709 out.write("""
1710/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001711 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001712 * using accessor functions
1713 * @param src Pointer to object to be duplicated
1714 * @returns A new object of type %(cls)s.
1715 *
1716 * The caller is responsible for deleting the returned value
1717 */
1718%(cls)s_t *
1719%(cls)s_%(ver_name)s_dup(
1720 %(cls)s_t *src)
1721{
1722 %(cls)s_t *dst;
1723""" % dict(cls=cls, ver_name=ver_name))
1724
1725 # Get members and types for the class
1726 members, member_types = loxi_utils.all_member_types_get(cls, version)
1727
1728 # Add declarations for each member type
1729 for m_type in member_types:
1730 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1731 # Declare instance of these
1732 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001733 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1734 out.write("""
1735 of_bsn_vport_q_in_q_t src_%(v_name)s;
1736 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1737""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001738 else:
1739 out.write("""
1740 %(m_type)s src_%(v_name)s;
1741 %(m_type)s *dst_%(v_name)s;
1742""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1743
1744 out.write("""
1745 if ((dst = %(cls)s_new(src->version)) == NULL) {
1746 return NULL;
1747 }
1748""" % dict(cls=cls))
1749
1750 for member in members:
1751 m_type = member["m_type"]
1752 m_name = member["name"]
1753 if loxi_utils.skip_member_name(m_name):
1754 continue
1755 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1756 out.write("""
1757 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1758 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1759""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1760 elif m_type in ["of_match_t", "of_octets_t"]:
1761 out.write("""
1762 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1763 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1764""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001765 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1766 sub_cls = "of_bsn_vport_q_in_q"
1767 out.write("""
1768 %(cls)s_%(m_name)s_bind(
1769 src, &src_%(v_name)s);
1770 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1771 if (dst_%(v_name)s == NULL) {
1772 %(cls)s_delete(dst);
1773 return NULL;
1774 }
1775 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1776 %(sub_cls)s_delete(dst_%(v_name)s);
1777""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1778 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001779 else:
1780 sub_cls = m_type[:-2] # Trim _t
1781 out.write("""
1782 %(cls)s_%(m_name)s_bind(
1783 src, &src_%(v_name)s);
1784 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1785 if (dst_%(v_name)s == NULL) {
1786 %(cls)s_delete(dst);
1787 return NULL;
1788 }
1789 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1790 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001791""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001792 v_name=var_name_map(m_type), ver_name=ver_name))
1793
1794 out.write("""
1795 return dst;
1796}
1797""")
1798
1799def gen_version_dup(out=sys.stdout):
1800 """
1801 Generate duplication routines for each object type
1802 """
1803 out.write("""
1804/* Special try macro for duplicating */
1805#define _TRY_FREE(op, obj, rv) do { \\
1806 int _rv; \\
1807 if ((_rv = (op)) < 0) { \\
1808 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1809 of_object_delete((of_object_t *)(obj)); \\
1810 return (rv); \\
1811 } \\
1812 } while (0)
1813""")
1814
1815 for version in of_g.of_version_range:
1816 for cls in of_g.standard_class_order:
1817 if not loxi_utils.class_in_version(cls, version):
1818 continue
1819 if cls in type_maps.inheritance_map:
1820 gen_dup_inheritance(out, cls, version)
1821 elif loxi_utils.class_is_list(cls):
1822 gen_dup_list(out, cls, version)
1823 else:
1824 gen_dup_cls(out, cls, version)
1825
1826def gen_dup(out=sys.stdout):
1827 """
1828 Generate non-version specific duplication routines for each object type
1829 """
1830
1831 for cls in of_g.standard_class_order:
1832 out.write("""
1833%(cls)s_t *
1834%(cls)s_dup(
1835 %(cls)s_t *src)
1836{
1837""" % dict(cls=cls))
1838 for version in of_g.of_version_range:
1839 if not loxi_utils.class_in_version(cls, version):
1840 continue
1841 hdr = "header." if cls in type_maps.inheritance_map else ""
1842
1843 ver_name = loxi_utils.version_to_name(version)
1844 out.write("""
1845 if (src->%(hdr)sversion == %(ver_name)s) {
1846 return %(cls)s_%(ver_name)s_dup(src);
1847 }
1848""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1849
1850 out.write("""
1851 /* Class not supported in given version */
1852 return NULL;
1853}
1854""")
1855
1856def dup_c_gen(out, name):
1857 """
1858 Generate the C file for duplication functions
1859 """
1860 loxi_utils.gen_c_copy_license(out)
1861 out.write("""\
1862/*
1863 * Duplication functions for all OF objects
1864 *
1865 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1866 *
1867 * These are test functions for exercising accessors. You can call
1868 * of_object_dup for an efficient duplication.
1869 */
1870
1871#define DISABLE_WARN_UNUSED_RESULT
1872#include "loci_log.h"
1873#include <locitest/of_dup.h>
1874
1875""")
1876
1877 gen_version_dup(out)
1878 gen_dup(out)
1879
1880
1881def dup_h_gen(out, name):
1882 """
1883 Generate the header file for duplication functions
1884 """
1885
1886 loxi_utils.gen_c_copy_license(out)
1887 out.write("""
1888/*
1889 * Duplication function header file
1890 *
1891 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1892 */
1893
1894#if !defined(_OF_DUP_H_)
1895#define _OF_DUP_H_
1896
1897#include <loci/loci.h>
1898""")
1899
1900 for cls in of_g.standard_class_order:
1901 out.write("""
1902extern %(cls)s_t *
1903 %(cls)s_dup(
1904 %(cls)s_t *src);
1905""" % dict(cls=cls))
1906
1907 for version in of_g.of_version_range:
1908 for cls in of_g.standard_class_order:
1909 if not loxi_utils.class_in_version(cls, version):
1910 continue
1911 ver_name = loxi_utils.version_to_name(version)
1912 out.write("""
1913extern %(cls)s_t *
1914 %(cls)s_%(ver_name)s_dup(
1915 %(cls)s_t *src);
1916""" % dict(cls=cls, ver_name=ver_name))
1917
1918 out.write("\n#endif /* _OF_DUP_H_ */\n")
1919
1920def gen_log_test(out):
1921 """
1922 Generate test for obj log calls
1923
1924 Define a trivial handler for object logging; call all obj log fns
1925 """
1926 out.write("""
1927
1928/**
1929 * Test object dump functions
1930 */
1931
1932int
1933test_dump_objs(void)
1934{
1935 of_object_t *obj;
1936
1937 FILE *out = fopen("/dev/null", "w");
1938
1939 /* Call each obj dump function */
1940""")
1941 for version in of_g.of_version_range:
1942 for j, cls in enumerate(of_g.all_class_order):
1943 if not loxi_utils.class_in_version(cls, version):
1944 continue
1945 if cls in type_maps.inheritance_map:
1946 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001947 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1948 out.write("""
1949 obj = (of_object_t *)%(cls)s_new(%(version)s);
1950 {
1951 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1952 %(cls)s_vport_set(obj, vport);
1953 of_object_delete(vport);
1954 }
1955 of_object_dump((loci_writer_f)fprintf, out, obj);
1956 of_object_delete(obj);
1957""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1958 else:
1959 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001960 obj = (of_object_t *)%(cls)s_new(%(version)s);
1961 of_object_dump((loci_writer_f)fprintf, out, obj);
1962 of_object_delete(obj);
1963""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001964
Rich Lanea06d0c32013-03-25 08:52:03 -07001965 out.write("""
1966 fclose(out);
1967 return TEST_PASS;
1968}
1969""")
1970
1971def gen_ident_tests(out):
1972 """
1973 Generate tests for identifiers
1974
1975 For all idents, instantiate, test version supported macros
1976 For flags, set it, test it, clear it, test it.
1977 """
1978 out.write("""
1979/**
1980 * Test cases for all flag accessor macros
1981 * These only test self consistency (and that they compile)
1982 */
1983int
1984test_ident_macros(void)
1985{
1986 int value __attribute__((unused));
1987 uint32_t flags;
1988
1989""")
1990
1991 for ident, info in of_g.identifiers.items():
1992 if not identifiers.defined_versions_agree(of_g.identifiers,
1993 of_g.target_version_list,
1994 ident):
1995 # @fixme
1996 continue
1997 out.write(" value = %s;\n" % ident)
1998 for version in of_g.target_version_list:
1999 if version in info["values_by_version"].keys():
2000 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2001 (ident, of_g.of_version_wire2name[version]))
2002 else:
2003 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2004 (ident, of_g.of_version_wire2name[version]))
2005 if flags.ident_is_flag(ident):
2006 # Grab first supported version
2007 for version in info["values_by_version"]:
2008 break
2009 out.write("""
2010 flags = 0;
2011 %(ident)s_SET(flags, %(ver_name)s);
2012 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2013 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2014 %(ident)s_CLEAR(flags, %(ver_name)s);
2015 TEST_ASSERT(flags == 0);
2016 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2017""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2018
2019 out.write("""
2020 return TEST_PASS;
2021}
2022""")
2023
Rich Laneccae0312013-07-21 23:34:13 -07002024def gen_datafiles_tests(out, name):
2025 tests = []
2026 for filename in test_data.list_files():
2027 data = test_data.read(filename)
2028 if not 'c' in data:
2029 continue
2030 name = filename[:-5].replace("/", "_")
2031 tests.append(dict(name=name,
2032 filename=filename,
2033 c=data['c'],
2034 binary=data['binary']))
2035
2036 util.render_template(out, "test_data.c", tests=tests)