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