blob: d94691f9c93fba2bcba0c794b8a50c1a81f66290 [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
258 for key, entry in match.of_match_members.items():
259 out.write("""
Andreas Wundsam53256162013-05-02 14:05:53 -0700260 if (!(of_match_incompat[version] &
Rich Lanea06d0c32013-03-25 08:52:03 -0700261 OF_OXM_BIT(OF_OXM_INDEX_%(ku)s))) {
262 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
263 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
264 value += 1;
265 }
266
267""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
268
269 out.write("""
270 if (value % 2) {
271 /* Sometimes set ipv4 addr masks to non-exact */
272 match->masks.ipv4_src = 0xffff0000;
273 match->masks.ipv4_dst = 0xfffff800;
274 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700275
276 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700277 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700278 return value;
279}
280
281int
282of_match_check(of_match_t *match, of_version_t version, int value)
283{
284 of_match_t check;
285
286 value = of_match_populate(&check, match->version, value);
287 TEST_ASSERT(value != 0);
288 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
289
290 return value;
291}
292""")
293
294def gen_common_test_header(out, name):
295 loxi_utils.gen_c_copy_license(out)
296 out.write("""
297/*
298 * Test header file
299 *
300 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
301 */
302
303#if !defined(_TEST_COMMON_H_)
304#define _TEST_COMMON_H_
305
306#define DISABLE_WARN_UNUSED_RESULT
307#include <loci/loci.h>
308#include <locitest/of_dup.h>
309#include <locitest/unittest.h>
310
311extern int global_error;
312extern int exit_on_error;
313
314/* @todo Make option for -k to continue tests if errors */
315#define RUN_TEST(test) do { \\
316 int rv; \\
317 TESTCASE(test, rv); \\
318 if (rv != TEST_PASS) { \\
319 global_error=1; \\
320 if (exit_on_error) return(1); \\
321 } \\
322 } while(0)
323
324#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
325#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
326
327/*
328 * Declarations of functions to populate scalar values in a a class
329 */
330
331extern void of_test_str_fill(uint8_t *buf, int value, int len);
332extern int of_test_str_check(uint8_t *buf, int value, int len);
333
334
335extern int of_octets_populate(of_octets_t *octets, int value);
336extern int of_octets_check(of_octets_t *octets, int value);
337extern int of_match_populate(of_match_t *match, of_version_t version,
338 int value);
339extern int of_match_check(of_match_t *match, of_version_t version, int value);
340extern int test_ident_macros(void);
341extern int test_dump_objs(void);
342
343/* In test_match_utils.c */
344extern int test_match_utils(void);
345
346extern int run_unified_accessor_tests(void);
347extern int run_match_tests(void);
348extern int run_utility_tests(void);
349
350extern int run_scalar_acc_tests(void);
351extern int run_list_tests(void);
352extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700353
354extern int run_validator_tests(void);
355
356extern int run_list_limits_tests(void);
357
358extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700359extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700360
361""")
362
363 for version in of_g.of_version_range:
364 for cls in of_g.standard_class_order:
365 if not loxi_utils.class_in_version(cls, version):
366 continue
367 if cls in type_maps.inheritance_map:
368 continue
369 out.write("""
370extern int %(cls)s_%(v_name)s_populate(
371 %(cls)s_t *obj, int value);
372extern int %(cls)s_%(v_name)s_check(
373 %(cls)s_t *obj, int value);
374extern int %(cls)s_%(v_name)s_populate_scalars(
375 %(cls)s_t *obj, int value);
376extern int %(cls)s_%(v_name)s_check_scalars(
377 %(cls)s_t *obj, int value);
378""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
379
380 out.write("""
381/*
382 * Declarations for list population and check primitives
383 */
384""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700385
Rich Lanea06d0c32013-03-25 08:52:03 -0700386 for version in of_g.of_version_range:
387 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700388 if version in of_g.unified[cls]:
389 out.write("""
390extern int
391 list_setup_%(cls)s_%(v_name)s(
392 %(cls)s_t *list, int value);
393extern int
394 list_check_%(cls)s_%(v_name)s(
395 %(cls)s_t *list, int value);
396""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
397
398 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
399
400def gen_common_test(out, name):
401 """
402 Generate common test content including main
403 """
404 loxi_utils.gen_c_copy_license(out)
405 out.write("""
406/*
407 * Common test code for LOCI
408 *
409 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
410 */
411
412#define DISABLE_WARN_UNUSED_RESULT
413#include "loci_log.h"
414#include <loci/loci_obj_dump.h>
415#include <locitest/unittest.h>
416#include <locitest/test_common.h>
417
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900418/* mcheck is a glibc extension */
419#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700420#include <mcheck.h>
421#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900422#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700423#define MCHECK_INIT do { } while (0)
424#endif
425
426/**
427 * Exit on error if set to 1
428 */
429int exit_on_error = 1;
430
431/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700432 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700433 */
434int global_error = 0;
435
436extern int run_unified_accessor_tests(void);
437extern int run_match_tests(void);
438extern int run_utility_tests(void);
439
440extern int run_scalar_acc_tests(void);
441extern int run_list_tests(void);
442extern int run_message_tests(void);
443
444/**
445 * Macros for initializing and checking scalar types
446 *
447 * @param var The variable being initialized or checked
448 * @param val The integer value to set/check against, see below
449 *
450 * Note that equality means something special for strings. Each byte
451 * is initialized to an incrementing value. So check is done against that.
452 *
453 */
454
455""")
456 for t in scalar_types:
457 if t in integer_types:
458 out.write("""
459#define VAR_%s_INIT(var, val) var = (%s)(val)
460#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
461""" % (t.upper(), t, t.upper(), t))
462 else:
463 out.write("""
464#define VAR_%s_INIT(var, val) \\
465 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
466#define VAR_%s_CHECK(var, val) \\
467 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
468""" % (t.upper(), t.upper()))
469
470 gen_fill_string(out)
471 gen_scalar_set_check_funs(out)
472 gen_list_set_check_funs(out)
473 gen_unified_accessor_funs(out)
474
475 gen_ident_tests(out)
476 gen_log_test(out)
477
478def gen_message_scalar_test(out, name):
479 """
480 Generate test cases for message objects, scalar accessors
481 """
482
483 loxi_utils.gen_c_copy_license(out)
484 out.write("""
485/**
486 *
487 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
488 *
489 * Message-scalar tests for all versions
490 */
491
492#include <locitest/test_common.h>
493""")
494 for version in of_g.of_version_range:
495 v_name = loxi_utils.version_to_name(version)
496 out.write("""
497/**
498 * Message-scalar tests for version %s
499 */
500""" % v_name)
501 for cls in of_g.standard_class_order:
502 if cls in type_maps.inheritance_map:
503 continue
504 if version in of_g.unified[cls]:
505 message_scalar_test(out, version, cls)
506
507 out.write("""
508int
509run_scalar_acc_tests(void)
510{
511""")
512 for version in of_g.of_version_range:
513 v_name = loxi_utils.version_to_name(version)
514 for cls in of_g.standard_class_order:
515 if cls in type_maps.inheritance_map:
516 continue
517 if version in of_g.unified[cls]:
518 test_name = "%s_%s" % (cls, v_name)
519 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
520
521 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700522
Rich Lanea06d0c32013-03-25 08:52:03 -0700523def message_scalar_test(out, version, cls):
524 """
525 Generate one test case for the given version and class
526 """
527
528 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700529 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700530 v_name = loxi_utils.version_to_name(version)
531
532 out.write("""
533static int
534test_%(cls)s_%(v_name)s_scalar(void)
535{
536 %(cls)s_t *obj;
537
538 obj = %(cls)s_new(%(v_name)s);
539 TEST_ASSERT(obj != NULL);
540 TEST_ASSERT(obj->version == %(v_name)s);
541 TEST_ASSERT(obj->length == %(length)d);
542 TEST_ASSERT(obj->parent == NULL);
543 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700544""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700545 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700546
547 # If this class is a concrete member of an inheritance hierarchy,
548 # run the hierarchy's root wire type parser and assert it returns
549 # the expected object id.
550 ofclass = loxi_globals.unified.class_by_name(cls)
551 if ofclass and not ofclass.virtual:
552 root = ofclass
553 while root.superclass:
554 root = root.superclass
555 if root.virtual:
556 out.write("""
557 {
558 of_object_id_t object_id;
559 %(root_cls)s_wire_object_id_get(obj, &object_id);
560 TEST_ASSERT(object_id == %(u_cls)s);
561 }
562""" % dict(root_cls=root.name, u_cls=cls.upper()))
563
Rich Lanea06d0c32013-03-25 08:52:03 -0700564 if not type_maps.class_is_virtual(cls):
565 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700566 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700567 int length;
568
Rich Lanedc46fe22014-04-03 15:10:38 -0700569 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700570 TEST_ASSERT(length == %(length)d);
571 }
572
573 /* Set up incrementing values for scalar members */
574 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
575
576 /* Check values just set */
577 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700578""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700579 v_name=v_name, length=length, version=version))
580
581 out.write("""
582 %(cls)s_delete(obj);
583
584 /* To do: Check memory */
585 return TEST_PASS;
586}
587""" % dict(cls=cls))
588
589# Get the members and list of scalar types for members of a given class
590def scalar_member_types_get(cls, version):
591 member_types = []
592
593 if not version in of_g.unified[cls]:
594 return ([], [])
595
596 if "use_version" in of_g.unified[cls][version]:
597 v = of_g.unified[cls][version]["use_version"]
598 members = of_g.unified[cls][v]["members"]
599 else:
600 members = of_g.unified[cls][version]["members"]
601 # Accumulate variables that are supported
602 for member in members:
603 m_type = member["m_type"]
604 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700605 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700606 ignore_member(cls, version, m_name, m_type)):
607 continue
608 if not m_type in member_types:
609 member_types.append(m_type)
610
611 return (members, member_types)
612
613def scalar_funs_instance(out, cls, version, members, member_types):
614 """
615 Generate one instance of scalar set/check functions
616 """
617 out.write("""
618/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700619 * Populate the scalar values in obj of type %(cls)s,
620 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700621 * @param obj Pointer to an object to populate
622 * @param value The seed value to use in populating the object
623 * @returns The value after increments for this object's values
624 */
625int %(cls)s_%(v_name)s_populate_scalars(
626 %(cls)s_t *obj, int value) {
627""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
628 # Declare string types
629 for t in member_types:
630 out.write(" %s %s;\n" % (t, var_name_map(t)))
631 for member in members:
632 m_type = member["m_type"]
633 m_name = member["name"]
634 if (not loxi_utils.type_is_scalar(m_type) or
635 ignore_member(cls, version, m_name, m_type)):
636 continue
637 v_name = var_name_map(m_type);
638 out.write("""
639 VAR_%(u_type)s_INIT(%(v_name)s, value);
640 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
641 value += 1;
642""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
643 out.write("""
644 return value;
645}
646""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700647
Rich Lanea06d0c32013-03-25 08:52:03 -0700648 out.write("""
649/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700650 * Check scalar values in obj of type %(cls)s,
651 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700652 * @param obj Pointer to an object to check
653 * @param value Starting value for checking
654 * @returns The value after increments for this object's values
655 */
656int %(cls)s_%(v_name)s_check_scalars(
657 %(cls)s_t *obj, int value) {
658""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
659
660 for t in member_types:
661 out.write(" %s %s;\n" % (t, var_name_map(t)))
662 for member in members:
663 m_type = member["m_type"]
664 m_name = member["name"]
665 if (not loxi_utils.type_is_scalar(m_type) or
666 ignore_member(cls, version, m_name, m_type)):
667 continue
668 v_name = var_name_map(m_type);
669 out.write("""
670 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
671 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
672 value += 1;
673""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
674
675 out.write("""
676 return value;
677}
678
679""")
680
681def gen_scalar_set_check_funs(out):
682 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700683 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700684 set and check their values
685 """
686 for version in of_g.of_version_range:
687 for cls in of_g.standard_class_order:
688 (members, member_types) = scalar_member_types_get(cls, version)
689 scalar_funs_instance(out, cls, version, members, member_types)
690
691
692# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700693def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700694 base_type = loxi_utils.list_to_entry_type(cls)
695 setup_template = """
696 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700697 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700698 (%(base_type)s_t *)%(inst)s);
699 value = %(subcls)s_%(v_name)s_populate(
700 %(inst)s, value);
701 cur_len += %(inst)s->length;
702 TEST_ASSERT(list->length == cur_len);
703"""
704 out.write("""
705 /* Append two instances of type %s */
706""" % subcls)
707 for i in range(2):
708 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700709 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700710 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700711 version=version))
712
Rich Lane9afc3b92014-04-09 22:55:53 -0700713def check_instance(out, cls, subcls, instance, v_name, version, last):
714 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700715 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
716 value = %(subcls)s_%(v_name)s_check(
717 %(inst)s, value);
718 TEST_ASSERT(value != 0);
719"""
720 out.write("\n /* Check two instances of type %s */" % instance)
721
Andreas Wundsam53256162013-05-02 14:05:53 -0700722 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700723 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700724 inst=instance, subcls=subcls,
725 v_name=loxi_utils.version_to_name(version)))
726 out.write("""\
727 TEST_OK(%(cls)s_next(list, &elt));
728""" % dict(cls=cls))
729
Andreas Wundsam53256162013-05-02 14:05:53 -0700730 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700731 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700732 inst=instance, subcls=subcls,
733 v_name=loxi_utils.version_to_name(version)))
734 if last:
735 out.write("""\
736 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
737""" % dict(cls=cls))
738 else:
739 out.write("""\
740 TEST_OK(%(cls)s_next(list, &elt));
741""" % dict(cls=cls))
742
743def setup_list_fn(out, version, cls):
744 """
745 Generate a helper function that populates a list with two
746 of each type of subclass it supports
747 """
748 out.write("""
749/**
750 * Set up a list of type %(cls)s with two of each type of subclass
751 */
752int
753list_setup_%(cls)s_%(v_name)s(
754 %(cls)s_t *list, int value)
755{
756""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
757 base_type = loxi_utils.list_to_entry_type(cls)
758 out.write("""
759 %(base_type)s_t elt;
760 int cur_len = 0;
761""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700762
Rich Lanea06d0c32013-03-25 08:52:03 -0700763 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700764 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 -0700765 v_name = loxi_utils.version_to_name(version)
766
767 if len(sub_classes) == 0:
768 out.write(" /* No subclasses for %s */\n"% base_type)
769 out.write(" %s_t *elt_p;\n" % base_type)
770 out.write("\n elt_p = &elt;\n")
771 else:
772 out.write(" /* Declare pointers for each subclass */\n")
773 for instance, subcls in sub_classes:
774 out.write(" %s_t *%s;\n" % (subcls, instance))
775 out.write("\n /* Instantiate pointers for each subclass */\n")
776 for instance, subcls in sub_classes:
777 out.write(" %s = &elt.%s;\n" % (instance, instance))
778
779 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700780 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700781 else:
782 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700783 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700784 out.write("""
785
786 return value;
787}
788""")
789
790def check_list_fn(out, version, cls):
791 """
792 Generate a helper function that checks a list populated by above fn
793 """
794 out.write("""
795/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700796 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700797 * list_setup_%(cls)s_%(v_name)s
798 */
799int
800list_check_%(cls)s_%(v_name)s(
801 %(cls)s_t *list, int value)
802{
803""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
804 base_type = loxi_utils.list_to_entry_type(cls)
805 out.write("""
806 %(base_type)s_t elt;
807""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700808
Rich Lanea06d0c32013-03-25 08:52:03 -0700809 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700810 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 -0700811 v_name = loxi_utils.version_to_name(version)
812
813 if len(sub_classes) == 0:
814 out.write(" /* No subclasses for %s */\n"% base_type)
815 out.write(" %s_t *elt_p;\n" % base_type)
816 out.write("\n elt_p = &elt;\n")
817 else:
818 out.write(" /* Declare pointers for each subclass */\n")
819 for instance, subcls in sub_classes:
820 out.write(" %s_t *%s;\n" % (subcls, instance))
821 out.write("\n /* Instantiate pointers for each subclass */\n")
822 for instance, subcls in sub_classes:
823 out.write(" %s = &elt.%s;\n" % (instance, instance))
824
825 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
826 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700827 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700828 else:
829 count = 0
830 for instance, subcls in sub_classes:
831 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700832 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700833 version, count==len(sub_classes))
834
835 out.write("""
836 return value;
837}
838""" % dict(base_type=base_type))
839
840def gen_list_set_check_funs(out):
841 for version in of_g.of_version_range:
842 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700843 if version in of_g.unified[cls]:
844 setup_list_fn(out, version, cls)
845 check_list_fn(out, version, cls)
846
847# Maybe: Get a map from list class to parent, mem_name of container
848
849def list_test(out, version, cls):
850 out.write("""
851static int
852test_%(cls)s_%(v_name)s(void)
853{
854""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
855 base_type = loxi_utils.list_to_entry_type(cls)
856
857 out.write(""" %(cls)s_t *list;
858 int value = 1;
859""" % dict(cls=cls, base_type=base_type))
860
861 out.write("""
862 list = %(cls)s_new(%(v_name)s);
863 TEST_ASSERT(list != NULL);
864 TEST_ASSERT(list->version == %(v_name)s);
865 TEST_ASSERT(list->length == 0);
866 TEST_ASSERT(list->parent == NULL);
867 TEST_ASSERT(list->object_id == %(enum_cls)s);
868
869 value = list_setup_%(cls)s_%(v_name)s(list, value);
870 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700871""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700872 enum_cls=loxi_utils.enum_name(cls)))
873
874 out.write("""
875 /* Now check values */
876 value = 1;
877 value = list_check_%(cls)s_%(v_name)s(list, value);
878 TEST_ASSERT(value != 0);
879""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
880
881 out.write("""
882 %(cls)s_delete(list);
883
884 return TEST_PASS;
885}
886""" % dict(cls=cls))
887
888def gen_list_test(out, name):
889 """
890 Generate base line test cases for lists
891 @param out The file handle to write to
892 """
893
894 loxi_utils.gen_c_copy_license(out)
895 out.write("""
896/**
897 *
898 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
899 *
900 * Message-scalar tests for all versions
901 */
902
903#include <locitest/test_common.h>
904""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700905
Rich Lanea06d0c32013-03-25 08:52:03 -0700906 for version in of_g.of_version_range:
907 v_name = loxi_utils.version_to_name(version)
908 out.write("""
909/**
910 * Baseline list tests for version %s
911 */
912""" % v_name)
913 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700914 if version in of_g.unified[cls]:
915 list_test(out, version, cls)
916
917 out.write("""
918int
919run_list_tests(void)
920{
921""")
922 for version in of_g.of_version_range:
923 v_name = loxi_utils.version_to_name(version)
924 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700925 if version in of_g.unified[cls]:
926 test_name = "%s_%s" % (cls, v_name)
927 out.write(" RUN_TEST(%s);\n" % test_name)
928
929 out.write("\n return TEST_PASS;\n}\n");
930
931def gen_match_test(out, name):
932 """
933 Generate baseline tests for match functions
934 """
935
936 loxi_utils.gen_c_copy_license(out)
937 out.write("""\
938/**
939 *
940 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
941 *
942 * Message-scalar tests for all versions
943 * @fixme These are mostly hard coded now.
944 */
945
946#include <locitest/test_common.h>
947
948static int
949test_match_1(void)
950{
951 of_match_v1_t *m_v1;
952 of_match_v2_t *m_v2;
953 of_match_v3_t *m_v3;
954 of_match_v4_t *m_v4;
955 of_match_t match;
956 int value = 1;
957 int idx;
958 uint32_t exp_value;
959
960 /* Verify default values for ip mask map */
961 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
962 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
963 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
964 if (idx < 32) {
965 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
966 }
967 }
968
969 TEST_ASSERT(of_ip_mask_map_set(17, 0xabcdef00) == OF_ERROR_NONE);
970 TEST_ASSERT(of_ip_mask_to_index(0xabcdef00) == 17);
971 TEST_ASSERT(of_ip_index_to_mask(17) == 0xabcdef00);
972
973 TEST_ASSERT(of_ip_mask_map_set(62, 0xabcdefff) == OF_ERROR_NONE);
974 TEST_ASSERT(of_ip_mask_to_index(0xabcdefff) == 62);
975 TEST_ASSERT(of_ip_index_to_mask(62) == 0xabcdefff);
976
977 /* Test re-init */
978 of_ip_mask_map_init();
979 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
980 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
981 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
982 if (idx < 32) {
983 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
984 }
985 }
986""")
987
988 for version in of_g.of_version_range:
989 out.write("""
990 /* Create/populate/convert and delete for version %(v_name)s */
991 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
992 TEST_ASSERT(m_v%(version)d != NULL);
993 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
994 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
995 of_match_v%(version)d_delete(m_v%(version)d);
996""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
997
998 out.write("""
999 return TEST_PASS;
1000}
1001""")
1002
1003 out.write("""
1004static int
1005test_match_2(void)
1006{
1007 of_match_v1_t *m_v1;
1008 of_match_v2_t *m_v2;
1009 of_match_v3_t *m_v3;
1010 of_match_v3_t *m_v4;
1011 of_match_t match1;
1012 of_match_t match2;
1013 int value = 1;
1014""")
1015
1016 for version in of_g.of_version_range:
1017 out.write("""
1018 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1019 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1020 TEST_ASSERT(m_v%(version)d != NULL);
1021 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1022 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1023 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1024 of_match_v%(version)d_delete(m_v%(version)d);
1025""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1026
1027 out.write("""
1028 return TEST_PASS;
1029}
1030""")
1031
1032 out.write("""
1033static int
1034test_match_3(void)
1035{
1036 of_match_t match1;
1037 of_match_t match2;
1038 int value = 1;
1039 of_octets_t octets;
1040""")
1041 for version in of_g.of_version_range:
1042 out.write("""
1043 /* Serialize to version %(v_name)s */
1044 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001045 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001046 OF_ERROR_NONE);
Andreas Wundsam53256162013-05-02 14:05:53 -07001047 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001048 OF_ERROR_NONE);
1049 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1050 FREE(octets.data);
1051""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1052
1053 out.write("""
1054 return TEST_PASS;
1055}
1056""")
1057
1058 out.write("""
1059int run_match_tests(void)
1060{
1061 RUN_TEST(match_1);
1062 RUN_TEST(match_2);
1063 RUN_TEST(match_3);
1064 RUN_TEST(match_utils);
1065
1066 return TEST_PASS;
1067}
1068""")
1069
1070def gen_msg_test(out, name):
1071 loxi_utils.gen_c_copy_license(out)
1072 out.write("""
1073/**
1074 *
1075 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1076 *
1077 * Message-scalar tests for all versions
1078 */
1079
1080#include <locitest/test_common.h>
1081""")
1082 for version in of_g.of_version_range:
1083 for cls in of_g.ordered_messages:
1084 if not (cls, version) in of_g.base_length:
1085 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001086 if type_maps.class_is_virtual(cls):
1087 continue
Rich Lanef70be942013-07-18 13:33:14 -07001088 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001089 out.write("""
1090static int
1091test_%(cls)s_create_%(v_name)s(void)
1092{
1093 %(cls)s_t *obj;
1094 uint8_t *msg_buf;
1095 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001096 of_object_id_t object_id;
Rich Lanea06d0c32013-03-25 08:52:03 -07001097
1098 obj = %(cls)s_new(%(v_name)s);
1099 TEST_ASSERT(obj != NULL);
1100 TEST_ASSERT(obj->version == %(v_name)s);
1101 TEST_ASSERT(obj->length == %(bytes)d);
1102 TEST_ASSERT(obj->parent == NULL);
1103 TEST_ASSERT(obj->object_id == %(enum)s);
1104
Rich Lanea4b68302014-03-12 15:17:58 -07001105 of_header_wire_object_id_get(obj, &object_id);
1106 TEST_ASSERT(object_id == %(enum)s);
1107
Rich Lanea06d0c32013-03-25 08:52:03 -07001108 /* Set up incrementing values for scalar members */
1109 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1110 TEST_ASSERT(value != 0);
1111
1112 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001113 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1114 TEST_ASSERT(msg_buf != NULL);
1115 %(cls)s_delete(obj);
Rich Lanea06d0c32013-03-25 08:52:03 -07001116 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1117
1118 TEST_ASSERT(obj != NULL);
1119
1120 /* @fixme Set up all message objects (recursively?) */
1121
1122 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1123 TEST_ASSERT(value != 0);
1124
1125 %(cls)s_delete(obj);
1126
1127 return TEST_PASS;
1128}
1129""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1130 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1131
1132 out.write("""
1133int
1134run_message_tests(void)
1135{
1136""")
1137 for version in of_g.of_version_range:
1138 for cls in of_g.ordered_messages:
1139 if not (cls, version) in of_g.base_length:
1140 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001141 if type_maps.class_is_virtual(cls):
1142 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001143 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1144 out.write(" RUN_TEST(%s);\n" % test_name)
1145
1146 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001147
Rich Lanea06d0c32013-03-25 08:52:03 -07001148
1149def gen_list_setup_check(out, cls, version):
1150 """
1151 Generate functions that populate and check a list with two
1152 of each type of subclass it supports
1153 """
1154 out.write("""
1155/**
1156 * Populate a list of type %(cls)s with two of each type of subclass
1157 * @param list Pointer to the list to be populated
1158 * @param value The seed value to use in populating the list
1159 * @returns The value after increments for this object's values
1160 */
1161int
1162%(cls)s_%(v_name)s_populate(
1163 %(cls)s_t *list, int value)
1164{
1165""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1166 base_type = loxi_utils.list_to_entry_type(cls)
1167 out.write("""
1168 %(base_type)s_t elt;
1169 int cur_len = 0;
1170""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001171
Rich Lanea06d0c32013-03-25 08:52:03 -07001172 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001173 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 -07001174 v_name = loxi_utils.version_to_name(version)
1175
1176 if len(sub_classes) == 0:
1177 out.write(" /* No subclasses for %s */\n"% base_type)
1178 out.write(" %s_t *elt_p;\n" % base_type)
1179 out.write("\n elt_p = &elt;\n")
1180 else:
1181 out.write(" /* Declare pointers for each subclass */\n")
1182 for instance, subcls in sub_classes:
1183 out.write(" %s_t *%s;\n" % (subcls, instance))
1184 out.write("\n /* Instantiate pointers for each subclass */\n")
1185 for instance, subcls in sub_classes:
1186 out.write(" %s = &elt.%s;\n" % (instance, instance))
1187
Rich Lanea06d0c32013-03-25 08:52:03 -07001188 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001189 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001190 else:
1191 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001192 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001193 out.write("""
1194 return value;
1195}
1196""")
1197 out.write("""
1198/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001199 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001200 * %(cls)s_%(v_name)s_populate
1201 * @param list Pointer to the list that was populated
1202 * @param value Starting value for checking
1203 * @returns The value after increments for this object's values
1204 */
1205int
1206%(cls)s_%(v_name)s_check(
1207 %(cls)s_t *list, int value)
1208{
1209""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1210 base_type = loxi_utils.list_to_entry_type(cls)
1211 out.write("""
1212 %(base_type)s_t elt;
1213 int count = 0;
1214 int rv;
1215""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001216
Rich Lanea06d0c32013-03-25 08:52:03 -07001217
1218 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001219 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 -07001220 v_name = loxi_utils.version_to_name(version)
1221
1222 if len(sub_classes) == 0:
1223 entry_count = 2
1224 out.write(" /* No subclasses for %s */\n"% base_type)
1225 out.write(" %s_t *elt_p;\n" % base_type)
1226 out.write("\n elt_p = &elt;\n")
1227 else:
1228 entry_count = 2 * len(sub_classes) # Two of each type appended
1229 out.write(" /* Declare pointers for each subclass */\n")
1230 for instance, subcls in sub_classes:
1231 out.write(" %s_t *%s;\n" % (subcls, instance))
1232 out.write("\n /* Instantiate pointers for each subclass */\n")
1233 for instance, subcls in sub_classes:
1234 out.write(" %s = &elt.%s;\n" % (instance, instance))
1235
1236 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1237 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001238 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001239 version, True)
1240 else:
1241 count = 0
1242 for instance, subcls in sub_classes:
1243 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001244 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001245 version, count==len(sub_classes))
1246 out.write("""
1247""" % dict(base_type=base_type))
1248
1249 out.write("""
1250 /* Do an iterate to test the iterator */
1251 %(u_cls)s_ITER(list, &elt, rv) {
1252 count += 1;
1253 }
1254
1255 TEST_ASSERT(rv == OF_ERROR_RANGE);
1256 TEST_ASSERT(count == %(entry_count)d);
1257
1258 /* We shoehorn a test of the dup functions here */
1259 {
1260 %(cls)s_t *dup;
1261
1262 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1263 TEST_ASSERT(dup->length == list->length);
1264 TEST_ASSERT(dup->object_id == list->object_id);
1265 TEST_ASSERT(dup->version == list->version);
1266 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1267 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1268 of_object_delete((of_object_t *)dup);
1269
1270 /* And now for the generic dup function */
1271 TEST_ASSERT((dup = (%(cls)s_t *)
1272 of_object_dup(list)) != NULL);
1273 TEST_ASSERT(dup->length == list->length);
1274 TEST_ASSERT(dup->object_id == list->object_id);
1275 TEST_ASSERT(dup->version == list->version);
1276 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1277 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1278 of_object_delete((of_object_t *)dup);
1279 }
1280
1281 return value;
1282}
1283""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1284
1285
1286def gen_class_setup_check(out, cls, version):
1287 out.write("""
1288/**
1289 * Populate all members of an object of type %(cls)s
1290 * with incrementing values
1291 * @param obj Pointer to an object to populate
1292 * @param value The seed value to use in populating the object
1293 * @returns The value after increments for this object's values
1294 */
1295
1296int
1297%(cls)s_%(v_name)s_populate(
1298 %(cls)s_t *obj, int value)
1299{
1300""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1301 members, member_types = loxi_utils.all_member_types_get(cls, version)
1302 for m_type in member_types:
1303 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1304 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001305 elif m_type == "of_bsn_vport_header_t":
1306 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001307 else:
1308 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1309 out.write("""
1310 /* Run thru accessors after new to ensure okay */
1311""")
1312 for member in members:
1313 m_type = member["m_type"]
1314 m_name = member["name"]
1315 if loxi_utils.skip_member_name(m_name):
1316 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001317 if m_type == "of_bsn_vport_header_t":
1318 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001319 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1320 out.write("""\
1321 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1322""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1323 else:
1324 sub_cls = m_type[:-2] # Trim _t
1325 out.write("""\
1326 {
1327 %(sub_cls)s_t sub_cls;
1328
1329 /* Test bind */
1330 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1331 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001332""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001333 m_name=m_name, sub_cls=sub_cls,
1334 v_name=loxi_utils.version_to_name(version)))
1335
1336 out.write("""
1337 value = %(cls)s_%(v_name)s_populate_scalars(
1338 obj, value);
1339 TEST_ASSERT(value != 0);
1340""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1341
1342 for member in members:
1343 m_type = member["m_type"]
1344 m_name = member["name"]
1345 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1346 continue
1347 if loxi_utils.skip_member_name(m_name):
1348 continue
1349 if m_type == "of_match_t":
1350 out.write("""\
1351 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1352 TEST_ASSERT(value != 0);
1353 %(cls)s_%(m_name)s_set(
1354 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001355""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001356 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1357 elif m_type == "of_octets_t":
1358 out.write("""\
1359 value = of_octets_populate(&%(var_name)s, value);
1360 TEST_ASSERT(value != 0);
1361 %(cls)s_%(m_name)s_set(
1362 obj, &%(var_name)s);
1363 if (octets.bytes) {
1364 FREE(octets.data);
1365 }
1366""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001367 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1368 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001369 out.write("""\
1370 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1371 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001372 value = %(sub_cls)s_%(v_name)s_populate(
1373 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001374 TEST_ASSERT(value != 0);
1375 %(cls)s_%(m_name)s_set(
1376 obj, %(var_name)s);
1377 %(sub_cls)s_delete(%(var_name)s);
1378""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1379 var_name=var_name_map(m_type),
1380 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001381 else:
1382 sub_cls = m_type[:-2] # Trim _t
1383 out.write("""
1384 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1385 TEST_ASSERT(%(var_name)s != NULL);
1386 value = %(sub_cls)s_%(v_name)s_populate(
1387 %(var_name)s, value);
1388 TEST_ASSERT(value != 0);
1389 %(cls)s_%(m_name)s_set(
1390 obj, %(var_name)s);
1391 %(sub_cls)s_delete(%(var_name)s);
1392""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1393 var_name=var_name_map(m_type),
1394 v_name=loxi_utils.version_to_name(version)))
1395
1396 out.write("""
1397 return value;
1398}
1399""")
1400
1401 out.write("""
1402/**
1403 * Check all members of an object of type %(cls)s
1404 * populated by the above function
1405 * @param obj Pointer to an object to check
1406 * @param value Starting value for checking
1407 * @returns The value after increments for this object's values
1408 */
1409
1410int
1411%(cls)s_%(v_name)s_check(
1412 %(cls)s_t *obj, int value)
1413{
1414""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1415 members, member_types = loxi_utils.all_member_types_get(cls, version)
1416 for m_type in member_types:
1417 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1418 continue
1419 if loxi_utils.type_is_of_object(m_type):
1420 continue
1421 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1422 out.write("""
1423 value = %(cls)s_%(v_name)s_check_scalars(
1424 obj, value);
1425 TEST_ASSERT(value != 0);
1426""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1427
1428 for member in members:
1429 m_type = member["m_type"]
1430 m_name = member["name"]
1431 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1432 continue
1433 if loxi_utils.skip_member_name(m_name):
1434 continue
1435 if m_type == "of_match_t":
1436 out.write("""\
1437 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1438 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1439""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1440 v_name=loxi_utils.version_to_name(version)))
1441 elif m_type == "of_octets_t":
1442 out.write("""\
1443 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1444 value = of_octets_check(&%(var_name)s, value);
1445""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1446 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001447 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1448 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001449 out.write("""
1450 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001451 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001452
1453 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1454 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001455 value = %(sub_cls)s_%(v_name)s_check(
1456 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001457 TEST_ASSERT(value != 0);
1458 %(sub_cls)s_delete(%(m_name)s_ptr);
1459 }
1460""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1461 var_name=var_name_map(m_type),
1462 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001463 else:
1464 sub_cls = m_type[:-2] # Trim _t
1465 out.write("""
1466 { /* Use get/delete to access on check */
1467 %(m_type)s *%(m_name)s_ptr;
1468
1469 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1470 TEST_ASSERT(%(m_name)s_ptr != NULL);
1471 value = %(sub_cls)s_%(v_name)s_check(
1472 %(m_name)s_ptr, value);
1473 TEST_ASSERT(value != 0);
1474 %(sub_cls)s_delete(%(m_name)s_ptr);
1475 }
1476""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1477 var_name=var_name_map(m_type),
1478 v_name=loxi_utils.version_to_name(version)))
1479
1480 out.write("""
1481 /* We shoehorn a test of the dup functions here */
1482 {
1483 %(cls)s_t *dup;
1484
1485 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1486 TEST_ASSERT(dup->length == obj->length);
1487 TEST_ASSERT(dup->object_id == obj->object_id);
1488 TEST_ASSERT(dup->version == obj->version);
1489 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1490 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1491 of_object_delete((of_object_t *)dup);
1492
1493 /* And now for the generic dup function */
1494 TEST_ASSERT((dup = (%(cls)s_t *)
1495 of_object_dup(obj)) != NULL);
1496 TEST_ASSERT(dup->length == obj->length);
1497 TEST_ASSERT(dup->object_id == obj->object_id);
1498 TEST_ASSERT(dup->version == obj->version);
1499 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1500 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1501 of_object_delete((of_object_t *)dup);
1502 }
1503
1504 return value;
1505}
1506""" % dict(cls=cls))
1507
1508def unified_accessor_test_case(out, cls, version):
1509 """
1510 Generate one test case for the given version and class
1511 """
1512
1513 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001514 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001515 v_name = loxi_utils.version_to_name(version)
1516
1517 out.write("""
1518static int
1519test_%(cls)s_%(v_name)s(void)
1520{
1521 %(cls)s_t *obj;
1522 obj = %(cls)s_new(%(v_name)s);
1523 TEST_ASSERT(obj != NULL);
1524 TEST_ASSERT(obj->version == %(v_name)s);
1525 TEST_ASSERT(obj->length == %(length)d);
1526 TEST_ASSERT(obj->parent == NULL);
1527 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001528""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001529 v_name=v_name, length=length, version=version))
1530 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1531 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001532 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001533 int length;
1534
Rich Lanedc46fe22014-04-03 15:10:38 -07001535 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001536 TEST_ASSERT(length == %(length)d);
1537 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001538 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001539 of_object_id_t obj_id;
1540
Rich Lanedc46fe22014-04-03 15:10:38 -07001541 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001542 TEST_ASSERT(obj_id == %(u_cls)s);
1543 }
1544
1545 /* Set up incrementing values for members */
1546 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1547 obj, 1) != 0);
1548
1549 /* Check values just set */
1550 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1551 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001552""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001553 v_name=v_name, length=length, version=version))
1554
1555 out.write("""
1556 %(cls)s_delete(obj);
1557
1558 /* To do: Check memory */
1559 return TEST_PASS;
1560}
1561""" % dict(cls=cls))
1562
1563
1564def gen_unified_accessor_funs(out):
1565 for version in of_g.of_version_range:
1566 for cls in of_g.standard_class_order:
1567 if not loxi_utils.class_in_version(cls, version):
1568 continue
1569 if cls in type_maps.inheritance_map:
1570 continue
1571 elif loxi_utils.class_is_list(cls):
1572 gen_list_setup_check(out, cls, version)
1573 else:
1574 gen_class_setup_check(out, cls, version)
1575
1576def gen_unified_accessor_tests(out, name):
1577 loxi_utils.gen_c_copy_license(out)
1578 out.write("""
1579/**
1580 *
1581 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1582 *
1583 * Unified simple class instantiation tests for all versions
1584 */
1585
1586#include <locitest/test_common.h>
1587""")
1588 for version in of_g.of_version_range:
1589 for cls in of_g.standard_class_order:
1590 if not loxi_utils.class_in_version(cls, version):
1591 continue
1592 if cls in type_maps.inheritance_map:
1593 continue
1594 unified_accessor_test_case(out, cls, version)
1595
1596 out.write("""
1597int
1598run_unified_accessor_tests(void)
1599{
1600""")
1601 for version in of_g.of_version_range:
1602 v_name = loxi_utils.version_to_name(version)
1603 for cls in of_g.standard_class_order:
1604 if not loxi_utils.class_in_version(cls, version):
1605 continue
1606 if cls in type_maps.inheritance_map:
1607 continue
1608 test_name = "%s_%s" % (cls, v_name)
1609 out.write(" RUN_TEST(%s);\n" % test_name)
1610
1611 out.write(" return TEST_PASS;\n}\n");
1612
1613
1614
1615################################################################
1616#
1617# Object duplication functions
1618#
1619# These exercise the accessors to create duplicate objects.
1620# They are used in the LOCI test shim which sits in an OF
1621# protocol stream.
1622#
1623# TODO
1624# Resolve version stuff
1625# Complete list dup
1626
1627def gen_dup_list(out, cls, version):
1628 ver_name = loxi_utils.version_to_name(version)
1629 elt_type = loxi_utils.list_to_entry_type(cls)
1630 out.write("""
1631/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001632 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001633 * using accessor functions
1634 * @param src Pointer to object to be duplicated
1635 * @returns A new object of type %(cls)s.
1636 *
1637 * The caller is responsible for deleting the returned value
1638 */
1639%(cls)s_t *
1640%(cls)s_%(ver_name)s_dup(
1641 %(cls)s_t *src)
1642{
1643 %(elt_type)s_t src_elt;
1644 %(elt_type)s_t *dst_elt;
1645 int rv;
1646 %(cls)s_t *dst;
1647
1648 if ((dst = %(cls)s_new(src->version)) == NULL) {
1649 return NULL;
1650 }
1651""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1652
1653 out.write("""
1654 %(u_cls)s_ITER(src, &src_elt, rv) {
1655 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1656 of_object_delete((of_object_t *)dst);
1657 return NULL;
1658 }
1659 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1660 dst, NULL);
1661 of_object_delete((of_object_t *)dst_elt);
1662 }
1663
1664 return dst;
1665}
1666""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1667
1668
1669def gen_dup_inheritance(out, cls, version):
1670 ver_name = loxi_utils.version_to_name(version)
1671 out.write("""
1672/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001673 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001674 * @param src Pointer to object to be duplicated
1675 * @returns A new object of type %(cls)s.
1676 *
1677 * The caller is responsible for deleting the returned value
1678 */
1679%(cls)s_t *
1680%(cls)s_%(ver_name)s_dup(
1681 %(cls)s_t *src)
1682{
1683""" % dict(cls=cls, ver_name=ver_name))
1684
1685 # For each subclass, check if this is an instance of that subclass
1686 version_classes = type_maps.inheritance_data[cls][version]
1687 for sub_cls in version_classes:
1688 sub_enum = (cls + "_" + sub_cls).upper()
1689 out.write("""
1690 if (src->header.object_id == %(sub_enum)s) {
1691 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1692 &src->%(sub_cls)s);
1693 }
1694""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1695
1696 out.write("""
1697 return NULL;
1698}
1699""")
1700
1701
1702def gen_dup_cls(out, cls, version):
1703 """
1704 Generate duplication routine for class cls
1705 """
1706 ver_name = loxi_utils.version_to_name(version)
1707
1708 out.write("""
1709/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001710 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001711 * using accessor functions
1712 * @param src Pointer to object to be duplicated
1713 * @returns A new object of type %(cls)s.
1714 *
1715 * The caller is responsible for deleting the returned value
1716 */
1717%(cls)s_t *
1718%(cls)s_%(ver_name)s_dup(
1719 %(cls)s_t *src)
1720{
1721 %(cls)s_t *dst;
1722""" % dict(cls=cls, ver_name=ver_name))
1723
1724 # Get members and types for the class
1725 members, member_types = loxi_utils.all_member_types_get(cls, version)
1726
1727 # Add declarations for each member type
1728 for m_type in member_types:
1729 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1730 # Declare instance of these
1731 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001732 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1733 out.write("""
1734 of_bsn_vport_q_in_q_t src_%(v_name)s;
1735 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1736""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001737 else:
1738 out.write("""
1739 %(m_type)s src_%(v_name)s;
1740 %(m_type)s *dst_%(v_name)s;
1741""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1742
1743 out.write("""
1744 if ((dst = %(cls)s_new(src->version)) == NULL) {
1745 return NULL;
1746 }
1747""" % dict(cls=cls))
1748
1749 for member in members:
1750 m_type = member["m_type"]
1751 m_name = member["name"]
1752 if loxi_utils.skip_member_name(m_name):
1753 continue
1754 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1755 out.write("""
1756 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1757 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1758""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1759 elif m_type in ["of_match_t", "of_octets_t"]:
1760 out.write("""
1761 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1762 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1763""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001764 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1765 sub_cls = "of_bsn_vport_q_in_q"
1766 out.write("""
1767 %(cls)s_%(m_name)s_bind(
1768 src, &src_%(v_name)s);
1769 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1770 if (dst_%(v_name)s == NULL) {
1771 %(cls)s_delete(dst);
1772 return NULL;
1773 }
1774 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1775 %(sub_cls)s_delete(dst_%(v_name)s);
1776""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1777 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001778 else:
1779 sub_cls = m_type[:-2] # Trim _t
1780 out.write("""
1781 %(cls)s_%(m_name)s_bind(
1782 src, &src_%(v_name)s);
1783 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1784 if (dst_%(v_name)s == NULL) {
1785 %(cls)s_delete(dst);
1786 return NULL;
1787 }
1788 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1789 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001790""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001791 v_name=var_name_map(m_type), ver_name=ver_name))
1792
1793 out.write("""
1794 return dst;
1795}
1796""")
1797
1798def gen_version_dup(out=sys.stdout):
1799 """
1800 Generate duplication routines for each object type
1801 """
1802 out.write("""
1803/* Special try macro for duplicating */
1804#define _TRY_FREE(op, obj, rv) do { \\
1805 int _rv; \\
1806 if ((_rv = (op)) < 0) { \\
1807 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1808 of_object_delete((of_object_t *)(obj)); \\
1809 return (rv); \\
1810 } \\
1811 } while (0)
1812""")
1813
1814 for version in of_g.of_version_range:
1815 for cls in of_g.standard_class_order:
1816 if not loxi_utils.class_in_version(cls, version):
1817 continue
1818 if cls in type_maps.inheritance_map:
1819 gen_dup_inheritance(out, cls, version)
1820 elif loxi_utils.class_is_list(cls):
1821 gen_dup_list(out, cls, version)
1822 else:
1823 gen_dup_cls(out, cls, version)
1824
1825def gen_dup(out=sys.stdout):
1826 """
1827 Generate non-version specific duplication routines for each object type
1828 """
1829
1830 for cls in of_g.standard_class_order:
1831 out.write("""
1832%(cls)s_t *
1833%(cls)s_dup(
1834 %(cls)s_t *src)
1835{
1836""" % dict(cls=cls))
1837 for version in of_g.of_version_range:
1838 if not loxi_utils.class_in_version(cls, version):
1839 continue
1840 hdr = "header." if cls in type_maps.inheritance_map else ""
1841
1842 ver_name = loxi_utils.version_to_name(version)
1843 out.write("""
1844 if (src->%(hdr)sversion == %(ver_name)s) {
1845 return %(cls)s_%(ver_name)s_dup(src);
1846 }
1847""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1848
1849 out.write("""
1850 /* Class not supported in given version */
1851 return NULL;
1852}
1853""")
1854
1855def dup_c_gen(out, name):
1856 """
1857 Generate the C file for duplication functions
1858 """
1859 loxi_utils.gen_c_copy_license(out)
1860 out.write("""\
1861/*
1862 * Duplication functions for all OF objects
1863 *
1864 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1865 *
1866 * These are test functions for exercising accessors. You can call
1867 * of_object_dup for an efficient duplication.
1868 */
1869
1870#define DISABLE_WARN_UNUSED_RESULT
1871#include "loci_log.h"
1872#include <locitest/of_dup.h>
1873
1874""")
1875
1876 gen_version_dup(out)
1877 gen_dup(out)
1878
1879
1880def dup_h_gen(out, name):
1881 """
1882 Generate the header file for duplication functions
1883 """
1884
1885 loxi_utils.gen_c_copy_license(out)
1886 out.write("""
1887/*
1888 * Duplication function header file
1889 *
1890 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1891 */
1892
1893#if !defined(_OF_DUP_H_)
1894#define _OF_DUP_H_
1895
1896#include <loci/loci.h>
1897""")
1898
1899 for cls in of_g.standard_class_order:
1900 out.write("""
1901extern %(cls)s_t *
1902 %(cls)s_dup(
1903 %(cls)s_t *src);
1904""" % dict(cls=cls))
1905
1906 for version in of_g.of_version_range:
1907 for cls in of_g.standard_class_order:
1908 if not loxi_utils.class_in_version(cls, version):
1909 continue
1910 ver_name = loxi_utils.version_to_name(version)
1911 out.write("""
1912extern %(cls)s_t *
1913 %(cls)s_%(ver_name)s_dup(
1914 %(cls)s_t *src);
1915""" % dict(cls=cls, ver_name=ver_name))
1916
1917 out.write("\n#endif /* _OF_DUP_H_ */\n")
1918
1919def gen_log_test(out):
1920 """
1921 Generate test for obj log calls
1922
1923 Define a trivial handler for object logging; call all obj log fns
1924 """
1925 out.write("""
1926
1927/**
1928 * Test object dump functions
1929 */
1930
1931int
1932test_dump_objs(void)
1933{
1934 of_object_t *obj;
1935
1936 FILE *out = fopen("/dev/null", "w");
1937
1938 /* Call each obj dump function */
1939""")
1940 for version in of_g.of_version_range:
1941 for j, cls in enumerate(of_g.all_class_order):
1942 if not loxi_utils.class_in_version(cls, version):
1943 continue
1944 if cls in type_maps.inheritance_map:
1945 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001946 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1947 out.write("""
1948 obj = (of_object_t *)%(cls)s_new(%(version)s);
1949 {
1950 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1951 %(cls)s_vport_set(obj, vport);
1952 of_object_delete(vport);
1953 }
1954 of_object_dump((loci_writer_f)fprintf, out, obj);
1955 of_object_delete(obj);
1956""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1957 else:
1958 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001959 obj = (of_object_t *)%(cls)s_new(%(version)s);
1960 of_object_dump((loci_writer_f)fprintf, out, obj);
1961 of_object_delete(obj);
1962""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001963
Rich Lanea06d0c32013-03-25 08:52:03 -07001964 out.write("""
1965 fclose(out);
1966 return TEST_PASS;
1967}
1968""")
1969
1970def gen_ident_tests(out):
1971 """
1972 Generate tests for identifiers
1973
1974 For all idents, instantiate, test version supported macros
1975 For flags, set it, test it, clear it, test it.
1976 """
1977 out.write("""
1978/**
1979 * Test cases for all flag accessor macros
1980 * These only test self consistency (and that they compile)
1981 */
1982int
1983test_ident_macros(void)
1984{
1985 int value __attribute__((unused));
1986 uint32_t flags;
1987
1988""")
1989
1990 for ident, info in of_g.identifiers.items():
1991 if not identifiers.defined_versions_agree(of_g.identifiers,
1992 of_g.target_version_list,
1993 ident):
1994 # @fixme
1995 continue
1996 out.write(" value = %s;\n" % ident)
1997 for version in of_g.target_version_list:
1998 if version in info["values_by_version"].keys():
1999 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2000 (ident, of_g.of_version_wire2name[version]))
2001 else:
2002 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2003 (ident, of_g.of_version_wire2name[version]))
2004 if flags.ident_is_flag(ident):
2005 # Grab first supported version
2006 for version in info["values_by_version"]:
2007 break
2008 out.write("""
2009 flags = 0;
2010 %(ident)s_SET(flags, %(ver_name)s);
2011 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2012 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2013 %(ident)s_CLEAR(flags, %(ver_name)s);
2014 TEST_ASSERT(flags == 0);
2015 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2016""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2017
2018 out.write("""
2019 return TEST_PASS;
2020}
2021""")
2022
Rich Laneccae0312013-07-21 23:34:13 -07002023def gen_datafiles_tests(out, name):
2024 tests = []
2025 for filename in test_data.list_files():
2026 data = test_data.read(filename)
2027 if not 'c' in data:
2028 continue
2029 name = filename[:-5].replace("/", "_")
2030 tests.append(dict(name=name,
2031 filename=filename,
2032 c=data['c'],
2033 binary=data['binary']))
2034
2035 util.render_template(out, "test_data.c", tests=tests)