blob: cb7ff7d7e639fb7ee20db1a04b39de8eec523506 [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 Lane8841f352014-10-12 19:18:36 -0700383 if type_maps.class_is_inheritance_root(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
396 out.write("""
397/*
398 * Declarations for list population and check primitives
399 */
400""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700401
Rich Lanea06d0c32013-03-25 08:52:03 -0700402 for version in of_g.of_version_range:
403 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700404 if version in of_g.unified[cls]:
405 out.write("""
406extern int
407 list_setup_%(cls)s_%(v_name)s(
408 %(cls)s_t *list, int value);
409extern int
410 list_check_%(cls)s_%(v_name)s(
411 %(cls)s_t *list, int value);
412""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
413
414 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
415
416def gen_common_test(out, name):
417 """
418 Generate common test content including main
419 """
420 loxi_utils.gen_c_copy_license(out)
421 out.write("""
422/*
423 * Common test code for LOCI
424 *
425 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
426 */
427
428#define DISABLE_WARN_UNUSED_RESULT
429#include "loci_log.h"
430#include <loci/loci_obj_dump.h>
431#include <locitest/unittest.h>
432#include <locitest/test_common.h>
433
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900434/* mcheck is a glibc extension */
435#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700436#include <mcheck.h>
437#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900438#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700439#define MCHECK_INIT do { } while (0)
440#endif
441
442/**
443 * Exit on error if set to 1
444 */
445int exit_on_error = 1;
446
447/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700448 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700449 */
450int global_error = 0;
451
452extern int run_unified_accessor_tests(void);
453extern int run_match_tests(void);
454extern int run_utility_tests(void);
455
456extern int run_scalar_acc_tests(void);
457extern int run_list_tests(void);
458extern int run_message_tests(void);
459
460/**
461 * Macros for initializing and checking scalar types
462 *
463 * @param var The variable being initialized or checked
464 * @param val The integer value to set/check against, see below
465 *
466 * Note that equality means something special for strings. Each byte
467 * is initialized to an incrementing value. So check is done against that.
468 *
469 */
470
471""")
472 for t in scalar_types:
473 if t in integer_types:
474 out.write("""
475#define VAR_%s_INIT(var, val) var = (%s)(val)
476#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
477""" % (t.upper(), t, t.upper(), t))
478 else:
479 out.write("""
480#define VAR_%s_INIT(var, val) \\
481 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
482#define VAR_%s_CHECK(var, val) \\
483 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
484""" % (t.upper(), t.upper()))
485
486 gen_fill_string(out)
487 gen_scalar_set_check_funs(out)
488 gen_list_set_check_funs(out)
489 gen_unified_accessor_funs(out)
490
491 gen_ident_tests(out)
492 gen_log_test(out)
493
494def gen_message_scalar_test(out, name):
495 """
496 Generate test cases for message objects, scalar accessors
497 """
498
499 loxi_utils.gen_c_copy_license(out)
500 out.write("""
501/**
502 *
503 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
504 *
505 * Message-scalar tests for all versions
506 */
507
508#include <locitest/test_common.h>
509""")
510 for version in of_g.of_version_range:
511 v_name = loxi_utils.version_to_name(version)
512 out.write("""
513/**
514 * Message-scalar tests for version %s
515 */
516""" % v_name)
517 for cls in of_g.standard_class_order:
Rich Lane8841f352014-10-12 19:18:36 -0700518 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700519 continue
520 if version in of_g.unified[cls]:
521 message_scalar_test(out, version, cls)
522
523 out.write("""
524int
525run_scalar_acc_tests(void)
526{
527""")
528 for version in of_g.of_version_range:
529 v_name = loxi_utils.version_to_name(version)
530 for cls in of_g.standard_class_order:
Rich Lane8841f352014-10-12 19:18:36 -0700531 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700532 continue
533 if version in of_g.unified[cls]:
534 test_name = "%s_%s" % (cls, v_name)
535 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
536
537 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700538
Rich Lanea06d0c32013-03-25 08:52:03 -0700539def message_scalar_test(out, version, cls):
540 """
541 Generate one test case for the given version and class
542 """
543
544 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700545 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700546 v_name = loxi_utils.version_to_name(version)
547
548 out.write("""
549static int
550test_%(cls)s_%(v_name)s_scalar(void)
551{
552 %(cls)s_t *obj;
553
554 obj = %(cls)s_new(%(v_name)s);
555 TEST_ASSERT(obj != NULL);
556 TEST_ASSERT(obj->version == %(v_name)s);
557 TEST_ASSERT(obj->length == %(length)d);
558 TEST_ASSERT(obj->parent == NULL);
559 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700560""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700561 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700562
563 # If this class is a concrete member of an inheritance hierarchy,
564 # run the hierarchy's root wire type parser and assert it returns
565 # the expected object id.
566 ofclass = loxi_globals.unified.class_by_name(cls)
567 if ofclass and not ofclass.virtual:
568 root = ofclass
569 while root.superclass:
570 root = root.superclass
571 if root.virtual:
572 out.write("""
573 {
574 of_object_id_t object_id;
575 %(root_cls)s_wire_object_id_get(obj, &object_id);
576 TEST_ASSERT(object_id == %(u_cls)s);
577 }
578""" % dict(root_cls=root.name, u_cls=cls.upper()))
579
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 if not type_maps.class_is_virtual(cls):
581 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700582 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700583 int length;
584
Rich Lanedc46fe22014-04-03 15:10:38 -0700585 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700586 TEST_ASSERT(length == %(length)d);
587 }
588
589 /* Set up incrementing values for scalar members */
590 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
591
592 /* Check values just set */
593 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700594""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700595 v_name=v_name, length=length, version=version))
596
597 out.write("""
598 %(cls)s_delete(obj);
599
600 /* To do: Check memory */
601 return TEST_PASS;
602}
603""" % dict(cls=cls))
604
605# Get the members and list of scalar types for members of a given class
606def scalar_member_types_get(cls, version):
607 member_types = []
608
609 if not version in of_g.unified[cls]:
610 return ([], [])
611
612 if "use_version" in of_g.unified[cls][version]:
613 v = of_g.unified[cls][version]["use_version"]
614 members = of_g.unified[cls][v]["members"]
615 else:
616 members = of_g.unified[cls][version]["members"]
617 # Accumulate variables that are supported
618 for member in members:
619 m_type = member["m_type"]
620 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700621 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700622 ignore_member(cls, version, m_name, m_type)):
623 continue
624 if not m_type in member_types:
625 member_types.append(m_type)
626
627 return (members, member_types)
628
629def scalar_funs_instance(out, cls, version, members, member_types):
630 """
631 Generate one instance of scalar set/check functions
632 """
633 out.write("""
634/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700635 * Populate the scalar values in obj of type %(cls)s,
636 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700637 * @param obj Pointer to an object to populate
638 * @param value The seed value to use in populating the object
639 * @returns The value after increments for this object's values
640 */
641int %(cls)s_%(v_name)s_populate_scalars(
642 %(cls)s_t *obj, int value) {
643""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
644 # Declare string types
645 for t in member_types:
646 out.write(" %s %s;\n" % (t, var_name_map(t)))
647 for member in members:
648 m_type = member["m_type"]
649 m_name = member["name"]
650 if (not loxi_utils.type_is_scalar(m_type) or
651 ignore_member(cls, version, m_name, m_type)):
652 continue
653 v_name = var_name_map(m_type);
654 out.write("""
655 VAR_%(u_type)s_INIT(%(v_name)s, value);
656 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
657 value += 1;
658""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
659 out.write("""
660 return value;
661}
662""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700663
Rich Lanea06d0c32013-03-25 08:52:03 -0700664 out.write("""
665/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700666 * Check scalar values in obj of type %(cls)s,
667 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700668 * @param obj Pointer to an object to check
669 * @param value Starting value for checking
670 * @returns The value after increments for this object's values
671 */
672int %(cls)s_%(v_name)s_check_scalars(
673 %(cls)s_t *obj, int value) {
674""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
675
676 for t in member_types:
677 out.write(" %s %s;\n" % (t, var_name_map(t)))
678 for member in members:
679 m_type = member["m_type"]
680 m_name = member["name"]
681 if (not loxi_utils.type_is_scalar(m_type) or
682 ignore_member(cls, version, m_name, m_type)):
683 continue
684 v_name = var_name_map(m_type);
685 out.write("""
686 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
687 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
688 value += 1;
689""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
690
691 out.write("""
692 return value;
693}
694
695""")
696
697def gen_scalar_set_check_funs(out):
698 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700699 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700700 set and check their values
701 """
702 for version in of_g.of_version_range:
703 for cls in of_g.standard_class_order:
Rich Lanee499bd12014-10-28 15:25:09 -0700704 if type_maps.class_is_inheritance_root(cls):
705 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700706 (members, member_types) = scalar_member_types_get(cls, version)
707 scalar_funs_instance(out, cls, version, members, member_types)
708
709
710# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700711def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700712 base_type = loxi_utils.list_to_entry_type(cls)
713 setup_template = """
714 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700715 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700716 value = %(subcls)s_%(v_name)s_populate(
717 %(inst)s, value);
718 cur_len += %(inst)s->length;
719 TEST_ASSERT(list->length == cur_len);
720"""
721 out.write("""
722 /* Append two instances of type %s */
723""" % subcls)
724 for i in range(2):
725 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700726 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700727 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700728 version=version))
729
Rich Lane9afc3b92014-04-09 22:55:53 -0700730def check_instance(out, cls, subcls, instance, v_name, version, last):
731 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700732 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
733 value = %(subcls)s_%(v_name)s_check(
734 %(inst)s, value);
735 TEST_ASSERT(value != 0);
736"""
737 out.write("\n /* Check two instances of type %s */" % instance)
738
Andreas Wundsam53256162013-05-02 14:05:53 -0700739 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700740 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700741 inst=instance, subcls=subcls,
742 v_name=loxi_utils.version_to_name(version)))
743 out.write("""\
744 TEST_OK(%(cls)s_next(list, &elt));
745""" % dict(cls=cls))
746
Andreas Wundsam53256162013-05-02 14:05:53 -0700747 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700748 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700749 inst=instance, subcls=subcls,
750 v_name=loxi_utils.version_to_name(version)))
751 if last:
752 out.write("""\
753 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
754""" % dict(cls=cls))
755 else:
756 out.write("""\
757 TEST_OK(%(cls)s_next(list, &elt));
758""" % dict(cls=cls))
759
760def setup_list_fn(out, version, cls):
761 """
762 Generate a helper function that populates a list with two
763 of each type of subclass it supports
764 """
765 out.write("""
766/**
767 * Set up a list of type %(cls)s with two of each type of subclass
768 */
769int
770list_setup_%(cls)s_%(v_name)s(
771 %(cls)s_t *list, int value)
772{
773""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
774 base_type = loxi_utils.list_to_entry_type(cls)
775 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -0700776 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -0700777 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700778 (void) elt;
779 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700780""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700781
Rich Lanea06d0c32013-03-25 08:52:03 -0700782 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700783 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 -0700784 v_name = loxi_utils.version_to_name(version)
785
Rich Lanee98ee5d2014-10-14 10:43:44 -0700786 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700787 out.write(" /* No subclasses for %s */\n"% base_type)
788 out.write(" %s_t *elt_p;\n" % base_type)
789 out.write("\n elt_p = &elt;\n")
790 else:
791 out.write(" /* Declare pointers for each subclass */\n")
792 for instance, subcls in sub_classes:
793 out.write(" %s_t *%s;\n" % (subcls, instance))
794 out.write("\n /* Instantiate pointers for each subclass */\n")
795 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -0700796 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -0700797
Rich Lanee98ee5d2014-10-14 10:43:44 -0700798 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700799 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700800 else:
801 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700802 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700803 out.write("""
804
805 return value;
806}
807""")
808
809def check_list_fn(out, version, cls):
810 """
811 Generate a helper function that checks a list populated by above fn
812 """
813 out.write("""
814/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700815 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700816 * list_setup_%(cls)s_%(v_name)s
817 */
818int
819list_check_%(cls)s_%(v_name)s(
820 %(cls)s_t *list, int value)
821{
822""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
823 base_type = loxi_utils.list_to_entry_type(cls)
824 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -0700825 of_object_t elt;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700826 (void) elt;
Rich Lanea06d0c32013-03-25 08:52:03 -0700827""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700828
Rich Lanea06d0c32013-03-25 08:52:03 -0700829 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700830 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 -0700831 v_name = loxi_utils.version_to_name(version)
832
Rich Lanee98ee5d2014-10-14 10:43:44 -0700833 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700834 out.write(" /* No subclasses for %s */\n"% base_type)
835 out.write(" %s_t *elt_p;\n" % base_type)
836 out.write("\n elt_p = &elt;\n")
837 else:
838 out.write(" /* Declare pointers for each subclass */\n")
839 for instance, subcls in sub_classes:
840 out.write(" %s_t *%s;\n" % (subcls, instance))
841 out.write("\n /* Instantiate pointers for each subclass */\n")
842 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -0700843 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -0700844
Rich Lanee98ee5d2014-10-14 10:43:44 -0700845 if not type_maps.class_is_virtual(base_type) or sub_classes:
846 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
847
848 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700849 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700850 else:
851 count = 0
852 for instance, subcls in sub_classes:
853 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700854 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700855 version, count==len(sub_classes))
856
857 out.write("""
858 return value;
859}
860""" % dict(base_type=base_type))
861
862def gen_list_set_check_funs(out):
863 for version in of_g.of_version_range:
864 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700865 if version in of_g.unified[cls]:
866 setup_list_fn(out, version, cls)
867 check_list_fn(out, version, cls)
868
869# Maybe: Get a map from list class to parent, mem_name of container
870
871def list_test(out, version, cls):
872 out.write("""
873static int
874test_%(cls)s_%(v_name)s(void)
875{
876""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
877 base_type = loxi_utils.list_to_entry_type(cls)
878
879 out.write(""" %(cls)s_t *list;
880 int value = 1;
881""" % dict(cls=cls, base_type=base_type))
882
883 out.write("""
884 list = %(cls)s_new(%(v_name)s);
885 TEST_ASSERT(list != NULL);
886 TEST_ASSERT(list->version == %(v_name)s);
887 TEST_ASSERT(list->length == 0);
888 TEST_ASSERT(list->parent == NULL);
889 TEST_ASSERT(list->object_id == %(enum_cls)s);
890
891 value = list_setup_%(cls)s_%(v_name)s(list, value);
892 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700893""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700894 enum_cls=loxi_utils.enum_name(cls)))
895
896 out.write("""
897 /* Now check values */
898 value = 1;
899 value = list_check_%(cls)s_%(v_name)s(list, value);
900 TEST_ASSERT(value != 0);
901""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
902
903 out.write("""
904 %(cls)s_delete(list);
905
906 return TEST_PASS;
907}
908""" % dict(cls=cls))
909
910def gen_list_test(out, name):
911 """
912 Generate base line test cases for lists
913 @param out The file handle to write to
914 """
915
916 loxi_utils.gen_c_copy_license(out)
917 out.write("""
918/**
919 *
920 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
921 *
922 * Message-scalar tests for all versions
923 */
924
925#include <locitest/test_common.h>
926""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700927
Rich Lanea06d0c32013-03-25 08:52:03 -0700928 for version in of_g.of_version_range:
929 v_name = loxi_utils.version_to_name(version)
930 out.write("""
931/**
932 * Baseline list tests for version %s
933 */
934""" % v_name)
935 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700936 if version in of_g.unified[cls]:
937 list_test(out, version, cls)
938
939 out.write("""
940int
941run_list_tests(void)
942{
943""")
944 for version in of_g.of_version_range:
945 v_name = loxi_utils.version_to_name(version)
946 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700947 if version in of_g.unified[cls]:
948 test_name = "%s_%s" % (cls, v_name)
949 out.write(" RUN_TEST(%s);\n" % test_name)
950
951 out.write("\n return TEST_PASS;\n}\n");
952
953def gen_match_test(out, name):
954 """
955 Generate baseline tests for match functions
956 """
957
958 loxi_utils.gen_c_copy_license(out)
959 out.write("""\
960/**
961 *
962 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
963 *
964 * Message-scalar tests for all versions
965 * @fixme These are mostly hard coded now.
966 */
967
968#include <locitest/test_common.h>
969
970static int
971test_match_1(void)
972{
Rich Lanef87f4c32014-10-14 11:56:02 -0700973""")
974
975 for version in of_g.of_version_range:
976 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
977
978 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700979 of_match_t match;
980 int value = 1;
981 int idx;
982 uint32_t exp_value;
983
984 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700985 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700986 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
987 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
988 if (idx < 32) {
989 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
990 }
991 }
992""")
993
994 for version in of_g.of_version_range:
995 out.write("""
996 /* Create/populate/convert and delete for version %(v_name)s */
997 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
998 TEST_ASSERT(m_v%(version)d != NULL);
999 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
1000 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
1001 of_match_v%(version)d_delete(m_v%(version)d);
1002""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1003
1004 out.write("""
1005 return TEST_PASS;
1006}
1007""")
1008
1009 out.write("""
1010static int
1011test_match_2(void)
1012{
Rich Lanef87f4c32014-10-14 11:56:02 -07001013""")
1014
1015 for version in of_g.of_version_range:
1016 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
1017
1018 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -07001019 of_match_t match1;
1020 of_match_t match2;
1021 int value = 1;
1022""")
1023
1024 for version in of_g.of_version_range:
1025 out.write("""
1026 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1027 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1028 TEST_ASSERT(m_v%(version)d != NULL);
1029 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1030 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1031 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1032 of_match_v%(version)d_delete(m_v%(version)d);
1033""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1034
1035 out.write("""
1036 return TEST_PASS;
1037}
1038""")
1039
1040 out.write("""
1041static int
1042test_match_3(void)
1043{
1044 of_match_t match1;
1045 of_match_t match2;
1046 int value = 1;
1047 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001048 of_object_storage_t storage;
1049 memset(&storage, 0, sizeof(storage));
1050 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001051""")
1052 for version in of_g.of_version_range:
1053 out.write("""
1054 /* Serialize to version %(v_name)s */
1055 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001056 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001057 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001058 storage.obj.wbuf->buf = octets.data;
1059 storage.obj.wbuf->alloc_bytes = octets.bytes;
1060 storage.obj.wbuf->current_bytes = octets.bytes;
1061 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001062 OF_ERROR_NONE);
1063 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1064 FREE(octets.data);
1065""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1066
1067 out.write("""
1068 return TEST_PASS;
1069}
1070""")
1071
1072 out.write("""
1073int run_match_tests(void)
1074{
1075 RUN_TEST(match_1);
1076 RUN_TEST(match_2);
1077 RUN_TEST(match_3);
1078 RUN_TEST(match_utils);
1079
1080 return TEST_PASS;
1081}
1082""")
1083
1084def gen_msg_test(out, name):
1085 loxi_utils.gen_c_copy_license(out)
1086 out.write("""
1087/**
1088 *
1089 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1090 *
1091 * Message-scalar tests for all versions
1092 */
1093
1094#include <locitest/test_common.h>
1095""")
1096 for version in of_g.of_version_range:
1097 for cls in of_g.ordered_messages:
1098 if not (cls, version) in of_g.base_length:
1099 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001100 if type_maps.class_is_virtual(cls):
1101 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -07001102 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001103 out.write("""
1104static int
1105test_%(cls)s_create_%(v_name)s(void)
1106{
1107 %(cls)s_t *obj;
1108 uint8_t *msg_buf;
1109 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001110 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001111 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001112
1113 obj = %(cls)s_new(%(v_name)s);
1114 TEST_ASSERT(obj != NULL);
1115 TEST_ASSERT(obj->version == %(v_name)s);
1116 TEST_ASSERT(obj->length == %(bytes)d);
1117 TEST_ASSERT(obj->parent == NULL);
1118 TEST_ASSERT(obj->object_id == %(enum)s);
1119
Rich Lanea4b68302014-03-12 15:17:58 -07001120 of_header_wire_object_id_get(obj, &object_id);
1121 TEST_ASSERT(object_id == %(enum)s);
1122
Rich Lanea06d0c32013-03-25 08:52:03 -07001123 /* Set up incrementing values for scalar members */
1124 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1125 TEST_ASSERT(value != 0);
1126
Rich Lanebb8f17c2014-06-12 13:14:09 -07001127 len = obj->length;
1128
Rich Lanea06d0c32013-03-25 08:52:03 -07001129 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001130 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1131 TEST_ASSERT(msg_buf != NULL);
1132 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001133 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001134
1135 TEST_ASSERT(obj != NULL);
1136
1137 /* @fixme Set up all message objects (recursively?) */
1138
1139 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1140 TEST_ASSERT(value != 0);
1141
1142 %(cls)s_delete(obj);
1143
1144 return TEST_PASS;
1145}
1146""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1147 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1148
1149 out.write("""
1150int
1151run_message_tests(void)
1152{
1153""")
1154 for version in of_g.of_version_range:
1155 for cls in of_g.ordered_messages:
1156 if not (cls, version) in of_g.base_length:
1157 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001158 if type_maps.class_is_virtual(cls):
1159 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001160 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1161 out.write(" RUN_TEST(%s);\n" % test_name)
1162
1163 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001164
Rich Lanea06d0c32013-03-25 08:52:03 -07001165
1166def gen_list_setup_check(out, cls, version):
1167 """
1168 Generate functions that populate and check a list with two
1169 of each type of subclass it supports
1170 """
1171 out.write("""
1172/**
1173 * Populate a list of type %(cls)s with two of each type of subclass
1174 * @param list Pointer to the list to be populated
1175 * @param value The seed value to use in populating the list
1176 * @returns The value after increments for this object's values
1177 */
1178int
1179%(cls)s_%(v_name)s_populate(
1180 %(cls)s_t *list, int value)
1181{
1182""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1183 base_type = loxi_utils.list_to_entry_type(cls)
1184 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001185 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001186 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001187 (void) elt;
1188 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001189""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001190
Rich Lanea06d0c32013-03-25 08:52:03 -07001191 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001192 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 -07001193 v_name = loxi_utils.version_to_name(version)
1194
Rich Lanee98ee5d2014-10-14 10:43:44 -07001195 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001196 out.write(" /* No subclasses for %s */\n"% base_type)
1197 out.write(" %s_t *elt_p;\n" % base_type)
1198 out.write("\n elt_p = &elt;\n")
1199 else:
1200 out.write(" /* Declare pointers for each subclass */\n")
1201 for instance, subcls in sub_classes:
1202 out.write(" %s_t *%s;\n" % (subcls, instance))
1203 out.write("\n /* Instantiate pointers for each subclass */\n")
1204 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001205 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001206
Rich Lanee98ee5d2014-10-14 10:43:44 -07001207 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001208 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001209 else:
1210 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001211 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001212 out.write("""
1213 return value;
1214}
1215""")
1216 out.write("""
1217/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001218 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001219 * %(cls)s_%(v_name)s_populate
1220 * @param list Pointer to the list that was populated
1221 * @param value Starting value for checking
1222 * @returns The value after increments for this object's values
1223 */
1224int
1225%(cls)s_%(v_name)s_check(
1226 %(cls)s_t *list, int value)
1227{
1228""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1229 base_type = loxi_utils.list_to_entry_type(cls)
1230 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001231 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001232 int count = 0;
1233 int rv;
1234""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001235
Rich Lanea06d0c32013-03-25 08:52:03 -07001236
1237 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001238 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 -07001239 v_name = loxi_utils.version_to_name(version)
1240
Rich Lanee98ee5d2014-10-14 10:43:44 -07001241 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001242 entry_count = 2
1243 out.write(" /* No subclasses for %s */\n"% base_type)
1244 out.write(" %s_t *elt_p;\n" % base_type)
1245 out.write("\n elt_p = &elt;\n")
1246 else:
1247 entry_count = 2 * len(sub_classes) # Two of each type appended
1248 out.write(" /* Declare pointers for each subclass */\n")
1249 for instance, subcls in sub_classes:
1250 out.write(" %s_t *%s;\n" % (subcls, instance))
1251 out.write("\n /* Instantiate pointers for each subclass */\n")
1252 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001253 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001254
Rich Lanee98ee5d2014-10-14 10:43:44 -07001255 if not type_maps.class_is_virtual(base_type) or sub_classes:
1256 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1257
1258 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001259 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001260 version, True)
1261 else:
1262 count = 0
1263 for instance, subcls in sub_classes:
1264 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001265 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001266 version, count==len(sub_classes))
1267 out.write("""
1268""" % dict(base_type=base_type))
1269
1270 out.write("""
1271 /* Do an iterate to test the iterator */
1272 %(u_cls)s_ITER(list, &elt, rv) {
1273 count += 1;
1274 }
1275
1276 TEST_ASSERT(rv == OF_ERROR_RANGE);
1277 TEST_ASSERT(count == %(entry_count)d);
1278
1279 /* We shoehorn a test of the dup functions here */
1280 {
1281 %(cls)s_t *dup;
1282
1283 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1284 TEST_ASSERT(dup->length == list->length);
1285 TEST_ASSERT(dup->object_id == list->object_id);
1286 TEST_ASSERT(dup->version == list->version);
1287 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1288 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1289 of_object_delete((of_object_t *)dup);
1290
1291 /* And now for the generic dup function */
1292 TEST_ASSERT((dup = (%(cls)s_t *)
1293 of_object_dup(list)) != NULL);
1294 TEST_ASSERT(dup->length == list->length);
1295 TEST_ASSERT(dup->object_id == list->object_id);
1296 TEST_ASSERT(dup->version == list->version);
1297 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1298 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1299 of_object_delete((of_object_t *)dup);
1300 }
1301
1302 return value;
1303}
1304""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1305
1306
1307def gen_class_setup_check(out, cls, version):
1308 out.write("""
1309/**
1310 * Populate all members of an object of type %(cls)s
1311 * with incrementing values
1312 * @param obj Pointer to an object to populate
1313 * @param value The seed value to use in populating the object
1314 * @returns The value after increments for this object's values
1315 */
1316
1317int
1318%(cls)s_%(v_name)s_populate(
1319 %(cls)s_t *obj, int value)
1320{
1321""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1322 members, member_types = loxi_utils.all_member_types_get(cls, version)
1323 for m_type in member_types:
1324 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1325 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001326 elif m_type in embedded_subclasses:
1327 subcls = embedded_subclasses[m_type]
1328 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001329 else:
1330 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1331 out.write("""
1332 /* Run thru accessors after new to ensure okay */
1333""")
1334 for member in members:
1335 m_type = member["m_type"]
1336 m_name = member["name"]
1337 if loxi_utils.skip_member_name(m_name):
1338 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001339 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001340 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001341 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1342 out.write("""\
1343 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1344""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1345 else:
1346 sub_cls = m_type[:-2] # Trim _t
1347 out.write("""\
1348 {
1349 %(sub_cls)s_t sub_cls;
1350
1351 /* Test bind */
1352 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1353 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001354""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001355 m_name=m_name, sub_cls=sub_cls,
1356 v_name=loxi_utils.version_to_name(version)))
1357
1358 out.write("""
1359 value = %(cls)s_%(v_name)s_populate_scalars(
1360 obj, value);
1361 TEST_ASSERT(value != 0);
1362""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1363
1364 for member in members:
1365 m_type = member["m_type"]
1366 m_name = member["name"]
1367 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1368 continue
1369 if loxi_utils.skip_member_name(m_name):
1370 continue
1371 if m_type == "of_match_t":
1372 out.write("""\
1373 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1374 TEST_ASSERT(value != 0);
1375 %(cls)s_%(m_name)s_set(
1376 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001377""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001378 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1379 elif m_type == "of_octets_t":
1380 out.write("""\
1381 value = of_octets_populate(&%(var_name)s, value);
1382 TEST_ASSERT(value != 0);
1383 %(cls)s_%(m_name)s_set(
1384 obj, &%(var_name)s);
1385 if (octets.bytes) {
1386 FREE(octets.data);
1387 }
1388""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001389 elif m_type in embedded_subclasses:
1390 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001391 out.write("""\
1392 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1393 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001394 value = %(sub_cls)s_%(v_name)s_populate(
1395 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001396 TEST_ASSERT(value != 0);
1397 %(cls)s_%(m_name)s_set(
1398 obj, %(var_name)s);
1399 %(sub_cls)s_delete(%(var_name)s);
1400""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1401 var_name=var_name_map(m_type),
1402 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001403 else:
1404 sub_cls = m_type[:-2] # Trim _t
1405 out.write("""
1406 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1407 TEST_ASSERT(%(var_name)s != NULL);
1408 value = %(sub_cls)s_%(v_name)s_populate(
1409 %(var_name)s, value);
1410 TEST_ASSERT(value != 0);
1411 %(cls)s_%(m_name)s_set(
1412 obj, %(var_name)s);
1413 %(sub_cls)s_delete(%(var_name)s);
1414""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1415 var_name=var_name_map(m_type),
1416 v_name=loxi_utils.version_to_name(version)))
1417
1418 out.write("""
1419 return value;
1420}
1421""")
1422
1423 out.write("""
1424/**
1425 * Check all members of an object of type %(cls)s
1426 * populated by the above function
1427 * @param obj Pointer to an object to check
1428 * @param value Starting value for checking
1429 * @returns The value after increments for this object's values
1430 */
1431
1432int
1433%(cls)s_%(v_name)s_check(
1434 %(cls)s_t *obj, int value)
1435{
1436""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1437 members, member_types = loxi_utils.all_member_types_get(cls, version)
1438 for m_type in member_types:
1439 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1440 continue
1441 if loxi_utils.type_is_of_object(m_type):
1442 continue
1443 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1444 out.write("""
1445 value = %(cls)s_%(v_name)s_check_scalars(
1446 obj, value);
1447 TEST_ASSERT(value != 0);
1448""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1449
1450 for member in members:
1451 m_type = member["m_type"]
1452 m_name = member["name"]
1453 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1454 continue
1455 if loxi_utils.skip_member_name(m_name):
1456 continue
1457 if m_type == "of_match_t":
1458 out.write("""\
1459 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1460 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1461""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1462 v_name=loxi_utils.version_to_name(version)))
1463 elif m_type == "of_octets_t":
1464 out.write("""\
1465 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1466 value = of_octets_check(&%(var_name)s, value);
1467""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1468 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001469 elif m_type in embedded_subclasses:
1470 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001471 out.write("""
1472 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001473 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001474
1475 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1476 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001477 value = %(sub_cls)s_%(v_name)s_check(
1478 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001479 TEST_ASSERT(value != 0);
1480 %(sub_cls)s_delete(%(m_name)s_ptr);
1481 }
1482""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1483 var_name=var_name_map(m_type),
1484 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001485 else:
1486 sub_cls = m_type[:-2] # Trim _t
1487 out.write("""
1488 { /* Use get/delete to access on check */
1489 %(m_type)s *%(m_name)s_ptr;
1490
1491 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1492 TEST_ASSERT(%(m_name)s_ptr != NULL);
1493 value = %(sub_cls)s_%(v_name)s_check(
1494 %(m_name)s_ptr, value);
1495 TEST_ASSERT(value != 0);
1496 %(sub_cls)s_delete(%(m_name)s_ptr);
1497 }
1498""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1499 var_name=var_name_map(m_type),
1500 v_name=loxi_utils.version_to_name(version)))
1501
1502 out.write("""
1503 /* We shoehorn a test of the dup functions here */
1504 {
1505 %(cls)s_t *dup;
1506
1507 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1508 TEST_ASSERT(dup->length == obj->length);
1509 TEST_ASSERT(dup->object_id == obj->object_id);
1510 TEST_ASSERT(dup->version == obj->version);
1511 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1512 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1513 of_object_delete((of_object_t *)dup);
1514
1515 /* And now for the generic dup function */
1516 TEST_ASSERT((dup = (%(cls)s_t *)
1517 of_object_dup(obj)) != NULL);
1518 TEST_ASSERT(dup->length == obj->length);
1519 TEST_ASSERT(dup->object_id == obj->object_id);
1520 TEST_ASSERT(dup->version == obj->version);
1521 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1522 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1523 of_object_delete((of_object_t *)dup);
1524 }
1525
1526 return value;
1527}
1528""" % dict(cls=cls))
1529
1530def unified_accessor_test_case(out, cls, version):
1531 """
1532 Generate one test case for the given version and class
1533 """
1534
1535 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001536 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001537 v_name = loxi_utils.version_to_name(version)
1538
1539 out.write("""
1540static int
1541test_%(cls)s_%(v_name)s(void)
1542{
1543 %(cls)s_t *obj;
1544 obj = %(cls)s_new(%(v_name)s);
1545 TEST_ASSERT(obj != NULL);
1546 TEST_ASSERT(obj->version == %(v_name)s);
1547 TEST_ASSERT(obj->length == %(length)d);
1548 TEST_ASSERT(obj->parent == NULL);
1549 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001550""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001551 v_name=v_name, length=length, version=version))
1552 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1553 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001554 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001555 int length;
1556
Rich Lanedc46fe22014-04-03 15:10:38 -07001557 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001558 TEST_ASSERT(length == %(length)d);
1559 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001560 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001561 of_object_id_t obj_id;
1562
Rich Lanedc46fe22014-04-03 15:10:38 -07001563 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001564 TEST_ASSERT(obj_id == %(u_cls)s);
1565 }
1566
1567 /* Set up incrementing values for members */
1568 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1569 obj, 1) != 0);
1570
1571 /* Check values just set */
1572 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1573 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001574""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001575 v_name=v_name, length=length, version=version))
1576
1577 out.write("""
1578 %(cls)s_delete(obj);
1579
1580 /* To do: Check memory */
1581 return TEST_PASS;
1582}
1583""" % dict(cls=cls))
1584
1585
1586def gen_unified_accessor_funs(out):
1587 for version in of_g.of_version_range:
1588 for cls in of_g.standard_class_order:
1589 if not loxi_utils.class_in_version(cls, version):
1590 continue
Rich Lane8841f352014-10-12 19:18:36 -07001591 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001592 continue
1593 elif loxi_utils.class_is_list(cls):
1594 gen_list_setup_check(out, cls, version)
1595 else:
1596 gen_class_setup_check(out, cls, version)
1597
1598def gen_unified_accessor_tests(out, name):
1599 loxi_utils.gen_c_copy_license(out)
1600 out.write("""
1601/**
1602 *
1603 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1604 *
1605 * Unified simple class instantiation tests for all versions
1606 */
1607
1608#include <locitest/test_common.h>
1609""")
1610 for version in of_g.of_version_range:
1611 for cls in of_g.standard_class_order:
1612 if not loxi_utils.class_in_version(cls, version):
1613 continue
Rich Lane8841f352014-10-12 19:18:36 -07001614 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001615 continue
1616 unified_accessor_test_case(out, cls, version)
1617
1618 out.write("""
1619int
1620run_unified_accessor_tests(void)
1621{
1622""")
1623 for version in of_g.of_version_range:
1624 v_name = loxi_utils.version_to_name(version)
1625 for cls in of_g.standard_class_order:
1626 if not loxi_utils.class_in_version(cls, version):
1627 continue
Rich Lane8841f352014-10-12 19:18:36 -07001628 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001629 continue
1630 test_name = "%s_%s" % (cls, v_name)
1631 out.write(" RUN_TEST(%s);\n" % test_name)
1632
1633 out.write(" return TEST_PASS;\n}\n");
1634
1635
1636
1637################################################################
1638#
1639# Object duplication functions
1640#
1641# These exercise the accessors to create duplicate objects.
1642# They are used in the LOCI test shim which sits in an OF
1643# protocol stream.
1644#
1645# TODO
1646# Resolve version stuff
1647# Complete list dup
1648
1649def gen_dup_list(out, cls, version):
1650 ver_name = loxi_utils.version_to_name(version)
1651 elt_type = loxi_utils.list_to_entry_type(cls)
1652 out.write("""
1653/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001654 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001655 * using accessor functions
1656 * @param src Pointer to object to be duplicated
1657 * @returns A new object of type %(cls)s.
1658 *
1659 * The caller is responsible for deleting the returned value
1660 */
1661%(cls)s_t *
1662%(cls)s_%(ver_name)s_dup(
1663 %(cls)s_t *src)
1664{
Rich Lanee499bd12014-10-28 15:25:09 -07001665 of_object_t src_elt;
1666 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001667 int rv;
1668 %(cls)s_t *dst;
1669
1670 if ((dst = %(cls)s_new(src->version)) == NULL) {
1671 return NULL;
1672 }
1673""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1674
1675 out.write("""
1676 %(u_cls)s_ITER(src, &src_elt, rv) {
1677 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1678 of_object_delete((of_object_t *)dst);
1679 return NULL;
1680 }
1681 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1682 dst, NULL);
1683 of_object_delete((of_object_t *)dst_elt);
1684 }
1685
1686 return dst;
1687}
1688""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1689
1690
1691def gen_dup_inheritance(out, cls, version):
1692 ver_name = loxi_utils.version_to_name(version)
1693 out.write("""
1694/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001695 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001696 * @param src Pointer to object to be duplicated
1697 * @returns A new object of type %(cls)s.
1698 *
1699 * The caller is responsible for deleting the returned value
1700 */
Rich Lanee499bd12014-10-28 15:25:09 -07001701of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001702%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001703 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001704{
1705""" % dict(cls=cls, ver_name=ver_name))
1706
1707 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001708 sub_classes = type_maps.sub_class_map(cls, version)
1709 for (_, sub_cls) in sub_classes:
1710 sub_enum = sub_cls.upper()
Rich Lanea06d0c32013-03-25 08:52:03 -07001711 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001712 if (src->object_id == %(sub_enum)s) {
1713 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001714 }
1715""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1716
1717 out.write("""
1718 return NULL;
1719}
1720""")
1721
1722
1723def gen_dup_cls(out, cls, version):
1724 """
1725 Generate duplication routine for class cls
1726 """
1727 ver_name = loxi_utils.version_to_name(version)
1728
1729 out.write("""
1730/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001731 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001732 * using accessor functions
1733 * @param src Pointer to object to be duplicated
1734 * @returns A new object of type %(cls)s.
1735 *
1736 * The caller is responsible for deleting the returned value
1737 */
1738%(cls)s_t *
1739%(cls)s_%(ver_name)s_dup(
1740 %(cls)s_t *src)
1741{
1742 %(cls)s_t *dst;
1743""" % dict(cls=cls, ver_name=ver_name))
1744
1745 # Get members and types for the class
1746 members, member_types = loxi_utils.all_member_types_get(cls, version)
1747
1748 # Add declarations for each member type
1749 for m_type in member_types:
1750 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1751 # Declare instance of these
1752 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001753 elif m_type in embedded_subclasses:
1754 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001755 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001756 %(sub_cls)s_t src_%(v_name)s;
1757 %(sub_cls)s_t *dst_%(v_name)s;
1758""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001759 else:
1760 out.write("""
1761 %(m_type)s src_%(v_name)s;
1762 %(m_type)s *dst_%(v_name)s;
1763""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1764
1765 out.write("""
1766 if ((dst = %(cls)s_new(src->version)) == NULL) {
1767 return NULL;
1768 }
1769""" % dict(cls=cls))
1770
1771 for member in members:
1772 m_type = member["m_type"]
1773 m_name = member["name"]
1774 if loxi_utils.skip_member_name(m_name):
1775 continue
1776 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1777 out.write("""
1778 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1779 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1780""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1781 elif m_type in ["of_match_t", "of_octets_t"]:
1782 out.write("""
1783 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1784 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1785""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001786 elif m_type in embedded_subclasses:
1787 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001788 out.write("""
1789 %(cls)s_%(m_name)s_bind(
1790 src, &src_%(v_name)s);
1791 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1792 if (dst_%(v_name)s == NULL) {
1793 %(cls)s_delete(dst);
1794 return NULL;
1795 }
1796 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1797 %(sub_cls)s_delete(dst_%(v_name)s);
1798""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1799 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001800 else:
1801 sub_cls = m_type[:-2] # Trim _t
1802 out.write("""
1803 %(cls)s_%(m_name)s_bind(
1804 src, &src_%(v_name)s);
1805 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1806 if (dst_%(v_name)s == NULL) {
1807 %(cls)s_delete(dst);
1808 return NULL;
1809 }
1810 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1811 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001812""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001813 v_name=var_name_map(m_type), ver_name=ver_name))
1814
1815 out.write("""
1816 return dst;
1817}
1818""")
1819
1820def gen_version_dup(out=sys.stdout):
1821 """
1822 Generate duplication routines for each object type
1823 """
1824 out.write("""
1825/* Special try macro for duplicating */
1826#define _TRY_FREE(op, obj, rv) do { \\
1827 int _rv; \\
1828 if ((_rv = (op)) < 0) { \\
1829 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1830 of_object_delete((of_object_t *)(obj)); \\
1831 return (rv); \\
1832 } \\
1833 } while (0)
1834""")
1835
1836 for version in of_g.of_version_range:
1837 for cls in of_g.standard_class_order:
1838 if not loxi_utils.class_in_version(cls, version):
1839 continue
Rich Lane8841f352014-10-12 19:18:36 -07001840 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001841 gen_dup_inheritance(out, cls, version)
1842 elif loxi_utils.class_is_list(cls):
1843 gen_dup_list(out, cls, version)
1844 else:
1845 gen_dup_cls(out, cls, version)
1846
1847def gen_dup(out=sys.stdout):
1848 """
1849 Generate non-version specific duplication routines for each object type
1850 """
1851
1852 for cls in of_g.standard_class_order:
1853 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001854of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001855%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001856 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001857{
1858""" % dict(cls=cls))
1859 for version in of_g.of_version_range:
1860 if not loxi_utils.class_in_version(cls, version):
1861 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001862
1863 ver_name = loxi_utils.version_to_name(version)
1864 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001865 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001866 return %(cls)s_%(ver_name)s_dup(src);
1867 }
Rich Lanee499bd12014-10-28 15:25:09 -07001868""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001869
1870 out.write("""
1871 /* Class not supported in given version */
1872 return NULL;
1873}
1874""")
1875
1876def dup_c_gen(out, name):
1877 """
1878 Generate the C file for duplication functions
1879 """
1880 loxi_utils.gen_c_copy_license(out)
1881 out.write("""\
1882/*
1883 * Duplication functions for all OF objects
1884 *
1885 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1886 *
1887 * These are test functions for exercising accessors. You can call
1888 * of_object_dup for an efficient duplication.
1889 */
1890
1891#define DISABLE_WARN_UNUSED_RESULT
1892#include "loci_log.h"
1893#include <locitest/of_dup.h>
1894
1895""")
1896
1897 gen_version_dup(out)
1898 gen_dup(out)
1899
1900
1901def dup_h_gen(out, name):
1902 """
1903 Generate the header file for duplication functions
1904 """
1905
1906 loxi_utils.gen_c_copy_license(out)
1907 out.write("""
1908/*
1909 * Duplication function header file
1910 *
1911 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1912 */
1913
1914#if !defined(_OF_DUP_H_)
1915#define _OF_DUP_H_
1916
1917#include <loci/loci.h>
1918""")
1919
1920 for cls in of_g.standard_class_order:
1921 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001922extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001923 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001924 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001925""" % dict(cls=cls))
1926
1927 for version in of_g.of_version_range:
1928 for cls in of_g.standard_class_order:
1929 if not loxi_utils.class_in_version(cls, version):
1930 continue
1931 ver_name = loxi_utils.version_to_name(version)
1932 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001933extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001934 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001935 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001936""" % dict(cls=cls, ver_name=ver_name))
1937
1938 out.write("\n#endif /* _OF_DUP_H_ */\n")
1939
1940def gen_log_test(out):
1941 """
1942 Generate test for obj log calls
1943
1944 Define a trivial handler for object logging; call all obj log fns
1945 """
1946 out.write("""
1947
1948/**
1949 * Test object dump functions
1950 */
1951
1952int
1953test_dump_objs(void)
1954{
1955 of_object_t *obj;
1956
1957 FILE *out = fopen("/dev/null", "w");
1958
1959 /* Call each obj dump function */
1960""")
1961 for version in of_g.of_version_range:
1962 for j, cls in enumerate(of_g.all_class_order):
1963 if not loxi_utils.class_in_version(cls, version):
1964 continue
Rich Lane8841f352014-10-12 19:18:36 -07001965 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001966 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001967 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1968 out.write("""
1969 obj = (of_object_t *)%(cls)s_new(%(version)s);
1970 {
1971 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1972 %(cls)s_vport_set(obj, vport);
1973 of_object_delete(vport);
1974 }
1975 of_object_dump((loci_writer_f)fprintf, out, obj);
1976 of_object_delete(obj);
1977""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1978 else:
1979 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001980 obj = (of_object_t *)%(cls)s_new(%(version)s);
1981 of_object_dump((loci_writer_f)fprintf, out, obj);
1982 of_object_delete(obj);
1983""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001984
Rich Lanea06d0c32013-03-25 08:52:03 -07001985 out.write("""
1986 fclose(out);
1987 return TEST_PASS;
1988}
1989""")
1990
1991def gen_ident_tests(out):
1992 """
1993 Generate tests for identifiers
1994
1995 For all idents, instantiate, test version supported macros
1996 For flags, set it, test it, clear it, test it.
1997 """
1998 out.write("""
1999/**
2000 * Test cases for all flag accessor macros
2001 * These only test self consistency (and that they compile)
2002 */
2003int
2004test_ident_macros(void)
2005{
2006 int value __attribute__((unused));
2007 uint32_t flags;
2008
2009""")
2010
2011 for ident, info in of_g.identifiers.items():
2012 if not identifiers.defined_versions_agree(of_g.identifiers,
2013 of_g.target_version_list,
2014 ident):
2015 # @fixme
2016 continue
2017 out.write(" value = %s;\n" % ident)
2018 for version in of_g.target_version_list:
2019 if version in info["values_by_version"].keys():
2020 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2021 (ident, of_g.of_version_wire2name[version]))
2022 else:
2023 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2024 (ident, of_g.of_version_wire2name[version]))
2025 if flags.ident_is_flag(ident):
2026 # Grab first supported version
2027 for version in info["values_by_version"]:
2028 break
2029 out.write("""
2030 flags = 0;
2031 %(ident)s_SET(flags, %(ver_name)s);
2032 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2033 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2034 %(ident)s_CLEAR(flags, %(ver_name)s);
2035 TEST_ASSERT(flags == 0);
2036 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2037""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2038
2039 out.write("""
2040 return TEST_PASS;
2041}
2042""")
2043
Rich Laneccae0312013-07-21 23:34:13 -07002044def gen_datafiles_tests(out, name):
2045 tests = []
2046 for filename in test_data.list_files():
2047 data = test_data.read(filename)
2048 if not 'c' in data:
2049 continue
2050 name = filename[:-5].replace("/", "_")
2051 tests.append(dict(name=name,
2052 filename=filename,
2053 c=data['c'],
2054 binary=data['binary']))
2055
2056 util.render_template(out, "test_data.c", tests=tests)