blob: be1b0dad6dbcb50aa6aeeb923851a1535fb6f153 [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 */
277 of_match_values_mask(match);
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)))
1309 else:
1310 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1311 out.write("""
1312 /* Run thru accessors after new to ensure okay */
1313""")
1314 for member in members:
1315 m_type = member["m_type"]
1316 m_name = member["name"]
1317 if loxi_utils.skip_member_name(m_name):
1318 continue
1319 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 Ngd6181882014-04-14 16:28:35 -07001367 elif m_type == "of_bsn_vport_t": # FIXME: tests only q_in_q
1368 out.write("""\
1369 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1370 TEST_ASSERT(%(var_name)s != NULL);
1371 value = %(sub_cls)s_q_in_q_%(v_name)s_populate(
1372 &%(var_name)s->q_in_q, value);
1373 TEST_ASSERT(value != 0);
1374 %(cls)s_%(m_name)s_set(
1375 obj, %(var_name)s);
1376 %(sub_cls)s_delete(%(var_name)s);
1377""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1378 var_name=var_name_map(m_type),
1379 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001380 else:
1381 sub_cls = m_type[:-2] # Trim _t
1382 out.write("""
1383 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1384 TEST_ASSERT(%(var_name)s != NULL);
1385 value = %(sub_cls)s_%(v_name)s_populate(
1386 %(var_name)s, value);
1387 TEST_ASSERT(value != 0);
1388 %(cls)s_%(m_name)s_set(
1389 obj, %(var_name)s);
1390 %(sub_cls)s_delete(%(var_name)s);
1391""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1392 var_name=var_name_map(m_type),
1393 v_name=loxi_utils.version_to_name(version)))
1394
1395 out.write("""
1396 return value;
1397}
1398""")
1399
1400 out.write("""
1401/**
1402 * Check all members of an object of type %(cls)s
1403 * populated by the above function
1404 * @param obj Pointer to an object to check
1405 * @param value Starting value for checking
1406 * @returns The value after increments for this object's values
1407 */
1408
1409int
1410%(cls)s_%(v_name)s_check(
1411 %(cls)s_t *obj, int value)
1412{
1413""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1414 members, member_types = loxi_utils.all_member_types_get(cls, version)
1415 for m_type in member_types:
1416 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1417 continue
1418 if loxi_utils.type_is_of_object(m_type):
1419 continue
1420 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1421 out.write("""
1422 value = %(cls)s_%(v_name)s_check_scalars(
1423 obj, value);
1424 TEST_ASSERT(value != 0);
1425""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1426
1427 for member in members:
1428 m_type = member["m_type"]
1429 m_name = member["name"]
1430 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1431 continue
1432 if loxi_utils.skip_member_name(m_name):
1433 continue
1434 if m_type == "of_match_t":
1435 out.write("""\
1436 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1437 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1438""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1439 v_name=loxi_utils.version_to_name(version)))
1440 elif m_type == "of_octets_t":
1441 out.write("""\
1442 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1443 value = of_octets_check(&%(var_name)s, value);
1444""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1445 v_name=loxi_utils.version_to_name(version)))
Wilson Ngd6181882014-04-14 16:28:35 -07001446 elif m_type == "of_bsn_vport_t": # FIXME: tests only q_in_q
1447 sub_cls = m_type[:-2] # Trim _t
1448 out.write("""
1449 { /* Use get/delete to access on check */
1450 %(m_type)s *%(m_name)s_ptr;
1451
1452 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1453 TEST_ASSERT(%(m_name)s_ptr != NULL);
1454 value = %(sub_cls)s_q_in_q_%(v_name)s_check(
1455 &%(m_name)s_ptr->q_in_q, value);
1456 TEST_ASSERT(value != 0);
1457 %(sub_cls)s_delete(%(m_name)s_ptr);
1458 }
1459""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1460 var_name=var_name_map(m_type),
1461 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001462 else:
1463 sub_cls = m_type[:-2] # Trim _t
1464 out.write("""
1465 { /* Use get/delete to access on check */
1466 %(m_type)s *%(m_name)s_ptr;
1467
1468 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1469 TEST_ASSERT(%(m_name)s_ptr != NULL);
1470 value = %(sub_cls)s_%(v_name)s_check(
1471 %(m_name)s_ptr, value);
1472 TEST_ASSERT(value != 0);
1473 %(sub_cls)s_delete(%(m_name)s_ptr);
1474 }
1475""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1476 var_name=var_name_map(m_type),
1477 v_name=loxi_utils.version_to_name(version)))
1478
1479 out.write("""
1480 /* We shoehorn a test of the dup functions here */
1481 {
1482 %(cls)s_t *dup;
1483
1484 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1485 TEST_ASSERT(dup->length == obj->length);
1486 TEST_ASSERT(dup->object_id == obj->object_id);
1487 TEST_ASSERT(dup->version == obj->version);
1488 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1489 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1490 of_object_delete((of_object_t *)dup);
1491
1492 /* And now for the generic dup function */
1493 TEST_ASSERT((dup = (%(cls)s_t *)
1494 of_object_dup(obj)) != NULL);
1495 TEST_ASSERT(dup->length == obj->length);
1496 TEST_ASSERT(dup->object_id == obj->object_id);
1497 TEST_ASSERT(dup->version == obj->version);
1498 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1499 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1500 of_object_delete((of_object_t *)dup);
1501 }
1502
1503 return value;
1504}
1505""" % dict(cls=cls))
1506
1507def unified_accessor_test_case(out, cls, version):
1508 """
1509 Generate one test case for the given version and class
1510 """
1511
1512 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001513 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001514 v_name = loxi_utils.version_to_name(version)
1515
1516 out.write("""
1517static int
1518test_%(cls)s_%(v_name)s(void)
1519{
1520 %(cls)s_t *obj;
1521 obj = %(cls)s_new(%(v_name)s);
1522 TEST_ASSERT(obj != NULL);
1523 TEST_ASSERT(obj->version == %(v_name)s);
1524 TEST_ASSERT(obj->length == %(length)d);
1525 TEST_ASSERT(obj->parent == NULL);
1526 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001527""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001528 v_name=v_name, length=length, version=version))
1529 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1530 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001531 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001532 int length;
1533
Rich Lanedc46fe22014-04-03 15:10:38 -07001534 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001535 TEST_ASSERT(length == %(length)d);
1536 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001537 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001538 of_object_id_t obj_id;
1539
Rich Lanedc46fe22014-04-03 15:10:38 -07001540 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001541 TEST_ASSERT(obj_id == %(u_cls)s);
1542 }
1543
1544 /* Set up incrementing values for members */
1545 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1546 obj, 1) != 0);
1547
1548 /* Check values just set */
1549 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1550 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001551""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001552 v_name=v_name, length=length, version=version))
1553
1554 out.write("""
1555 %(cls)s_delete(obj);
1556
1557 /* To do: Check memory */
1558 return TEST_PASS;
1559}
1560""" % dict(cls=cls))
1561
1562
1563def gen_unified_accessor_funs(out):
1564 for version in of_g.of_version_range:
1565 for cls in of_g.standard_class_order:
1566 if not loxi_utils.class_in_version(cls, version):
1567 continue
1568 if cls in type_maps.inheritance_map:
1569 continue
1570 elif loxi_utils.class_is_list(cls):
1571 gen_list_setup_check(out, cls, version)
1572 else:
1573 gen_class_setup_check(out, cls, version)
1574
1575def gen_unified_accessor_tests(out, name):
1576 loxi_utils.gen_c_copy_license(out)
1577 out.write("""
1578/**
1579 *
1580 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1581 *
1582 * Unified simple class instantiation tests for all versions
1583 */
1584
1585#include <locitest/test_common.h>
1586""")
1587 for version in of_g.of_version_range:
1588 for cls in of_g.standard_class_order:
1589 if not loxi_utils.class_in_version(cls, version):
1590 continue
1591 if cls in type_maps.inheritance_map:
1592 continue
1593 unified_accessor_test_case(out, cls, version)
1594
1595 out.write("""
1596int
1597run_unified_accessor_tests(void)
1598{
1599""")
1600 for version in of_g.of_version_range:
1601 v_name = loxi_utils.version_to_name(version)
1602 for cls in of_g.standard_class_order:
1603 if not loxi_utils.class_in_version(cls, version):
1604 continue
1605 if cls in type_maps.inheritance_map:
1606 continue
1607 test_name = "%s_%s" % (cls, v_name)
1608 out.write(" RUN_TEST(%s);\n" % test_name)
1609
1610 out.write(" return TEST_PASS;\n}\n");
1611
1612
1613
1614################################################################
1615#
1616# Object duplication functions
1617#
1618# These exercise the accessors to create duplicate objects.
1619# They are used in the LOCI test shim which sits in an OF
1620# protocol stream.
1621#
1622# TODO
1623# Resolve version stuff
1624# Complete list dup
1625
1626def gen_dup_list(out, cls, version):
1627 ver_name = loxi_utils.version_to_name(version)
1628 elt_type = loxi_utils.list_to_entry_type(cls)
1629 out.write("""
1630/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001631 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001632 * using accessor functions
1633 * @param src Pointer to object to be duplicated
1634 * @returns A new object of type %(cls)s.
1635 *
1636 * The caller is responsible for deleting the returned value
1637 */
1638%(cls)s_t *
1639%(cls)s_%(ver_name)s_dup(
1640 %(cls)s_t *src)
1641{
1642 %(elt_type)s_t src_elt;
1643 %(elt_type)s_t *dst_elt;
1644 int rv;
1645 %(cls)s_t *dst;
1646
1647 if ((dst = %(cls)s_new(src->version)) == NULL) {
1648 return NULL;
1649 }
1650""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1651
1652 out.write("""
1653 %(u_cls)s_ITER(src, &src_elt, rv) {
1654 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1655 of_object_delete((of_object_t *)dst);
1656 return NULL;
1657 }
1658 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1659 dst, NULL);
1660 of_object_delete((of_object_t *)dst_elt);
1661 }
1662
1663 return dst;
1664}
1665""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1666
1667
1668def gen_dup_inheritance(out, cls, version):
1669 ver_name = loxi_utils.version_to_name(version)
1670 out.write("""
1671/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001672 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001673 * @param src Pointer to object to be duplicated
1674 * @returns A new object of type %(cls)s.
1675 *
1676 * The caller is responsible for deleting the returned value
1677 */
1678%(cls)s_t *
1679%(cls)s_%(ver_name)s_dup(
1680 %(cls)s_t *src)
1681{
1682""" % dict(cls=cls, ver_name=ver_name))
1683
1684 # For each subclass, check if this is an instance of that subclass
1685 version_classes = type_maps.inheritance_data[cls][version]
1686 for sub_cls in version_classes:
1687 sub_enum = (cls + "_" + sub_cls).upper()
1688 out.write("""
1689 if (src->header.object_id == %(sub_enum)s) {
1690 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1691 &src->%(sub_cls)s);
1692 }
1693""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1694
1695 out.write("""
1696 return NULL;
1697}
1698""")
1699
1700
1701def gen_dup_cls(out, cls, version):
1702 """
1703 Generate duplication routine for class cls
1704 """
1705 ver_name = loxi_utils.version_to_name(version)
1706
1707 out.write("""
1708/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001709 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001710 * using accessor functions
1711 * @param src Pointer to object to be duplicated
1712 * @returns A new object of type %(cls)s.
1713 *
1714 * The caller is responsible for deleting the returned value
1715 */
1716%(cls)s_t *
1717%(cls)s_%(ver_name)s_dup(
1718 %(cls)s_t *src)
1719{
1720 %(cls)s_t *dst;
1721""" % dict(cls=cls, ver_name=ver_name))
1722
1723 # Get members and types for the class
1724 members, member_types = loxi_utils.all_member_types_get(cls, version)
1725
1726 # Add declarations for each member type
1727 for m_type in member_types:
1728 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1729 # Declare instance of these
1730 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1731 else:
1732 out.write("""
1733 %(m_type)s src_%(v_name)s;
1734 %(m_type)s *dst_%(v_name)s;
1735""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1736
1737 out.write("""
1738 if ((dst = %(cls)s_new(src->version)) == NULL) {
1739 return NULL;
1740 }
1741""" % dict(cls=cls))
1742
1743 for member in members:
1744 m_type = member["m_type"]
1745 m_name = member["name"]
1746 if loxi_utils.skip_member_name(m_name):
1747 continue
1748 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1749 out.write("""
1750 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1751 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1752""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1753 elif m_type in ["of_match_t", "of_octets_t"]:
1754 out.write("""
1755 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1756 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1757""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1758 else:
1759 sub_cls = m_type[:-2] # Trim _t
1760 out.write("""
1761 %(cls)s_%(m_name)s_bind(
1762 src, &src_%(v_name)s);
1763 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1764 if (dst_%(v_name)s == NULL) {
1765 %(cls)s_delete(dst);
1766 return NULL;
1767 }
1768 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1769 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001770""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001771 v_name=var_name_map(m_type), ver_name=ver_name))
1772
1773 out.write("""
1774 return dst;
1775}
1776""")
1777
1778def gen_version_dup(out=sys.stdout):
1779 """
1780 Generate duplication routines for each object type
1781 """
1782 out.write("""
1783/* Special try macro for duplicating */
1784#define _TRY_FREE(op, obj, rv) do { \\
1785 int _rv; \\
1786 if ((_rv = (op)) < 0) { \\
1787 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1788 of_object_delete((of_object_t *)(obj)); \\
1789 return (rv); \\
1790 } \\
1791 } while (0)
1792""")
1793
1794 for version in of_g.of_version_range:
1795 for cls in of_g.standard_class_order:
1796 if not loxi_utils.class_in_version(cls, version):
1797 continue
1798 if cls in type_maps.inheritance_map:
1799 gen_dup_inheritance(out, cls, version)
1800 elif loxi_utils.class_is_list(cls):
1801 gen_dup_list(out, cls, version)
1802 else:
1803 gen_dup_cls(out, cls, version)
1804
1805def gen_dup(out=sys.stdout):
1806 """
1807 Generate non-version specific duplication routines for each object type
1808 """
1809
1810 for cls in of_g.standard_class_order:
1811 out.write("""
1812%(cls)s_t *
1813%(cls)s_dup(
1814 %(cls)s_t *src)
1815{
1816""" % dict(cls=cls))
1817 for version in of_g.of_version_range:
1818 if not loxi_utils.class_in_version(cls, version):
1819 continue
1820 hdr = "header." if cls in type_maps.inheritance_map else ""
1821
1822 ver_name = loxi_utils.version_to_name(version)
1823 out.write("""
1824 if (src->%(hdr)sversion == %(ver_name)s) {
1825 return %(cls)s_%(ver_name)s_dup(src);
1826 }
1827""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1828
1829 out.write("""
1830 /* Class not supported in given version */
1831 return NULL;
1832}
1833""")
1834
1835def dup_c_gen(out, name):
1836 """
1837 Generate the C file for duplication functions
1838 """
1839 loxi_utils.gen_c_copy_license(out)
1840 out.write("""\
1841/*
1842 * Duplication functions for all OF objects
1843 *
1844 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1845 *
1846 * These are test functions for exercising accessors. You can call
1847 * of_object_dup for an efficient duplication.
1848 */
1849
1850#define DISABLE_WARN_UNUSED_RESULT
1851#include "loci_log.h"
1852#include <locitest/of_dup.h>
1853
1854""")
1855
1856 gen_version_dup(out)
1857 gen_dup(out)
1858
1859
1860def dup_h_gen(out, name):
1861 """
1862 Generate the header file for duplication functions
1863 """
1864
1865 loxi_utils.gen_c_copy_license(out)
1866 out.write("""
1867/*
1868 * Duplication function header file
1869 *
1870 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1871 */
1872
1873#if !defined(_OF_DUP_H_)
1874#define _OF_DUP_H_
1875
1876#include <loci/loci.h>
1877""")
1878
1879 for cls in of_g.standard_class_order:
1880 out.write("""
1881extern %(cls)s_t *
1882 %(cls)s_dup(
1883 %(cls)s_t *src);
1884""" % dict(cls=cls))
1885
1886 for version in of_g.of_version_range:
1887 for cls in of_g.standard_class_order:
1888 if not loxi_utils.class_in_version(cls, version):
1889 continue
1890 ver_name = loxi_utils.version_to_name(version)
1891 out.write("""
1892extern %(cls)s_t *
1893 %(cls)s_%(ver_name)s_dup(
1894 %(cls)s_t *src);
1895""" % dict(cls=cls, ver_name=ver_name))
1896
1897 out.write("\n#endif /* _OF_DUP_H_ */\n")
1898
1899def gen_log_test(out):
1900 """
1901 Generate test for obj log calls
1902
1903 Define a trivial handler for object logging; call all obj log fns
1904 """
1905 out.write("""
1906
1907/**
1908 * Test object dump functions
1909 */
1910
1911int
1912test_dump_objs(void)
1913{
1914 of_object_t *obj;
1915
1916 FILE *out = fopen("/dev/null", "w");
1917
1918 /* Call each obj dump function */
1919""")
1920 for version in of_g.of_version_range:
1921 for j, cls in enumerate(of_g.all_class_order):
1922 if not loxi_utils.class_in_version(cls, version):
1923 continue
1924 if cls in type_maps.inheritance_map:
1925 continue
1926 out.write("""
1927 obj = (of_object_t *)%(cls)s_new(%(version)s);
1928 of_object_dump((loci_writer_f)fprintf, out, obj);
1929 of_object_delete(obj);
1930""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001931
Rich Lanea06d0c32013-03-25 08:52:03 -07001932 out.write("""
1933 fclose(out);
1934 return TEST_PASS;
1935}
1936""")
1937
1938def gen_ident_tests(out):
1939 """
1940 Generate tests for identifiers
1941
1942 For all idents, instantiate, test version supported macros
1943 For flags, set it, test it, clear it, test it.
1944 """
1945 out.write("""
1946/**
1947 * Test cases for all flag accessor macros
1948 * These only test self consistency (and that they compile)
1949 */
1950int
1951test_ident_macros(void)
1952{
1953 int value __attribute__((unused));
1954 uint32_t flags;
1955
1956""")
1957
1958 for ident, info in of_g.identifiers.items():
1959 if not identifiers.defined_versions_agree(of_g.identifiers,
1960 of_g.target_version_list,
1961 ident):
1962 # @fixme
1963 continue
1964 out.write(" value = %s;\n" % ident)
1965 for version in of_g.target_version_list:
1966 if version in info["values_by_version"].keys():
1967 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1968 (ident, of_g.of_version_wire2name[version]))
1969 else:
1970 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1971 (ident, of_g.of_version_wire2name[version]))
1972 if flags.ident_is_flag(ident):
1973 # Grab first supported version
1974 for version in info["values_by_version"]:
1975 break
1976 out.write("""
1977 flags = 0;
1978 %(ident)s_SET(flags, %(ver_name)s);
1979 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1980 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1981 %(ident)s_CLEAR(flags, %(ver_name)s);
1982 TEST_ASSERT(flags == 0);
1983 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1984""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1985
1986 out.write("""
1987 return TEST_PASS;
1988}
1989""")
1990
Rich Laneccae0312013-07-21 23:34:13 -07001991def gen_datafiles_tests(out, name):
1992 tests = []
1993 for filename in test_data.list_files():
1994 data = test_data.read(filename)
1995 if not 'c' in data:
1996 continue
1997 name = filename[:-5].replace("/", "_")
1998 tests.append(dict(name=name,
1999 filename=filename,
2000 c=data['c'],
2001 binary=data['binary']))
2002
2003 util.render_template(out, "test_data.c", tests=tests)