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