blob: 71615e69d6afc74447eebe7e8fffb343904ad9bf [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;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001030 of_object_storage_t storage;
1031 memset(&storage, 0, sizeof(storage));
1032 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001033""")
1034 for version in of_g.of_version_range:
1035 out.write("""
1036 /* Serialize to version %(v_name)s */
1037 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001038 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001039 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001040 storage.obj.wbuf->buf = octets.data;
1041 storage.obj.wbuf->alloc_bytes = octets.bytes;
1042 storage.obj.wbuf->current_bytes = octets.bytes;
1043 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001044 OF_ERROR_NONE);
1045 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1046 FREE(octets.data);
1047""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1048
1049 out.write("""
1050 return TEST_PASS;
1051}
1052""")
1053
1054 out.write("""
1055int run_match_tests(void)
1056{
1057 RUN_TEST(match_1);
1058 RUN_TEST(match_2);
1059 RUN_TEST(match_3);
1060 RUN_TEST(match_utils);
1061
1062 return TEST_PASS;
1063}
1064""")
1065
1066def gen_msg_test(out, name):
1067 loxi_utils.gen_c_copy_license(out)
1068 out.write("""
1069/**
1070 *
1071 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1072 *
1073 * Message-scalar tests for all versions
1074 */
1075
1076#include <locitest/test_common.h>
1077""")
1078 for version in of_g.of_version_range:
1079 for cls in of_g.ordered_messages:
1080 if not (cls, version) in of_g.base_length:
1081 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001082 if type_maps.class_is_virtual(cls):
1083 continue
Rich Lanef70be942013-07-18 13:33:14 -07001084 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001085 out.write("""
1086static int
1087test_%(cls)s_create_%(v_name)s(void)
1088{
1089 %(cls)s_t *obj;
1090 uint8_t *msg_buf;
1091 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001092 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001093 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001094
1095 obj = %(cls)s_new(%(v_name)s);
1096 TEST_ASSERT(obj != NULL);
1097 TEST_ASSERT(obj->version == %(v_name)s);
1098 TEST_ASSERT(obj->length == %(bytes)d);
1099 TEST_ASSERT(obj->parent == NULL);
1100 TEST_ASSERT(obj->object_id == %(enum)s);
1101
Rich Lanea4b68302014-03-12 15:17:58 -07001102 of_header_wire_object_id_get(obj, &object_id);
1103 TEST_ASSERT(object_id == %(enum)s);
1104
Rich Lanea06d0c32013-03-25 08:52:03 -07001105 /* Set up incrementing values for scalar members */
1106 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1107 TEST_ASSERT(value != 0);
1108
Rich Lanebb8f17c2014-06-12 13:14:09 -07001109 len = obj->length;
1110
Rich Lanea06d0c32013-03-25 08:52:03 -07001111 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001112 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1113 TEST_ASSERT(msg_buf != NULL);
1114 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001115 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001116
1117 TEST_ASSERT(obj != NULL);
1118
1119 /* @fixme Set up all message objects (recursively?) */
1120
1121 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1122 TEST_ASSERT(value != 0);
1123
1124 %(cls)s_delete(obj);
1125
1126 return TEST_PASS;
1127}
1128""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1129 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1130
1131 out.write("""
1132int
1133run_message_tests(void)
1134{
1135""")
1136 for version in of_g.of_version_range:
1137 for cls in of_g.ordered_messages:
1138 if not (cls, version) in of_g.base_length:
1139 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001140 if type_maps.class_is_virtual(cls):
1141 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001142 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1143 out.write(" RUN_TEST(%s);\n" % test_name)
1144
1145 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001146
Rich Lanea06d0c32013-03-25 08:52:03 -07001147
1148def gen_list_setup_check(out, cls, version):
1149 """
1150 Generate functions that populate and check a list with two
1151 of each type of subclass it supports
1152 """
1153 out.write("""
1154/**
1155 * Populate a list of type %(cls)s with two of each type of subclass
1156 * @param list Pointer to the list to be populated
1157 * @param value The seed value to use in populating the list
1158 * @returns The value after increments for this object's values
1159 */
1160int
1161%(cls)s_%(v_name)s_populate(
1162 %(cls)s_t *list, int value)
1163{
1164""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1165 base_type = loxi_utils.list_to_entry_type(cls)
1166 out.write("""
1167 %(base_type)s_t elt;
1168 int cur_len = 0;
1169""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001170
Rich Lanea06d0c32013-03-25 08:52:03 -07001171 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001172 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 -07001173 v_name = loxi_utils.version_to_name(version)
1174
1175 if len(sub_classes) == 0:
1176 out.write(" /* No subclasses for %s */\n"% base_type)
1177 out.write(" %s_t *elt_p;\n" % base_type)
1178 out.write("\n elt_p = &elt;\n")
1179 else:
1180 out.write(" /* Declare pointers for each subclass */\n")
1181 for instance, subcls in sub_classes:
1182 out.write(" %s_t *%s;\n" % (subcls, instance))
1183 out.write("\n /* Instantiate pointers for each subclass */\n")
1184 for instance, subcls in sub_classes:
1185 out.write(" %s = &elt.%s;\n" % (instance, instance))
1186
Rich Lanea06d0c32013-03-25 08:52:03 -07001187 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001188 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001189 else:
1190 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001191 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 out.write("""
1193 return value;
1194}
1195""")
1196 out.write("""
1197/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001198 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001199 * %(cls)s_%(v_name)s_populate
1200 * @param list Pointer to the list that was populated
1201 * @param value Starting value for checking
1202 * @returns The value after increments for this object's values
1203 */
1204int
1205%(cls)s_%(v_name)s_check(
1206 %(cls)s_t *list, int value)
1207{
1208""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1209 base_type = loxi_utils.list_to_entry_type(cls)
1210 out.write("""
1211 %(base_type)s_t elt;
1212 int count = 0;
1213 int rv;
1214""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001215
Rich Lanea06d0c32013-03-25 08:52:03 -07001216
1217 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001218 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 -07001219 v_name = loxi_utils.version_to_name(version)
1220
1221 if len(sub_classes) == 0:
1222 entry_count = 2
1223 out.write(" /* No subclasses for %s */\n"% base_type)
1224 out.write(" %s_t *elt_p;\n" % base_type)
1225 out.write("\n elt_p = &elt;\n")
1226 else:
1227 entry_count = 2 * len(sub_classes) # Two of each type appended
1228 out.write(" /* Declare pointers for each subclass */\n")
1229 for instance, subcls in sub_classes:
1230 out.write(" %s_t *%s;\n" % (subcls, instance))
1231 out.write("\n /* Instantiate pointers for each subclass */\n")
1232 for instance, subcls in sub_classes:
1233 out.write(" %s = &elt.%s;\n" % (instance, instance))
1234
1235 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1236 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001237 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001238 version, True)
1239 else:
1240 count = 0
1241 for instance, subcls in sub_classes:
1242 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001243 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001244 version, count==len(sub_classes))
1245 out.write("""
1246""" % dict(base_type=base_type))
1247
1248 out.write("""
1249 /* Do an iterate to test the iterator */
1250 %(u_cls)s_ITER(list, &elt, rv) {
1251 count += 1;
1252 }
1253
1254 TEST_ASSERT(rv == OF_ERROR_RANGE);
1255 TEST_ASSERT(count == %(entry_count)d);
1256
1257 /* We shoehorn a test of the dup functions here */
1258 {
1259 %(cls)s_t *dup;
1260
1261 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1262 TEST_ASSERT(dup->length == list->length);
1263 TEST_ASSERT(dup->object_id == list->object_id);
1264 TEST_ASSERT(dup->version == list->version);
1265 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1266 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1267 of_object_delete((of_object_t *)dup);
1268
1269 /* And now for the generic dup function */
1270 TEST_ASSERT((dup = (%(cls)s_t *)
1271 of_object_dup(list)) != NULL);
1272 TEST_ASSERT(dup->length == list->length);
1273 TEST_ASSERT(dup->object_id == list->object_id);
1274 TEST_ASSERT(dup->version == list->version);
1275 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1276 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1277 of_object_delete((of_object_t *)dup);
1278 }
1279
1280 return value;
1281}
1282""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1283
1284
1285def gen_class_setup_check(out, cls, version):
1286 out.write("""
1287/**
1288 * Populate all members of an object of type %(cls)s
1289 * with incrementing values
1290 * @param obj Pointer to an object to populate
1291 * @param value The seed value to use in populating the object
1292 * @returns The value after increments for this object's values
1293 */
1294
1295int
1296%(cls)s_%(v_name)s_populate(
1297 %(cls)s_t *obj, int value)
1298{
1299""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1300 members, member_types = loxi_utils.all_member_types_get(cls, version)
1301 for m_type in member_types:
1302 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1303 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001304 elif m_type == "of_bsn_vport_header_t":
1305 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001306 else:
1307 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1308 out.write("""
1309 /* Run thru accessors after new to ensure okay */
1310""")
1311 for member in members:
1312 m_type = member["m_type"]
1313 m_name = member["name"]
1314 if loxi_utils.skip_member_name(m_name):
1315 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001316 if m_type == "of_bsn_vport_header_t":
1317 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001318 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1319 out.write("""\
1320 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1321""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1322 else:
1323 sub_cls = m_type[:-2] # Trim _t
1324 out.write("""\
1325 {
1326 %(sub_cls)s_t sub_cls;
1327
1328 /* Test bind */
1329 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1330 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001331""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001332 m_name=m_name, sub_cls=sub_cls,
1333 v_name=loxi_utils.version_to_name(version)))
1334
1335 out.write("""
1336 value = %(cls)s_%(v_name)s_populate_scalars(
1337 obj, value);
1338 TEST_ASSERT(value != 0);
1339""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1340
1341 for member in members:
1342 m_type = member["m_type"]
1343 m_name = member["name"]
1344 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1345 continue
1346 if loxi_utils.skip_member_name(m_name):
1347 continue
1348 if m_type == "of_match_t":
1349 out.write("""\
1350 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1351 TEST_ASSERT(value != 0);
1352 %(cls)s_%(m_name)s_set(
1353 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001354""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001355 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1356 elif m_type == "of_octets_t":
1357 out.write("""\
1358 value = of_octets_populate(&%(var_name)s, value);
1359 TEST_ASSERT(value != 0);
1360 %(cls)s_%(m_name)s_set(
1361 obj, &%(var_name)s);
1362 if (octets.bytes) {
1363 FREE(octets.data);
1364 }
1365""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001366 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1367 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001368 out.write("""\
1369 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1370 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001371 value = %(sub_cls)s_%(v_name)s_populate(
1372 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001373 TEST_ASSERT(value != 0);
1374 %(cls)s_%(m_name)s_set(
1375 obj, %(var_name)s);
1376 %(sub_cls)s_delete(%(var_name)s);
1377""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1378 var_name=var_name_map(m_type),
1379 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001380 else:
1381 sub_cls = m_type[:-2] # Trim _t
1382 out.write("""
1383 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1384 TEST_ASSERT(%(var_name)s != NULL);
1385 value = %(sub_cls)s_%(v_name)s_populate(
1386 %(var_name)s, value);
1387 TEST_ASSERT(value != 0);
1388 %(cls)s_%(m_name)s_set(
1389 obj, %(var_name)s);
1390 %(sub_cls)s_delete(%(var_name)s);
1391""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1392 var_name=var_name_map(m_type),
1393 v_name=loxi_utils.version_to_name(version)))
1394
1395 out.write("""
1396 return value;
1397}
1398""")
1399
1400 out.write("""
1401/**
1402 * Check all members of an object of type %(cls)s
1403 * populated by the above function
1404 * @param obj Pointer to an object to check
1405 * @param value Starting value for checking
1406 * @returns The value after increments for this object's values
1407 */
1408
1409int
1410%(cls)s_%(v_name)s_check(
1411 %(cls)s_t *obj, int value)
1412{
1413""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1414 members, member_types = loxi_utils.all_member_types_get(cls, version)
1415 for m_type in member_types:
1416 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1417 continue
1418 if loxi_utils.type_is_of_object(m_type):
1419 continue
1420 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1421 out.write("""
1422 value = %(cls)s_%(v_name)s_check_scalars(
1423 obj, value);
1424 TEST_ASSERT(value != 0);
1425""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1426
1427 for member in members:
1428 m_type = member["m_type"]
1429 m_name = member["name"]
1430 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1431 continue
1432 if loxi_utils.skip_member_name(m_name):
1433 continue
1434 if m_type == "of_match_t":
1435 out.write("""\
1436 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1437 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1438""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1439 v_name=loxi_utils.version_to_name(version)))
1440 elif m_type == "of_octets_t":
1441 out.write("""\
1442 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1443 value = of_octets_check(&%(var_name)s, value);
1444""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1445 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001446 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1447 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001448 out.write("""
1449 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001450 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001451
1452 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1453 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001454 value = %(sub_cls)s_%(v_name)s_check(
1455 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001456 TEST_ASSERT(value != 0);
1457 %(sub_cls)s_delete(%(m_name)s_ptr);
1458 }
1459""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1460 var_name=var_name_map(m_type),
1461 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001462 else:
1463 sub_cls = m_type[:-2] # Trim _t
1464 out.write("""
1465 { /* Use get/delete to access on check */
1466 %(m_type)s *%(m_name)s_ptr;
1467
1468 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1469 TEST_ASSERT(%(m_name)s_ptr != NULL);
1470 value = %(sub_cls)s_%(v_name)s_check(
1471 %(m_name)s_ptr, value);
1472 TEST_ASSERT(value != 0);
1473 %(sub_cls)s_delete(%(m_name)s_ptr);
1474 }
1475""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1476 var_name=var_name_map(m_type),
1477 v_name=loxi_utils.version_to_name(version)))
1478
1479 out.write("""
1480 /* We shoehorn a test of the dup functions here */
1481 {
1482 %(cls)s_t *dup;
1483
1484 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1485 TEST_ASSERT(dup->length == obj->length);
1486 TEST_ASSERT(dup->object_id == obj->object_id);
1487 TEST_ASSERT(dup->version == obj->version);
1488 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1489 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1490 of_object_delete((of_object_t *)dup);
1491
1492 /* And now for the generic dup function */
1493 TEST_ASSERT((dup = (%(cls)s_t *)
1494 of_object_dup(obj)) != NULL);
1495 TEST_ASSERT(dup->length == obj->length);
1496 TEST_ASSERT(dup->object_id == obj->object_id);
1497 TEST_ASSERT(dup->version == obj->version);
1498 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1499 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1500 of_object_delete((of_object_t *)dup);
1501 }
1502
1503 return value;
1504}
1505""" % dict(cls=cls))
1506
1507def unified_accessor_test_case(out, cls, version):
1508 """
1509 Generate one test case for the given version and class
1510 """
1511
1512 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001513 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001514 v_name = loxi_utils.version_to_name(version)
1515
1516 out.write("""
1517static int
1518test_%(cls)s_%(v_name)s(void)
1519{
1520 %(cls)s_t *obj;
1521 obj = %(cls)s_new(%(v_name)s);
1522 TEST_ASSERT(obj != NULL);
1523 TEST_ASSERT(obj->version == %(v_name)s);
1524 TEST_ASSERT(obj->length == %(length)d);
1525 TEST_ASSERT(obj->parent == NULL);
1526 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001527""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001528 v_name=v_name, length=length, version=version))
1529 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1530 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001531 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001532 int length;
1533
Rich Lanedc46fe22014-04-03 15:10:38 -07001534 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001535 TEST_ASSERT(length == %(length)d);
1536 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001537 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001538 of_object_id_t obj_id;
1539
Rich Lanedc46fe22014-04-03 15:10:38 -07001540 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001541 TEST_ASSERT(obj_id == %(u_cls)s);
1542 }
1543
1544 /* Set up incrementing values for members */
1545 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1546 obj, 1) != 0);
1547
1548 /* Check values just set */
1549 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1550 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001551""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001552 v_name=v_name, length=length, version=version))
1553
1554 out.write("""
1555 %(cls)s_delete(obj);
1556
1557 /* To do: Check memory */
1558 return TEST_PASS;
1559}
1560""" % dict(cls=cls))
1561
1562
1563def gen_unified_accessor_funs(out):
1564 for version in of_g.of_version_range:
1565 for cls in of_g.standard_class_order:
1566 if not loxi_utils.class_in_version(cls, version):
1567 continue
1568 if cls in type_maps.inheritance_map:
1569 continue
1570 elif loxi_utils.class_is_list(cls):
1571 gen_list_setup_check(out, cls, version)
1572 else:
1573 gen_class_setup_check(out, cls, version)
1574
1575def gen_unified_accessor_tests(out, name):
1576 loxi_utils.gen_c_copy_license(out)
1577 out.write("""
1578/**
1579 *
1580 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1581 *
1582 * Unified simple class instantiation tests for all versions
1583 */
1584
1585#include <locitest/test_common.h>
1586""")
1587 for version in of_g.of_version_range:
1588 for cls in of_g.standard_class_order:
1589 if not loxi_utils.class_in_version(cls, version):
1590 continue
1591 if cls in type_maps.inheritance_map:
1592 continue
1593 unified_accessor_test_case(out, cls, version)
1594
1595 out.write("""
1596int
1597run_unified_accessor_tests(void)
1598{
1599""")
1600 for version in of_g.of_version_range:
1601 v_name = loxi_utils.version_to_name(version)
1602 for cls in of_g.standard_class_order:
1603 if not loxi_utils.class_in_version(cls, version):
1604 continue
1605 if cls in type_maps.inheritance_map:
1606 continue
1607 test_name = "%s_%s" % (cls, v_name)
1608 out.write(" RUN_TEST(%s);\n" % test_name)
1609
1610 out.write(" return TEST_PASS;\n}\n");
1611
1612
1613
1614################################################################
1615#
1616# Object duplication functions
1617#
1618# These exercise the accessors to create duplicate objects.
1619# They are used in the LOCI test shim which sits in an OF
1620# protocol stream.
1621#
1622# TODO
1623# Resolve version stuff
1624# Complete list dup
1625
1626def gen_dup_list(out, cls, version):
1627 ver_name = loxi_utils.version_to_name(version)
1628 elt_type = loxi_utils.list_to_entry_type(cls)
1629 out.write("""
1630/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001631 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001632 * using accessor functions
1633 * @param src Pointer to object to be duplicated
1634 * @returns A new object of type %(cls)s.
1635 *
1636 * The caller is responsible for deleting the returned value
1637 */
1638%(cls)s_t *
1639%(cls)s_%(ver_name)s_dup(
1640 %(cls)s_t *src)
1641{
1642 %(elt_type)s_t src_elt;
1643 %(elt_type)s_t *dst_elt;
1644 int rv;
1645 %(cls)s_t *dst;
1646
1647 if ((dst = %(cls)s_new(src->version)) == NULL) {
1648 return NULL;
1649 }
1650""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1651
1652 out.write("""
1653 %(u_cls)s_ITER(src, &src_elt, rv) {
1654 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1655 of_object_delete((of_object_t *)dst);
1656 return NULL;
1657 }
1658 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1659 dst, NULL);
1660 of_object_delete((of_object_t *)dst_elt);
1661 }
1662
1663 return dst;
1664}
1665""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1666
1667
1668def gen_dup_inheritance(out, cls, version):
1669 ver_name = loxi_utils.version_to_name(version)
1670 out.write("""
1671/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001672 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001673 * @param src Pointer to object to be duplicated
1674 * @returns A new object of type %(cls)s.
1675 *
1676 * The caller is responsible for deleting the returned value
1677 */
1678%(cls)s_t *
1679%(cls)s_%(ver_name)s_dup(
1680 %(cls)s_t *src)
1681{
1682""" % dict(cls=cls, ver_name=ver_name))
1683
1684 # For each subclass, check if this is an instance of that subclass
1685 version_classes = type_maps.inheritance_data[cls][version]
1686 for sub_cls in version_classes:
1687 sub_enum = (cls + "_" + sub_cls).upper()
1688 out.write("""
1689 if (src->header.object_id == %(sub_enum)s) {
1690 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1691 &src->%(sub_cls)s);
1692 }
1693""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1694
1695 out.write("""
1696 return NULL;
1697}
1698""")
1699
1700
1701def gen_dup_cls(out, cls, version):
1702 """
1703 Generate duplication routine for class cls
1704 """
1705 ver_name = loxi_utils.version_to_name(version)
1706
1707 out.write("""
1708/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001709 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001710 * using accessor functions
1711 * @param src Pointer to object to be duplicated
1712 * @returns A new object of type %(cls)s.
1713 *
1714 * The caller is responsible for deleting the returned value
1715 */
1716%(cls)s_t *
1717%(cls)s_%(ver_name)s_dup(
1718 %(cls)s_t *src)
1719{
1720 %(cls)s_t *dst;
1721""" % dict(cls=cls, ver_name=ver_name))
1722
1723 # Get members and types for the class
1724 members, member_types = loxi_utils.all_member_types_get(cls, version)
1725
1726 # Add declarations for each member type
1727 for m_type in member_types:
1728 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1729 # Declare instance of these
1730 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001731 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1732 out.write("""
1733 of_bsn_vport_q_in_q_t src_%(v_name)s;
1734 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1735""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001736 else:
1737 out.write("""
1738 %(m_type)s src_%(v_name)s;
1739 %(m_type)s *dst_%(v_name)s;
1740""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1741
1742 out.write("""
1743 if ((dst = %(cls)s_new(src->version)) == NULL) {
1744 return NULL;
1745 }
1746""" % dict(cls=cls))
1747
1748 for member in members:
1749 m_type = member["m_type"]
1750 m_name = member["name"]
1751 if loxi_utils.skip_member_name(m_name):
1752 continue
1753 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1754 out.write("""
1755 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1756 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1757""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1758 elif m_type in ["of_match_t", "of_octets_t"]:
1759 out.write("""
1760 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1761 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1762""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001763 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1764 sub_cls = "of_bsn_vport_q_in_q"
1765 out.write("""
1766 %(cls)s_%(m_name)s_bind(
1767 src, &src_%(v_name)s);
1768 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1769 if (dst_%(v_name)s == NULL) {
1770 %(cls)s_delete(dst);
1771 return NULL;
1772 }
1773 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1774 %(sub_cls)s_delete(dst_%(v_name)s);
1775""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1776 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001777 else:
1778 sub_cls = m_type[:-2] # Trim _t
1779 out.write("""
1780 %(cls)s_%(m_name)s_bind(
1781 src, &src_%(v_name)s);
1782 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1783 if (dst_%(v_name)s == NULL) {
1784 %(cls)s_delete(dst);
1785 return NULL;
1786 }
1787 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1788 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001789""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001790 v_name=var_name_map(m_type), ver_name=ver_name))
1791
1792 out.write("""
1793 return dst;
1794}
1795""")
1796
1797def gen_version_dup(out=sys.stdout):
1798 """
1799 Generate duplication routines for each object type
1800 """
1801 out.write("""
1802/* Special try macro for duplicating */
1803#define _TRY_FREE(op, obj, rv) do { \\
1804 int _rv; \\
1805 if ((_rv = (op)) < 0) { \\
1806 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1807 of_object_delete((of_object_t *)(obj)); \\
1808 return (rv); \\
1809 } \\
1810 } while (0)
1811""")
1812
1813 for version in of_g.of_version_range:
1814 for cls in of_g.standard_class_order:
1815 if not loxi_utils.class_in_version(cls, version):
1816 continue
1817 if cls in type_maps.inheritance_map:
1818 gen_dup_inheritance(out, cls, version)
1819 elif loxi_utils.class_is_list(cls):
1820 gen_dup_list(out, cls, version)
1821 else:
1822 gen_dup_cls(out, cls, version)
1823
1824def gen_dup(out=sys.stdout):
1825 """
1826 Generate non-version specific duplication routines for each object type
1827 """
1828
1829 for cls in of_g.standard_class_order:
1830 out.write("""
1831%(cls)s_t *
1832%(cls)s_dup(
1833 %(cls)s_t *src)
1834{
1835""" % dict(cls=cls))
1836 for version in of_g.of_version_range:
1837 if not loxi_utils.class_in_version(cls, version):
1838 continue
1839 hdr = "header." if cls in type_maps.inheritance_map else ""
1840
1841 ver_name = loxi_utils.version_to_name(version)
1842 out.write("""
1843 if (src->%(hdr)sversion == %(ver_name)s) {
1844 return %(cls)s_%(ver_name)s_dup(src);
1845 }
1846""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1847
1848 out.write("""
1849 /* Class not supported in given version */
1850 return NULL;
1851}
1852""")
1853
1854def dup_c_gen(out, name):
1855 """
1856 Generate the C file for duplication functions
1857 """
1858 loxi_utils.gen_c_copy_license(out)
1859 out.write("""\
1860/*
1861 * Duplication functions for all OF objects
1862 *
1863 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1864 *
1865 * These are test functions for exercising accessors. You can call
1866 * of_object_dup for an efficient duplication.
1867 */
1868
1869#define DISABLE_WARN_UNUSED_RESULT
1870#include "loci_log.h"
1871#include <locitest/of_dup.h>
1872
1873""")
1874
1875 gen_version_dup(out)
1876 gen_dup(out)
1877
1878
1879def dup_h_gen(out, name):
1880 """
1881 Generate the header file for duplication functions
1882 """
1883
1884 loxi_utils.gen_c_copy_license(out)
1885 out.write("""
1886/*
1887 * Duplication function header file
1888 *
1889 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1890 */
1891
1892#if !defined(_OF_DUP_H_)
1893#define _OF_DUP_H_
1894
1895#include <loci/loci.h>
1896""")
1897
1898 for cls in of_g.standard_class_order:
1899 out.write("""
1900extern %(cls)s_t *
1901 %(cls)s_dup(
1902 %(cls)s_t *src);
1903""" % dict(cls=cls))
1904
1905 for version in of_g.of_version_range:
1906 for cls in of_g.standard_class_order:
1907 if not loxi_utils.class_in_version(cls, version):
1908 continue
1909 ver_name = loxi_utils.version_to_name(version)
1910 out.write("""
1911extern %(cls)s_t *
1912 %(cls)s_%(ver_name)s_dup(
1913 %(cls)s_t *src);
1914""" % dict(cls=cls, ver_name=ver_name))
1915
1916 out.write("\n#endif /* _OF_DUP_H_ */\n")
1917
1918def gen_log_test(out):
1919 """
1920 Generate test for obj log calls
1921
1922 Define a trivial handler for object logging; call all obj log fns
1923 """
1924 out.write("""
1925
1926/**
1927 * Test object dump functions
1928 */
1929
1930int
1931test_dump_objs(void)
1932{
1933 of_object_t *obj;
1934
1935 FILE *out = fopen("/dev/null", "w");
1936
1937 /* Call each obj dump function */
1938""")
1939 for version in of_g.of_version_range:
1940 for j, cls in enumerate(of_g.all_class_order):
1941 if not loxi_utils.class_in_version(cls, version):
1942 continue
1943 if cls in type_maps.inheritance_map:
1944 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001945 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1946 out.write("""
1947 obj = (of_object_t *)%(cls)s_new(%(version)s);
1948 {
1949 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1950 %(cls)s_vport_set(obj, vport);
1951 of_object_delete(vport);
1952 }
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]))
1956 else:
1957 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001958 obj = (of_object_t *)%(cls)s_new(%(version)s);
1959 of_object_dump((loci_writer_f)fprintf, out, obj);
1960 of_object_delete(obj);
1961""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001962
Rich Lanea06d0c32013-03-25 08:52:03 -07001963 out.write("""
1964 fclose(out);
1965 return TEST_PASS;
1966}
1967""")
1968
1969def gen_ident_tests(out):
1970 """
1971 Generate tests for identifiers
1972
1973 For all idents, instantiate, test version supported macros
1974 For flags, set it, test it, clear it, test it.
1975 """
1976 out.write("""
1977/**
1978 * Test cases for all flag accessor macros
1979 * These only test self consistency (and that they compile)
1980 */
1981int
1982test_ident_macros(void)
1983{
1984 int value __attribute__((unused));
1985 uint32_t flags;
1986
1987""")
1988
1989 for ident, info in of_g.identifiers.items():
1990 if not identifiers.defined_versions_agree(of_g.identifiers,
1991 of_g.target_version_list,
1992 ident):
1993 # @fixme
1994 continue
1995 out.write(" value = %s;\n" % ident)
1996 for version in of_g.target_version_list:
1997 if version in info["values_by_version"].keys():
1998 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1999 (ident, of_g.of_version_wire2name[version]))
2000 else:
2001 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2002 (ident, of_g.of_version_wire2name[version]))
2003 if flags.ident_is_flag(ident):
2004 # Grab first supported version
2005 for version in info["values_by_version"]:
2006 break
2007 out.write("""
2008 flags = 0;
2009 %(ident)s_SET(flags, %(ver_name)s);
2010 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2011 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2012 %(ident)s_CLEAR(flags, %(ver_name)s);
2013 TEST_ASSERT(flags == 0);
2014 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2015""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2016
2017 out.write("""
2018 return TEST_PASS;
2019}
2020""")
2021
Rich Laneccae0312013-07-21 23:34:13 -07002022def gen_datafiles_tests(out, name):
2023 tests = []
2024 for filename in test_data.list_files():
2025 data = test_data.read(filename)
2026 if not 'c' in data:
2027 continue
2028 name = filename[:-5].replace("/", "_")
2029 tests.append(dict(name=name,
2030 filename=filename,
2031 c=data['c'],
2032 binary=data['binary']))
2033
2034 util.render_template(out, "test_data.c", tests=tests)