blob: 57d141dd0b07559dcfc703c43d0675500ae84211 [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;
1096 int len;
Rich Lanea4b68302014-03-12 15:17:58 -07001097 of_object_id_t object_id;
Rich Lanea06d0c32013-03-25 08:52:03 -07001098
1099 obj = %(cls)s_new(%(v_name)s);
1100 TEST_ASSERT(obj != NULL);
1101 TEST_ASSERT(obj->version == %(v_name)s);
1102 TEST_ASSERT(obj->length == %(bytes)d);
1103 TEST_ASSERT(obj->parent == NULL);
1104 TEST_ASSERT(obj->object_id == %(enum)s);
1105
Rich Lanea4b68302014-03-12 15:17:58 -07001106 of_header_wire_object_id_get(obj, &object_id);
1107 TEST_ASSERT(object_id == %(enum)s);
1108
Rich Lanea06d0c32013-03-25 08:52:03 -07001109 /* Set up incrementing values for scalar members */
1110 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1111 TEST_ASSERT(value != 0);
1112
1113 /* Grab the underlying buffer from the message */
1114 len = obj->length;
1115 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1116 TEST_ASSERT(msg_buf != NULL);
1117 %(cls)s_delete(obj);
1118 /* TODO: */
1119 TEST_ASSERT(of_message_to_object_id(msg_buf, len) == %(enum)s);
1120 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1121
1122 TEST_ASSERT(obj != NULL);
1123
1124 /* @fixme Set up all message objects (recursively?) */
1125
1126 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1127 TEST_ASSERT(value != 0);
1128
1129 %(cls)s_delete(obj);
1130
1131 return TEST_PASS;
1132}
1133""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1134 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1135
1136 out.write("""
1137int
1138run_message_tests(void)
1139{
1140""")
1141 for version in of_g.of_version_range:
1142 for cls in of_g.ordered_messages:
1143 if not (cls, version) in of_g.base_length:
1144 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001145 if type_maps.class_is_virtual(cls):
1146 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001147 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1148 out.write(" RUN_TEST(%s);\n" % test_name)
1149
1150 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001151
Rich Lanea06d0c32013-03-25 08:52:03 -07001152
1153def gen_list_setup_check(out, cls, version):
1154 """
1155 Generate functions that populate and check a list with two
1156 of each type of subclass it supports
1157 """
1158 out.write("""
1159/**
1160 * Populate a list of type %(cls)s with two of each type of subclass
1161 * @param list Pointer to the list to be populated
1162 * @param value The seed value to use in populating the list
1163 * @returns The value after increments for this object's values
1164 */
1165int
1166%(cls)s_%(v_name)s_populate(
1167 %(cls)s_t *list, int value)
1168{
1169""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1170 base_type = loxi_utils.list_to_entry_type(cls)
1171 out.write("""
1172 %(base_type)s_t elt;
1173 int cur_len = 0;
1174""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001175
Rich Lanea06d0c32013-03-25 08:52:03 -07001176 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001177 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 -07001178 v_name = loxi_utils.version_to_name(version)
1179
1180 if len(sub_classes) == 0:
1181 out.write(" /* No subclasses for %s */\n"% base_type)
1182 out.write(" %s_t *elt_p;\n" % base_type)
1183 out.write("\n elt_p = &elt;\n")
1184 else:
1185 out.write(" /* Declare pointers for each subclass */\n")
1186 for instance, subcls in sub_classes:
1187 out.write(" %s_t *%s;\n" % (subcls, instance))
1188 out.write("\n /* Instantiate pointers for each subclass */\n")
1189 for instance, subcls in sub_classes:
1190 out.write(" %s = &elt.%s;\n" % (instance, instance))
1191
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001193 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001194 else:
1195 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001196 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001197 out.write("""
1198 return value;
1199}
1200""")
1201 out.write("""
1202/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001203 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001204 * %(cls)s_%(v_name)s_populate
1205 * @param list Pointer to the list that was populated
1206 * @param value Starting value for checking
1207 * @returns The value after increments for this object's values
1208 */
1209int
1210%(cls)s_%(v_name)s_check(
1211 %(cls)s_t *list, int value)
1212{
1213""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1214 base_type = loxi_utils.list_to_entry_type(cls)
1215 out.write("""
1216 %(base_type)s_t elt;
1217 int count = 0;
1218 int rv;
1219""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001220
Rich Lanea06d0c32013-03-25 08:52:03 -07001221
1222 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001223 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 -07001224 v_name = loxi_utils.version_to_name(version)
1225
1226 if len(sub_classes) == 0:
1227 entry_count = 2
1228 out.write(" /* No subclasses for %s */\n"% base_type)
1229 out.write(" %s_t *elt_p;\n" % base_type)
1230 out.write("\n elt_p = &elt;\n")
1231 else:
1232 entry_count = 2 * len(sub_classes) # Two of each type appended
1233 out.write(" /* Declare pointers for each subclass */\n")
1234 for instance, subcls in sub_classes:
1235 out.write(" %s_t *%s;\n" % (subcls, instance))
1236 out.write("\n /* Instantiate pointers for each subclass */\n")
1237 for instance, subcls in sub_classes:
1238 out.write(" %s = &elt.%s;\n" % (instance, instance))
1239
1240 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1241 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001242 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001243 version, True)
1244 else:
1245 count = 0
1246 for instance, subcls in sub_classes:
1247 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001248 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001249 version, count==len(sub_classes))
1250 out.write("""
1251""" % dict(base_type=base_type))
1252
1253 out.write("""
1254 /* Do an iterate to test the iterator */
1255 %(u_cls)s_ITER(list, &elt, rv) {
1256 count += 1;
1257 }
1258
1259 TEST_ASSERT(rv == OF_ERROR_RANGE);
1260 TEST_ASSERT(count == %(entry_count)d);
1261
1262 /* We shoehorn a test of the dup functions here */
1263 {
1264 %(cls)s_t *dup;
1265
1266 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1267 TEST_ASSERT(dup->length == list->length);
1268 TEST_ASSERT(dup->object_id == list->object_id);
1269 TEST_ASSERT(dup->version == list->version);
1270 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1271 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1272 of_object_delete((of_object_t *)dup);
1273
1274 /* And now for the generic dup function */
1275 TEST_ASSERT((dup = (%(cls)s_t *)
1276 of_object_dup(list)) != NULL);
1277 TEST_ASSERT(dup->length == list->length);
1278 TEST_ASSERT(dup->object_id == list->object_id);
1279 TEST_ASSERT(dup->version == list->version);
1280 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1281 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1282 of_object_delete((of_object_t *)dup);
1283 }
1284
1285 return value;
1286}
1287""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1288
1289
1290def gen_class_setup_check(out, cls, version):
1291 out.write("""
1292/**
1293 * Populate all members of an object of type %(cls)s
1294 * with incrementing values
1295 * @param obj Pointer to an object to populate
1296 * @param value The seed value to use in populating the object
1297 * @returns The value after increments for this object's values
1298 */
1299
1300int
1301%(cls)s_%(v_name)s_populate(
1302 %(cls)s_t *obj, int value)
1303{
1304""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1305 members, member_types = loxi_utils.all_member_types_get(cls, version)
1306 for m_type in member_types:
1307 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1308 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001309 elif m_type == "of_bsn_vport_header_t":
1310 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001311 else:
1312 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1313 out.write("""
1314 /* Run thru accessors after new to ensure okay */
1315""")
1316 for member in members:
1317 m_type = member["m_type"]
1318 m_name = member["name"]
1319 if loxi_utils.skip_member_name(m_name):
1320 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001321 if m_type == "of_bsn_vport_header_t":
1322 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001323 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1324 out.write("""\
1325 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1326""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1327 else:
1328 sub_cls = m_type[:-2] # Trim _t
1329 out.write("""\
1330 {
1331 %(sub_cls)s_t sub_cls;
1332
1333 /* Test bind */
1334 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1335 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001336""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001337 m_name=m_name, sub_cls=sub_cls,
1338 v_name=loxi_utils.version_to_name(version)))
1339
1340 out.write("""
1341 value = %(cls)s_%(v_name)s_populate_scalars(
1342 obj, value);
1343 TEST_ASSERT(value != 0);
1344""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1345
1346 for member in members:
1347 m_type = member["m_type"]
1348 m_name = member["name"]
1349 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1350 continue
1351 if loxi_utils.skip_member_name(m_name):
1352 continue
1353 if m_type == "of_match_t":
1354 out.write("""\
1355 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1356 TEST_ASSERT(value != 0);
1357 %(cls)s_%(m_name)s_set(
1358 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001359""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001360 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1361 elif m_type == "of_octets_t":
1362 out.write("""\
1363 value = of_octets_populate(&%(var_name)s, value);
1364 TEST_ASSERT(value != 0);
1365 %(cls)s_%(m_name)s_set(
1366 obj, &%(var_name)s);
1367 if (octets.bytes) {
1368 FREE(octets.data);
1369 }
1370""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001371 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1372 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001373 out.write("""\
1374 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1375 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001376 value = %(sub_cls)s_%(v_name)s_populate(
1377 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001378 TEST_ASSERT(value != 0);
1379 %(cls)s_%(m_name)s_set(
1380 obj, %(var_name)s);
1381 %(sub_cls)s_delete(%(var_name)s);
1382""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1383 var_name=var_name_map(m_type),
1384 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001385 else:
1386 sub_cls = m_type[:-2] # Trim _t
1387 out.write("""
1388 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1389 TEST_ASSERT(%(var_name)s != NULL);
1390 value = %(sub_cls)s_%(v_name)s_populate(
1391 %(var_name)s, value);
1392 TEST_ASSERT(value != 0);
1393 %(cls)s_%(m_name)s_set(
1394 obj, %(var_name)s);
1395 %(sub_cls)s_delete(%(var_name)s);
1396""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1397 var_name=var_name_map(m_type),
1398 v_name=loxi_utils.version_to_name(version)))
1399
1400 out.write("""
1401 return value;
1402}
1403""")
1404
1405 out.write("""
1406/**
1407 * Check all members of an object of type %(cls)s
1408 * populated by the above function
1409 * @param obj Pointer to an object to check
1410 * @param value Starting value for checking
1411 * @returns The value after increments for this object's values
1412 */
1413
1414int
1415%(cls)s_%(v_name)s_check(
1416 %(cls)s_t *obj, int value)
1417{
1418""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1419 members, member_types = loxi_utils.all_member_types_get(cls, version)
1420 for m_type in member_types:
1421 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1422 continue
1423 if loxi_utils.type_is_of_object(m_type):
1424 continue
1425 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1426 out.write("""
1427 value = %(cls)s_%(v_name)s_check_scalars(
1428 obj, value);
1429 TEST_ASSERT(value != 0);
1430""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1431
1432 for member in members:
1433 m_type = member["m_type"]
1434 m_name = member["name"]
1435 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1436 continue
1437 if loxi_utils.skip_member_name(m_name):
1438 continue
1439 if m_type == "of_match_t":
1440 out.write("""\
1441 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1442 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1443""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1444 v_name=loxi_utils.version_to_name(version)))
1445 elif m_type == "of_octets_t":
1446 out.write("""\
1447 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1448 value = of_octets_check(&%(var_name)s, value);
1449""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1450 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001451 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1452 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001453 out.write("""
1454 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001455 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001456
1457 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1458 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001459 value = %(sub_cls)s_%(v_name)s_check(
1460 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001461 TEST_ASSERT(value != 0);
1462 %(sub_cls)s_delete(%(m_name)s_ptr);
1463 }
1464""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1465 var_name=var_name_map(m_type),
1466 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001467 else:
1468 sub_cls = m_type[:-2] # Trim _t
1469 out.write("""
1470 { /* Use get/delete to access on check */
1471 %(m_type)s *%(m_name)s_ptr;
1472
1473 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1474 TEST_ASSERT(%(m_name)s_ptr != NULL);
1475 value = %(sub_cls)s_%(v_name)s_check(
1476 %(m_name)s_ptr, value);
1477 TEST_ASSERT(value != 0);
1478 %(sub_cls)s_delete(%(m_name)s_ptr);
1479 }
1480""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1481 var_name=var_name_map(m_type),
1482 v_name=loxi_utils.version_to_name(version)))
1483
1484 out.write("""
1485 /* We shoehorn a test of the dup functions here */
1486 {
1487 %(cls)s_t *dup;
1488
1489 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1490 TEST_ASSERT(dup->length == obj->length);
1491 TEST_ASSERT(dup->object_id == obj->object_id);
1492 TEST_ASSERT(dup->version == obj->version);
1493 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1494 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1495 of_object_delete((of_object_t *)dup);
1496
1497 /* And now for the generic dup function */
1498 TEST_ASSERT((dup = (%(cls)s_t *)
1499 of_object_dup(obj)) != NULL);
1500 TEST_ASSERT(dup->length == obj->length);
1501 TEST_ASSERT(dup->object_id == obj->object_id);
1502 TEST_ASSERT(dup->version == obj->version);
1503 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1504 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1505 of_object_delete((of_object_t *)dup);
1506 }
1507
1508 return value;
1509}
1510""" % dict(cls=cls))
1511
1512def unified_accessor_test_case(out, cls, version):
1513 """
1514 Generate one test case for the given version and class
1515 """
1516
1517 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001518 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001519 v_name = loxi_utils.version_to_name(version)
1520
1521 out.write("""
1522static int
1523test_%(cls)s_%(v_name)s(void)
1524{
1525 %(cls)s_t *obj;
1526 obj = %(cls)s_new(%(v_name)s);
1527 TEST_ASSERT(obj != NULL);
1528 TEST_ASSERT(obj->version == %(v_name)s);
1529 TEST_ASSERT(obj->length == %(length)d);
1530 TEST_ASSERT(obj->parent == NULL);
1531 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001532""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001533 v_name=v_name, length=length, version=version))
1534 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1535 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001536 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001537 int length;
1538
Rich Lanedc46fe22014-04-03 15:10:38 -07001539 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001540 TEST_ASSERT(length == %(length)d);
1541 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001542 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001543 of_object_id_t obj_id;
1544
Rich Lanedc46fe22014-04-03 15:10:38 -07001545 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001546 TEST_ASSERT(obj_id == %(u_cls)s);
1547 }
1548
1549 /* Set up incrementing values for members */
1550 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1551 obj, 1) != 0);
1552
1553 /* Check values just set */
1554 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1555 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001556""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001557 v_name=v_name, length=length, version=version))
1558
1559 out.write("""
1560 %(cls)s_delete(obj);
1561
1562 /* To do: Check memory */
1563 return TEST_PASS;
1564}
1565""" % dict(cls=cls))
1566
1567
1568def gen_unified_accessor_funs(out):
1569 for version in of_g.of_version_range:
1570 for cls in of_g.standard_class_order:
1571 if not loxi_utils.class_in_version(cls, version):
1572 continue
1573 if cls in type_maps.inheritance_map:
1574 continue
1575 elif loxi_utils.class_is_list(cls):
1576 gen_list_setup_check(out, cls, version)
1577 else:
1578 gen_class_setup_check(out, cls, version)
1579
1580def gen_unified_accessor_tests(out, name):
1581 loxi_utils.gen_c_copy_license(out)
1582 out.write("""
1583/**
1584 *
1585 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1586 *
1587 * Unified simple class instantiation tests for all versions
1588 */
1589
1590#include <locitest/test_common.h>
1591""")
1592 for version in of_g.of_version_range:
1593 for cls in of_g.standard_class_order:
1594 if not loxi_utils.class_in_version(cls, version):
1595 continue
1596 if cls in type_maps.inheritance_map:
1597 continue
1598 unified_accessor_test_case(out, cls, version)
1599
1600 out.write("""
1601int
1602run_unified_accessor_tests(void)
1603{
1604""")
1605 for version in of_g.of_version_range:
1606 v_name = loxi_utils.version_to_name(version)
1607 for cls in of_g.standard_class_order:
1608 if not loxi_utils.class_in_version(cls, version):
1609 continue
1610 if cls in type_maps.inheritance_map:
1611 continue
1612 test_name = "%s_%s" % (cls, v_name)
1613 out.write(" RUN_TEST(%s);\n" % test_name)
1614
1615 out.write(" return TEST_PASS;\n}\n");
1616
1617
1618
1619################################################################
1620#
1621# Object duplication functions
1622#
1623# These exercise the accessors to create duplicate objects.
1624# They are used in the LOCI test shim which sits in an OF
1625# protocol stream.
1626#
1627# TODO
1628# Resolve version stuff
1629# Complete list dup
1630
1631def gen_dup_list(out, cls, version):
1632 ver_name = loxi_utils.version_to_name(version)
1633 elt_type = loxi_utils.list_to_entry_type(cls)
1634 out.write("""
1635/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001636 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001637 * using accessor functions
1638 * @param src Pointer to object to be duplicated
1639 * @returns A new object of type %(cls)s.
1640 *
1641 * The caller is responsible for deleting the returned value
1642 */
1643%(cls)s_t *
1644%(cls)s_%(ver_name)s_dup(
1645 %(cls)s_t *src)
1646{
1647 %(elt_type)s_t src_elt;
1648 %(elt_type)s_t *dst_elt;
1649 int rv;
1650 %(cls)s_t *dst;
1651
1652 if ((dst = %(cls)s_new(src->version)) == NULL) {
1653 return NULL;
1654 }
1655""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1656
1657 out.write("""
1658 %(u_cls)s_ITER(src, &src_elt, rv) {
1659 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1660 of_object_delete((of_object_t *)dst);
1661 return NULL;
1662 }
1663 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1664 dst, NULL);
1665 of_object_delete((of_object_t *)dst_elt);
1666 }
1667
1668 return dst;
1669}
1670""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1671
1672
1673def gen_dup_inheritance(out, cls, version):
1674 ver_name = loxi_utils.version_to_name(version)
1675 out.write("""
1676/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001677 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001678 * @param src Pointer to object to be duplicated
1679 * @returns A new object of type %(cls)s.
1680 *
1681 * The caller is responsible for deleting the returned value
1682 */
1683%(cls)s_t *
1684%(cls)s_%(ver_name)s_dup(
1685 %(cls)s_t *src)
1686{
1687""" % dict(cls=cls, ver_name=ver_name))
1688
1689 # For each subclass, check if this is an instance of that subclass
1690 version_classes = type_maps.inheritance_data[cls][version]
1691 for sub_cls in version_classes:
1692 sub_enum = (cls + "_" + sub_cls).upper()
1693 out.write("""
1694 if (src->header.object_id == %(sub_enum)s) {
1695 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1696 &src->%(sub_cls)s);
1697 }
1698""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1699
1700 out.write("""
1701 return NULL;
1702}
1703""")
1704
1705
1706def gen_dup_cls(out, cls, version):
1707 """
1708 Generate duplication routine for class cls
1709 """
1710 ver_name = loxi_utils.version_to_name(version)
1711
1712 out.write("""
1713/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001714 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001715 * using accessor functions
1716 * @param src Pointer to object to be duplicated
1717 * @returns A new object of type %(cls)s.
1718 *
1719 * The caller is responsible for deleting the returned value
1720 */
1721%(cls)s_t *
1722%(cls)s_%(ver_name)s_dup(
1723 %(cls)s_t *src)
1724{
1725 %(cls)s_t *dst;
1726""" % dict(cls=cls, ver_name=ver_name))
1727
1728 # Get members and types for the class
1729 members, member_types = loxi_utils.all_member_types_get(cls, version)
1730
1731 # Add declarations for each member type
1732 for m_type in member_types:
1733 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1734 # Declare instance of these
1735 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001736 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1737 out.write("""
1738 of_bsn_vport_q_in_q_t src_%(v_name)s;
1739 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1740""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001741 else:
1742 out.write("""
1743 %(m_type)s src_%(v_name)s;
1744 %(m_type)s *dst_%(v_name)s;
1745""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1746
1747 out.write("""
1748 if ((dst = %(cls)s_new(src->version)) == NULL) {
1749 return NULL;
1750 }
1751""" % dict(cls=cls))
1752
1753 for member in members:
1754 m_type = member["m_type"]
1755 m_name = member["name"]
1756 if loxi_utils.skip_member_name(m_name):
1757 continue
1758 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1759 out.write("""
1760 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1761 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1762""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1763 elif m_type in ["of_match_t", "of_octets_t"]:
1764 out.write("""
1765 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1766 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1767""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001768 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1769 sub_cls = "of_bsn_vport_q_in_q"
1770 out.write("""
1771 %(cls)s_%(m_name)s_bind(
1772 src, &src_%(v_name)s);
1773 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1774 if (dst_%(v_name)s == NULL) {
1775 %(cls)s_delete(dst);
1776 return NULL;
1777 }
1778 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1779 %(sub_cls)s_delete(dst_%(v_name)s);
1780""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1781 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001782 else:
1783 sub_cls = m_type[:-2] # Trim _t
1784 out.write("""
1785 %(cls)s_%(m_name)s_bind(
1786 src, &src_%(v_name)s);
1787 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1788 if (dst_%(v_name)s == NULL) {
1789 %(cls)s_delete(dst);
1790 return NULL;
1791 }
1792 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1793 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001794""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001795 v_name=var_name_map(m_type), ver_name=ver_name))
1796
1797 out.write("""
1798 return dst;
1799}
1800""")
1801
1802def gen_version_dup(out=sys.stdout):
1803 """
1804 Generate duplication routines for each object type
1805 """
1806 out.write("""
1807/* Special try macro for duplicating */
1808#define _TRY_FREE(op, obj, rv) do { \\
1809 int _rv; \\
1810 if ((_rv = (op)) < 0) { \\
1811 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1812 of_object_delete((of_object_t *)(obj)); \\
1813 return (rv); \\
1814 } \\
1815 } while (0)
1816""")
1817
1818 for version in of_g.of_version_range:
1819 for cls in of_g.standard_class_order:
1820 if not loxi_utils.class_in_version(cls, version):
1821 continue
1822 if cls in type_maps.inheritance_map:
1823 gen_dup_inheritance(out, cls, version)
1824 elif loxi_utils.class_is_list(cls):
1825 gen_dup_list(out, cls, version)
1826 else:
1827 gen_dup_cls(out, cls, version)
1828
1829def gen_dup(out=sys.stdout):
1830 """
1831 Generate non-version specific duplication routines for each object type
1832 """
1833
1834 for cls in of_g.standard_class_order:
1835 out.write("""
1836%(cls)s_t *
1837%(cls)s_dup(
1838 %(cls)s_t *src)
1839{
1840""" % dict(cls=cls))
1841 for version in of_g.of_version_range:
1842 if not loxi_utils.class_in_version(cls, version):
1843 continue
1844 hdr = "header." if cls in type_maps.inheritance_map else ""
1845
1846 ver_name = loxi_utils.version_to_name(version)
1847 out.write("""
1848 if (src->%(hdr)sversion == %(ver_name)s) {
1849 return %(cls)s_%(ver_name)s_dup(src);
1850 }
1851""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1852
1853 out.write("""
1854 /* Class not supported in given version */
1855 return NULL;
1856}
1857""")
1858
1859def dup_c_gen(out, name):
1860 """
1861 Generate the C file for duplication functions
1862 """
1863 loxi_utils.gen_c_copy_license(out)
1864 out.write("""\
1865/*
1866 * Duplication functions for all OF objects
1867 *
1868 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1869 *
1870 * These are test functions for exercising accessors. You can call
1871 * of_object_dup for an efficient duplication.
1872 */
1873
1874#define DISABLE_WARN_UNUSED_RESULT
1875#include "loci_log.h"
1876#include <locitest/of_dup.h>
1877
1878""")
1879
1880 gen_version_dup(out)
1881 gen_dup(out)
1882
1883
1884def dup_h_gen(out, name):
1885 """
1886 Generate the header file for duplication functions
1887 """
1888
1889 loxi_utils.gen_c_copy_license(out)
1890 out.write("""
1891/*
1892 * Duplication function header file
1893 *
1894 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1895 */
1896
1897#if !defined(_OF_DUP_H_)
1898#define _OF_DUP_H_
1899
1900#include <loci/loci.h>
1901""")
1902
1903 for cls in of_g.standard_class_order:
1904 out.write("""
1905extern %(cls)s_t *
1906 %(cls)s_dup(
1907 %(cls)s_t *src);
1908""" % dict(cls=cls))
1909
1910 for version in of_g.of_version_range:
1911 for cls in of_g.standard_class_order:
1912 if not loxi_utils.class_in_version(cls, version):
1913 continue
1914 ver_name = loxi_utils.version_to_name(version)
1915 out.write("""
1916extern %(cls)s_t *
1917 %(cls)s_%(ver_name)s_dup(
1918 %(cls)s_t *src);
1919""" % dict(cls=cls, ver_name=ver_name))
1920
1921 out.write("\n#endif /* _OF_DUP_H_ */\n")
1922
1923def gen_log_test(out):
1924 """
1925 Generate test for obj log calls
1926
1927 Define a trivial handler for object logging; call all obj log fns
1928 """
1929 out.write("""
1930
1931/**
1932 * Test object dump functions
1933 */
1934
1935int
1936test_dump_objs(void)
1937{
1938 of_object_t *obj;
1939
1940 FILE *out = fopen("/dev/null", "w");
1941
1942 /* Call each obj dump function */
1943""")
1944 for version in of_g.of_version_range:
1945 for j, cls in enumerate(of_g.all_class_order):
1946 if not loxi_utils.class_in_version(cls, version):
1947 continue
1948 if cls in type_maps.inheritance_map:
1949 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001950 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1951 out.write("""
1952 obj = (of_object_t *)%(cls)s_new(%(version)s);
1953 {
1954 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1955 %(cls)s_vport_set(obj, vport);
1956 of_object_delete(vport);
1957 }
1958 of_object_dump((loci_writer_f)fprintf, out, obj);
1959 of_object_delete(obj);
1960""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1961 else:
1962 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001963 obj = (of_object_t *)%(cls)s_new(%(version)s);
1964 of_object_dump((loci_writer_f)fprintf, out, obj);
1965 of_object_delete(obj);
1966""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001967
Rich Lanea06d0c32013-03-25 08:52:03 -07001968 out.write("""
1969 fclose(out);
1970 return TEST_PASS;
1971}
1972""")
1973
1974def gen_ident_tests(out):
1975 """
1976 Generate tests for identifiers
1977
1978 For all idents, instantiate, test version supported macros
1979 For flags, set it, test it, clear it, test it.
1980 """
1981 out.write("""
1982/**
1983 * Test cases for all flag accessor macros
1984 * These only test self consistency (and that they compile)
1985 */
1986int
1987test_ident_macros(void)
1988{
1989 int value __attribute__((unused));
1990 uint32_t flags;
1991
1992""")
1993
1994 for ident, info in of_g.identifiers.items():
1995 if not identifiers.defined_versions_agree(of_g.identifiers,
1996 of_g.target_version_list,
1997 ident):
1998 # @fixme
1999 continue
2000 out.write(" value = %s;\n" % ident)
2001 for version in of_g.target_version_list:
2002 if version in info["values_by_version"].keys():
2003 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2004 (ident, of_g.of_version_wire2name[version]))
2005 else:
2006 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2007 (ident, of_g.of_version_wire2name[version]))
2008 if flags.ident_is_flag(ident):
2009 # Grab first supported version
2010 for version in info["values_by_version"]:
2011 break
2012 out.write("""
2013 flags = 0;
2014 %(ident)s_SET(flags, %(ver_name)s);
2015 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2016 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2017 %(ident)s_CLEAR(flags, %(ver_name)s);
2018 TEST_ASSERT(flags == 0);
2019 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2020""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2021
2022 out.write("""
2023 return TEST_PASS;
2024}
2025""")
2026
Rich Laneccae0312013-07-21 23:34:13 -07002027def gen_datafiles_tests(out, name):
2028 tests = []
2029 for filename in test_data.list_files():
2030 data = test_data.read(filename)
2031 if not 'c' in data:
2032 continue
2033 name = filename[:-5].replace("/", "_")
2034 tests.append(dict(name=name,
2035 filename=filename,
2036 c=data['c'],
2037 binary=data['binary']))
2038
2039 util.render_template(out, "test_data.c", tests=tests)