blob: dacc8bf6acc8182b9982fc59af7d79e18cf3a89f [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Test case generation functions
30
31@fixme Update the following
32The following components are generated.
33
34test_common.[ch]: A collection of common code for tests. Currently
35this includes the ability to set the scalar members of an object with
36incrementing values and then similarly verify those values
37
38test_scalar_acc.c: Instantiate each type of object, then set and get
39scalar values in the objects.
40
41test_list.c: Instantiate each type of list, add an element of each
42type the list supports, setting scalar values of the elements.
43
44test_match.c: Various tests for match objects
45
46test_msg.c: Instantiate top level messages
47
48These will move towards unified tests that do the following:
49
50Create or init an object.
51Populate the object with incrementing values.
52Possibly transform the object in some way (e.g., run the underlying
53wire buffer through a parse routine).
54Verify that the members all have the appropriate value
55
56Through out, checking the consistency of memory and memory operations
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +090057is done with mcheck (if available).
Rich Lanea06d0c32013-03-25 08:52:03 -070058
59"""
60
61import sys
Andreas Wundsam76db0062013-11-15 13:34:41 -080062import c_gen.of_g_legacy as of_g
Andreas Wundsam542a13c2013-11-15 13:28:55 -080063import c_gen.match as match
64import c_gen.flags as flags
Rich Lanea06d0c32013-03-25 08:52:03 -070065from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080066import c_gen.type_maps as type_maps
67import c_gen.loxi_utils_legacy as loxi_utils
68import c_gen.identifiers as identifiers
Rich Laneccae0312013-07-21 23:34:13 -070069import util
70import test_data
Rich Lane79c87192014-03-04 10:56:59 -080071import loxi_globals
72from loxi_ir import *
Rich Lanea06d0c32013-03-25 08:52:03 -070073
74def var_name_map(m_type):
75 """
76 Map a type to a generic variable name for the type.
77 @param m_type The data type
78
79 Used mostly in test code generation, but also for the dup functions.
80 """
81 _var_name_map= dict(
82 uint8_t="val8",
83 uint16_t="val16",
84 uint32_t="val32",
85 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070086 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_port_no_t="port_no",
88 of_fm_cmd_t="fm_cmd",
89 of_wc_bmap_t="wc_bmap",
90 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070091 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070092 of_table_name_t="table_name",
93 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070094 of_serial_num_t="ser_num",
Rich Lanef8a3d002014-03-19 13:33:52 -070095 of_str64_t="str64",
Andreas Wundsam53256162013-05-02 14:05:53 -070096 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070097 of_ipv6_t="ipv6",
98 # Non-scalars; more TBD
99 of_octets_t="octets",
100 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700101 of_match_t="match",
Rich Lane90020b42014-04-07 12:05:45 -0700102 of_oxm_header_t="oxm",
Wilson Ngd6181882014-04-14 16:28:35 -0700103 of_bsn_vport_header_t="bsn_vport",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700104 # BSN extensions
105 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700106 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800107 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700108 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700109
110 if m_type.find("of_list_") == 0:
111 return "list"
112 if m_type in of_g.of_mixed_types:
113 return of_g.of_mixed_types[m_type]["short_name"]
114 return _var_name_map[m_type]
115
116integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
117 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700118 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700119string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700120 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700121 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
122 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700123
124scalar_types = integer_types[:]
125scalar_types.extend(string_types)
126
Rich Lane1f315aa2014-10-13 17:11:35 -0700127# When embedding an object inside of another object we have to pick a single
128# subclass to use, unlike lists where we use all subclasses.
129embedded_subclasses = {
130 'of_oxm_header_t': 'of_oxm_eth_type',
131 'of_bsn_vport_header_t': 'of_bsn_vport_q_in_q',
132}
133
Rich Lanea06d0c32013-03-25 08:52:03 -0700134def ignore_member(cls, version, m_name, m_type):
135 """
136 Filter out names or types that either don't have accessors
137 or those that should not be messed with
138 or whose types we're not ready to deal with yet.
139 """
Rich Lane79c87192014-03-04 10:56:59 -0800140
141 uclass = loxi_globals.unified.class_by_name(cls)
142 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700143 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800144
Rich Lane79c87192014-03-04 10:56:59 -0800145 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800146 return True
Rich Lane79c87192014-03-04 10:56:59 -0800147
Rich Lanea06d0c32013-03-25 08:52:03 -0700148 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
149
150def gen_fill_string(out):
151 out.write("""
152
153/**
154 * The increment to use on values inside a string
155 */
156#define OF_TEST_STR_INCR 3
157
158/**
159 * Fill in a buffer with incrementing values starting
160 * at the given offset with the given value
161 * @param buf The buffer to fill
162 * @param value The value to use for data
163 * @param len The number of bytes to fill
164 */
165
166void
167of_test_str_fill(uint8_t *buf, int value, int len)
168{
169 int i;
170
171 for (i = 0; i < len; i++) {
172 *buf = value;
173 value += OF_TEST_STR_INCR;
174 buf++;
175 }
176}
177
178/**
179 * Given a buffer, verify that it's filled as above
180 * @param buf The buffer to check
181 * @param value The value to use for data
182 * @param len The number of bytes to fill
183 * @return Boolean True on equality (success)
184 */
185
186int
187of_test_str_check(uint8_t *buf, int value, int len)
188{
189 int i;
190 uint8_t val8;
191
192 val8 = value;
193
194 for (i = 0; i < len; i++) {
195 if (*buf != val8) {
196 return 0;
197 }
198 val8 += OF_TEST_STR_INCR;
199 buf++;
200 }
201
202 return 1;
203}
204
205/**
206 * Global that determines how octets should be populated
207 * -1 means use value % MAX (below) to determine length
208 * 0, 1, ... means used that fixed length
209 *
210 * Note: Was 16K, but that made objects too big. May add flexibility
211 * to call populate with a max parameter for length
212 */
213int octets_pop_style = -1;
214#define OCTETS_MAX_VALUE (128) /* 16K was too big */
215#define OCTETS_MULTIPLIER 6367 /* A prime */
216
217int
218of_octets_populate(of_octets_t *octets, int value)
219{
220 if (octets_pop_style < 0) {
221 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
222 } else {
223 octets->bytes = octets_pop_style;
224 }
225
226 if (octets->bytes != 0) {
227 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
228 return 0;
229 }
230 of_test_str_fill(octets->data, value, octets->bytes);
231 value += 1;
232 }
233
234 return value;
235}
236
237int
238of_octets_check(of_octets_t *octets, int value)
239{
240 int len;
241
242 if (octets_pop_style < 0) {
243 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
244 TEST_ASSERT(octets->bytes == len);
245 } else {
246 TEST_ASSERT(octets->bytes == octets_pop_style);
247 }
248
249 if (octets->bytes != 0) {
250 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
251 == 1);
252 value += 1;
253 }
254
255 return value;
256}
257
258int
259of_match_populate(of_match_t *match, of_version_t version, int value)
260{
261 MEMSET(match, 0, sizeof(*match));
262 match->version = version;
263""")
264
Rich Laned56f8d22014-05-06 14:52:55 -0700265 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700266 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700267 if (version == %d) {\
268""" % wire_version)
269 for key in keys:
270 entry = match.of_match_members[key]
271 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700272 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
273 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
274 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700275""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
276 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700277 }
278
Rich Laned56f8d22014-05-06 14:52:55 -0700279""")
280
Rich Laneb4a63a52014-05-22 14:41:57 -0700281 for wire_version, match_keys in match.match_keys.items():
282 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700283
284 out.write("""
285 if (value % 2) {
286 /* Sometimes set ipv4 addr masks to non-exact */
287 match->masks.ipv4_src = 0xffff0000;
288 match->masks.ipv4_dst = 0xfffff800;
289 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700290
291 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700292 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700293 return value;
294}
295
296int
297of_match_check(of_match_t *match, of_version_t version, int value)
298{
299 of_match_t check;
300
301 value = of_match_populate(&check, match->version, value);
302 TEST_ASSERT(value != 0);
303 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
304
305 return value;
306}
307""")
308
309def gen_common_test_header(out, name):
310 loxi_utils.gen_c_copy_license(out)
311 out.write("""
312/*
313 * Test header file
314 *
315 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
316 */
317
318#if !defined(_TEST_COMMON_H_)
319#define _TEST_COMMON_H_
320
321#define DISABLE_WARN_UNUSED_RESULT
322#include <loci/loci.h>
323#include <locitest/of_dup.h>
324#include <locitest/unittest.h>
325
326extern int global_error;
327extern int exit_on_error;
328
329/* @todo Make option for -k to continue tests if errors */
330#define RUN_TEST(test) do { \\
331 int rv; \\
332 TESTCASE(test, rv); \\
333 if (rv != TEST_PASS) { \\
334 global_error=1; \\
335 if (exit_on_error) return(1); \\
336 } \\
337 } while(0)
338
339#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
340#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
341
342/*
343 * Declarations of functions to populate scalar values in a a class
344 */
345
346extern void of_test_str_fill(uint8_t *buf, int value, int len);
347extern int of_test_str_check(uint8_t *buf, int value, int len);
348
349
350extern int of_octets_populate(of_octets_t *octets, int value);
351extern int of_octets_check(of_octets_t *octets, int value);
352extern int of_match_populate(of_match_t *match, of_version_t version,
353 int value);
354extern int of_match_check(of_match_t *match, of_version_t version, int value);
355extern int test_ident_macros(void);
356extern int test_dump_objs(void);
357
358/* In test_match_utils.c */
359extern int test_match_utils(void);
360
361extern int run_unified_accessor_tests(void);
362extern int run_match_tests(void);
363extern int run_utility_tests(void);
364
365extern int run_scalar_acc_tests(void);
366extern int run_list_tests(void);
367extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700368
369extern int run_validator_tests(void);
370
371extern int run_list_limits_tests(void);
372
373extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700374extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700375
376""")
377
378 for version in of_g.of_version_range:
379 for cls in of_g.standard_class_order:
380 if not loxi_utils.class_in_version(cls, version):
381 continue
Rich Lane8841f352014-10-12 19:18:36 -0700382 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700383 continue
384 out.write("""
385extern int %(cls)s_%(v_name)s_populate(
386 %(cls)s_t *obj, int value);
387extern int %(cls)s_%(v_name)s_check(
388 %(cls)s_t *obj, int value);
389extern int %(cls)s_%(v_name)s_populate_scalars(
390 %(cls)s_t *obj, int value);
391extern int %(cls)s_%(v_name)s_check_scalars(
392 %(cls)s_t *obj, int value);
393""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
394
395 out.write("""
396/*
397 * Declarations for list population and check primitives
398 */
399""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700400
Rich Lanea06d0c32013-03-25 08:52:03 -0700401 for version in of_g.of_version_range:
402 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700403 if version in of_g.unified[cls]:
404 out.write("""
405extern int
406 list_setup_%(cls)s_%(v_name)s(
407 %(cls)s_t *list, int value);
408extern int
409 list_check_%(cls)s_%(v_name)s(
410 %(cls)s_t *list, int value);
411""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
412
413 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
414
415def gen_common_test(out, name):
416 """
417 Generate common test content including main
418 """
419 loxi_utils.gen_c_copy_license(out)
420 out.write("""
421/*
422 * Common test code for LOCI
423 *
424 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
425 */
426
427#define DISABLE_WARN_UNUSED_RESULT
428#include "loci_log.h"
429#include <loci/loci_obj_dump.h>
430#include <locitest/unittest.h>
431#include <locitest/test_common.h>
432
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900433/* mcheck is a glibc extension */
434#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700435#include <mcheck.h>
436#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900437#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700438#define MCHECK_INIT do { } while (0)
439#endif
440
441/**
442 * Exit on error if set to 1
443 */
444int exit_on_error = 1;
445
446/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700447 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700448 */
449int global_error = 0;
450
451extern int run_unified_accessor_tests(void);
452extern int run_match_tests(void);
453extern int run_utility_tests(void);
454
455extern int run_scalar_acc_tests(void);
456extern int run_list_tests(void);
457extern int run_message_tests(void);
458
459/**
460 * Macros for initializing and checking scalar types
461 *
462 * @param var The variable being initialized or checked
463 * @param val The integer value to set/check against, see below
464 *
465 * Note that equality means something special for strings. Each byte
466 * is initialized to an incrementing value. So check is done against that.
467 *
468 */
469
470""")
471 for t in scalar_types:
472 if t in integer_types:
473 out.write("""
474#define VAR_%s_INIT(var, val) var = (%s)(val)
475#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
476""" % (t.upper(), t, t.upper(), t))
477 else:
478 out.write("""
479#define VAR_%s_INIT(var, val) \\
480 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
481#define VAR_%s_CHECK(var, val) \\
482 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
483""" % (t.upper(), t.upper()))
484
485 gen_fill_string(out)
486 gen_scalar_set_check_funs(out)
487 gen_list_set_check_funs(out)
488 gen_unified_accessor_funs(out)
489
490 gen_ident_tests(out)
491 gen_log_test(out)
492
493def gen_message_scalar_test(out, name):
494 """
495 Generate test cases for message objects, scalar accessors
496 """
497
498 loxi_utils.gen_c_copy_license(out)
499 out.write("""
500/**
501 *
502 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
503 *
504 * Message-scalar tests for all versions
505 */
506
507#include <locitest/test_common.h>
508""")
509 for version in of_g.of_version_range:
510 v_name = loxi_utils.version_to_name(version)
511 out.write("""
512/**
513 * Message-scalar tests for version %s
514 */
515""" % v_name)
516 for cls in of_g.standard_class_order:
Rich Lane8841f352014-10-12 19:18:36 -0700517 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700518 continue
519 if version in of_g.unified[cls]:
520 message_scalar_test(out, version, cls)
521
522 out.write("""
523int
524run_scalar_acc_tests(void)
525{
526""")
527 for version in of_g.of_version_range:
528 v_name = loxi_utils.version_to_name(version)
529 for cls in of_g.standard_class_order:
Rich Lane8841f352014-10-12 19:18:36 -0700530 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700531 continue
532 if version in of_g.unified[cls]:
533 test_name = "%s_%s" % (cls, v_name)
534 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
535
536 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700537
Rich Lanea06d0c32013-03-25 08:52:03 -0700538def message_scalar_test(out, version, cls):
539 """
540 Generate one test case for the given version and class
541 """
542
543 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700544 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700545 v_name = loxi_utils.version_to_name(version)
546
547 out.write("""
548static int
549test_%(cls)s_%(v_name)s_scalar(void)
550{
551 %(cls)s_t *obj;
552
553 obj = %(cls)s_new(%(v_name)s);
554 TEST_ASSERT(obj != NULL);
555 TEST_ASSERT(obj->version == %(v_name)s);
556 TEST_ASSERT(obj->length == %(length)d);
557 TEST_ASSERT(obj->parent == NULL);
558 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700559""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700560 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700561
562 # If this class is a concrete member of an inheritance hierarchy,
563 # run the hierarchy's root wire type parser and assert it returns
564 # the expected object id.
565 ofclass = loxi_globals.unified.class_by_name(cls)
566 if ofclass and not ofclass.virtual:
567 root = ofclass
568 while root.superclass:
569 root = root.superclass
570 if root.virtual:
571 out.write("""
572 {
573 of_object_id_t object_id;
574 %(root_cls)s_wire_object_id_get(obj, &object_id);
575 TEST_ASSERT(object_id == %(u_cls)s);
576 }
577""" % dict(root_cls=root.name, u_cls=cls.upper()))
578
Rich Lanea06d0c32013-03-25 08:52:03 -0700579 if not type_maps.class_is_virtual(cls):
580 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700581 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700582 int length;
583
Rich Lanedc46fe22014-04-03 15:10:38 -0700584 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700585 TEST_ASSERT(length == %(length)d);
586 }
587
588 /* Set up incrementing values for scalar members */
589 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
590
591 /* Check values just set */
592 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700593""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700594 v_name=v_name, length=length, version=version))
595
596 out.write("""
597 %(cls)s_delete(obj);
598
599 /* To do: Check memory */
600 return TEST_PASS;
601}
602""" % dict(cls=cls))
603
604# Get the members and list of scalar types for members of a given class
605def scalar_member_types_get(cls, version):
606 member_types = []
607
608 if not version in of_g.unified[cls]:
609 return ([], [])
610
611 if "use_version" in of_g.unified[cls][version]:
612 v = of_g.unified[cls][version]["use_version"]
613 members = of_g.unified[cls][v]["members"]
614 else:
615 members = of_g.unified[cls][version]["members"]
616 # Accumulate variables that are supported
617 for member in members:
618 m_type = member["m_type"]
619 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700620 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700621 ignore_member(cls, version, m_name, m_type)):
622 continue
623 if not m_type in member_types:
624 member_types.append(m_type)
625
626 return (members, member_types)
627
628def scalar_funs_instance(out, cls, version, members, member_types):
629 """
630 Generate one instance of scalar set/check functions
631 """
632 out.write("""
633/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700634 * Populate the scalar values in obj of type %(cls)s,
635 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700636 * @param obj Pointer to an object to populate
637 * @param value The seed value to use in populating the object
638 * @returns The value after increments for this object's values
639 */
640int %(cls)s_%(v_name)s_populate_scalars(
641 %(cls)s_t *obj, int value) {
642""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
643 # Declare string types
644 for t in member_types:
645 out.write(" %s %s;\n" % (t, var_name_map(t)))
646 for member in members:
647 m_type = member["m_type"]
648 m_name = member["name"]
649 if (not loxi_utils.type_is_scalar(m_type) or
650 ignore_member(cls, version, m_name, m_type)):
651 continue
652 v_name = var_name_map(m_type);
653 out.write("""
654 VAR_%(u_type)s_INIT(%(v_name)s, value);
655 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
656 value += 1;
657""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
658 out.write("""
659 return value;
660}
661""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700662
Rich Lanea06d0c32013-03-25 08:52:03 -0700663 out.write("""
664/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700665 * Check scalar values in obj of type %(cls)s,
666 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700667 * @param obj Pointer to an object to check
668 * @param value Starting value for checking
669 * @returns The value after increments for this object's values
670 */
671int %(cls)s_%(v_name)s_check_scalars(
672 %(cls)s_t *obj, int value) {
673""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
674
675 for t in member_types:
676 out.write(" %s %s;\n" % (t, var_name_map(t)))
677 for member in members:
678 m_type = member["m_type"]
679 m_name = member["name"]
680 if (not loxi_utils.type_is_scalar(m_type) or
681 ignore_member(cls, version, m_name, m_type)):
682 continue
683 v_name = var_name_map(m_type);
684 out.write("""
685 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
686 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
687 value += 1;
688""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
689
690 out.write("""
691 return value;
692}
693
694""")
695
696def gen_scalar_set_check_funs(out):
697 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700698 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700699 set and check their values
700 """
701 for version in of_g.of_version_range:
702 for cls in of_g.standard_class_order:
703 (members, member_types) = scalar_member_types_get(cls, version)
704 scalar_funs_instance(out, cls, version, members, member_types)
705
706
707# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700708def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700709 base_type = loxi_utils.list_to_entry_type(cls)
710 setup_template = """
711 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700712 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700713 (%(base_type)s_t *)%(inst)s);
714 value = %(subcls)s_%(v_name)s_populate(
715 %(inst)s, value);
716 cur_len += %(inst)s->length;
717 TEST_ASSERT(list->length == cur_len);
718"""
719 out.write("""
720 /* Append two instances of type %s */
721""" % subcls)
722 for i in range(2):
723 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700724 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700725 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700726 version=version))
727
Rich Lane9afc3b92014-04-09 22:55:53 -0700728def check_instance(out, cls, subcls, instance, v_name, version, last):
729 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700730 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
731 value = %(subcls)s_%(v_name)s_check(
732 %(inst)s, value);
733 TEST_ASSERT(value != 0);
734"""
735 out.write("\n /* Check two instances of type %s */" % instance)
736
Andreas Wundsam53256162013-05-02 14:05:53 -0700737 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700738 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700739 inst=instance, subcls=subcls,
740 v_name=loxi_utils.version_to_name(version)))
741 out.write("""\
742 TEST_OK(%(cls)s_next(list, &elt));
743""" % dict(cls=cls))
744
Andreas Wundsam53256162013-05-02 14:05:53 -0700745 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700746 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700747 inst=instance, subcls=subcls,
748 v_name=loxi_utils.version_to_name(version)))
749 if last:
750 out.write("""\
751 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
752""" % dict(cls=cls))
753 else:
754 out.write("""\
755 TEST_OK(%(cls)s_next(list, &elt));
756""" % dict(cls=cls))
757
758def setup_list_fn(out, version, cls):
759 """
760 Generate a helper function that populates a list with two
761 of each type of subclass it supports
762 """
763 out.write("""
764/**
765 * Set up a list of type %(cls)s with two of each type of subclass
766 */
767int
768list_setup_%(cls)s_%(v_name)s(
769 %(cls)s_t *list, int value)
770{
771""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
772 base_type = loxi_utils.list_to_entry_type(cls)
773 out.write("""
774 %(base_type)s_t elt;
775 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700776 (void) elt;
777 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700778""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700779
Rich Lanea06d0c32013-03-25 08:52:03 -0700780 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700781 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 -0700782 v_name = loxi_utils.version_to_name(version)
783
Rich Lanee98ee5d2014-10-14 10:43:44 -0700784 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700785 out.write(" /* No subclasses for %s */\n"% base_type)
786 out.write(" %s_t *elt_p;\n" % base_type)
787 out.write("\n elt_p = &elt;\n")
788 else:
789 out.write(" /* Declare pointers for each subclass */\n")
790 for instance, subcls in sub_classes:
791 out.write(" %s_t *%s;\n" % (subcls, instance))
792 out.write("\n /* Instantiate pointers for each subclass */\n")
793 for instance, subcls in sub_classes:
794 out.write(" %s = &elt.%s;\n" % (instance, instance))
795
Rich Lanee98ee5d2014-10-14 10:43:44 -0700796 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700797 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700798 else:
799 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700800 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700801 out.write("""
802
803 return value;
804}
805""")
806
807def check_list_fn(out, version, cls):
808 """
809 Generate a helper function that checks a list populated by above fn
810 """
811 out.write("""
812/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700813 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700814 * list_setup_%(cls)s_%(v_name)s
815 */
816int
817list_check_%(cls)s_%(v_name)s(
818 %(cls)s_t *list, int value)
819{
820""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
821 base_type = loxi_utils.list_to_entry_type(cls)
822 out.write("""
823 %(base_type)s_t elt;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700824 (void) elt;
Rich Lanea06d0c32013-03-25 08:52:03 -0700825""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700826
Rich Lanea06d0c32013-03-25 08:52:03 -0700827 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700828 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 -0700829 v_name = loxi_utils.version_to_name(version)
830
Rich Lanee98ee5d2014-10-14 10:43:44 -0700831 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700832 out.write(" /* No subclasses for %s */\n"% base_type)
833 out.write(" %s_t *elt_p;\n" % base_type)
834 out.write("\n elt_p = &elt;\n")
835 else:
836 out.write(" /* Declare pointers for each subclass */\n")
837 for instance, subcls in sub_classes:
838 out.write(" %s_t *%s;\n" % (subcls, instance))
839 out.write("\n /* Instantiate pointers for each subclass */\n")
840 for instance, subcls in sub_classes:
841 out.write(" %s = &elt.%s;\n" % (instance, instance))
842
Rich Lanee98ee5d2014-10-14 10:43:44 -0700843 if not type_maps.class_is_virtual(base_type) or sub_classes:
844 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
845
846 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700847 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700848 else:
849 count = 0
850 for instance, subcls in sub_classes:
851 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700852 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700853 version, count==len(sub_classes))
854
855 out.write("""
856 return value;
857}
858""" % dict(base_type=base_type))
859
860def gen_list_set_check_funs(out):
861 for version in of_g.of_version_range:
862 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700863 if version in of_g.unified[cls]:
864 setup_list_fn(out, version, cls)
865 check_list_fn(out, version, cls)
866
867# Maybe: Get a map from list class to parent, mem_name of container
868
869def list_test(out, version, cls):
870 out.write("""
871static int
872test_%(cls)s_%(v_name)s(void)
873{
874""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
875 base_type = loxi_utils.list_to_entry_type(cls)
876
877 out.write(""" %(cls)s_t *list;
878 int value = 1;
879""" % dict(cls=cls, base_type=base_type))
880
881 out.write("""
882 list = %(cls)s_new(%(v_name)s);
883 TEST_ASSERT(list != NULL);
884 TEST_ASSERT(list->version == %(v_name)s);
885 TEST_ASSERT(list->length == 0);
886 TEST_ASSERT(list->parent == NULL);
887 TEST_ASSERT(list->object_id == %(enum_cls)s);
888
889 value = list_setup_%(cls)s_%(v_name)s(list, value);
890 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700891""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700892 enum_cls=loxi_utils.enum_name(cls)))
893
894 out.write("""
895 /* Now check values */
896 value = 1;
897 value = list_check_%(cls)s_%(v_name)s(list, value);
898 TEST_ASSERT(value != 0);
899""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
900
901 out.write("""
902 %(cls)s_delete(list);
903
904 return TEST_PASS;
905}
906""" % dict(cls=cls))
907
908def gen_list_test(out, name):
909 """
910 Generate base line test cases for lists
911 @param out The file handle to write to
912 """
913
914 loxi_utils.gen_c_copy_license(out)
915 out.write("""
916/**
917 *
918 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
919 *
920 * Message-scalar tests for all versions
921 */
922
923#include <locitest/test_common.h>
924""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700925
Rich Lanea06d0c32013-03-25 08:52:03 -0700926 for version in of_g.of_version_range:
927 v_name = loxi_utils.version_to_name(version)
928 out.write("""
929/**
930 * Baseline list tests for version %s
931 */
932""" % v_name)
933 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700934 if version in of_g.unified[cls]:
935 list_test(out, version, cls)
936
937 out.write("""
938int
939run_list_tests(void)
940{
941""")
942 for version in of_g.of_version_range:
943 v_name = loxi_utils.version_to_name(version)
944 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700945 if version in of_g.unified[cls]:
946 test_name = "%s_%s" % (cls, v_name)
947 out.write(" RUN_TEST(%s);\n" % test_name)
948
949 out.write("\n return TEST_PASS;\n}\n");
950
951def gen_match_test(out, name):
952 """
953 Generate baseline tests for match functions
954 """
955
956 loxi_utils.gen_c_copy_license(out)
957 out.write("""\
958/**
959 *
960 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
961 *
962 * Message-scalar tests for all versions
963 * @fixme These are mostly hard coded now.
964 */
965
966#include <locitest/test_common.h>
967
968static int
969test_match_1(void)
970{
Rich Lanef87f4c32014-10-14 11:56:02 -0700971""")
972
973 for version in of_g.of_version_range:
974 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
975
976 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700977 of_match_t match;
978 int value = 1;
979 int idx;
980 uint32_t exp_value;
981
982 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700983 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700984 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
985 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
986 if (idx < 32) {
987 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
988 }
989 }
990""")
991
992 for version in of_g.of_version_range:
993 out.write("""
994 /* Create/populate/convert and delete for version %(v_name)s */
995 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
996 TEST_ASSERT(m_v%(version)d != NULL);
997 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
998 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
999 of_match_v%(version)d_delete(m_v%(version)d);
1000""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1001
1002 out.write("""
1003 return TEST_PASS;
1004}
1005""")
1006
1007 out.write("""
1008static int
1009test_match_2(void)
1010{
Rich Lanef87f4c32014-10-14 11:56:02 -07001011""")
1012
1013 for version in of_g.of_version_range:
1014 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
1015
1016 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -07001017 of_match_t match1;
1018 of_match_t match2;
1019 int value = 1;
1020""")
1021
1022 for version in of_g.of_version_range:
1023 out.write("""
1024 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1025 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1026 TEST_ASSERT(m_v%(version)d != NULL);
1027 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1028 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1029 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1030 of_match_v%(version)d_delete(m_v%(version)d);
1031""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1032
1033 out.write("""
1034 return TEST_PASS;
1035}
1036""")
1037
1038 out.write("""
1039static int
1040test_match_3(void)
1041{
1042 of_match_t match1;
1043 of_match_t match2;
1044 int value = 1;
1045 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001046 of_object_storage_t storage;
1047 memset(&storage, 0, sizeof(storage));
1048 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001049""")
1050 for version in of_g.of_version_range:
1051 out.write("""
1052 /* Serialize to version %(v_name)s */
1053 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001054 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001055 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001056 storage.obj.wbuf->buf = octets.data;
1057 storage.obj.wbuf->alloc_bytes = octets.bytes;
1058 storage.obj.wbuf->current_bytes = octets.bytes;
1059 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001060 OF_ERROR_NONE);
1061 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1062 FREE(octets.data);
1063""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1064
1065 out.write("""
1066 return TEST_PASS;
1067}
1068""")
1069
1070 out.write("""
1071int run_match_tests(void)
1072{
1073 RUN_TEST(match_1);
1074 RUN_TEST(match_2);
1075 RUN_TEST(match_3);
1076 RUN_TEST(match_utils);
1077
1078 return TEST_PASS;
1079}
1080""")
1081
1082def gen_msg_test(out, name):
1083 loxi_utils.gen_c_copy_license(out)
1084 out.write("""
1085/**
1086 *
1087 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1088 *
1089 * Message-scalar tests for all versions
1090 */
1091
1092#include <locitest/test_common.h>
1093""")
1094 for version in of_g.of_version_range:
1095 for cls in of_g.ordered_messages:
1096 if not (cls, version) in of_g.base_length:
1097 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001098 if type_maps.class_is_virtual(cls):
1099 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -07001100 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001101 out.write("""
1102static int
1103test_%(cls)s_create_%(v_name)s(void)
1104{
1105 %(cls)s_t *obj;
1106 uint8_t *msg_buf;
1107 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001108 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001109 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001110
1111 obj = %(cls)s_new(%(v_name)s);
1112 TEST_ASSERT(obj != NULL);
1113 TEST_ASSERT(obj->version == %(v_name)s);
1114 TEST_ASSERT(obj->length == %(bytes)d);
1115 TEST_ASSERT(obj->parent == NULL);
1116 TEST_ASSERT(obj->object_id == %(enum)s);
1117
Rich Lanea4b68302014-03-12 15:17:58 -07001118 of_header_wire_object_id_get(obj, &object_id);
1119 TEST_ASSERT(object_id == %(enum)s);
1120
Rich Lanea06d0c32013-03-25 08:52:03 -07001121 /* Set up incrementing values for scalar members */
1122 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1123 TEST_ASSERT(value != 0);
1124
Rich Lanebb8f17c2014-06-12 13:14:09 -07001125 len = obj->length;
1126
Rich Lanea06d0c32013-03-25 08:52:03 -07001127 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001128 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1129 TEST_ASSERT(msg_buf != NULL);
1130 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001131 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001132
1133 TEST_ASSERT(obj != NULL);
1134
1135 /* @fixme Set up all message objects (recursively?) */
1136
1137 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1138 TEST_ASSERT(value != 0);
1139
1140 %(cls)s_delete(obj);
1141
1142 return TEST_PASS;
1143}
1144""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1145 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1146
1147 out.write("""
1148int
1149run_message_tests(void)
1150{
1151""")
1152 for version in of_g.of_version_range:
1153 for cls in of_g.ordered_messages:
1154 if not (cls, version) in of_g.base_length:
1155 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001156 if type_maps.class_is_virtual(cls):
1157 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001158 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1159 out.write(" RUN_TEST(%s);\n" % test_name)
1160
1161 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001162
Rich Lanea06d0c32013-03-25 08:52:03 -07001163
1164def gen_list_setup_check(out, cls, version):
1165 """
1166 Generate functions that populate and check a list with two
1167 of each type of subclass it supports
1168 """
1169 out.write("""
1170/**
1171 * Populate a list of type %(cls)s with two of each type of subclass
1172 * @param list Pointer to the list to be populated
1173 * @param value The seed value to use in populating the list
1174 * @returns The value after increments for this object's values
1175 */
1176int
1177%(cls)s_%(v_name)s_populate(
1178 %(cls)s_t *list, int value)
1179{
1180""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1181 base_type = loxi_utils.list_to_entry_type(cls)
1182 out.write("""
1183 %(base_type)s_t elt;
1184 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001185 (void) elt;
1186 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001187""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001188
Rich Lanea06d0c32013-03-25 08:52:03 -07001189 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001190 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 -07001191 v_name = loxi_utils.version_to_name(version)
1192
Rich Lanee98ee5d2014-10-14 10:43:44 -07001193 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001194 out.write(" /* No subclasses for %s */\n"% base_type)
1195 out.write(" %s_t *elt_p;\n" % base_type)
1196 out.write("\n elt_p = &elt;\n")
1197 else:
1198 out.write(" /* Declare pointers for each subclass */\n")
1199 for instance, subcls in sub_classes:
1200 out.write(" %s_t *%s;\n" % (subcls, instance))
1201 out.write("\n /* Instantiate pointers for each subclass */\n")
1202 for instance, subcls in sub_classes:
1203 out.write(" %s = &elt.%s;\n" % (instance, instance))
1204
Rich Lanee98ee5d2014-10-14 10:43:44 -07001205 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001206 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001207 else:
1208 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001209 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001210 out.write("""
1211 return value;
1212}
1213""")
1214 out.write("""
1215/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001216 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001217 * %(cls)s_%(v_name)s_populate
1218 * @param list Pointer to the list that was populated
1219 * @param value Starting value for checking
1220 * @returns The value after increments for this object's values
1221 */
1222int
1223%(cls)s_%(v_name)s_check(
1224 %(cls)s_t *list, int value)
1225{
1226""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1227 base_type = loxi_utils.list_to_entry_type(cls)
1228 out.write("""
1229 %(base_type)s_t elt;
1230 int count = 0;
1231 int rv;
1232""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001233
Rich Lanea06d0c32013-03-25 08:52:03 -07001234
1235 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001236 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 -07001237 v_name = loxi_utils.version_to_name(version)
1238
Rich Lanee98ee5d2014-10-14 10:43:44 -07001239 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001240 entry_count = 2
1241 out.write(" /* No subclasses for %s */\n"% base_type)
1242 out.write(" %s_t *elt_p;\n" % base_type)
1243 out.write("\n elt_p = &elt;\n")
1244 else:
1245 entry_count = 2 * len(sub_classes) # Two of each type appended
1246 out.write(" /* Declare pointers for each subclass */\n")
1247 for instance, subcls in sub_classes:
1248 out.write(" %s_t *%s;\n" % (subcls, instance))
1249 out.write("\n /* Instantiate pointers for each subclass */\n")
1250 for instance, subcls in sub_classes:
1251 out.write(" %s = &elt.%s;\n" % (instance, instance))
1252
Rich Lanee98ee5d2014-10-14 10:43:44 -07001253 if not type_maps.class_is_virtual(base_type) or sub_classes:
1254 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1255
1256 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001257 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001258 version, True)
1259 else:
1260 count = 0
1261 for instance, subcls in sub_classes:
1262 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001263 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001264 version, count==len(sub_classes))
1265 out.write("""
1266""" % dict(base_type=base_type))
1267
1268 out.write("""
1269 /* Do an iterate to test the iterator */
1270 %(u_cls)s_ITER(list, &elt, rv) {
1271 count += 1;
1272 }
1273
1274 TEST_ASSERT(rv == OF_ERROR_RANGE);
1275 TEST_ASSERT(count == %(entry_count)d);
1276
1277 /* We shoehorn a test of the dup functions here */
1278 {
1279 %(cls)s_t *dup;
1280
1281 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1282 TEST_ASSERT(dup->length == list->length);
1283 TEST_ASSERT(dup->object_id == list->object_id);
1284 TEST_ASSERT(dup->version == list->version);
1285 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1286 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1287 of_object_delete((of_object_t *)dup);
1288
1289 /* And now for the generic dup function */
1290 TEST_ASSERT((dup = (%(cls)s_t *)
1291 of_object_dup(list)) != NULL);
1292 TEST_ASSERT(dup->length == list->length);
1293 TEST_ASSERT(dup->object_id == list->object_id);
1294 TEST_ASSERT(dup->version == list->version);
1295 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1296 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1297 of_object_delete((of_object_t *)dup);
1298 }
1299
1300 return value;
1301}
1302""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1303
1304
1305def gen_class_setup_check(out, cls, version):
1306 out.write("""
1307/**
1308 * Populate all members of an object of type %(cls)s
1309 * with incrementing values
1310 * @param obj Pointer to an object to populate
1311 * @param value The seed value to use in populating the object
1312 * @returns The value after increments for this object's values
1313 */
1314
1315int
1316%(cls)s_%(v_name)s_populate(
1317 %(cls)s_t *obj, int value)
1318{
1319""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1320 members, member_types = loxi_utils.all_member_types_get(cls, version)
1321 for m_type in member_types:
1322 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1323 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001324 elif m_type in embedded_subclasses:
1325 subcls = embedded_subclasses[m_type]
1326 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001327 else:
1328 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1329 out.write("""
1330 /* Run thru accessors after new to ensure okay */
1331""")
1332 for member in members:
1333 m_type = member["m_type"]
1334 m_name = member["name"]
1335 if loxi_utils.skip_member_name(m_name):
1336 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001337 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001338 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001339 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1340 out.write("""\
1341 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1342""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1343 else:
1344 sub_cls = m_type[:-2] # Trim _t
1345 out.write("""\
1346 {
1347 %(sub_cls)s_t sub_cls;
1348
1349 /* Test bind */
1350 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1351 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001352""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001353 m_name=m_name, sub_cls=sub_cls,
1354 v_name=loxi_utils.version_to_name(version)))
1355
1356 out.write("""
1357 value = %(cls)s_%(v_name)s_populate_scalars(
1358 obj, value);
1359 TEST_ASSERT(value != 0);
1360""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1361
1362 for member in members:
1363 m_type = member["m_type"]
1364 m_name = member["name"]
1365 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1366 continue
1367 if loxi_utils.skip_member_name(m_name):
1368 continue
1369 if m_type == "of_match_t":
1370 out.write("""\
1371 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1372 TEST_ASSERT(value != 0);
1373 %(cls)s_%(m_name)s_set(
1374 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001375""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001376 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1377 elif m_type == "of_octets_t":
1378 out.write("""\
1379 value = of_octets_populate(&%(var_name)s, value);
1380 TEST_ASSERT(value != 0);
1381 %(cls)s_%(m_name)s_set(
1382 obj, &%(var_name)s);
1383 if (octets.bytes) {
1384 FREE(octets.data);
1385 }
1386""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001387 elif m_type in embedded_subclasses:
1388 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001389 out.write("""\
1390 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1391 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001392 value = %(sub_cls)s_%(v_name)s_populate(
1393 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001394 TEST_ASSERT(value != 0);
1395 %(cls)s_%(m_name)s_set(
1396 obj, %(var_name)s);
1397 %(sub_cls)s_delete(%(var_name)s);
1398""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1399 var_name=var_name_map(m_type),
1400 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001401 else:
1402 sub_cls = m_type[:-2] # Trim _t
1403 out.write("""
1404 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1405 TEST_ASSERT(%(var_name)s != NULL);
1406 value = %(sub_cls)s_%(v_name)s_populate(
1407 %(var_name)s, value);
1408 TEST_ASSERT(value != 0);
1409 %(cls)s_%(m_name)s_set(
1410 obj, %(var_name)s);
1411 %(sub_cls)s_delete(%(var_name)s);
1412""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1413 var_name=var_name_map(m_type),
1414 v_name=loxi_utils.version_to_name(version)))
1415
1416 out.write("""
1417 return value;
1418}
1419""")
1420
1421 out.write("""
1422/**
1423 * Check all members of an object of type %(cls)s
1424 * populated by the above function
1425 * @param obj Pointer to an object to check
1426 * @param value Starting value for checking
1427 * @returns The value after increments for this object's values
1428 */
1429
1430int
1431%(cls)s_%(v_name)s_check(
1432 %(cls)s_t *obj, int value)
1433{
1434""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1435 members, member_types = loxi_utils.all_member_types_get(cls, version)
1436 for m_type in member_types:
1437 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1438 continue
1439 if loxi_utils.type_is_of_object(m_type):
1440 continue
1441 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1442 out.write("""
1443 value = %(cls)s_%(v_name)s_check_scalars(
1444 obj, value);
1445 TEST_ASSERT(value != 0);
1446""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1447
1448 for member in members:
1449 m_type = member["m_type"]
1450 m_name = member["name"]
1451 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1452 continue
1453 if loxi_utils.skip_member_name(m_name):
1454 continue
1455 if m_type == "of_match_t":
1456 out.write("""\
1457 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1458 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1459""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1460 v_name=loxi_utils.version_to_name(version)))
1461 elif m_type == "of_octets_t":
1462 out.write("""\
1463 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1464 value = of_octets_check(&%(var_name)s, value);
1465""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1466 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001467 elif m_type in embedded_subclasses:
1468 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001469 out.write("""
1470 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001471 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001472
1473 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1474 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001475 value = %(sub_cls)s_%(v_name)s_check(
1476 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001477 TEST_ASSERT(value != 0);
1478 %(sub_cls)s_delete(%(m_name)s_ptr);
1479 }
1480""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1481 var_name=var_name_map(m_type),
1482 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001483 else:
1484 sub_cls = m_type[:-2] # Trim _t
1485 out.write("""
1486 { /* Use get/delete to access on check */
1487 %(m_type)s *%(m_name)s_ptr;
1488
1489 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1490 TEST_ASSERT(%(m_name)s_ptr != NULL);
1491 value = %(sub_cls)s_%(v_name)s_check(
1492 %(m_name)s_ptr, value);
1493 TEST_ASSERT(value != 0);
1494 %(sub_cls)s_delete(%(m_name)s_ptr);
1495 }
1496""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1497 var_name=var_name_map(m_type),
1498 v_name=loxi_utils.version_to_name(version)))
1499
1500 out.write("""
1501 /* We shoehorn a test of the dup functions here */
1502 {
1503 %(cls)s_t *dup;
1504
1505 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1506 TEST_ASSERT(dup->length == obj->length);
1507 TEST_ASSERT(dup->object_id == obj->object_id);
1508 TEST_ASSERT(dup->version == obj->version);
1509 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1510 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1511 of_object_delete((of_object_t *)dup);
1512
1513 /* And now for the generic dup function */
1514 TEST_ASSERT((dup = (%(cls)s_t *)
1515 of_object_dup(obj)) != NULL);
1516 TEST_ASSERT(dup->length == obj->length);
1517 TEST_ASSERT(dup->object_id == obj->object_id);
1518 TEST_ASSERT(dup->version == obj->version);
1519 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1520 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1521 of_object_delete((of_object_t *)dup);
1522 }
1523
1524 return value;
1525}
1526""" % dict(cls=cls))
1527
1528def unified_accessor_test_case(out, cls, version):
1529 """
1530 Generate one test case for the given version and class
1531 """
1532
1533 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001534 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001535 v_name = loxi_utils.version_to_name(version)
1536
1537 out.write("""
1538static int
1539test_%(cls)s_%(v_name)s(void)
1540{
1541 %(cls)s_t *obj;
1542 obj = %(cls)s_new(%(v_name)s);
1543 TEST_ASSERT(obj != NULL);
1544 TEST_ASSERT(obj->version == %(v_name)s);
1545 TEST_ASSERT(obj->length == %(length)d);
1546 TEST_ASSERT(obj->parent == NULL);
1547 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001548""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001549 v_name=v_name, length=length, version=version))
1550 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1551 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001552 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001553 int length;
1554
Rich Lanedc46fe22014-04-03 15:10:38 -07001555 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001556 TEST_ASSERT(length == %(length)d);
1557 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001558 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001559 of_object_id_t obj_id;
1560
Rich Lanedc46fe22014-04-03 15:10:38 -07001561 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001562 TEST_ASSERT(obj_id == %(u_cls)s);
1563 }
1564
1565 /* Set up incrementing values for members */
1566 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1567 obj, 1) != 0);
1568
1569 /* Check values just set */
1570 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1571 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001572""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001573 v_name=v_name, length=length, version=version))
1574
1575 out.write("""
1576 %(cls)s_delete(obj);
1577
1578 /* To do: Check memory */
1579 return TEST_PASS;
1580}
1581""" % dict(cls=cls))
1582
1583
1584def gen_unified_accessor_funs(out):
1585 for version in of_g.of_version_range:
1586 for cls in of_g.standard_class_order:
1587 if not loxi_utils.class_in_version(cls, version):
1588 continue
Rich Lane8841f352014-10-12 19:18:36 -07001589 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001590 continue
1591 elif loxi_utils.class_is_list(cls):
1592 gen_list_setup_check(out, cls, version)
1593 else:
1594 gen_class_setup_check(out, cls, version)
1595
1596def gen_unified_accessor_tests(out, name):
1597 loxi_utils.gen_c_copy_license(out)
1598 out.write("""
1599/**
1600 *
1601 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1602 *
1603 * Unified simple class instantiation tests for all versions
1604 */
1605
1606#include <locitest/test_common.h>
1607""")
1608 for version in of_g.of_version_range:
1609 for cls in of_g.standard_class_order:
1610 if not loxi_utils.class_in_version(cls, version):
1611 continue
Rich Lane8841f352014-10-12 19:18:36 -07001612 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001613 continue
1614 unified_accessor_test_case(out, cls, version)
1615
1616 out.write("""
1617int
1618run_unified_accessor_tests(void)
1619{
1620""")
1621 for version in of_g.of_version_range:
1622 v_name = loxi_utils.version_to_name(version)
1623 for cls in of_g.standard_class_order:
1624 if not loxi_utils.class_in_version(cls, version):
1625 continue
Rich Lane8841f352014-10-12 19:18:36 -07001626 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001627 continue
1628 test_name = "%s_%s" % (cls, v_name)
1629 out.write(" RUN_TEST(%s);\n" % test_name)
1630
1631 out.write(" return TEST_PASS;\n}\n");
1632
1633
1634
1635################################################################
1636#
1637# Object duplication functions
1638#
1639# These exercise the accessors to create duplicate objects.
1640# They are used in the LOCI test shim which sits in an OF
1641# protocol stream.
1642#
1643# TODO
1644# Resolve version stuff
1645# Complete list dup
1646
1647def gen_dup_list(out, cls, version):
1648 ver_name = loxi_utils.version_to_name(version)
1649 elt_type = loxi_utils.list_to_entry_type(cls)
1650 out.write("""
1651/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001652 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001653 * using accessor functions
1654 * @param src Pointer to object to be duplicated
1655 * @returns A new object of type %(cls)s.
1656 *
1657 * The caller is responsible for deleting the returned value
1658 */
1659%(cls)s_t *
1660%(cls)s_%(ver_name)s_dup(
1661 %(cls)s_t *src)
1662{
1663 %(elt_type)s_t src_elt;
1664 %(elt_type)s_t *dst_elt;
1665 int rv;
1666 %(cls)s_t *dst;
1667
1668 if ((dst = %(cls)s_new(src->version)) == NULL) {
1669 return NULL;
1670 }
1671""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1672
1673 out.write("""
1674 %(u_cls)s_ITER(src, &src_elt, rv) {
1675 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1676 of_object_delete((of_object_t *)dst);
1677 return NULL;
1678 }
1679 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1680 dst, NULL);
1681 of_object_delete((of_object_t *)dst_elt);
1682 }
1683
1684 return dst;
1685}
1686""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1687
1688
1689def gen_dup_inheritance(out, cls, version):
1690 ver_name = loxi_utils.version_to_name(version)
1691 out.write("""
1692/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001693 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001694 * @param src Pointer to object to be duplicated
1695 * @returns A new object of type %(cls)s.
1696 *
1697 * The caller is responsible for deleting the returned value
1698 */
1699%(cls)s_t *
1700%(cls)s_%(ver_name)s_dup(
1701 %(cls)s_t *src)
1702{
1703""" % dict(cls=cls, ver_name=ver_name))
1704
1705 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001706 sub_classes = type_maps.sub_class_map(cls, version)
1707 for (_, sub_cls) in sub_classes:
1708 sub_enum = sub_cls.upper()
Rich Lanea06d0c32013-03-25 08:52:03 -07001709 out.write("""
1710 if (src->header.object_id == %(sub_enum)s) {
Rich Lane10daa5b2014-10-12 11:36:50 -07001711 return (%(cls)s_t *)%(sub_cls)s_%(ver_name)s_dup(
1712 (of_object_t *)src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001713 }
1714""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1715
1716 out.write("""
1717 return NULL;
1718}
1719""")
1720
1721
1722def gen_dup_cls(out, cls, version):
1723 """
1724 Generate duplication routine for class cls
1725 """
1726 ver_name = loxi_utils.version_to_name(version)
1727
1728 out.write("""
1729/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001730 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001731 * using accessor functions
1732 * @param src Pointer to object to be duplicated
1733 * @returns A new object of type %(cls)s.
1734 *
1735 * The caller is responsible for deleting the returned value
1736 */
1737%(cls)s_t *
1738%(cls)s_%(ver_name)s_dup(
1739 %(cls)s_t *src)
1740{
1741 %(cls)s_t *dst;
1742""" % dict(cls=cls, ver_name=ver_name))
1743
1744 # Get members and types for the class
1745 members, member_types = loxi_utils.all_member_types_get(cls, version)
1746
1747 # Add declarations for each member type
1748 for m_type in member_types:
1749 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1750 # Declare instance of these
1751 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001752 elif m_type in embedded_subclasses:
1753 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001754 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001755 %(sub_cls)s_t src_%(v_name)s;
1756 %(sub_cls)s_t *dst_%(v_name)s;
1757""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001758 else:
1759 out.write("""
1760 %(m_type)s src_%(v_name)s;
1761 %(m_type)s *dst_%(v_name)s;
1762""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1763
1764 out.write("""
1765 if ((dst = %(cls)s_new(src->version)) == NULL) {
1766 return NULL;
1767 }
1768""" % dict(cls=cls))
1769
1770 for member in members:
1771 m_type = member["m_type"]
1772 m_name = member["name"]
1773 if loxi_utils.skip_member_name(m_name):
1774 continue
1775 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1776 out.write("""
1777 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1778 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1779""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1780 elif m_type in ["of_match_t", "of_octets_t"]:
1781 out.write("""
1782 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1783 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1784""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001785 elif m_type in embedded_subclasses:
1786 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001787 out.write("""
1788 %(cls)s_%(m_name)s_bind(
1789 src, &src_%(v_name)s);
1790 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1791 if (dst_%(v_name)s == NULL) {
1792 %(cls)s_delete(dst);
1793 return NULL;
1794 }
1795 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1796 %(sub_cls)s_delete(dst_%(v_name)s);
1797""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1798 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001799 else:
1800 sub_cls = m_type[:-2] # Trim _t
1801 out.write("""
1802 %(cls)s_%(m_name)s_bind(
1803 src, &src_%(v_name)s);
1804 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1805 if (dst_%(v_name)s == NULL) {
1806 %(cls)s_delete(dst);
1807 return NULL;
1808 }
1809 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1810 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001811""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001812 v_name=var_name_map(m_type), ver_name=ver_name))
1813
1814 out.write("""
1815 return dst;
1816}
1817""")
1818
1819def gen_version_dup(out=sys.stdout):
1820 """
1821 Generate duplication routines for each object type
1822 """
1823 out.write("""
1824/* Special try macro for duplicating */
1825#define _TRY_FREE(op, obj, rv) do { \\
1826 int _rv; \\
1827 if ((_rv = (op)) < 0) { \\
1828 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1829 of_object_delete((of_object_t *)(obj)); \\
1830 return (rv); \\
1831 } \\
1832 } while (0)
1833""")
1834
1835 for version in of_g.of_version_range:
1836 for cls in of_g.standard_class_order:
1837 if not loxi_utils.class_in_version(cls, version):
1838 continue
Rich Lane8841f352014-10-12 19:18:36 -07001839 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001840 gen_dup_inheritance(out, cls, version)
1841 elif loxi_utils.class_is_list(cls):
1842 gen_dup_list(out, cls, version)
1843 else:
1844 gen_dup_cls(out, cls, version)
1845
1846def gen_dup(out=sys.stdout):
1847 """
1848 Generate non-version specific duplication routines for each object type
1849 """
1850
1851 for cls in of_g.standard_class_order:
1852 out.write("""
1853%(cls)s_t *
1854%(cls)s_dup(
1855 %(cls)s_t *src)
1856{
1857""" % dict(cls=cls))
1858 for version in of_g.of_version_range:
1859 if not loxi_utils.class_in_version(cls, version):
1860 continue
Rich Lane8841f352014-10-12 19:18:36 -07001861 hdr = "header." if type_maps.class_is_inheritance_root(cls) else ""
Rich Lanea06d0c32013-03-25 08:52:03 -07001862
1863 ver_name = loxi_utils.version_to_name(version)
1864 out.write("""
1865 if (src->%(hdr)sversion == %(ver_name)s) {
1866 return %(cls)s_%(ver_name)s_dup(src);
1867 }
1868""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1869
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("""
1922extern %(cls)s_t *
1923 %(cls)s_dup(
1924 %(cls)s_t *src);
1925""" % 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("""
1933extern %(cls)s_t *
1934 %(cls)s_%(ver_name)s_dup(
1935 %(cls)s_t *src);
1936""" % 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)