blob: 5501ed3eaa4d42efe9cb086d3ee208110fe7d3df [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",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700108 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700109
110 if m_type.find("of_list_") == 0:
111 return "list"
112 if m_type in of_g.of_mixed_types:
113 return of_g.of_mixed_types[m_type]["short_name"]
114 return _var_name_map[m_type]
115
116integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
117 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700118 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700119string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700120 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700121 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
122 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700123
124scalar_types = integer_types[:]
125scalar_types.extend(string_types)
126
127def ignore_member(cls, version, m_name, m_type):
128 """
129 Filter out names or types that either don't have accessors
130 or those that should not be messed with
131 or whose types we're not ready to deal with yet.
132 """
Rich Lane79c87192014-03-04 10:56:59 -0800133
134 uclass = loxi_globals.unified.class_by_name(cls)
135 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700136 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800137
Rich Lane79c87192014-03-04 10:56:59 -0800138 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800139 return True
Rich Lane79c87192014-03-04 10:56:59 -0800140
Rich Lanea06d0c32013-03-25 08:52:03 -0700141 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
142
143def gen_fill_string(out):
144 out.write("""
145
146/**
147 * The increment to use on values inside a string
148 */
149#define OF_TEST_STR_INCR 3
150
151/**
152 * Fill in a buffer with incrementing values starting
153 * at the given offset with the given value
154 * @param buf The buffer to fill
155 * @param value The value to use for data
156 * @param len The number of bytes to fill
157 */
158
159void
160of_test_str_fill(uint8_t *buf, int value, int len)
161{
162 int i;
163
164 for (i = 0; i < len; i++) {
165 *buf = value;
166 value += OF_TEST_STR_INCR;
167 buf++;
168 }
169}
170
171/**
172 * Given a buffer, verify that it's filled as above
173 * @param buf The buffer to check
174 * @param value The value to use for data
175 * @param len The number of bytes to fill
176 * @return Boolean True on equality (success)
177 */
178
179int
180of_test_str_check(uint8_t *buf, int value, int len)
181{
182 int i;
183 uint8_t val8;
184
185 val8 = value;
186
187 for (i = 0; i < len; i++) {
188 if (*buf != val8) {
189 return 0;
190 }
191 val8 += OF_TEST_STR_INCR;
192 buf++;
193 }
194
195 return 1;
196}
197
198/**
199 * Global that determines how octets should be populated
200 * -1 means use value % MAX (below) to determine length
201 * 0, 1, ... means used that fixed length
202 *
203 * Note: Was 16K, but that made objects too big. May add flexibility
204 * to call populate with a max parameter for length
205 */
206int octets_pop_style = -1;
207#define OCTETS_MAX_VALUE (128) /* 16K was too big */
208#define OCTETS_MULTIPLIER 6367 /* A prime */
209
210int
211of_octets_populate(of_octets_t *octets, int value)
212{
213 if (octets_pop_style < 0) {
214 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
215 } else {
216 octets->bytes = octets_pop_style;
217 }
218
219 if (octets->bytes != 0) {
220 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
221 return 0;
222 }
223 of_test_str_fill(octets->data, value, octets->bytes);
224 value += 1;
225 }
226
227 return value;
228}
229
230int
231of_octets_check(of_octets_t *octets, int value)
232{
233 int len;
234
235 if (octets_pop_style < 0) {
236 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
237 TEST_ASSERT(octets->bytes == len);
238 } else {
239 TEST_ASSERT(octets->bytes == octets_pop_style);
240 }
241
242 if (octets->bytes != 0) {
243 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
244 == 1);
245 value += 1;
246 }
247
248 return value;
249}
250
251int
252of_match_populate(of_match_t *match, of_version_t version, int value)
253{
254 MEMSET(match, 0, sizeof(*match));
255 match->version = version;
256""")
257
Rich Laned56f8d22014-05-06 14:52:55 -0700258 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700259 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700260 if (version == %d) {\
261""" % wire_version)
262 for key in keys:
263 entry = match.of_match_members[key]
264 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700265 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
266 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
267 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700268""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
269 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700270 }
271
Rich Laned56f8d22014-05-06 14:52:55 -0700272""")
273
274 populate_match_version(1, match.of_v1_keys)
275 populate_match_version(2, match.of_v2_keys)
276 populate_match_version(3, match.match_keys_sorted)
277 populate_match_version(4, match.match_keys_sorted)
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;
1032""")
1033 for version in of_g.of_version_range:
1034 out.write("""
1035 /* Serialize to version %(v_name)s */
1036 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001037 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001038 OF_ERROR_NONE);
Andreas Wundsam53256162013-05-02 14:05:53 -07001039 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001040 OF_ERROR_NONE);
1041 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1042 FREE(octets.data);
1043""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1044
1045 out.write("""
1046 return TEST_PASS;
1047}
1048""")
1049
1050 out.write("""
1051int run_match_tests(void)
1052{
1053 RUN_TEST(match_1);
1054 RUN_TEST(match_2);
1055 RUN_TEST(match_3);
1056 RUN_TEST(match_utils);
1057
1058 return TEST_PASS;
1059}
1060""")
1061
1062def gen_msg_test(out, name):
1063 loxi_utils.gen_c_copy_license(out)
1064 out.write("""
1065/**
1066 *
1067 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1068 *
1069 * Message-scalar tests for all versions
1070 */
1071
1072#include <locitest/test_common.h>
1073""")
1074 for version in of_g.of_version_range:
1075 for cls in of_g.ordered_messages:
1076 if not (cls, version) in of_g.base_length:
1077 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001078 if type_maps.class_is_virtual(cls):
1079 continue
Rich Lanef70be942013-07-18 13:33:14 -07001080 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001081 out.write("""
1082static int
1083test_%(cls)s_create_%(v_name)s(void)
1084{
1085 %(cls)s_t *obj;
1086 uint8_t *msg_buf;
1087 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001088 of_object_id_t object_id;
Rich Lanea06d0c32013-03-25 08:52:03 -07001089
1090 obj = %(cls)s_new(%(v_name)s);
1091 TEST_ASSERT(obj != NULL);
1092 TEST_ASSERT(obj->version == %(v_name)s);
1093 TEST_ASSERT(obj->length == %(bytes)d);
1094 TEST_ASSERT(obj->parent == NULL);
1095 TEST_ASSERT(obj->object_id == %(enum)s);
1096
Rich Lanea4b68302014-03-12 15:17:58 -07001097 of_header_wire_object_id_get(obj, &object_id);
1098 TEST_ASSERT(object_id == %(enum)s);
1099
Rich Lanea06d0c32013-03-25 08:52:03 -07001100 /* Set up incrementing values for scalar members */
1101 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1102 TEST_ASSERT(value != 0);
1103
1104 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001105 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1106 TEST_ASSERT(msg_buf != NULL);
1107 %(cls)s_delete(obj);
Rich Lanea06d0c32013-03-25 08:52:03 -07001108 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1109
1110 TEST_ASSERT(obj != NULL);
1111
1112 /* @fixme Set up all message objects (recursively?) */
1113
1114 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1115 TEST_ASSERT(value != 0);
1116
1117 %(cls)s_delete(obj);
1118
1119 return TEST_PASS;
1120}
1121""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1122 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1123
1124 out.write("""
1125int
1126run_message_tests(void)
1127{
1128""")
1129 for version in of_g.of_version_range:
1130 for cls in of_g.ordered_messages:
1131 if not (cls, version) in of_g.base_length:
1132 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001133 if type_maps.class_is_virtual(cls):
1134 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001135 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1136 out.write(" RUN_TEST(%s);\n" % test_name)
1137
1138 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001139
Rich Lanea06d0c32013-03-25 08:52:03 -07001140
1141def gen_list_setup_check(out, cls, version):
1142 """
1143 Generate functions that populate and check a list with two
1144 of each type of subclass it supports
1145 """
1146 out.write("""
1147/**
1148 * Populate a list of type %(cls)s with two of each type of subclass
1149 * @param list Pointer to the list to be populated
1150 * @param value The seed value to use in populating the list
1151 * @returns The value after increments for this object's values
1152 */
1153int
1154%(cls)s_%(v_name)s_populate(
1155 %(cls)s_t *list, int value)
1156{
1157""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1158 base_type = loxi_utils.list_to_entry_type(cls)
1159 out.write("""
1160 %(base_type)s_t elt;
1161 int cur_len = 0;
1162""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001163
Rich Lanea06d0c32013-03-25 08:52:03 -07001164 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001165 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 -07001166 v_name = loxi_utils.version_to_name(version)
1167
1168 if len(sub_classes) == 0:
1169 out.write(" /* No subclasses for %s */\n"% base_type)
1170 out.write(" %s_t *elt_p;\n" % base_type)
1171 out.write("\n elt_p = &elt;\n")
1172 else:
1173 out.write(" /* Declare pointers for each subclass */\n")
1174 for instance, subcls in sub_classes:
1175 out.write(" %s_t *%s;\n" % (subcls, instance))
1176 out.write("\n /* Instantiate pointers for each subclass */\n")
1177 for instance, subcls in sub_classes:
1178 out.write(" %s = &elt.%s;\n" % (instance, instance))
1179
Rich Lanea06d0c32013-03-25 08:52:03 -07001180 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001181 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001182 else:
1183 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001184 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001185 out.write("""
1186 return value;
1187}
1188""")
1189 out.write("""
1190/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001191 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 * %(cls)s_%(v_name)s_populate
1193 * @param list Pointer to the list that was populated
1194 * @param value Starting value for checking
1195 * @returns The value after increments for this object's values
1196 */
1197int
1198%(cls)s_%(v_name)s_check(
1199 %(cls)s_t *list, int value)
1200{
1201""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1202 base_type = loxi_utils.list_to_entry_type(cls)
1203 out.write("""
1204 %(base_type)s_t elt;
1205 int count = 0;
1206 int rv;
1207""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001208
Rich Lanea06d0c32013-03-25 08:52:03 -07001209
1210 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001211 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 -07001212 v_name = loxi_utils.version_to_name(version)
1213
1214 if len(sub_classes) == 0:
1215 entry_count = 2
1216 out.write(" /* No subclasses for %s */\n"% base_type)
1217 out.write(" %s_t *elt_p;\n" % base_type)
1218 out.write("\n elt_p = &elt;\n")
1219 else:
1220 entry_count = 2 * len(sub_classes) # Two of each type appended
1221 out.write(" /* Declare pointers for each subclass */\n")
1222 for instance, subcls in sub_classes:
1223 out.write(" %s_t *%s;\n" % (subcls, instance))
1224 out.write("\n /* Instantiate pointers for each subclass */\n")
1225 for instance, subcls in sub_classes:
1226 out.write(" %s = &elt.%s;\n" % (instance, instance))
1227
1228 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1229 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001230 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001231 version, True)
1232 else:
1233 count = 0
1234 for instance, subcls in sub_classes:
1235 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001236 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001237 version, count==len(sub_classes))
1238 out.write("""
1239""" % dict(base_type=base_type))
1240
1241 out.write("""
1242 /* Do an iterate to test the iterator */
1243 %(u_cls)s_ITER(list, &elt, rv) {
1244 count += 1;
1245 }
1246
1247 TEST_ASSERT(rv == OF_ERROR_RANGE);
1248 TEST_ASSERT(count == %(entry_count)d);
1249
1250 /* We shoehorn a test of the dup functions here */
1251 {
1252 %(cls)s_t *dup;
1253
1254 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1255 TEST_ASSERT(dup->length == list->length);
1256 TEST_ASSERT(dup->object_id == list->object_id);
1257 TEST_ASSERT(dup->version == list->version);
1258 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1259 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1260 of_object_delete((of_object_t *)dup);
1261
1262 /* And now for the generic dup function */
1263 TEST_ASSERT((dup = (%(cls)s_t *)
1264 of_object_dup(list)) != NULL);
1265 TEST_ASSERT(dup->length == list->length);
1266 TEST_ASSERT(dup->object_id == list->object_id);
1267 TEST_ASSERT(dup->version == list->version);
1268 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1269 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1270 of_object_delete((of_object_t *)dup);
1271 }
1272
1273 return value;
1274}
1275""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1276
1277
1278def gen_class_setup_check(out, cls, version):
1279 out.write("""
1280/**
1281 * Populate all members of an object of type %(cls)s
1282 * with incrementing values
1283 * @param obj Pointer to an object to populate
1284 * @param value The seed value to use in populating the object
1285 * @returns The value after increments for this object's values
1286 */
1287
1288int
1289%(cls)s_%(v_name)s_populate(
1290 %(cls)s_t *obj, int value)
1291{
1292""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1293 members, member_types = loxi_utils.all_member_types_get(cls, version)
1294 for m_type in member_types:
1295 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1296 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001297 elif m_type == "of_bsn_vport_header_t":
1298 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001299 else:
1300 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1301 out.write("""
1302 /* Run thru accessors after new to ensure okay */
1303""")
1304 for member in members:
1305 m_type = member["m_type"]
1306 m_name = member["name"]
1307 if loxi_utils.skip_member_name(m_name):
1308 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001309 if m_type == "of_bsn_vport_header_t":
1310 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001311 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1312 out.write("""\
1313 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1314""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1315 else:
1316 sub_cls = m_type[:-2] # Trim _t
1317 out.write("""\
1318 {
1319 %(sub_cls)s_t sub_cls;
1320
1321 /* Test bind */
1322 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1323 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001324""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001325 m_name=m_name, sub_cls=sub_cls,
1326 v_name=loxi_utils.version_to_name(version)))
1327
1328 out.write("""
1329 value = %(cls)s_%(v_name)s_populate_scalars(
1330 obj, value);
1331 TEST_ASSERT(value != 0);
1332""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1333
1334 for member in members:
1335 m_type = member["m_type"]
1336 m_name = member["name"]
1337 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1338 continue
1339 if loxi_utils.skip_member_name(m_name):
1340 continue
1341 if m_type == "of_match_t":
1342 out.write("""\
1343 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1344 TEST_ASSERT(value != 0);
1345 %(cls)s_%(m_name)s_set(
1346 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001347""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001348 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1349 elif m_type == "of_octets_t":
1350 out.write("""\
1351 value = of_octets_populate(&%(var_name)s, value);
1352 TEST_ASSERT(value != 0);
1353 %(cls)s_%(m_name)s_set(
1354 obj, &%(var_name)s);
1355 if (octets.bytes) {
1356 FREE(octets.data);
1357 }
1358""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001359 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1360 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001361 out.write("""\
1362 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1363 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001364 value = %(sub_cls)s_%(v_name)s_populate(
1365 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001366 TEST_ASSERT(value != 0);
1367 %(cls)s_%(m_name)s_set(
1368 obj, %(var_name)s);
1369 %(sub_cls)s_delete(%(var_name)s);
1370""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1371 var_name=var_name_map(m_type),
1372 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001373 else:
1374 sub_cls = m_type[:-2] # Trim _t
1375 out.write("""
1376 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1377 TEST_ASSERT(%(var_name)s != NULL);
1378 value = %(sub_cls)s_%(v_name)s_populate(
1379 %(var_name)s, value);
1380 TEST_ASSERT(value != 0);
1381 %(cls)s_%(m_name)s_set(
1382 obj, %(var_name)s);
1383 %(sub_cls)s_delete(%(var_name)s);
1384""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1385 var_name=var_name_map(m_type),
1386 v_name=loxi_utils.version_to_name(version)))
1387
1388 out.write("""
1389 return value;
1390}
1391""")
1392
1393 out.write("""
1394/**
1395 * Check all members of an object of type %(cls)s
1396 * populated by the above function
1397 * @param obj Pointer to an object to check
1398 * @param value Starting value for checking
1399 * @returns The value after increments for this object's values
1400 */
1401
1402int
1403%(cls)s_%(v_name)s_check(
1404 %(cls)s_t *obj, int value)
1405{
1406""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1407 members, member_types = loxi_utils.all_member_types_get(cls, version)
1408 for m_type in member_types:
1409 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1410 continue
1411 if loxi_utils.type_is_of_object(m_type):
1412 continue
1413 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1414 out.write("""
1415 value = %(cls)s_%(v_name)s_check_scalars(
1416 obj, value);
1417 TEST_ASSERT(value != 0);
1418""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1419
1420 for member in members:
1421 m_type = member["m_type"]
1422 m_name = member["name"]
1423 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1424 continue
1425 if loxi_utils.skip_member_name(m_name):
1426 continue
1427 if m_type == "of_match_t":
1428 out.write("""\
1429 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1430 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1431""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1432 v_name=loxi_utils.version_to_name(version)))
1433 elif m_type == "of_octets_t":
1434 out.write("""\
1435 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1436 value = of_octets_check(&%(var_name)s, value);
1437""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1438 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001439 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1440 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001441 out.write("""
1442 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001443 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001444
1445 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1446 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001447 value = %(sub_cls)s_%(v_name)s_check(
1448 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001449 TEST_ASSERT(value != 0);
1450 %(sub_cls)s_delete(%(m_name)s_ptr);
1451 }
1452""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1453 var_name=var_name_map(m_type),
1454 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001455 else:
1456 sub_cls = m_type[:-2] # Trim _t
1457 out.write("""
1458 { /* Use get/delete to access on check */
1459 %(m_type)s *%(m_name)s_ptr;
1460
1461 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1462 TEST_ASSERT(%(m_name)s_ptr != NULL);
1463 value = %(sub_cls)s_%(v_name)s_check(
1464 %(m_name)s_ptr, value);
1465 TEST_ASSERT(value != 0);
1466 %(sub_cls)s_delete(%(m_name)s_ptr);
1467 }
1468""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1469 var_name=var_name_map(m_type),
1470 v_name=loxi_utils.version_to_name(version)))
1471
1472 out.write("""
1473 /* We shoehorn a test of the dup functions here */
1474 {
1475 %(cls)s_t *dup;
1476
1477 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1478 TEST_ASSERT(dup->length == obj->length);
1479 TEST_ASSERT(dup->object_id == obj->object_id);
1480 TEST_ASSERT(dup->version == obj->version);
1481 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1482 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1483 of_object_delete((of_object_t *)dup);
1484
1485 /* And now for the generic dup function */
1486 TEST_ASSERT((dup = (%(cls)s_t *)
1487 of_object_dup(obj)) != NULL);
1488 TEST_ASSERT(dup->length == obj->length);
1489 TEST_ASSERT(dup->object_id == obj->object_id);
1490 TEST_ASSERT(dup->version == obj->version);
1491 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1492 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1493 of_object_delete((of_object_t *)dup);
1494 }
1495
1496 return value;
1497}
1498""" % dict(cls=cls))
1499
1500def unified_accessor_test_case(out, cls, version):
1501 """
1502 Generate one test case for the given version and class
1503 """
1504
1505 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001506 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001507 v_name = loxi_utils.version_to_name(version)
1508
1509 out.write("""
1510static int
1511test_%(cls)s_%(v_name)s(void)
1512{
1513 %(cls)s_t *obj;
1514 obj = %(cls)s_new(%(v_name)s);
1515 TEST_ASSERT(obj != NULL);
1516 TEST_ASSERT(obj->version == %(v_name)s);
1517 TEST_ASSERT(obj->length == %(length)d);
1518 TEST_ASSERT(obj->parent == NULL);
1519 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001520""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001521 v_name=v_name, length=length, version=version))
1522 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1523 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001524 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001525 int length;
1526
Rich Lanedc46fe22014-04-03 15:10:38 -07001527 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001528 TEST_ASSERT(length == %(length)d);
1529 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001530 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001531 of_object_id_t obj_id;
1532
Rich Lanedc46fe22014-04-03 15:10:38 -07001533 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001534 TEST_ASSERT(obj_id == %(u_cls)s);
1535 }
1536
1537 /* Set up incrementing values for members */
1538 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1539 obj, 1) != 0);
1540
1541 /* Check values just set */
1542 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1543 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001544""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001545 v_name=v_name, length=length, version=version))
1546
1547 out.write("""
1548 %(cls)s_delete(obj);
1549
1550 /* To do: Check memory */
1551 return TEST_PASS;
1552}
1553""" % dict(cls=cls))
1554
1555
1556def gen_unified_accessor_funs(out):
1557 for version in of_g.of_version_range:
1558 for cls in of_g.standard_class_order:
1559 if not loxi_utils.class_in_version(cls, version):
1560 continue
1561 if cls in type_maps.inheritance_map:
1562 continue
1563 elif loxi_utils.class_is_list(cls):
1564 gen_list_setup_check(out, cls, version)
1565 else:
1566 gen_class_setup_check(out, cls, version)
1567
1568def gen_unified_accessor_tests(out, name):
1569 loxi_utils.gen_c_copy_license(out)
1570 out.write("""
1571/**
1572 *
1573 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1574 *
1575 * Unified simple class instantiation tests for all versions
1576 */
1577
1578#include <locitest/test_common.h>
1579""")
1580 for version in of_g.of_version_range:
1581 for cls in of_g.standard_class_order:
1582 if not loxi_utils.class_in_version(cls, version):
1583 continue
1584 if cls in type_maps.inheritance_map:
1585 continue
1586 unified_accessor_test_case(out, cls, version)
1587
1588 out.write("""
1589int
1590run_unified_accessor_tests(void)
1591{
1592""")
1593 for version in of_g.of_version_range:
1594 v_name = loxi_utils.version_to_name(version)
1595 for cls in of_g.standard_class_order:
1596 if not loxi_utils.class_in_version(cls, version):
1597 continue
1598 if cls in type_maps.inheritance_map:
1599 continue
1600 test_name = "%s_%s" % (cls, v_name)
1601 out.write(" RUN_TEST(%s);\n" % test_name)
1602
1603 out.write(" return TEST_PASS;\n}\n");
1604
1605
1606
1607################################################################
1608#
1609# Object duplication functions
1610#
1611# These exercise the accessors to create duplicate objects.
1612# They are used in the LOCI test shim which sits in an OF
1613# protocol stream.
1614#
1615# TODO
1616# Resolve version stuff
1617# Complete list dup
1618
1619def gen_dup_list(out, cls, version):
1620 ver_name = loxi_utils.version_to_name(version)
1621 elt_type = loxi_utils.list_to_entry_type(cls)
1622 out.write("""
1623/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001624 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001625 * using accessor functions
1626 * @param src Pointer to object to be duplicated
1627 * @returns A new object of type %(cls)s.
1628 *
1629 * The caller is responsible for deleting the returned value
1630 */
1631%(cls)s_t *
1632%(cls)s_%(ver_name)s_dup(
1633 %(cls)s_t *src)
1634{
1635 %(elt_type)s_t src_elt;
1636 %(elt_type)s_t *dst_elt;
1637 int rv;
1638 %(cls)s_t *dst;
1639
1640 if ((dst = %(cls)s_new(src->version)) == NULL) {
1641 return NULL;
1642 }
1643""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1644
1645 out.write("""
1646 %(u_cls)s_ITER(src, &src_elt, rv) {
1647 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1648 of_object_delete((of_object_t *)dst);
1649 return NULL;
1650 }
1651 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1652 dst, NULL);
1653 of_object_delete((of_object_t *)dst_elt);
1654 }
1655
1656 return dst;
1657}
1658""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1659
1660
1661def gen_dup_inheritance(out, cls, version):
1662 ver_name = loxi_utils.version_to_name(version)
1663 out.write("""
1664/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001665 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001666 * @param src Pointer to object to be duplicated
1667 * @returns A new object of type %(cls)s.
1668 *
1669 * The caller is responsible for deleting the returned value
1670 */
1671%(cls)s_t *
1672%(cls)s_%(ver_name)s_dup(
1673 %(cls)s_t *src)
1674{
1675""" % dict(cls=cls, ver_name=ver_name))
1676
1677 # For each subclass, check if this is an instance of that subclass
1678 version_classes = type_maps.inheritance_data[cls][version]
1679 for sub_cls in version_classes:
1680 sub_enum = (cls + "_" + sub_cls).upper()
1681 out.write("""
1682 if (src->header.object_id == %(sub_enum)s) {
1683 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1684 &src->%(sub_cls)s);
1685 }
1686""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1687
1688 out.write("""
1689 return NULL;
1690}
1691""")
1692
1693
1694def gen_dup_cls(out, cls, version):
1695 """
1696 Generate duplication routine for class cls
1697 """
1698 ver_name = loxi_utils.version_to_name(version)
1699
1700 out.write("""
1701/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001702 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001703 * using accessor functions
1704 * @param src Pointer to object to be duplicated
1705 * @returns A new object of type %(cls)s.
1706 *
1707 * The caller is responsible for deleting the returned value
1708 */
1709%(cls)s_t *
1710%(cls)s_%(ver_name)s_dup(
1711 %(cls)s_t *src)
1712{
1713 %(cls)s_t *dst;
1714""" % dict(cls=cls, ver_name=ver_name))
1715
1716 # Get members and types for the class
1717 members, member_types = loxi_utils.all_member_types_get(cls, version)
1718
1719 # Add declarations for each member type
1720 for m_type in member_types:
1721 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1722 # Declare instance of these
1723 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001724 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1725 out.write("""
1726 of_bsn_vport_q_in_q_t src_%(v_name)s;
1727 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1728""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001729 else:
1730 out.write("""
1731 %(m_type)s src_%(v_name)s;
1732 %(m_type)s *dst_%(v_name)s;
1733""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1734
1735 out.write("""
1736 if ((dst = %(cls)s_new(src->version)) == NULL) {
1737 return NULL;
1738 }
1739""" % dict(cls=cls))
1740
1741 for member in members:
1742 m_type = member["m_type"]
1743 m_name = member["name"]
1744 if loxi_utils.skip_member_name(m_name):
1745 continue
1746 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1747 out.write("""
1748 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1749 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1750""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1751 elif m_type in ["of_match_t", "of_octets_t"]:
1752 out.write("""
1753 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1754 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1755""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001756 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1757 sub_cls = "of_bsn_vport_q_in_q"
1758 out.write("""
1759 %(cls)s_%(m_name)s_bind(
1760 src, &src_%(v_name)s);
1761 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1762 if (dst_%(v_name)s == NULL) {
1763 %(cls)s_delete(dst);
1764 return NULL;
1765 }
1766 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1767 %(sub_cls)s_delete(dst_%(v_name)s);
1768""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1769 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001770 else:
1771 sub_cls = m_type[:-2] # Trim _t
1772 out.write("""
1773 %(cls)s_%(m_name)s_bind(
1774 src, &src_%(v_name)s);
1775 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1776 if (dst_%(v_name)s == NULL) {
1777 %(cls)s_delete(dst);
1778 return NULL;
1779 }
1780 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1781 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001782""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001783 v_name=var_name_map(m_type), ver_name=ver_name))
1784
1785 out.write("""
1786 return dst;
1787}
1788""")
1789
1790def gen_version_dup(out=sys.stdout):
1791 """
1792 Generate duplication routines for each object type
1793 """
1794 out.write("""
1795/* Special try macro for duplicating */
1796#define _TRY_FREE(op, obj, rv) do { \\
1797 int _rv; \\
1798 if ((_rv = (op)) < 0) { \\
1799 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1800 of_object_delete((of_object_t *)(obj)); \\
1801 return (rv); \\
1802 } \\
1803 } while (0)
1804""")
1805
1806 for version in of_g.of_version_range:
1807 for cls in of_g.standard_class_order:
1808 if not loxi_utils.class_in_version(cls, version):
1809 continue
1810 if cls in type_maps.inheritance_map:
1811 gen_dup_inheritance(out, cls, version)
1812 elif loxi_utils.class_is_list(cls):
1813 gen_dup_list(out, cls, version)
1814 else:
1815 gen_dup_cls(out, cls, version)
1816
1817def gen_dup(out=sys.stdout):
1818 """
1819 Generate non-version specific duplication routines for each object type
1820 """
1821
1822 for cls in of_g.standard_class_order:
1823 out.write("""
1824%(cls)s_t *
1825%(cls)s_dup(
1826 %(cls)s_t *src)
1827{
1828""" % dict(cls=cls))
1829 for version in of_g.of_version_range:
1830 if not loxi_utils.class_in_version(cls, version):
1831 continue
1832 hdr = "header." if cls in type_maps.inheritance_map else ""
1833
1834 ver_name = loxi_utils.version_to_name(version)
1835 out.write("""
1836 if (src->%(hdr)sversion == %(ver_name)s) {
1837 return %(cls)s_%(ver_name)s_dup(src);
1838 }
1839""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1840
1841 out.write("""
1842 /* Class not supported in given version */
1843 return NULL;
1844}
1845""")
1846
1847def dup_c_gen(out, name):
1848 """
1849 Generate the C file for duplication functions
1850 """
1851 loxi_utils.gen_c_copy_license(out)
1852 out.write("""\
1853/*
1854 * Duplication functions for all OF objects
1855 *
1856 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1857 *
1858 * These are test functions for exercising accessors. You can call
1859 * of_object_dup for an efficient duplication.
1860 */
1861
1862#define DISABLE_WARN_UNUSED_RESULT
1863#include "loci_log.h"
1864#include <locitest/of_dup.h>
1865
1866""")
1867
1868 gen_version_dup(out)
1869 gen_dup(out)
1870
1871
1872def dup_h_gen(out, name):
1873 """
1874 Generate the header file for duplication functions
1875 """
1876
1877 loxi_utils.gen_c_copy_license(out)
1878 out.write("""
1879/*
1880 * Duplication function header file
1881 *
1882 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1883 */
1884
1885#if !defined(_OF_DUP_H_)
1886#define _OF_DUP_H_
1887
1888#include <loci/loci.h>
1889""")
1890
1891 for cls in of_g.standard_class_order:
1892 out.write("""
1893extern %(cls)s_t *
1894 %(cls)s_dup(
1895 %(cls)s_t *src);
1896""" % dict(cls=cls))
1897
1898 for version in of_g.of_version_range:
1899 for cls in of_g.standard_class_order:
1900 if not loxi_utils.class_in_version(cls, version):
1901 continue
1902 ver_name = loxi_utils.version_to_name(version)
1903 out.write("""
1904extern %(cls)s_t *
1905 %(cls)s_%(ver_name)s_dup(
1906 %(cls)s_t *src);
1907""" % dict(cls=cls, ver_name=ver_name))
1908
1909 out.write("\n#endif /* _OF_DUP_H_ */\n")
1910
1911def gen_log_test(out):
1912 """
1913 Generate test for obj log calls
1914
1915 Define a trivial handler for object logging; call all obj log fns
1916 """
1917 out.write("""
1918
1919/**
1920 * Test object dump functions
1921 */
1922
1923int
1924test_dump_objs(void)
1925{
1926 of_object_t *obj;
1927
1928 FILE *out = fopen("/dev/null", "w");
1929
1930 /* Call each obj dump function */
1931""")
1932 for version in of_g.of_version_range:
1933 for j, cls in enumerate(of_g.all_class_order):
1934 if not loxi_utils.class_in_version(cls, version):
1935 continue
1936 if cls in type_maps.inheritance_map:
1937 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001938 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1939 out.write("""
1940 obj = (of_object_t *)%(cls)s_new(%(version)s);
1941 {
1942 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1943 %(cls)s_vport_set(obj, vport);
1944 of_object_delete(vport);
1945 }
1946 of_object_dump((loci_writer_f)fprintf, out, obj);
1947 of_object_delete(obj);
1948""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1949 else:
1950 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001951 obj = (of_object_t *)%(cls)s_new(%(version)s);
1952 of_object_dump((loci_writer_f)fprintf, out, obj);
1953 of_object_delete(obj);
1954""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001955
Rich Lanea06d0c32013-03-25 08:52:03 -07001956 out.write("""
1957 fclose(out);
1958 return TEST_PASS;
1959}
1960""")
1961
1962def gen_ident_tests(out):
1963 """
1964 Generate tests for identifiers
1965
1966 For all idents, instantiate, test version supported macros
1967 For flags, set it, test it, clear it, test it.
1968 """
1969 out.write("""
1970/**
1971 * Test cases for all flag accessor macros
1972 * These only test self consistency (and that they compile)
1973 */
1974int
1975test_ident_macros(void)
1976{
1977 int value __attribute__((unused));
1978 uint32_t flags;
1979
1980""")
1981
1982 for ident, info in of_g.identifiers.items():
1983 if not identifiers.defined_versions_agree(of_g.identifiers,
1984 of_g.target_version_list,
1985 ident):
1986 # @fixme
1987 continue
1988 out.write(" value = %s;\n" % ident)
1989 for version in of_g.target_version_list:
1990 if version in info["values_by_version"].keys():
1991 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1992 (ident, of_g.of_version_wire2name[version]))
1993 else:
1994 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1995 (ident, of_g.of_version_wire2name[version]))
1996 if flags.ident_is_flag(ident):
1997 # Grab first supported version
1998 for version in info["values_by_version"]:
1999 break
2000 out.write("""
2001 flags = 0;
2002 %(ident)s_SET(flags, %(ver_name)s);
2003 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2004 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2005 %(ident)s_CLEAR(flags, %(ver_name)s);
2006 TEST_ASSERT(flags == 0);
2007 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2008""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2009
2010 out.write("""
2011 return TEST_PASS;
2012}
2013""")
2014
Rich Laneccae0312013-07-21 23:34:13 -07002015def gen_datafiles_tests(out, name):
2016 tests = []
2017 for filename in test_data.list_files():
2018 data = test_data.read(filename)
2019 if not 'c' in data:
2020 continue
2021 name = filename[:-5].replace("/", "_")
2022 tests.append(dict(name=name,
2023 filename=filename,
2024 c=data['c'],
2025 binary=data['binary']))
2026
2027 util.render_template(out, "test_data.c", tests=tests)