blob: 07959b400fe4108b9d12301d4cde3018e28c00be [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 Lanee98ee5d2014-10-14 10:43:44 -07001059 (void) elt;
1060 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001061""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001062
Rich Lanea06d0c32013-03-25 08:52:03 -07001063 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001064 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 -07001065 v_name = loxi_utils.version_to_name(version)
1066
Rich Lanee98ee5d2014-10-14 10:43:44 -07001067 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001068 out.write(" /* No subclasses for %s */\n"% base_type)
1069 out.write(" %s_t *elt_p;\n" % base_type)
1070 out.write("\n elt_p = &elt;\n")
1071 else:
1072 out.write(" /* Declare pointers for each subclass */\n")
1073 for instance, subcls in sub_classes:
1074 out.write(" %s_t *%s;\n" % (subcls, instance))
1075 out.write("\n /* Instantiate pointers for each subclass */\n")
1076 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001077 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001078
Rich Lanee98ee5d2014-10-14 10:43:44 -07001079 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001080 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001081 else:
1082 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001083 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001084 out.write("""
1085 return value;
1086}
1087""")
1088 out.write("""
1089/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001090 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001091 * %(cls)s_%(v_name)s_populate
1092 * @param list Pointer to the list that was populated
1093 * @param value Starting value for checking
1094 * @returns The value after increments for this object's values
1095 */
1096int
1097%(cls)s_%(v_name)s_check(
1098 %(cls)s_t *list, int value)
1099{
1100""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1101 base_type = loxi_utils.list_to_entry_type(cls)
1102 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001103 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001104 int count = 0;
1105 int rv;
1106""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001107
Rich Lanea06d0c32013-03-25 08:52:03 -07001108
1109 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001110 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 -07001111 v_name = loxi_utils.version_to_name(version)
1112
Rich Lanee98ee5d2014-10-14 10:43:44 -07001113 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001114 entry_count = 2
1115 out.write(" /* No subclasses for %s */\n"% base_type)
1116 out.write(" %s_t *elt_p;\n" % base_type)
1117 out.write("\n elt_p = &elt;\n")
1118 else:
1119 entry_count = 2 * len(sub_classes) # Two of each type appended
1120 out.write(" /* Declare pointers for each subclass */\n")
1121 for instance, subcls in sub_classes:
1122 out.write(" %s_t *%s;\n" % (subcls, instance))
1123 out.write("\n /* Instantiate pointers for each subclass */\n")
1124 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001125 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001126
Rich Lanee98ee5d2014-10-14 10:43:44 -07001127 if not type_maps.class_is_virtual(base_type) or sub_classes:
1128 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1129
1130 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001131 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001132 version, True)
1133 else:
1134 count = 0
1135 for instance, subcls in sub_classes:
1136 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001137 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001138 version, count==len(sub_classes))
1139 out.write("""
1140""" % dict(base_type=base_type))
1141
1142 out.write("""
1143 /* Do an iterate to test the iterator */
1144 %(u_cls)s_ITER(list, &elt, rv) {
1145 count += 1;
1146 }
1147
1148 TEST_ASSERT(rv == OF_ERROR_RANGE);
1149 TEST_ASSERT(count == %(entry_count)d);
1150
1151 /* We shoehorn a test of the dup functions here */
1152 {
1153 %(cls)s_t *dup;
1154
1155 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1156 TEST_ASSERT(dup->length == list->length);
1157 TEST_ASSERT(dup->object_id == list->object_id);
1158 TEST_ASSERT(dup->version == list->version);
1159 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1160 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1161 of_object_delete((of_object_t *)dup);
1162
1163 /* And now for the generic dup function */
1164 TEST_ASSERT((dup = (%(cls)s_t *)
1165 of_object_dup(list)) != NULL);
1166 TEST_ASSERT(dup->length == list->length);
1167 TEST_ASSERT(dup->object_id == list->object_id);
1168 TEST_ASSERT(dup->version == list->version);
1169 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1170 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1171 of_object_delete((of_object_t *)dup);
1172 }
1173
1174 return value;
1175}
1176""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1177
1178
1179def gen_class_setup_check(out, cls, version):
1180 out.write("""
1181/**
1182 * Populate all members of an object of type %(cls)s
1183 * with incrementing values
1184 * @param obj Pointer to an object to populate
1185 * @param value The seed value to use in populating the object
1186 * @returns The value after increments for this object's values
1187 */
1188
1189int
1190%(cls)s_%(v_name)s_populate(
1191 %(cls)s_t *obj, int value)
1192{
1193""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1194 members, member_types = loxi_utils.all_member_types_get(cls, version)
1195 for m_type in member_types:
1196 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1197 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001198 elif m_type in embedded_subclasses:
1199 subcls = embedded_subclasses[m_type]
1200 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001201 else:
1202 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1203 out.write("""
1204 /* Run thru accessors after new to ensure okay */
1205""")
1206 for member in members:
1207 m_type = member["m_type"]
1208 m_name = member["name"]
1209 if loxi_utils.skip_member_name(m_name):
1210 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001211 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001212 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001213 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1214 out.write("""\
1215 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1216""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1217 else:
1218 sub_cls = m_type[:-2] # Trim _t
1219 out.write("""\
1220 {
1221 %(sub_cls)s_t sub_cls;
1222
1223 /* Test bind */
1224 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1225 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001226""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001227 m_name=m_name, sub_cls=sub_cls,
1228 v_name=loxi_utils.version_to_name(version)))
1229
1230 out.write("""
1231 value = %(cls)s_%(v_name)s_populate_scalars(
1232 obj, value);
1233 TEST_ASSERT(value != 0);
1234""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1235
1236 for member in members:
1237 m_type = member["m_type"]
1238 m_name = member["name"]
1239 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1240 continue
1241 if loxi_utils.skip_member_name(m_name):
1242 continue
1243 if m_type == "of_match_t":
1244 out.write("""\
1245 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1246 TEST_ASSERT(value != 0);
1247 %(cls)s_%(m_name)s_set(
1248 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001249""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001250 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1251 elif m_type == "of_octets_t":
1252 out.write("""\
1253 value = of_octets_populate(&%(var_name)s, value);
1254 TEST_ASSERT(value != 0);
1255 %(cls)s_%(m_name)s_set(
1256 obj, &%(var_name)s);
1257 if (octets.bytes) {
1258 FREE(octets.data);
1259 }
1260""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001261 elif m_type in embedded_subclasses:
1262 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001263 out.write("""\
1264 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1265 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001266 value = %(sub_cls)s_%(v_name)s_populate(
1267 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001268 TEST_ASSERT(value != 0);
1269 %(cls)s_%(m_name)s_set(
1270 obj, %(var_name)s);
1271 %(sub_cls)s_delete(%(var_name)s);
1272""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1273 var_name=var_name_map(m_type),
1274 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001275 else:
1276 sub_cls = m_type[:-2] # Trim _t
1277 out.write("""
1278 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1279 TEST_ASSERT(%(var_name)s != NULL);
1280 value = %(sub_cls)s_%(v_name)s_populate(
1281 %(var_name)s, value);
1282 TEST_ASSERT(value != 0);
1283 %(cls)s_%(m_name)s_set(
1284 obj, %(var_name)s);
1285 %(sub_cls)s_delete(%(var_name)s);
1286""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1287 var_name=var_name_map(m_type),
1288 v_name=loxi_utils.version_to_name(version)))
1289
1290 out.write("""
1291 return value;
1292}
1293""")
1294
1295 out.write("""
1296/**
1297 * Check all members of an object of type %(cls)s
1298 * populated by the above function
1299 * @param obj Pointer to an object to check
1300 * @param value Starting value for checking
1301 * @returns The value after increments for this object's values
1302 */
1303
1304int
1305%(cls)s_%(v_name)s_check(
1306 %(cls)s_t *obj, int value)
1307{
1308""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1309 members, member_types = loxi_utils.all_member_types_get(cls, version)
1310 for m_type in member_types:
1311 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1312 continue
1313 if loxi_utils.type_is_of_object(m_type):
1314 continue
1315 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1316 out.write("""
1317 value = %(cls)s_%(v_name)s_check_scalars(
1318 obj, value);
1319 TEST_ASSERT(value != 0);
1320""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1321
1322 for member in members:
1323 m_type = member["m_type"]
1324 m_name = member["name"]
1325 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1326 continue
1327 if loxi_utils.skip_member_name(m_name):
1328 continue
1329 if m_type == "of_match_t":
1330 out.write("""\
1331 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1332 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1333""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1334 v_name=loxi_utils.version_to_name(version)))
1335 elif m_type == "of_octets_t":
1336 out.write("""\
1337 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1338 value = of_octets_check(&%(var_name)s, value);
1339""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1340 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001341 elif m_type in embedded_subclasses:
1342 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001343 out.write("""
1344 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001345 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001346
1347 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1348 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001349 value = %(sub_cls)s_%(v_name)s_check(
1350 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001351 TEST_ASSERT(value != 0);
1352 %(sub_cls)s_delete(%(m_name)s_ptr);
1353 }
1354""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1355 var_name=var_name_map(m_type),
1356 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001357 else:
1358 sub_cls = m_type[:-2] # Trim _t
1359 out.write("""
1360 { /* Use get/delete to access on check */
1361 %(m_type)s *%(m_name)s_ptr;
1362
1363 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1364 TEST_ASSERT(%(m_name)s_ptr != NULL);
1365 value = %(sub_cls)s_%(v_name)s_check(
1366 %(m_name)s_ptr, value);
1367 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)))
1373
1374 out.write("""
1375 /* We shoehorn a test of the dup functions here */
1376 {
1377 %(cls)s_t *dup;
1378
1379 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1380 TEST_ASSERT(dup->length == obj->length);
1381 TEST_ASSERT(dup->object_id == obj->object_id);
1382 TEST_ASSERT(dup->version == obj->version);
1383 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1384 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1385 of_object_delete((of_object_t *)dup);
1386
1387 /* And now for the generic dup function */
1388 TEST_ASSERT((dup = (%(cls)s_t *)
1389 of_object_dup(obj)) != NULL);
1390 TEST_ASSERT(dup->length == obj->length);
1391 TEST_ASSERT(dup->object_id == obj->object_id);
1392 TEST_ASSERT(dup->version == obj->version);
1393 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1394 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1395 of_object_delete((of_object_t *)dup);
1396 }
1397
1398 return value;
1399}
1400""" % dict(cls=cls))
1401
1402def unified_accessor_test_case(out, cls, version):
1403 """
1404 Generate one test case for the given version and class
1405 """
1406
1407 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001408 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001409 v_name = loxi_utils.version_to_name(version)
1410
1411 out.write("""
1412static int
1413test_%(cls)s_%(v_name)s(void)
1414{
1415 %(cls)s_t *obj;
1416 obj = %(cls)s_new(%(v_name)s);
1417 TEST_ASSERT(obj != NULL);
1418 TEST_ASSERT(obj->version == %(v_name)s);
1419 TEST_ASSERT(obj->length == %(length)d);
1420 TEST_ASSERT(obj->parent == NULL);
1421 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001422""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001423 v_name=v_name, length=length, version=version))
1424 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1425 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001426 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001427 int length;
1428
Rich Lanedc46fe22014-04-03 15:10:38 -07001429 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001430 TEST_ASSERT(length == %(length)d);
1431 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001432 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001433 of_object_id_t obj_id;
1434
Rich Lanedc46fe22014-04-03 15:10:38 -07001435 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001436 TEST_ASSERT(obj_id == %(u_cls)s);
1437 }
1438
1439 /* Set up incrementing values for members */
1440 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1441 obj, 1) != 0);
1442
1443 /* Check values just set */
1444 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1445 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001446""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001447 v_name=v_name, length=length, version=version))
1448
1449 out.write("""
1450 %(cls)s_delete(obj);
1451
1452 /* To do: Check memory */
1453 return TEST_PASS;
1454}
1455""" % dict(cls=cls))
1456
1457
1458def gen_unified_accessor_funs(out):
1459 for version in of_g.of_version_range:
1460 for cls in of_g.standard_class_order:
1461 if not loxi_utils.class_in_version(cls, version):
1462 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001463 elif loxi_utils.class_is_list(cls):
1464 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001465 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001466 gen_class_setup_check(out, cls, version)
1467
1468def gen_unified_accessor_tests(out, name):
1469 loxi_utils.gen_c_copy_license(out)
1470 out.write("""
1471/**
1472 *
1473 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1474 *
1475 * Unified simple class instantiation tests for all versions
1476 */
1477
1478#include <locitest/test_common.h>
1479""")
1480 for version in of_g.of_version_range:
1481 for cls in of_g.standard_class_order:
1482 if not loxi_utils.class_in_version(cls, version):
1483 continue
Rich Lane6171e632014-11-07 10:23:38 -08001484 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001485 continue
1486 unified_accessor_test_case(out, cls, version)
1487
1488 out.write("""
1489int
1490run_unified_accessor_tests(void)
1491{
1492""")
1493 for version in of_g.of_version_range:
1494 v_name = loxi_utils.version_to_name(version)
1495 for cls in of_g.standard_class_order:
1496 if not loxi_utils.class_in_version(cls, version):
1497 continue
Rich Lane6171e632014-11-07 10:23:38 -08001498 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001499 continue
1500 test_name = "%s_%s" % (cls, v_name)
1501 out.write(" RUN_TEST(%s);\n" % test_name)
1502
1503 out.write(" return TEST_PASS;\n}\n");
1504
1505
1506
1507################################################################
1508#
1509# Object duplication functions
1510#
1511# These exercise the accessors to create duplicate objects.
1512# They are used in the LOCI test shim which sits in an OF
1513# protocol stream.
1514#
1515# TODO
1516# Resolve version stuff
1517# Complete list dup
1518
1519def gen_dup_list(out, cls, version):
1520 ver_name = loxi_utils.version_to_name(version)
1521 elt_type = loxi_utils.list_to_entry_type(cls)
1522 out.write("""
1523/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001524 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001525 * using accessor functions
1526 * @param src Pointer to object to be duplicated
1527 * @returns A new object of type %(cls)s.
1528 *
1529 * The caller is responsible for deleting the returned value
1530 */
1531%(cls)s_t *
1532%(cls)s_%(ver_name)s_dup(
1533 %(cls)s_t *src)
1534{
Rich Lanee499bd12014-10-28 15:25:09 -07001535 of_object_t src_elt;
1536 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001537 int rv;
1538 %(cls)s_t *dst;
1539
1540 if ((dst = %(cls)s_new(src->version)) == NULL) {
1541 return NULL;
1542 }
1543""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1544
1545 out.write("""
1546 %(u_cls)s_ITER(src, &src_elt, rv) {
1547 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1548 of_object_delete((of_object_t *)dst);
1549 return NULL;
1550 }
1551 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1552 dst, NULL);
1553 of_object_delete((of_object_t *)dst_elt);
1554 }
1555
1556 return dst;
1557}
1558""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1559
1560
1561def gen_dup_inheritance(out, cls, version):
1562 ver_name = loxi_utils.version_to_name(version)
1563 out.write("""
1564/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001565 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001566 * @param src Pointer to object to be duplicated
1567 * @returns A new object of type %(cls)s.
1568 *
1569 * The caller is responsible for deleting the returned value
1570 */
Rich Lanee499bd12014-10-28 15:25:09 -07001571of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001572%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001573 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001574{
1575""" % dict(cls=cls, ver_name=ver_name))
1576
1577 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001578 sub_classes = type_maps.sub_class_map(cls, version)
1579 for (_, sub_cls) in sub_classes:
1580 sub_enum = sub_cls.upper()
Rich Lane6171e632014-11-07 10:23:38 -08001581 if type_maps.class_is_virtual(sub_cls):
1582 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001583 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001584 if (src->object_id == %(sub_enum)s) {
1585 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001586 }
1587""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1588
1589 out.write("""
1590 return NULL;
1591}
1592""")
1593
1594
1595def gen_dup_cls(out, cls, version):
1596 """
1597 Generate duplication routine for class cls
1598 """
1599 ver_name = loxi_utils.version_to_name(version)
1600
1601 out.write("""
1602/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001603 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001604 * using accessor functions
1605 * @param src Pointer to object to be duplicated
1606 * @returns A new object of type %(cls)s.
1607 *
1608 * The caller is responsible for deleting the returned value
1609 */
1610%(cls)s_t *
1611%(cls)s_%(ver_name)s_dup(
1612 %(cls)s_t *src)
1613{
1614 %(cls)s_t *dst;
1615""" % dict(cls=cls, ver_name=ver_name))
1616
1617 # Get members and types for the class
1618 members, member_types = loxi_utils.all_member_types_get(cls, version)
1619
1620 # Add declarations for each member type
1621 for m_type in member_types:
1622 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1623 # Declare instance of these
1624 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001625 elif m_type in embedded_subclasses:
1626 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001627 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001628 %(sub_cls)s_t src_%(v_name)s;
1629 %(sub_cls)s_t *dst_%(v_name)s;
1630""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001631 else:
1632 out.write("""
1633 %(m_type)s src_%(v_name)s;
1634 %(m_type)s *dst_%(v_name)s;
1635""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1636
1637 out.write("""
1638 if ((dst = %(cls)s_new(src->version)) == NULL) {
1639 return NULL;
1640 }
1641""" % dict(cls=cls))
1642
1643 for member in members:
1644 m_type = member["m_type"]
1645 m_name = member["name"]
1646 if loxi_utils.skip_member_name(m_name):
1647 continue
1648 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1649 out.write("""
1650 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1651 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1652""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1653 elif m_type in ["of_match_t", "of_octets_t"]:
1654 out.write("""
1655 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1656 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1657""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001658 elif m_type in embedded_subclasses:
1659 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001660 out.write("""
1661 %(cls)s_%(m_name)s_bind(
1662 src, &src_%(v_name)s);
1663 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1664 if (dst_%(v_name)s == NULL) {
1665 %(cls)s_delete(dst);
1666 return NULL;
1667 }
1668 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1669 %(sub_cls)s_delete(dst_%(v_name)s);
1670""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1671 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001672 else:
1673 sub_cls = m_type[:-2] # Trim _t
1674 out.write("""
1675 %(cls)s_%(m_name)s_bind(
1676 src, &src_%(v_name)s);
1677 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1678 if (dst_%(v_name)s == NULL) {
1679 %(cls)s_delete(dst);
1680 return NULL;
1681 }
1682 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1683 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001684""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001685 v_name=var_name_map(m_type), ver_name=ver_name))
1686
1687 out.write("""
1688 return dst;
1689}
1690""")
1691
1692def gen_version_dup(out=sys.stdout):
1693 """
1694 Generate duplication routines for each object type
1695 """
1696 out.write("""
1697/* Special try macro for duplicating */
1698#define _TRY_FREE(op, obj, rv) do { \\
1699 int _rv; \\
1700 if ((_rv = (op)) < 0) { \\
1701 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1702 of_object_delete((of_object_t *)(obj)); \\
1703 return (rv); \\
1704 } \\
1705 } while (0)
1706""")
1707
1708 for version in of_g.of_version_range:
1709 for cls in of_g.standard_class_order:
1710 if not loxi_utils.class_in_version(cls, version):
1711 continue
Rich Lane8841f352014-10-12 19:18:36 -07001712 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001713 gen_dup_inheritance(out, cls, version)
1714 elif loxi_utils.class_is_list(cls):
1715 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001716 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001717 gen_dup_cls(out, cls, version)
1718
1719def gen_dup(out=sys.stdout):
1720 """
1721 Generate non-version specific duplication routines for each object type
1722 """
1723
1724 for cls in of_g.standard_class_order:
1725 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001726of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001727%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001728 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001729{
1730""" % dict(cls=cls))
1731 for version in of_g.of_version_range:
1732 if not loxi_utils.class_in_version(cls, version):
1733 continue
Rich Lane6171e632014-11-07 10:23:38 -08001734 elif type_maps.class_is_inheritance_root(cls):
1735 pass
1736 elif loxi_utils.class_is_list(cls):
1737 pass
1738 elif type_maps.class_is_virtual(cls):
1739 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001740 ver_name = loxi_utils.version_to_name(version)
1741 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001742 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001743 return %(cls)s_%(ver_name)s_dup(src);
1744 }
Rich Lanee499bd12014-10-28 15:25:09 -07001745""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001746
1747 out.write("""
1748 /* Class not supported in given version */
1749 return NULL;
1750}
1751""")
1752
1753def dup_c_gen(out, name):
1754 """
1755 Generate the C file for duplication functions
1756 """
1757 loxi_utils.gen_c_copy_license(out)
1758 out.write("""\
1759/*
1760 * Duplication functions for all OF objects
1761 *
1762 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1763 *
1764 * These are test functions for exercising accessors. You can call
1765 * of_object_dup for an efficient duplication.
1766 */
1767
1768#define DISABLE_WARN_UNUSED_RESULT
1769#include "loci_log.h"
1770#include <locitest/of_dup.h>
1771
1772""")
1773
1774 gen_version_dup(out)
1775 gen_dup(out)
1776
1777
1778def dup_h_gen(out, name):
1779 """
1780 Generate the header file for duplication functions
1781 """
1782
1783 loxi_utils.gen_c_copy_license(out)
1784 out.write("""
1785/*
1786 * Duplication function header file
1787 *
1788 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1789 */
1790
1791#if !defined(_OF_DUP_H_)
1792#define _OF_DUP_H_
1793
1794#include <loci/loci.h>
1795""")
1796
1797 for cls in of_g.standard_class_order:
1798 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001799extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001800 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001801 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001802""" % dict(cls=cls))
1803
1804 for version in of_g.of_version_range:
1805 for cls in of_g.standard_class_order:
1806 if not loxi_utils.class_in_version(cls, version):
1807 continue
Rich Lane6171e632014-11-07 10:23:38 -08001808 elif type_maps.class_is_inheritance_root(cls):
1809 pass
1810 elif loxi_utils.class_is_list(cls):
1811 pass
1812 elif type_maps.class_is_virtual(cls):
1813 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001814 ver_name = loxi_utils.version_to_name(version)
1815 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001816extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001817 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001818 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001819""" % dict(cls=cls, ver_name=ver_name))
1820
1821 out.write("\n#endif /* _OF_DUP_H_ */\n")
1822
1823def gen_log_test(out):
1824 """
1825 Generate test for obj log calls
1826
1827 Define a trivial handler for object logging; call all obj log fns
1828 """
1829 out.write("""
1830
1831/**
1832 * Test object dump functions
1833 */
1834
1835int
1836test_dump_objs(void)
1837{
1838 of_object_t *obj;
1839
1840 FILE *out = fopen("/dev/null", "w");
1841
1842 /* Call each obj dump function */
1843""")
1844 for version in of_g.of_version_range:
1845 for j, cls in enumerate(of_g.all_class_order):
1846 if not loxi_utils.class_in_version(cls, version):
1847 continue
Rich Lane6171e632014-11-07 10:23:38 -08001848 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001849 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001850 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1851 out.write("""
1852 obj = (of_object_t *)%(cls)s_new(%(version)s);
1853 {
1854 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1855 %(cls)s_vport_set(obj, vport);
1856 of_object_delete(vport);
1857 }
1858 of_object_dump((loci_writer_f)fprintf, out, obj);
1859 of_object_delete(obj);
1860""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1861 else:
1862 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001863 obj = (of_object_t *)%(cls)s_new(%(version)s);
1864 of_object_dump((loci_writer_f)fprintf, out, obj);
1865 of_object_delete(obj);
1866""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001867
Rich Lanea06d0c32013-03-25 08:52:03 -07001868 out.write("""
1869 fclose(out);
1870 return TEST_PASS;
1871}
1872""")
1873
1874def gen_ident_tests(out):
1875 """
1876 Generate tests for identifiers
1877
1878 For all idents, instantiate, test version supported macros
1879 For flags, set it, test it, clear it, test it.
1880 """
1881 out.write("""
1882/**
1883 * Test cases for all flag accessor macros
1884 * These only test self consistency (and that they compile)
1885 */
1886int
1887test_ident_macros(void)
1888{
1889 int value __attribute__((unused));
1890 uint32_t flags;
1891
1892""")
1893
1894 for ident, info in of_g.identifiers.items():
1895 if not identifiers.defined_versions_agree(of_g.identifiers,
1896 of_g.target_version_list,
1897 ident):
1898 # @fixme
1899 continue
1900 out.write(" value = %s;\n" % ident)
1901 for version in of_g.target_version_list:
1902 if version in info["values_by_version"].keys():
1903 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1904 (ident, of_g.of_version_wire2name[version]))
1905 else:
1906 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1907 (ident, of_g.of_version_wire2name[version]))
1908 if flags.ident_is_flag(ident):
1909 # Grab first supported version
1910 for version in info["values_by_version"]:
1911 break
1912 out.write("""
1913 flags = 0;
1914 %(ident)s_SET(flags, %(ver_name)s);
1915 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1916 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1917 %(ident)s_CLEAR(flags, %(ver_name)s);
1918 TEST_ASSERT(flags == 0);
1919 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1920""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1921
1922 out.write("""
1923 return TEST_PASS;
1924}
1925""")
1926
Rich Laneccae0312013-07-21 23:34:13 -07001927def gen_datafiles_tests(out, name):
1928 tests = []
1929 for filename in test_data.list_files():
1930 data = test_data.read(filename)
1931 if not 'c' in data:
1932 continue
1933 name = filename[:-5].replace("/", "_")
1934 tests.append(dict(name=name,
1935 filename=filename,
1936 c=data['c'],
1937 binary=data['binary']))
1938
1939 util.render_template(out, "test_data.c", tests=tests)