blob: 5342a429c8ee121496bdb9919b1283fa1eced537 [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 Lanec247ade2014-11-07 09:33:24 -0800102 of_oxm_t="oxm",
103 of_bsn_vport_t="bsn_vport",
Rich Lane41b278f2014-10-17 18:29:56 -0700104 of_table_desc_t="table_desc",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700105 # BSN extensions
106 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700107 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800108 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700109 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700110
111 if m_type.find("of_list_") == 0:
112 return "list"
113 if m_type in of_g.of_mixed_types:
114 return of_g.of_mixed_types[m_type]["short_name"]
115 return _var_name_map[m_type]
116
117integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
118 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700119 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700120string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700121 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700122 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
123 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700124
125scalar_types = integer_types[:]
126scalar_types.extend(string_types)
127
Rich Lane1f315aa2014-10-13 17:11:35 -0700128# When embedding an object inside of another object we have to pick a single
129# subclass to use, unlike lists where we use all subclasses.
130embedded_subclasses = {
Rich Lanec247ade2014-11-07 09:33:24 -0800131 'of_oxm_t': 'of_oxm_eth_type',
132 'of_bsn_vport_t': 'of_bsn_vport_q_in_q',
Rich Lane1f315aa2014-10-13 17:11:35 -0700133}
134
Rich Lanea06d0c32013-03-25 08:52:03 -0700135def ignore_member(cls, version, m_name, m_type):
136 """
137 Filter out names or types that either don't have accessors
138 or those that should not be messed with
139 or whose types we're not ready to deal with yet.
140 """
Rich Lane79c87192014-03-04 10:56:59 -0800141
142 uclass = loxi_globals.unified.class_by_name(cls)
143 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700144 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800145
Rich Lane79c87192014-03-04 10:56:59 -0800146 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800147 return True
Rich Lane79c87192014-03-04 10:56:59 -0800148
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
150
151def gen_fill_string(out):
152 out.write("""
153
154/**
155 * The increment to use on values inside a string
156 */
157#define OF_TEST_STR_INCR 3
158
159/**
160 * Fill in a buffer with incrementing values starting
161 * at the given offset with the given value
162 * @param buf The buffer to fill
163 * @param value The value to use for data
164 * @param len The number of bytes to fill
165 */
166
167void
168of_test_str_fill(uint8_t *buf, int value, int len)
169{
170 int i;
171
172 for (i = 0; i < len; i++) {
173 *buf = value;
174 value += OF_TEST_STR_INCR;
175 buf++;
176 }
177}
178
179/**
180 * Given a buffer, verify that it's filled as above
181 * @param buf The buffer to check
182 * @param value The value to use for data
183 * @param len The number of bytes to fill
184 * @return Boolean True on equality (success)
185 */
186
187int
188of_test_str_check(uint8_t *buf, int value, int len)
189{
190 int i;
191 uint8_t val8;
192
193 val8 = value;
194
195 for (i = 0; i < len; i++) {
196 if (*buf != val8) {
197 return 0;
198 }
199 val8 += OF_TEST_STR_INCR;
200 buf++;
201 }
202
203 return 1;
204}
205
206/**
207 * Global that determines how octets should be populated
208 * -1 means use value % MAX (below) to determine length
209 * 0, 1, ... means used that fixed length
210 *
211 * Note: Was 16K, but that made objects too big. May add flexibility
212 * to call populate with a max parameter for length
213 */
214int octets_pop_style = -1;
215#define OCTETS_MAX_VALUE (128) /* 16K was too big */
216#define OCTETS_MULTIPLIER 6367 /* A prime */
217
218int
219of_octets_populate(of_octets_t *octets, int value)
220{
221 if (octets_pop_style < 0) {
222 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
223 } else {
224 octets->bytes = octets_pop_style;
225 }
226
227 if (octets->bytes != 0) {
228 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
229 return 0;
230 }
231 of_test_str_fill(octets->data, value, octets->bytes);
232 value += 1;
233 }
234
235 return value;
236}
237
238int
239of_octets_check(of_octets_t *octets, int value)
240{
241 int len;
242
243 if (octets_pop_style < 0) {
244 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
245 TEST_ASSERT(octets->bytes == len);
246 } else {
247 TEST_ASSERT(octets->bytes == octets_pop_style);
248 }
249
250 if (octets->bytes != 0) {
251 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
252 == 1);
253 value += 1;
254 }
255
256 return value;
257}
258
259int
260of_match_populate(of_match_t *match, of_version_t version, int value)
261{
262 MEMSET(match, 0, sizeof(*match));
263 match->version = version;
264""")
265
Rich Laned56f8d22014-05-06 14:52:55 -0700266 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700267 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700268 if (version == %d) {\
269""" % wire_version)
270 for key in keys:
271 entry = match.of_match_members[key]
272 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700273 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
274 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
275 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700276""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
277 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700278 }
279
Rich Laned56f8d22014-05-06 14:52:55 -0700280""")
281
Rich Laneb4a63a52014-05-22 14:41:57 -0700282 for wire_version, match_keys in match.match_keys.items():
283 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700284
285 out.write("""
286 if (value % 2) {
287 /* Sometimes set ipv4 addr masks to non-exact */
288 match->masks.ipv4_src = 0xffff0000;
289 match->masks.ipv4_dst = 0xfffff800;
290 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700291
292 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700293 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700294 return value;
295}
296
297int
298of_match_check(of_match_t *match, of_version_t version, int value)
299{
300 of_match_t check;
301
302 value = of_match_populate(&check, match->version, value);
303 TEST_ASSERT(value != 0);
304 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
305
306 return value;
307}
308""")
309
310def gen_common_test_header(out, name):
311 loxi_utils.gen_c_copy_license(out)
312 out.write("""
313/*
314 * Test header file
315 *
316 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
317 */
318
319#if !defined(_TEST_COMMON_H_)
320#define _TEST_COMMON_H_
321
322#define DISABLE_WARN_UNUSED_RESULT
323#include <loci/loci.h>
324#include <locitest/of_dup.h>
325#include <locitest/unittest.h>
326
327extern int global_error;
328extern int exit_on_error;
329
330/* @todo Make option for -k to continue tests if errors */
331#define RUN_TEST(test) do { \\
332 int rv; \\
333 TESTCASE(test, rv); \\
334 if (rv != TEST_PASS) { \\
335 global_error=1; \\
336 if (exit_on_error) return(1); \\
337 } \\
338 } while(0)
339
340#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
341#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
342
343/*
344 * Declarations of functions to populate scalar values in a a class
345 */
346
347extern void of_test_str_fill(uint8_t *buf, int value, int len);
348extern int of_test_str_check(uint8_t *buf, int value, int len);
349
350
351extern int of_octets_populate(of_octets_t *octets, int value);
352extern int of_octets_check(of_octets_t *octets, int value);
353extern int of_match_populate(of_match_t *match, of_version_t version,
354 int value);
355extern int of_match_check(of_match_t *match, of_version_t version, int value);
356extern int test_ident_macros(void);
357extern int test_dump_objs(void);
358
359/* In test_match_utils.c */
360extern int test_match_utils(void);
361
362extern int run_unified_accessor_tests(void);
363extern int run_match_tests(void);
364extern int run_utility_tests(void);
365
366extern int run_scalar_acc_tests(void);
367extern int run_list_tests(void);
368extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700369
370extern int run_validator_tests(void);
371
372extern int run_list_limits_tests(void);
373
374extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700375extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700376
377""")
378
379 for version in of_g.of_version_range:
380 for cls in of_g.standard_class_order:
381 if not loxi_utils.class_in_version(cls, version):
382 continue
Rich Lane6171e632014-11-07 10:23:38 -0800383 if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700384 continue
385 out.write("""
386extern int %(cls)s_%(v_name)s_populate(
387 %(cls)s_t *obj, int value);
388extern int %(cls)s_%(v_name)s_check(
389 %(cls)s_t *obj, int value);
390extern int %(cls)s_%(v_name)s_populate_scalars(
391 %(cls)s_t *obj, int value);
392extern int %(cls)s_%(v_name)s_check_scalars(
393 %(cls)s_t *obj, int value);
394""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
395
Rich Lanea06d0c32013-03-25 08:52:03 -0700396 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
397
398def gen_common_test(out, name):
399 """
400 Generate common test content including main
401 """
402 loxi_utils.gen_c_copy_license(out)
403 out.write("""
404/*
405 * Common test code for LOCI
406 *
407 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
408 */
409
410#define DISABLE_WARN_UNUSED_RESULT
411#include "loci_log.h"
412#include <loci/loci_obj_dump.h>
413#include <locitest/unittest.h>
414#include <locitest/test_common.h>
415
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900416/* mcheck is a glibc extension */
417#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700418#include <mcheck.h>
419#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900420#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700421#define MCHECK_INIT do { } while (0)
422#endif
423
424/**
425 * Exit on error if set to 1
426 */
427int exit_on_error = 1;
428
429/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700430 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700431 */
432int global_error = 0;
433
434extern int run_unified_accessor_tests(void);
435extern int run_match_tests(void);
436extern int run_utility_tests(void);
437
438extern int run_scalar_acc_tests(void);
439extern int run_list_tests(void);
440extern int run_message_tests(void);
441
442/**
443 * Macros for initializing and checking scalar types
444 *
445 * @param var The variable being initialized or checked
446 * @param val The integer value to set/check against, see below
447 *
448 * Note that equality means something special for strings. Each byte
449 * is initialized to an incrementing value. So check is done against that.
450 *
451 */
452
453""")
454 for t in scalar_types:
455 if t in integer_types:
456 out.write("""
457#define VAR_%s_INIT(var, val) var = (%s)(val)
458#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
459""" % (t.upper(), t, t.upper(), t))
460 else:
461 out.write("""
462#define VAR_%s_INIT(var, val) \\
463 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
464#define VAR_%s_CHECK(var, val) \\
465 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
466""" % (t.upper(), t.upper()))
467
468 gen_fill_string(out)
469 gen_scalar_set_check_funs(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700470 gen_unified_accessor_funs(out)
471
472 gen_ident_tests(out)
473 gen_log_test(out)
474
475def gen_message_scalar_test(out, name):
476 """
477 Generate test cases for message objects, scalar accessors
478 """
479
480 loxi_utils.gen_c_copy_license(out)
481 out.write("""
482/**
483 *
484 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
485 *
486 * Message-scalar tests for all versions
487 */
488
489#include <locitest/test_common.h>
490""")
491 for version in of_g.of_version_range:
492 v_name = loxi_utils.version_to_name(version)
493 out.write("""
494/**
495 * Message-scalar tests for version %s
496 */
497""" % v_name)
498 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800499 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700500 continue
501 if version in of_g.unified[cls]:
502 message_scalar_test(out, version, cls)
503
504 out.write("""
505int
506run_scalar_acc_tests(void)
507{
508""")
509 for version in of_g.of_version_range:
510 v_name = loxi_utils.version_to_name(version)
511 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800512 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700513 continue
514 if version in of_g.unified[cls]:
515 test_name = "%s_%s" % (cls, v_name)
516 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
517
518 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700519
Rich Lanea06d0c32013-03-25 08:52:03 -0700520def message_scalar_test(out, version, cls):
521 """
522 Generate one test case for the given version and class
523 """
524
525 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700526 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700527 v_name = loxi_utils.version_to_name(version)
528
529 out.write("""
530static int
531test_%(cls)s_%(v_name)s_scalar(void)
532{
533 %(cls)s_t *obj;
534
535 obj = %(cls)s_new(%(v_name)s);
536 TEST_ASSERT(obj != NULL);
537 TEST_ASSERT(obj->version == %(v_name)s);
538 TEST_ASSERT(obj->length == %(length)d);
539 TEST_ASSERT(obj->parent == NULL);
540 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700541""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700542 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700543
544 # If this class is a concrete member of an inheritance hierarchy,
545 # run the hierarchy's root wire type parser and assert it returns
546 # the expected object id.
547 ofclass = loxi_globals.unified.class_by_name(cls)
548 if ofclass and not ofclass.virtual:
549 root = ofclass
550 while root.superclass:
551 root = root.superclass
552 if root.virtual:
553 out.write("""
554 {
555 of_object_id_t object_id;
556 %(root_cls)s_wire_object_id_get(obj, &object_id);
557 TEST_ASSERT(object_id == %(u_cls)s);
558 }
559""" % dict(root_cls=root.name, u_cls=cls.upper()))
560
Rich Lanea06d0c32013-03-25 08:52:03 -0700561 if not type_maps.class_is_virtual(cls):
562 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700563 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700564 int length;
565
Rich Lanedc46fe22014-04-03 15:10:38 -0700566 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700567 TEST_ASSERT(length == %(length)d);
568 }
569
570 /* Set up incrementing values for scalar members */
571 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
572
573 /* Check values just set */
574 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700575""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700576 v_name=v_name, length=length, version=version))
577
578 out.write("""
579 %(cls)s_delete(obj);
580
581 /* To do: Check memory */
582 return TEST_PASS;
583}
584""" % dict(cls=cls))
585
586# Get the members and list of scalar types for members of a given class
587def scalar_member_types_get(cls, version):
588 member_types = []
589
590 if not version in of_g.unified[cls]:
591 return ([], [])
592
593 if "use_version" in of_g.unified[cls][version]:
594 v = of_g.unified[cls][version]["use_version"]
595 members = of_g.unified[cls][v]["members"]
596 else:
597 members = of_g.unified[cls][version]["members"]
598 # Accumulate variables that are supported
599 for member in members:
600 m_type = member["m_type"]
601 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700602 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700603 ignore_member(cls, version, m_name, m_type)):
604 continue
605 if not m_type in member_types:
606 member_types.append(m_type)
607
608 return (members, member_types)
609
610def scalar_funs_instance(out, cls, version, members, member_types):
611 """
612 Generate one instance of scalar set/check functions
613 """
614 out.write("""
615/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700616 * Populate the scalar values in obj of type %(cls)s,
617 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700618 * @param obj Pointer to an object to populate
619 * @param value The seed value to use in populating the object
620 * @returns The value after increments for this object's values
621 */
622int %(cls)s_%(v_name)s_populate_scalars(
623 %(cls)s_t *obj, int value) {
624""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
625 # Declare string types
626 for t in member_types:
627 out.write(" %s %s;\n" % (t, var_name_map(t)))
628 for member in members:
629 m_type = member["m_type"]
630 m_name = member["name"]
631 if (not loxi_utils.type_is_scalar(m_type) or
632 ignore_member(cls, version, m_name, m_type)):
633 continue
634 v_name = var_name_map(m_type);
635 out.write("""
636 VAR_%(u_type)s_INIT(%(v_name)s, value);
637 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
638 value += 1;
639""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
640 out.write("""
641 return value;
642}
643""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700644
Rich Lanea06d0c32013-03-25 08:52:03 -0700645 out.write("""
646/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700647 * Check scalar values in obj of type %(cls)s,
648 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700649 * @param obj Pointer to an object to check
650 * @param value Starting value for checking
651 * @returns The value after increments for this object's values
652 */
653int %(cls)s_%(v_name)s_check_scalars(
654 %(cls)s_t *obj, int value) {
655""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
656
657 for t in member_types:
658 out.write(" %s %s;\n" % (t, var_name_map(t)))
659 for member in members:
660 m_type = member["m_type"]
661 m_name = member["name"]
662 if (not loxi_utils.type_is_scalar(m_type) or
663 ignore_member(cls, version, m_name, m_type)):
664 continue
665 v_name = var_name_map(m_type);
666 out.write("""
667 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
668 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
669 value += 1;
670""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
671
672 out.write("""
673 return value;
674}
675
676""")
677
678def gen_scalar_set_check_funs(out):
679 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700680 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700681 set and check their values
682 """
683 for version in of_g.of_version_range:
684 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800685 if type_maps.class_is_virtual(cls):
Rich Lanee499bd12014-10-28 15:25:09 -0700686 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700687 (members, member_types) = scalar_member_types_get(cls, version)
688 scalar_funs_instance(out, cls, version, members, member_types)
689
690
691# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700692def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700693 base_type = loxi_utils.list_to_entry_type(cls)
694 setup_template = """
695 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700696 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700697 value = %(subcls)s_%(v_name)s_populate(
698 %(inst)s, value);
699 cur_len += %(inst)s->length;
700 TEST_ASSERT(list->length == cur_len);
701"""
702 out.write("""
703 /* Append two instances of type %s */
704""" % subcls)
705 for i in range(2):
706 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700707 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700708 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700709 version=version))
710
Rich Lane9afc3b92014-04-09 22:55:53 -0700711def check_instance(out, cls, subcls, instance, v_name, version, last):
712 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700713 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
714 value = %(subcls)s_%(v_name)s_check(
715 %(inst)s, value);
716 TEST_ASSERT(value != 0);
717"""
718 out.write("\n /* Check two instances of type %s */" % instance)
719
Andreas Wundsam53256162013-05-02 14:05:53 -0700720 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700721 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700722 inst=instance, subcls=subcls,
723 v_name=loxi_utils.version_to_name(version)))
724 out.write("""\
725 TEST_OK(%(cls)s_next(list, &elt));
726""" % dict(cls=cls))
727
Andreas Wundsam53256162013-05-02 14:05:53 -0700728 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700729 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700730 inst=instance, subcls=subcls,
731 v_name=loxi_utils.version_to_name(version)))
732 if last:
733 out.write("""\
734 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
735""" % dict(cls=cls))
736 else:
737 out.write("""\
738 TEST_OK(%(cls)s_next(list, &elt));
739""" % dict(cls=cls))
740
Rich Lanea06d0c32013-03-25 08:52:03 -0700741# Maybe: Get a map from list class to parent, mem_name of container
742
743def list_test(out, version, cls):
744 out.write("""
745static int
746test_%(cls)s_%(v_name)s(void)
747{
748""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
749 base_type = loxi_utils.list_to_entry_type(cls)
750
751 out.write(""" %(cls)s_t *list;
752 int value = 1;
753""" % dict(cls=cls, base_type=base_type))
754
755 out.write("""
756 list = %(cls)s_new(%(v_name)s);
757 TEST_ASSERT(list != NULL);
758 TEST_ASSERT(list->version == %(v_name)s);
759 TEST_ASSERT(list->length == 0);
760 TEST_ASSERT(list->parent == NULL);
761 TEST_ASSERT(list->object_id == %(enum_cls)s);
762
Rich Lanec6e97f72014-12-03 12:08:25 -0800763 value = %(cls)s_%(v_name)s_populate(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700764 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700765""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700766 enum_cls=loxi_utils.enum_name(cls)))
767
768 out.write("""
769 /* Now check values */
770 value = 1;
Rich Lanec6e97f72014-12-03 12:08:25 -0800771 value = %(cls)s_%(v_name)s_check(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700772 TEST_ASSERT(value != 0);
773""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
774
775 out.write("""
776 %(cls)s_delete(list);
777
778 return TEST_PASS;
779}
780""" % dict(cls=cls))
781
782def gen_list_test(out, name):
783 """
784 Generate base line test cases for lists
785 @param out The file handle to write to
786 """
787
788 loxi_utils.gen_c_copy_license(out)
789 out.write("""
790/**
791 *
792 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
793 *
794 * Message-scalar tests for all versions
795 */
796
797#include <locitest/test_common.h>
798""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700799
Rich Lanea06d0c32013-03-25 08:52:03 -0700800 for version in of_g.of_version_range:
801 v_name = loxi_utils.version_to_name(version)
802 out.write("""
803/**
804 * Baseline list tests for version %s
805 */
806""" % v_name)
807 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700808 if version in of_g.unified[cls]:
809 list_test(out, version, cls)
810
811 out.write("""
812int
813run_list_tests(void)
814{
815""")
816 for version in of_g.of_version_range:
817 v_name = loxi_utils.version_to_name(version)
818 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700819 if version in of_g.unified[cls]:
820 test_name = "%s_%s" % (cls, v_name)
821 out.write(" RUN_TEST(%s);\n" % test_name)
822
823 out.write("\n return TEST_PASS;\n}\n");
824
825def gen_match_test(out, name):
826 """
827 Generate baseline tests for match functions
828 """
829
830 loxi_utils.gen_c_copy_license(out)
831 out.write("""\
832/**
833 *
834 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
835 *
836 * Message-scalar tests for all versions
837 * @fixme These are mostly hard coded now.
838 */
839
840#include <locitest/test_common.h>
841
842static int
843test_match_1(void)
844{
Rich Lanef87f4c32014-10-14 11:56:02 -0700845""")
846
847 for version in of_g.of_version_range:
848 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
849
850 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700851 of_match_t match;
852 int value = 1;
853 int idx;
854 uint32_t exp_value;
855
856 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700857 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700858 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
859 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
860 if (idx < 32) {
861 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
862 }
863 }
864""")
865
866 for version in of_g.of_version_range:
867 out.write("""
868 /* Create/populate/convert and delete for version %(v_name)s */
869 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
870 TEST_ASSERT(m_v%(version)d != NULL);
871 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
872 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
873 of_match_v%(version)d_delete(m_v%(version)d);
874""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
875
876 out.write("""
877 return TEST_PASS;
878}
879""")
880
881 out.write("""
882static int
883test_match_2(void)
884{
Rich Lanef87f4c32014-10-14 11:56:02 -0700885""")
886
887 for version in of_g.of_version_range:
888 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
889
890 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700891 of_match_t match1;
892 of_match_t match2;
893 int value = 1;
894""")
895
896 for version in of_g.of_version_range:
897 out.write("""
898 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
899 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
900 TEST_ASSERT(m_v%(version)d != NULL);
901 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
902 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
903 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
904 of_match_v%(version)d_delete(m_v%(version)d);
905""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
906
907 out.write("""
908 return TEST_PASS;
909}
910""")
911
912 out.write("""
913static int
914test_match_3(void)
915{
916 of_match_t match1;
917 of_match_t match2;
918 int value = 1;
919 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -0700920 of_object_storage_t storage;
921 memset(&storage, 0, sizeof(storage));
922 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700923""")
924 for version in of_g.of_version_range:
925 out.write("""
926 /* Serialize to version %(v_name)s */
927 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700928 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700929 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -0700930 storage.obj.wbuf->buf = octets.data;
931 storage.obj.wbuf->alloc_bytes = octets.bytes;
932 storage.obj.wbuf->current_bytes = octets.bytes;
933 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700934 OF_ERROR_NONE);
935 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
936 FREE(octets.data);
937""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
938
939 out.write("""
940 return TEST_PASS;
941}
942""")
943
944 out.write("""
945int run_match_tests(void)
946{
947 RUN_TEST(match_1);
948 RUN_TEST(match_2);
949 RUN_TEST(match_3);
950 RUN_TEST(match_utils);
951
952 return TEST_PASS;
953}
954""")
955
956def gen_msg_test(out, name):
957 loxi_utils.gen_c_copy_license(out)
958 out.write("""
959/**
960 *
961 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
962 *
963 * Message-scalar tests for all versions
964 */
965
966#include <locitest/test_common.h>
967""")
968 for version in of_g.of_version_range:
969 for cls in of_g.ordered_messages:
970 if not (cls, version) in of_g.base_length:
971 continue
Rich Lane488b3c52013-06-21 18:11:02 -0700972 if type_maps.class_is_virtual(cls):
973 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -0700974 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700975 out.write("""
976static int
977test_%(cls)s_create_%(v_name)s(void)
978{
979 %(cls)s_t *obj;
980 uint8_t *msg_buf;
981 int value;
Rich Lanea4b68302014-03-12 15:17:58 -0700982 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -0700983 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700984
985 obj = %(cls)s_new(%(v_name)s);
986 TEST_ASSERT(obj != NULL);
987 TEST_ASSERT(obj->version == %(v_name)s);
988 TEST_ASSERT(obj->length == %(bytes)d);
989 TEST_ASSERT(obj->parent == NULL);
990 TEST_ASSERT(obj->object_id == %(enum)s);
991
Rich Lanea4b68302014-03-12 15:17:58 -0700992 of_header_wire_object_id_get(obj, &object_id);
993 TEST_ASSERT(object_id == %(enum)s);
994
Rich Lanea06d0c32013-03-25 08:52:03 -0700995 /* Set up incrementing values for scalar members */
996 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
997 TEST_ASSERT(value != 0);
998
Rich Lanebb8f17c2014-06-12 13:14:09 -0700999 len = obj->length;
1000
Rich Lanea06d0c32013-03-25 08:52:03 -07001001 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001002 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1003 TEST_ASSERT(msg_buf != NULL);
1004 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001005 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001006
1007 TEST_ASSERT(obj != NULL);
1008
1009 /* @fixme Set up all message objects (recursively?) */
1010
1011 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1012 TEST_ASSERT(value != 0);
1013
1014 %(cls)s_delete(obj);
1015
1016 return TEST_PASS;
1017}
1018""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1019 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1020
1021 out.write("""
1022int
1023run_message_tests(void)
1024{
1025""")
1026 for version in of_g.of_version_range:
1027 for cls in of_g.ordered_messages:
1028 if not (cls, version) in of_g.base_length:
1029 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001030 if type_maps.class_is_virtual(cls):
1031 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001032 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1033 out.write(" RUN_TEST(%s);\n" % test_name)
1034
1035 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001036
Rich Lanea06d0c32013-03-25 08:52:03 -07001037
1038def gen_list_setup_check(out, cls, version):
1039 """
1040 Generate functions that populate and check a list with two
1041 of each type of subclass it supports
1042 """
1043 out.write("""
1044/**
1045 * Populate a list of type %(cls)s with two of each type of subclass
1046 * @param list Pointer to the list to be populated
1047 * @param value The seed value to use in populating the list
1048 * @returns The value after increments for this object's values
1049 */
1050int
1051%(cls)s_%(v_name)s_populate(
1052 %(cls)s_t *list, int value)
1053{
1054""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1055 base_type = loxi_utils.list_to_entry_type(cls)
1056 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001057 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001058 int cur_len = 0;
Rich Lanead708032014-12-03 12:40:58 -08001059 static int recursion;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001060 (void) elt;
1061 (void) cur_len;
Rich Lanead708032014-12-03 12:40:58 -08001062
1063 if (recursion > 0) {
1064 return value;
1065 }
1066
1067 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001068""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001069
Rich Lanea06d0c32013-03-25 08:52:03 -07001070 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001071 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 -07001072 v_name = loxi_utils.version_to_name(version)
1073
Rich Lanee98ee5d2014-10-14 10:43:44 -07001074 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001075 out.write(" /* No subclasses for %s */\n"% base_type)
1076 out.write(" %s_t *elt_p;\n" % base_type)
1077 out.write("\n elt_p = &elt;\n")
1078 else:
1079 out.write(" /* Declare pointers for each subclass */\n")
1080 for instance, subcls in sub_classes:
1081 out.write(" %s_t *%s;\n" % (subcls, instance))
1082 out.write("\n /* Instantiate pointers for each subclass */\n")
1083 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001084 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001085
Rich Lanee98ee5d2014-10-14 10:43:44 -07001086 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001087 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001088 else:
1089 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001090 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001091 out.write("""
Rich Lanead708032014-12-03 12:40:58 -08001092 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001093 return value;
1094}
1095""")
1096 out.write("""
1097/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001098 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001099 * %(cls)s_%(v_name)s_populate
1100 * @param list Pointer to the list that was populated
1101 * @param value Starting value for checking
1102 * @returns The value after increments for this object's values
1103 */
1104int
1105%(cls)s_%(v_name)s_check(
1106 %(cls)s_t *list, int value)
1107{
1108""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1109 base_type = loxi_utils.list_to_entry_type(cls)
1110 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001111 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001112 int count = 0;
1113 int rv;
Rich Lanead708032014-12-03 12:40:58 -08001114 static int recursion;
1115
1116 if (recursion > 0) {
1117 return value;
1118 }
1119
1120 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001121""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001122
Rich Lanea06d0c32013-03-25 08:52:03 -07001123
1124 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001125 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 -07001126 v_name = loxi_utils.version_to_name(version)
1127
Rich Lanee98ee5d2014-10-14 10:43:44 -07001128 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001129 entry_count = 2
1130 out.write(" /* No subclasses for %s */\n"% base_type)
1131 out.write(" %s_t *elt_p;\n" % base_type)
1132 out.write("\n elt_p = &elt;\n")
1133 else:
1134 entry_count = 2 * len(sub_classes) # Two of each type appended
1135 out.write(" /* Declare pointers for each subclass */\n")
1136 for instance, subcls in sub_classes:
1137 out.write(" %s_t *%s;\n" % (subcls, instance))
1138 out.write("\n /* Instantiate pointers for each subclass */\n")
1139 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001140 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001141
Rich Lanee98ee5d2014-10-14 10:43:44 -07001142 if not type_maps.class_is_virtual(base_type) or sub_classes:
1143 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1144
1145 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001146 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001147 version, True)
1148 else:
1149 count = 0
1150 for instance, subcls in sub_classes:
1151 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001152 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001153 version, count==len(sub_classes))
1154 out.write("""
1155""" % dict(base_type=base_type))
1156
1157 out.write("""
1158 /* Do an iterate to test the iterator */
1159 %(u_cls)s_ITER(list, &elt, rv) {
1160 count += 1;
1161 }
1162
1163 TEST_ASSERT(rv == OF_ERROR_RANGE);
1164 TEST_ASSERT(count == %(entry_count)d);
1165
1166 /* We shoehorn a test of the dup functions here */
1167 {
1168 %(cls)s_t *dup;
1169
1170 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1171 TEST_ASSERT(dup->length == list->length);
1172 TEST_ASSERT(dup->object_id == list->object_id);
1173 TEST_ASSERT(dup->version == list->version);
1174 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1175 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1176 of_object_delete((of_object_t *)dup);
1177
1178 /* And now for the generic dup function */
1179 TEST_ASSERT((dup = (%(cls)s_t *)
1180 of_object_dup(list)) != NULL);
1181 TEST_ASSERT(dup->length == list->length);
1182 TEST_ASSERT(dup->object_id == list->object_id);
1183 TEST_ASSERT(dup->version == list->version);
1184 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1185 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1186 of_object_delete((of_object_t *)dup);
1187 }
1188
Rich Lanead708032014-12-03 12:40:58 -08001189 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001190 return value;
1191}
1192""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1193
1194
1195def gen_class_setup_check(out, cls, version):
1196 out.write("""
1197/**
1198 * Populate all members of an object of type %(cls)s
1199 * with incrementing values
1200 * @param obj Pointer to an object to populate
1201 * @param value The seed value to use in populating the object
1202 * @returns The value after increments for this object's values
1203 */
1204
1205int
1206%(cls)s_%(v_name)s_populate(
1207 %(cls)s_t *obj, int value)
1208{
1209""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1210 members, member_types = loxi_utils.all_member_types_get(cls, version)
1211 for m_type in member_types:
1212 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1213 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001214 elif m_type in embedded_subclasses:
1215 subcls = embedded_subclasses[m_type]
1216 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001217 else:
1218 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1219 out.write("""
1220 /* Run thru accessors after new to ensure okay */
1221""")
1222 for member in members:
1223 m_type = member["m_type"]
1224 m_name = member["name"]
1225 if loxi_utils.skip_member_name(m_name):
1226 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001227 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001228 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001229 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1230 out.write("""\
1231 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1232""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1233 else:
1234 sub_cls = m_type[:-2] # Trim _t
1235 out.write("""\
1236 {
1237 %(sub_cls)s_t sub_cls;
1238
1239 /* Test bind */
1240 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1241 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001242""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001243 m_name=m_name, sub_cls=sub_cls,
1244 v_name=loxi_utils.version_to_name(version)))
1245
1246 out.write("""
1247 value = %(cls)s_%(v_name)s_populate_scalars(
1248 obj, value);
1249 TEST_ASSERT(value != 0);
1250""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1251
1252 for member in members:
1253 m_type = member["m_type"]
1254 m_name = member["name"]
1255 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1256 continue
1257 if loxi_utils.skip_member_name(m_name):
1258 continue
1259 if m_type == "of_match_t":
1260 out.write("""\
1261 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1262 TEST_ASSERT(value != 0);
1263 %(cls)s_%(m_name)s_set(
1264 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001265""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001266 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1267 elif m_type == "of_octets_t":
1268 out.write("""\
1269 value = of_octets_populate(&%(var_name)s, value);
1270 TEST_ASSERT(value != 0);
1271 %(cls)s_%(m_name)s_set(
1272 obj, &%(var_name)s);
1273 if (octets.bytes) {
1274 FREE(octets.data);
1275 }
1276""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001277 elif m_type in embedded_subclasses:
1278 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001279 out.write("""\
1280 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1281 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001282 value = %(sub_cls)s_%(v_name)s_populate(
1283 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001284 TEST_ASSERT(value != 0);
1285 %(cls)s_%(m_name)s_set(
1286 obj, %(var_name)s);
1287 %(sub_cls)s_delete(%(var_name)s);
1288""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1289 var_name=var_name_map(m_type),
1290 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001291 else:
1292 sub_cls = m_type[:-2] # Trim _t
1293 out.write("""
1294 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1295 TEST_ASSERT(%(var_name)s != NULL);
1296 value = %(sub_cls)s_%(v_name)s_populate(
1297 %(var_name)s, value);
1298 TEST_ASSERT(value != 0);
1299 %(cls)s_%(m_name)s_set(
1300 obj, %(var_name)s);
1301 %(sub_cls)s_delete(%(var_name)s);
1302""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1303 var_name=var_name_map(m_type),
1304 v_name=loxi_utils.version_to_name(version)))
1305
1306 out.write("""
1307 return value;
1308}
1309""")
1310
1311 out.write("""
1312/**
1313 * Check all members of an object of type %(cls)s
1314 * populated by the above function
1315 * @param obj Pointer to an object to check
1316 * @param value Starting value for checking
1317 * @returns The value after increments for this object's values
1318 */
1319
1320int
1321%(cls)s_%(v_name)s_check(
1322 %(cls)s_t *obj, int value)
1323{
1324""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1325 members, member_types = loxi_utils.all_member_types_get(cls, version)
1326 for m_type in member_types:
1327 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1328 continue
1329 if loxi_utils.type_is_of_object(m_type):
1330 continue
1331 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1332 out.write("""
1333 value = %(cls)s_%(v_name)s_check_scalars(
1334 obj, value);
1335 TEST_ASSERT(value != 0);
1336""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1337
1338 for member in members:
1339 m_type = member["m_type"]
1340 m_name = member["name"]
1341 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1342 continue
1343 if loxi_utils.skip_member_name(m_name):
1344 continue
1345 if m_type == "of_match_t":
1346 out.write("""\
1347 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1348 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1349""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1350 v_name=loxi_utils.version_to_name(version)))
1351 elif m_type == "of_octets_t":
1352 out.write("""\
1353 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1354 value = of_octets_check(&%(var_name)s, value);
1355""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1356 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001357 elif m_type in embedded_subclasses:
1358 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001359 out.write("""
1360 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001361 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001362
1363 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1364 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001365 value = %(sub_cls)s_%(v_name)s_check(
1366 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001367 TEST_ASSERT(value != 0);
1368 %(sub_cls)s_delete(%(m_name)s_ptr);
1369 }
1370""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1371 var_name=var_name_map(m_type),
1372 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001373 else:
1374 sub_cls = m_type[:-2] # Trim _t
1375 out.write("""
1376 { /* Use get/delete to access on check */
1377 %(m_type)s *%(m_name)s_ptr;
1378
1379 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1380 TEST_ASSERT(%(m_name)s_ptr != NULL);
1381 value = %(sub_cls)s_%(v_name)s_check(
1382 %(m_name)s_ptr, value);
1383 TEST_ASSERT(value != 0);
1384 %(sub_cls)s_delete(%(m_name)s_ptr);
1385 }
1386""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1387 var_name=var_name_map(m_type),
1388 v_name=loxi_utils.version_to_name(version)))
1389
1390 out.write("""
1391 /* We shoehorn a test of the dup functions here */
1392 {
1393 %(cls)s_t *dup;
1394
1395 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1396 TEST_ASSERT(dup->length == obj->length);
1397 TEST_ASSERT(dup->object_id == obj->object_id);
1398 TEST_ASSERT(dup->version == obj->version);
1399 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1400 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1401 of_object_delete((of_object_t *)dup);
1402
1403 /* And now for the generic dup function */
1404 TEST_ASSERT((dup = (%(cls)s_t *)
1405 of_object_dup(obj)) != NULL);
1406 TEST_ASSERT(dup->length == obj->length);
1407 TEST_ASSERT(dup->object_id == obj->object_id);
1408 TEST_ASSERT(dup->version == obj->version);
1409 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1410 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1411 of_object_delete((of_object_t *)dup);
1412 }
1413
1414 return value;
1415}
1416""" % dict(cls=cls))
1417
1418def unified_accessor_test_case(out, cls, version):
1419 """
1420 Generate one test case for the given version and class
1421 """
1422
1423 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001424 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001425 v_name = loxi_utils.version_to_name(version)
1426
1427 out.write("""
1428static int
1429test_%(cls)s_%(v_name)s(void)
1430{
1431 %(cls)s_t *obj;
1432 obj = %(cls)s_new(%(v_name)s);
1433 TEST_ASSERT(obj != NULL);
1434 TEST_ASSERT(obj->version == %(v_name)s);
1435 TEST_ASSERT(obj->length == %(length)d);
1436 TEST_ASSERT(obj->parent == NULL);
1437 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001438""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001439 v_name=v_name, length=length, version=version))
1440 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1441 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001442 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001443 int length;
1444
Rich Lanedc46fe22014-04-03 15:10:38 -07001445 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001446 TEST_ASSERT(length == %(length)d);
1447 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001448 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001449 of_object_id_t obj_id;
1450
Rich Lanedc46fe22014-04-03 15:10:38 -07001451 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001452 TEST_ASSERT(obj_id == %(u_cls)s);
1453 }
1454
1455 /* Set up incrementing values for members */
1456 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1457 obj, 1) != 0);
1458
1459 /* Check values just set */
1460 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1461 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001462""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001463 v_name=v_name, length=length, version=version))
1464
1465 out.write("""
1466 %(cls)s_delete(obj);
1467
1468 /* To do: Check memory */
1469 return TEST_PASS;
1470}
1471""" % dict(cls=cls))
1472
1473
1474def gen_unified_accessor_funs(out):
1475 for version in of_g.of_version_range:
1476 for cls in of_g.standard_class_order:
1477 if not loxi_utils.class_in_version(cls, version):
1478 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001479 elif loxi_utils.class_is_list(cls):
1480 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001481 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001482 gen_class_setup_check(out, cls, version)
1483
1484def gen_unified_accessor_tests(out, name):
1485 loxi_utils.gen_c_copy_license(out)
1486 out.write("""
1487/**
1488 *
1489 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1490 *
1491 * Unified simple class instantiation tests for all versions
1492 */
1493
1494#include <locitest/test_common.h>
1495""")
1496 for version in of_g.of_version_range:
1497 for cls in of_g.standard_class_order:
1498 if not loxi_utils.class_in_version(cls, version):
1499 continue
Rich Lane6171e632014-11-07 10:23:38 -08001500 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001501 continue
1502 unified_accessor_test_case(out, cls, version)
1503
1504 out.write("""
1505int
1506run_unified_accessor_tests(void)
1507{
1508""")
1509 for version in of_g.of_version_range:
1510 v_name = loxi_utils.version_to_name(version)
1511 for cls in of_g.standard_class_order:
1512 if not loxi_utils.class_in_version(cls, version):
1513 continue
Rich Lane6171e632014-11-07 10:23:38 -08001514 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001515 continue
1516 test_name = "%s_%s" % (cls, v_name)
1517 out.write(" RUN_TEST(%s);\n" % test_name)
1518
1519 out.write(" return TEST_PASS;\n}\n");
1520
1521
1522
1523################################################################
1524#
1525# Object duplication functions
1526#
1527# These exercise the accessors to create duplicate objects.
1528# They are used in the LOCI test shim which sits in an OF
1529# protocol stream.
1530#
1531# TODO
1532# Resolve version stuff
1533# Complete list dup
1534
1535def gen_dup_list(out, cls, version):
1536 ver_name = loxi_utils.version_to_name(version)
1537 elt_type = loxi_utils.list_to_entry_type(cls)
1538 out.write("""
1539/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001540 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001541 * using accessor functions
1542 * @param src Pointer to object to be duplicated
1543 * @returns A new object of type %(cls)s.
1544 *
1545 * The caller is responsible for deleting the returned value
1546 */
1547%(cls)s_t *
1548%(cls)s_%(ver_name)s_dup(
1549 %(cls)s_t *src)
1550{
Rich Lanee499bd12014-10-28 15:25:09 -07001551 of_object_t src_elt;
1552 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001553 int rv;
1554 %(cls)s_t *dst;
1555
1556 if ((dst = %(cls)s_new(src->version)) == NULL) {
1557 return NULL;
1558 }
1559""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1560
1561 out.write("""
1562 %(u_cls)s_ITER(src, &src_elt, rv) {
1563 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1564 of_object_delete((of_object_t *)dst);
1565 return NULL;
1566 }
1567 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1568 dst, NULL);
1569 of_object_delete((of_object_t *)dst_elt);
1570 }
1571
1572 return dst;
1573}
1574""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1575
1576
1577def gen_dup_inheritance(out, cls, version):
1578 ver_name = loxi_utils.version_to_name(version)
1579 out.write("""
1580/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001581 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001582 * @param src Pointer to object to be duplicated
1583 * @returns A new object of type %(cls)s.
1584 *
1585 * The caller is responsible for deleting the returned value
1586 */
Rich Lanee499bd12014-10-28 15:25:09 -07001587of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001588%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001589 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001590{
1591""" % dict(cls=cls, ver_name=ver_name))
1592
1593 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001594 sub_classes = type_maps.sub_class_map(cls, version)
1595 for (_, sub_cls) in sub_classes:
1596 sub_enum = sub_cls.upper()
Rich Lane6171e632014-11-07 10:23:38 -08001597 if type_maps.class_is_virtual(sub_cls):
1598 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001599 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001600 if (src->object_id == %(sub_enum)s) {
1601 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001602 }
1603""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1604
1605 out.write("""
1606 return NULL;
1607}
1608""")
1609
1610
1611def gen_dup_cls(out, cls, version):
1612 """
1613 Generate duplication routine for class cls
1614 """
1615 ver_name = loxi_utils.version_to_name(version)
1616
1617 out.write("""
1618/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001619 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001620 * using accessor functions
1621 * @param src Pointer to object to be duplicated
1622 * @returns A new object of type %(cls)s.
1623 *
1624 * The caller is responsible for deleting the returned value
1625 */
1626%(cls)s_t *
1627%(cls)s_%(ver_name)s_dup(
1628 %(cls)s_t *src)
1629{
1630 %(cls)s_t *dst;
1631""" % dict(cls=cls, ver_name=ver_name))
1632
1633 # Get members and types for the class
1634 members, member_types = loxi_utils.all_member_types_get(cls, version)
1635
1636 # Add declarations for each member type
1637 for m_type in member_types:
1638 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1639 # Declare instance of these
1640 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001641 elif m_type in embedded_subclasses:
1642 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001643 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001644 %(sub_cls)s_t src_%(v_name)s;
1645 %(sub_cls)s_t *dst_%(v_name)s;
1646""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001647 else:
1648 out.write("""
1649 %(m_type)s src_%(v_name)s;
1650 %(m_type)s *dst_%(v_name)s;
1651""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1652
1653 out.write("""
1654 if ((dst = %(cls)s_new(src->version)) == NULL) {
1655 return NULL;
1656 }
1657""" % dict(cls=cls))
1658
1659 for member in members:
1660 m_type = member["m_type"]
1661 m_name = member["name"]
1662 if loxi_utils.skip_member_name(m_name):
1663 continue
1664 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1665 out.write("""
1666 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1667 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1668""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1669 elif m_type in ["of_match_t", "of_octets_t"]:
1670 out.write("""
1671 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1672 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1673""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001674 elif m_type in embedded_subclasses:
1675 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001676 out.write("""
1677 %(cls)s_%(m_name)s_bind(
1678 src, &src_%(v_name)s);
1679 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1680 if (dst_%(v_name)s == NULL) {
1681 %(cls)s_delete(dst);
1682 return NULL;
1683 }
1684 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1685 %(sub_cls)s_delete(dst_%(v_name)s);
1686""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1687 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001688 else:
1689 sub_cls = m_type[:-2] # Trim _t
1690 out.write("""
1691 %(cls)s_%(m_name)s_bind(
1692 src, &src_%(v_name)s);
1693 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1694 if (dst_%(v_name)s == NULL) {
1695 %(cls)s_delete(dst);
1696 return NULL;
1697 }
1698 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1699 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001700""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001701 v_name=var_name_map(m_type), ver_name=ver_name))
1702
1703 out.write("""
1704 return dst;
1705}
1706""")
1707
1708def gen_version_dup(out=sys.stdout):
1709 """
1710 Generate duplication routines for each object type
1711 """
1712 out.write("""
1713/* Special try macro for duplicating */
1714#define _TRY_FREE(op, obj, rv) do { \\
1715 int _rv; \\
1716 if ((_rv = (op)) < 0) { \\
1717 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1718 of_object_delete((of_object_t *)(obj)); \\
1719 return (rv); \\
1720 } \\
1721 } while (0)
1722""")
1723
1724 for version in of_g.of_version_range:
1725 for cls in of_g.standard_class_order:
1726 if not loxi_utils.class_in_version(cls, version):
1727 continue
Rich Lane8841f352014-10-12 19:18:36 -07001728 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001729 gen_dup_inheritance(out, cls, version)
1730 elif loxi_utils.class_is_list(cls):
1731 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001732 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001733 gen_dup_cls(out, cls, version)
1734
1735def gen_dup(out=sys.stdout):
1736 """
1737 Generate non-version specific duplication routines for each object type
1738 """
1739
1740 for cls in of_g.standard_class_order:
1741 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001742of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001743%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001744 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001745{
1746""" % dict(cls=cls))
1747 for version in of_g.of_version_range:
1748 if not loxi_utils.class_in_version(cls, version):
1749 continue
Rich Lane6171e632014-11-07 10:23:38 -08001750 elif type_maps.class_is_inheritance_root(cls):
1751 pass
1752 elif loxi_utils.class_is_list(cls):
1753 pass
1754 elif type_maps.class_is_virtual(cls):
1755 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001756 ver_name = loxi_utils.version_to_name(version)
1757 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001758 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001759 return %(cls)s_%(ver_name)s_dup(src);
1760 }
Rich Lanee499bd12014-10-28 15:25:09 -07001761""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001762
1763 out.write("""
1764 /* Class not supported in given version */
1765 return NULL;
1766}
1767""")
1768
1769def dup_c_gen(out, name):
1770 """
1771 Generate the C file for duplication functions
1772 """
1773 loxi_utils.gen_c_copy_license(out)
1774 out.write("""\
1775/*
1776 * Duplication functions for all OF objects
1777 *
1778 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1779 *
1780 * These are test functions for exercising accessors. You can call
1781 * of_object_dup for an efficient duplication.
1782 */
1783
1784#define DISABLE_WARN_UNUSED_RESULT
1785#include "loci_log.h"
1786#include <locitest/of_dup.h>
1787
1788""")
1789
1790 gen_version_dup(out)
1791 gen_dup(out)
1792
1793
1794def dup_h_gen(out, name):
1795 """
1796 Generate the header file for duplication functions
1797 """
1798
1799 loxi_utils.gen_c_copy_license(out)
1800 out.write("""
1801/*
1802 * Duplication function header file
1803 *
1804 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1805 */
1806
1807#if !defined(_OF_DUP_H_)
1808#define _OF_DUP_H_
1809
1810#include <loci/loci.h>
1811""")
1812
1813 for cls in of_g.standard_class_order:
1814 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001815extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001816 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001817 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001818""" % dict(cls=cls))
1819
1820 for version in of_g.of_version_range:
1821 for cls in of_g.standard_class_order:
1822 if not loxi_utils.class_in_version(cls, version):
1823 continue
Rich Lane6171e632014-11-07 10:23:38 -08001824 elif type_maps.class_is_inheritance_root(cls):
1825 pass
1826 elif loxi_utils.class_is_list(cls):
1827 pass
1828 elif type_maps.class_is_virtual(cls):
1829 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001830 ver_name = loxi_utils.version_to_name(version)
1831 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001832extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001833 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001834 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001835""" % dict(cls=cls, ver_name=ver_name))
1836
1837 out.write("\n#endif /* _OF_DUP_H_ */\n")
1838
1839def gen_log_test(out):
1840 """
1841 Generate test for obj log calls
1842
1843 Define a trivial handler for object logging; call all obj log fns
1844 """
1845 out.write("""
1846
1847/**
1848 * Test object dump functions
1849 */
1850
1851int
1852test_dump_objs(void)
1853{
1854 of_object_t *obj;
1855
1856 FILE *out = fopen("/dev/null", "w");
1857
1858 /* Call each obj dump function */
1859""")
1860 for version in of_g.of_version_range:
1861 for j, cls in enumerate(of_g.all_class_order):
1862 if not loxi_utils.class_in_version(cls, version):
1863 continue
Rich Lane6171e632014-11-07 10:23:38 -08001864 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001865 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001866 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1867 out.write("""
1868 obj = (of_object_t *)%(cls)s_new(%(version)s);
1869 {
1870 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1871 %(cls)s_vport_set(obj, vport);
1872 of_object_delete(vport);
1873 }
1874 of_object_dump((loci_writer_f)fprintf, out, obj);
1875 of_object_delete(obj);
1876""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1877 else:
1878 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001879 obj = (of_object_t *)%(cls)s_new(%(version)s);
1880 of_object_dump((loci_writer_f)fprintf, out, obj);
1881 of_object_delete(obj);
1882""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001883
Rich Lanea06d0c32013-03-25 08:52:03 -07001884 out.write("""
1885 fclose(out);
1886 return TEST_PASS;
1887}
1888""")
1889
1890def gen_ident_tests(out):
1891 """
1892 Generate tests for identifiers
1893
1894 For all idents, instantiate, test version supported macros
1895 For flags, set it, test it, clear it, test it.
1896 """
1897 out.write("""
1898/**
1899 * Test cases for all flag accessor macros
1900 * These only test self consistency (and that they compile)
1901 */
1902int
1903test_ident_macros(void)
1904{
1905 int value __attribute__((unused));
1906 uint32_t flags;
1907
1908""")
1909
1910 for ident, info in of_g.identifiers.items():
1911 if not identifiers.defined_versions_agree(of_g.identifiers,
1912 of_g.target_version_list,
1913 ident):
1914 # @fixme
1915 continue
1916 out.write(" value = %s;\n" % ident)
1917 for version in of_g.target_version_list:
1918 if version in info["values_by_version"].keys():
1919 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1920 (ident, of_g.of_version_wire2name[version]))
1921 else:
1922 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1923 (ident, of_g.of_version_wire2name[version]))
1924 if flags.ident_is_flag(ident):
1925 # Grab first supported version
1926 for version in info["values_by_version"]:
1927 break
1928 out.write("""
1929 flags = 0;
1930 %(ident)s_SET(flags, %(ver_name)s);
1931 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1932 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1933 %(ident)s_CLEAR(flags, %(ver_name)s);
1934 TEST_ASSERT(flags == 0);
1935 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1936""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1937
1938 out.write("""
1939 return TEST_PASS;
1940}
1941""")
1942
Rich Laneccae0312013-07-21 23:34:13 -07001943def gen_datafiles_tests(out, name):
1944 tests = []
1945 for filename in test_data.list_files():
1946 data = test_data.read(filename)
1947 if not 'c' in data:
1948 continue
1949 name = filename[:-5].replace("/", "_")
1950 tests.append(dict(name=name,
1951 filename=filename,
1952 c=data['c'],
1953 binary=data['binary']))
1954
1955 util.render_template(out, "test_data.c", tests=tests)