blob: 41fe1220b716e8110d1ea95d49d76093221d266b [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 Lanef70be942013-07-18 13:33:14 -0700544 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
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;
776""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700777
Rich Lanea06d0c32013-03-25 08:52:03 -0700778 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700779 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 -0700780 v_name = loxi_utils.version_to_name(version)
781
782 if len(sub_classes) == 0:
783 out.write(" /* No subclasses for %s */\n"% base_type)
784 out.write(" %s_t *elt_p;\n" % base_type)
785 out.write("\n elt_p = &elt;\n")
786 else:
787 out.write(" /* Declare pointers for each subclass */\n")
788 for instance, subcls in sub_classes:
789 out.write(" %s_t *%s;\n" % (subcls, instance))
790 out.write("\n /* Instantiate pointers for each subclass */\n")
791 for instance, subcls in sub_classes:
792 out.write(" %s = &elt.%s;\n" % (instance, instance))
793
794 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700795 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700796 else:
797 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700798 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700799 out.write("""
800
801 return value;
802}
803""")
804
805def check_list_fn(out, version, cls):
806 """
807 Generate a helper function that checks a list populated by above fn
808 """
809 out.write("""
810/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700811 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700812 * list_setup_%(cls)s_%(v_name)s
813 */
814int
815list_check_%(cls)s_%(v_name)s(
816 %(cls)s_t *list, int value)
817{
818""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
819 base_type = loxi_utils.list_to_entry_type(cls)
820 out.write("""
821 %(base_type)s_t elt;
822""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700823
Rich Lanea06d0c32013-03-25 08:52:03 -0700824 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700825 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 -0700826 v_name = loxi_utils.version_to_name(version)
827
828 if len(sub_classes) == 0:
829 out.write(" /* No subclasses for %s */\n"% base_type)
830 out.write(" %s_t *elt_p;\n" % base_type)
831 out.write("\n elt_p = &elt;\n")
832 else:
833 out.write(" /* Declare pointers for each subclass */\n")
834 for instance, subcls in sub_classes:
835 out.write(" %s_t *%s;\n" % (subcls, instance))
836 out.write("\n /* Instantiate pointers for each subclass */\n")
837 for instance, subcls in sub_classes:
838 out.write(" %s = &elt.%s;\n" % (instance, instance))
839
840 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
841 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700842 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700843 else:
844 count = 0
845 for instance, subcls in sub_classes:
846 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700847 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700848 version, count==len(sub_classes))
849
850 out.write("""
851 return value;
852}
853""" % dict(base_type=base_type))
854
855def gen_list_set_check_funs(out):
856 for version in of_g.of_version_range:
857 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700858 if version in of_g.unified[cls]:
859 setup_list_fn(out, version, cls)
860 check_list_fn(out, version, cls)
861
862# Maybe: Get a map from list class to parent, mem_name of container
863
864def list_test(out, version, cls):
865 out.write("""
866static int
867test_%(cls)s_%(v_name)s(void)
868{
869""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
870 base_type = loxi_utils.list_to_entry_type(cls)
871
872 out.write(""" %(cls)s_t *list;
873 int value = 1;
874""" % dict(cls=cls, base_type=base_type))
875
876 out.write("""
877 list = %(cls)s_new(%(v_name)s);
878 TEST_ASSERT(list != NULL);
879 TEST_ASSERT(list->version == %(v_name)s);
880 TEST_ASSERT(list->length == 0);
881 TEST_ASSERT(list->parent == NULL);
882 TEST_ASSERT(list->object_id == %(enum_cls)s);
883
884 value = list_setup_%(cls)s_%(v_name)s(list, value);
885 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700886""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700887 enum_cls=loxi_utils.enum_name(cls)))
888
889 out.write("""
890 /* Now check values */
891 value = 1;
892 value = list_check_%(cls)s_%(v_name)s(list, value);
893 TEST_ASSERT(value != 0);
894""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
895
896 out.write("""
897 %(cls)s_delete(list);
898
899 return TEST_PASS;
900}
901""" % dict(cls=cls))
902
903def gen_list_test(out, name):
904 """
905 Generate base line test cases for lists
906 @param out The file handle to write to
907 """
908
909 loxi_utils.gen_c_copy_license(out)
910 out.write("""
911/**
912 *
913 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
914 *
915 * Message-scalar tests for all versions
916 */
917
918#include <locitest/test_common.h>
919""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700920
Rich Lanea06d0c32013-03-25 08:52:03 -0700921 for version in of_g.of_version_range:
922 v_name = loxi_utils.version_to_name(version)
923 out.write("""
924/**
925 * Baseline list tests for version %s
926 */
927""" % v_name)
928 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700929 if version in of_g.unified[cls]:
930 list_test(out, version, cls)
931
932 out.write("""
933int
934run_list_tests(void)
935{
936""")
937 for version in of_g.of_version_range:
938 v_name = loxi_utils.version_to_name(version)
939 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700940 if version in of_g.unified[cls]:
941 test_name = "%s_%s" % (cls, v_name)
942 out.write(" RUN_TEST(%s);\n" % test_name)
943
944 out.write("\n return TEST_PASS;\n}\n");
945
946def gen_match_test(out, name):
947 """
948 Generate baseline tests for match functions
949 """
950
951 loxi_utils.gen_c_copy_license(out)
952 out.write("""\
953/**
954 *
955 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
956 *
957 * Message-scalar tests for all versions
958 * @fixme These are mostly hard coded now.
959 */
960
961#include <locitest/test_common.h>
962
963static int
964test_match_1(void)
965{
966 of_match_v1_t *m_v1;
967 of_match_v2_t *m_v2;
968 of_match_v3_t *m_v3;
969 of_match_v4_t *m_v4;
970 of_match_t match;
971 int value = 1;
972 int idx;
973 uint32_t exp_value;
974
975 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700976 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700977 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
978 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
979 if (idx < 32) {
980 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
981 }
982 }
983""")
984
985 for version in of_g.of_version_range:
986 out.write("""
987 /* Create/populate/convert and delete for version %(v_name)s */
988 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
989 TEST_ASSERT(m_v%(version)d != NULL);
990 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
991 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
992 of_match_v%(version)d_delete(m_v%(version)d);
993""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
994
995 out.write("""
996 return TEST_PASS;
997}
998""")
999
1000 out.write("""
1001static int
1002test_match_2(void)
1003{
1004 of_match_v1_t *m_v1;
1005 of_match_v2_t *m_v2;
1006 of_match_v3_t *m_v3;
1007 of_match_v3_t *m_v4;
1008 of_match_t match1;
1009 of_match_t match2;
1010 int value = 1;
1011""")
1012
1013 for version in of_g.of_version_range:
1014 out.write("""
1015 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1016 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1017 TEST_ASSERT(m_v%(version)d != NULL);
1018 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1019 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1020 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1021 of_match_v%(version)d_delete(m_v%(version)d);
1022""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1023
1024 out.write("""
1025 return TEST_PASS;
1026}
1027""")
1028
1029 out.write("""
1030static int
1031test_match_3(void)
1032{
1033 of_match_t match1;
1034 of_match_t match2;
1035 int value = 1;
1036 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001037 of_object_storage_t storage;
1038 memset(&storage, 0, sizeof(storage));
1039 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001040""")
1041 for version in of_g.of_version_range:
1042 out.write("""
1043 /* Serialize to version %(v_name)s */
1044 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001045 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001046 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001047 storage.obj.wbuf->buf = octets.data;
1048 storage.obj.wbuf->alloc_bytes = octets.bytes;
1049 storage.obj.wbuf->current_bytes = octets.bytes;
1050 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001051 OF_ERROR_NONE);
1052 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1053 FREE(octets.data);
1054""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1055
1056 out.write("""
1057 return TEST_PASS;
1058}
1059""")
1060
1061 out.write("""
1062int run_match_tests(void)
1063{
1064 RUN_TEST(match_1);
1065 RUN_TEST(match_2);
1066 RUN_TEST(match_3);
1067 RUN_TEST(match_utils);
1068
1069 return TEST_PASS;
1070}
1071""")
1072
1073def gen_msg_test(out, name):
1074 loxi_utils.gen_c_copy_license(out)
1075 out.write("""
1076/**
1077 *
1078 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1079 *
1080 * Message-scalar tests for all versions
1081 */
1082
1083#include <locitest/test_common.h>
1084""")
1085 for version in of_g.of_version_range:
1086 for cls in of_g.ordered_messages:
1087 if not (cls, version) in of_g.base_length:
1088 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001089 if type_maps.class_is_virtual(cls):
1090 continue
Rich Lanef70be942013-07-18 13:33:14 -07001091 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001092 out.write("""
1093static int
1094test_%(cls)s_create_%(v_name)s(void)
1095{
1096 %(cls)s_t *obj;
1097 uint8_t *msg_buf;
1098 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001099 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001100 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001101
1102 obj = %(cls)s_new(%(v_name)s);
1103 TEST_ASSERT(obj != NULL);
1104 TEST_ASSERT(obj->version == %(v_name)s);
1105 TEST_ASSERT(obj->length == %(bytes)d);
1106 TEST_ASSERT(obj->parent == NULL);
1107 TEST_ASSERT(obj->object_id == %(enum)s);
1108
Rich Lanea4b68302014-03-12 15:17:58 -07001109 of_header_wire_object_id_get(obj, &object_id);
1110 TEST_ASSERT(object_id == %(enum)s);
1111
Rich Lanea06d0c32013-03-25 08:52:03 -07001112 /* Set up incrementing values for scalar members */
1113 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1114 TEST_ASSERT(value != 0);
1115
Rich Lanebb8f17c2014-06-12 13:14:09 -07001116 len = obj->length;
1117
Rich Lanea06d0c32013-03-25 08:52:03 -07001118 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001119 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1120 TEST_ASSERT(msg_buf != NULL);
1121 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001122 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001123
1124 TEST_ASSERT(obj != NULL);
1125
1126 /* @fixme Set up all message objects (recursively?) */
1127
1128 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1129 TEST_ASSERT(value != 0);
1130
1131 %(cls)s_delete(obj);
1132
1133 return TEST_PASS;
1134}
1135""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1136 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1137
1138 out.write("""
1139int
1140run_message_tests(void)
1141{
1142""")
1143 for version in of_g.of_version_range:
1144 for cls in of_g.ordered_messages:
1145 if not (cls, version) in of_g.base_length:
1146 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001147 if type_maps.class_is_virtual(cls):
1148 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001149 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1150 out.write(" RUN_TEST(%s);\n" % test_name)
1151
1152 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001153
Rich Lanea06d0c32013-03-25 08:52:03 -07001154
1155def gen_list_setup_check(out, cls, version):
1156 """
1157 Generate functions that populate and check a list with two
1158 of each type of subclass it supports
1159 """
1160 out.write("""
1161/**
1162 * Populate a list of type %(cls)s with two of each type of subclass
1163 * @param list Pointer to the list to be populated
1164 * @param value The seed value to use in populating the list
1165 * @returns The value after increments for this object's values
1166 */
1167int
1168%(cls)s_%(v_name)s_populate(
1169 %(cls)s_t *list, int value)
1170{
1171""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1172 base_type = loxi_utils.list_to_entry_type(cls)
1173 out.write("""
1174 %(base_type)s_t elt;
1175 int cur_len = 0;
1176""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001177
Rich Lanea06d0c32013-03-25 08:52:03 -07001178 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001179 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 -07001180 v_name = loxi_utils.version_to_name(version)
1181
1182 if len(sub_classes) == 0:
1183 out.write(" /* No subclasses for %s */\n"% base_type)
1184 out.write(" %s_t *elt_p;\n" % base_type)
1185 out.write("\n elt_p = &elt;\n")
1186 else:
1187 out.write(" /* Declare pointers for each subclass */\n")
1188 for instance, subcls in sub_classes:
1189 out.write(" %s_t *%s;\n" % (subcls, instance))
1190 out.write("\n /* Instantiate pointers for each subclass */\n")
1191 for instance, subcls in sub_classes:
1192 out.write(" %s = &elt.%s;\n" % (instance, instance))
1193
Rich Lanea06d0c32013-03-25 08:52:03 -07001194 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001195 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001196 else:
1197 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001198 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001199 out.write("""
1200 return value;
1201}
1202""")
1203 out.write("""
1204/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001205 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001206 * %(cls)s_%(v_name)s_populate
1207 * @param list Pointer to the list that was populated
1208 * @param value Starting value for checking
1209 * @returns The value after increments for this object's values
1210 */
1211int
1212%(cls)s_%(v_name)s_check(
1213 %(cls)s_t *list, int value)
1214{
1215""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1216 base_type = loxi_utils.list_to_entry_type(cls)
1217 out.write("""
1218 %(base_type)s_t elt;
1219 int count = 0;
1220 int rv;
1221""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001222
Rich Lanea06d0c32013-03-25 08:52:03 -07001223
1224 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001225 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 -07001226 v_name = loxi_utils.version_to_name(version)
1227
1228 if len(sub_classes) == 0:
1229 entry_count = 2
1230 out.write(" /* No subclasses for %s */\n"% base_type)
1231 out.write(" %s_t *elt_p;\n" % base_type)
1232 out.write("\n elt_p = &elt;\n")
1233 else:
1234 entry_count = 2 * len(sub_classes) # Two of each type appended
1235 out.write(" /* Declare pointers for each subclass */\n")
1236 for instance, subcls in sub_classes:
1237 out.write(" %s_t *%s;\n" % (subcls, instance))
1238 out.write("\n /* Instantiate pointers for each subclass */\n")
1239 for instance, subcls in sub_classes:
1240 out.write(" %s = &elt.%s;\n" % (instance, instance))
1241
1242 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1243 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001244 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001245 version, True)
1246 else:
1247 count = 0
1248 for instance, subcls in sub_classes:
1249 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001250 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001251 version, count==len(sub_classes))
1252 out.write("""
1253""" % dict(base_type=base_type))
1254
1255 out.write("""
1256 /* Do an iterate to test the iterator */
1257 %(u_cls)s_ITER(list, &elt, rv) {
1258 count += 1;
1259 }
1260
1261 TEST_ASSERT(rv == OF_ERROR_RANGE);
1262 TEST_ASSERT(count == %(entry_count)d);
1263
1264 /* We shoehorn a test of the dup functions here */
1265 {
1266 %(cls)s_t *dup;
1267
1268 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1269 TEST_ASSERT(dup->length == list->length);
1270 TEST_ASSERT(dup->object_id == list->object_id);
1271 TEST_ASSERT(dup->version == list->version);
1272 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1273 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1274 of_object_delete((of_object_t *)dup);
1275
1276 /* And now for the generic dup function */
1277 TEST_ASSERT((dup = (%(cls)s_t *)
1278 of_object_dup(list)) != NULL);
1279 TEST_ASSERT(dup->length == list->length);
1280 TEST_ASSERT(dup->object_id == list->object_id);
1281 TEST_ASSERT(dup->version == list->version);
1282 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1283 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1284 of_object_delete((of_object_t *)dup);
1285 }
1286
1287 return value;
1288}
1289""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1290
1291
1292def gen_class_setup_check(out, cls, version):
1293 out.write("""
1294/**
1295 * Populate all members of an object of type %(cls)s
1296 * with incrementing values
1297 * @param obj Pointer to an object to populate
1298 * @param value The seed value to use in populating the object
1299 * @returns The value after increments for this object's values
1300 */
1301
1302int
1303%(cls)s_%(v_name)s_populate(
1304 %(cls)s_t *obj, int value)
1305{
1306""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1307 members, member_types = loxi_utils.all_member_types_get(cls, version)
1308 for m_type in member_types:
1309 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1310 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001311 elif m_type in embedded_subclasses:
1312 subcls = embedded_subclasses[m_type]
1313 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001314 else:
1315 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1316 out.write("""
1317 /* Run thru accessors after new to ensure okay */
1318""")
1319 for member in members:
1320 m_type = member["m_type"]
1321 m_name = member["name"]
1322 if loxi_utils.skip_member_name(m_name):
1323 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001324 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001325 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001326 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1327 out.write("""\
1328 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1329""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1330 else:
1331 sub_cls = m_type[:-2] # Trim _t
1332 out.write("""\
1333 {
1334 %(sub_cls)s_t sub_cls;
1335
1336 /* Test bind */
1337 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1338 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001339""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001340 m_name=m_name, sub_cls=sub_cls,
1341 v_name=loxi_utils.version_to_name(version)))
1342
1343 out.write("""
1344 value = %(cls)s_%(v_name)s_populate_scalars(
1345 obj, value);
1346 TEST_ASSERT(value != 0);
1347""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1348
1349 for member in members:
1350 m_type = member["m_type"]
1351 m_name = member["name"]
1352 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1353 continue
1354 if loxi_utils.skip_member_name(m_name):
1355 continue
1356 if m_type == "of_match_t":
1357 out.write("""\
1358 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1359 TEST_ASSERT(value != 0);
1360 %(cls)s_%(m_name)s_set(
1361 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001362""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001363 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1364 elif m_type == "of_octets_t":
1365 out.write("""\
1366 value = of_octets_populate(&%(var_name)s, value);
1367 TEST_ASSERT(value != 0);
1368 %(cls)s_%(m_name)s_set(
1369 obj, &%(var_name)s);
1370 if (octets.bytes) {
1371 FREE(octets.data);
1372 }
1373""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001374 elif m_type in embedded_subclasses:
1375 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001376 out.write("""\
1377 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1378 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001379 value = %(sub_cls)s_%(v_name)s_populate(
1380 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001381 TEST_ASSERT(value != 0);
1382 %(cls)s_%(m_name)s_set(
1383 obj, %(var_name)s);
1384 %(sub_cls)s_delete(%(var_name)s);
1385""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1386 var_name=var_name_map(m_type),
1387 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001388 else:
1389 sub_cls = m_type[:-2] # Trim _t
1390 out.write("""
1391 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1392 TEST_ASSERT(%(var_name)s != NULL);
1393 value = %(sub_cls)s_%(v_name)s_populate(
1394 %(var_name)s, value);
1395 TEST_ASSERT(value != 0);
1396 %(cls)s_%(m_name)s_set(
1397 obj, %(var_name)s);
1398 %(sub_cls)s_delete(%(var_name)s);
1399""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1400 var_name=var_name_map(m_type),
1401 v_name=loxi_utils.version_to_name(version)))
1402
1403 out.write("""
1404 return value;
1405}
1406""")
1407
1408 out.write("""
1409/**
1410 * Check all members of an object of type %(cls)s
1411 * populated by the above function
1412 * @param obj Pointer to an object to check
1413 * @param value Starting value for checking
1414 * @returns The value after increments for this object's values
1415 */
1416
1417int
1418%(cls)s_%(v_name)s_check(
1419 %(cls)s_t *obj, int value)
1420{
1421""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1422 members, member_types = loxi_utils.all_member_types_get(cls, version)
1423 for m_type in member_types:
1424 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1425 continue
1426 if loxi_utils.type_is_of_object(m_type):
1427 continue
1428 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1429 out.write("""
1430 value = %(cls)s_%(v_name)s_check_scalars(
1431 obj, value);
1432 TEST_ASSERT(value != 0);
1433""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1434
1435 for member in members:
1436 m_type = member["m_type"]
1437 m_name = member["name"]
1438 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1439 continue
1440 if loxi_utils.skip_member_name(m_name):
1441 continue
1442 if m_type == "of_match_t":
1443 out.write("""\
1444 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1445 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1446""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1447 v_name=loxi_utils.version_to_name(version)))
1448 elif m_type == "of_octets_t":
1449 out.write("""\
1450 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1451 value = of_octets_check(&%(var_name)s, value);
1452""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1453 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001454 elif m_type in embedded_subclasses:
1455 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001456 out.write("""
1457 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001458 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001459
1460 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1461 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001462 value = %(sub_cls)s_%(v_name)s_check(
1463 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001464 TEST_ASSERT(value != 0);
1465 %(sub_cls)s_delete(%(m_name)s_ptr);
1466 }
1467""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1468 var_name=var_name_map(m_type),
1469 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001470 else:
1471 sub_cls = m_type[:-2] # Trim _t
1472 out.write("""
1473 { /* Use get/delete to access on check */
1474 %(m_type)s *%(m_name)s_ptr;
1475
1476 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1477 TEST_ASSERT(%(m_name)s_ptr != NULL);
1478 value = %(sub_cls)s_%(v_name)s_check(
1479 %(m_name)s_ptr, value);
1480 TEST_ASSERT(value != 0);
1481 %(sub_cls)s_delete(%(m_name)s_ptr);
1482 }
1483""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1484 var_name=var_name_map(m_type),
1485 v_name=loxi_utils.version_to_name(version)))
1486
1487 out.write("""
1488 /* We shoehorn a test of the dup functions here */
1489 {
1490 %(cls)s_t *dup;
1491
1492 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1493 TEST_ASSERT(dup->length == obj->length);
1494 TEST_ASSERT(dup->object_id == obj->object_id);
1495 TEST_ASSERT(dup->version == obj->version);
1496 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1497 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1498 of_object_delete((of_object_t *)dup);
1499
1500 /* And now for the generic dup function */
1501 TEST_ASSERT((dup = (%(cls)s_t *)
1502 of_object_dup(obj)) != NULL);
1503 TEST_ASSERT(dup->length == obj->length);
1504 TEST_ASSERT(dup->object_id == obj->object_id);
1505 TEST_ASSERT(dup->version == obj->version);
1506 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1507 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1508 of_object_delete((of_object_t *)dup);
1509 }
1510
1511 return value;
1512}
1513""" % dict(cls=cls))
1514
1515def unified_accessor_test_case(out, cls, version):
1516 """
1517 Generate one test case for the given version and class
1518 """
1519
1520 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001521 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001522 v_name = loxi_utils.version_to_name(version)
1523
1524 out.write("""
1525static int
1526test_%(cls)s_%(v_name)s(void)
1527{
1528 %(cls)s_t *obj;
1529 obj = %(cls)s_new(%(v_name)s);
1530 TEST_ASSERT(obj != NULL);
1531 TEST_ASSERT(obj->version == %(v_name)s);
1532 TEST_ASSERT(obj->length == %(length)d);
1533 TEST_ASSERT(obj->parent == NULL);
1534 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001535""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001536 v_name=v_name, length=length, version=version))
1537 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1538 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001539 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001540 int length;
1541
Rich Lanedc46fe22014-04-03 15:10:38 -07001542 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001543 TEST_ASSERT(length == %(length)d);
1544 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001545 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001546 of_object_id_t obj_id;
1547
Rich Lanedc46fe22014-04-03 15:10:38 -07001548 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001549 TEST_ASSERT(obj_id == %(u_cls)s);
1550 }
1551
1552 /* Set up incrementing values for members */
1553 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1554 obj, 1) != 0);
1555
1556 /* Check values just set */
1557 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1558 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001559""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001560 v_name=v_name, length=length, version=version))
1561
1562 out.write("""
1563 %(cls)s_delete(obj);
1564
1565 /* To do: Check memory */
1566 return TEST_PASS;
1567}
1568""" % dict(cls=cls))
1569
1570
1571def gen_unified_accessor_funs(out):
1572 for version in of_g.of_version_range:
1573 for cls in of_g.standard_class_order:
1574 if not loxi_utils.class_in_version(cls, version):
1575 continue
Rich Lane8841f352014-10-12 19:18:36 -07001576 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001577 continue
1578 elif loxi_utils.class_is_list(cls):
1579 gen_list_setup_check(out, cls, version)
1580 else:
1581 gen_class_setup_check(out, cls, version)
1582
1583def gen_unified_accessor_tests(out, name):
1584 loxi_utils.gen_c_copy_license(out)
1585 out.write("""
1586/**
1587 *
1588 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1589 *
1590 * Unified simple class instantiation tests for all versions
1591 */
1592
1593#include <locitest/test_common.h>
1594""")
1595 for version in of_g.of_version_range:
1596 for cls in of_g.standard_class_order:
1597 if not loxi_utils.class_in_version(cls, version):
1598 continue
Rich Lane8841f352014-10-12 19:18:36 -07001599 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001600 continue
1601 unified_accessor_test_case(out, cls, version)
1602
1603 out.write("""
1604int
1605run_unified_accessor_tests(void)
1606{
1607""")
1608 for version in of_g.of_version_range:
1609 v_name = loxi_utils.version_to_name(version)
1610 for cls in of_g.standard_class_order:
1611 if not loxi_utils.class_in_version(cls, version):
1612 continue
Rich Lane8841f352014-10-12 19:18:36 -07001613 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001614 continue
1615 test_name = "%s_%s" % (cls, v_name)
1616 out.write(" RUN_TEST(%s);\n" % test_name)
1617
1618 out.write(" return TEST_PASS;\n}\n");
1619
1620
1621
1622################################################################
1623#
1624# Object duplication functions
1625#
1626# These exercise the accessors to create duplicate objects.
1627# They are used in the LOCI test shim which sits in an OF
1628# protocol stream.
1629#
1630# TODO
1631# Resolve version stuff
1632# Complete list dup
1633
1634def gen_dup_list(out, cls, version):
1635 ver_name = loxi_utils.version_to_name(version)
1636 elt_type = loxi_utils.list_to_entry_type(cls)
1637 out.write("""
1638/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001639 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001640 * using accessor functions
1641 * @param src Pointer to object to be duplicated
1642 * @returns A new object of type %(cls)s.
1643 *
1644 * The caller is responsible for deleting the returned value
1645 */
1646%(cls)s_t *
1647%(cls)s_%(ver_name)s_dup(
1648 %(cls)s_t *src)
1649{
1650 %(elt_type)s_t src_elt;
1651 %(elt_type)s_t *dst_elt;
1652 int rv;
1653 %(cls)s_t *dst;
1654
1655 if ((dst = %(cls)s_new(src->version)) == NULL) {
1656 return NULL;
1657 }
1658""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1659
1660 out.write("""
1661 %(u_cls)s_ITER(src, &src_elt, rv) {
1662 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1663 of_object_delete((of_object_t *)dst);
1664 return NULL;
1665 }
1666 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1667 dst, NULL);
1668 of_object_delete((of_object_t *)dst_elt);
1669 }
1670
1671 return dst;
1672}
1673""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1674
1675
1676def gen_dup_inheritance(out, cls, version):
1677 ver_name = loxi_utils.version_to_name(version)
1678 out.write("""
1679/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001680 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001681 * @param src Pointer to object to be duplicated
1682 * @returns A new object of type %(cls)s.
1683 *
1684 * The caller is responsible for deleting the returned value
1685 */
1686%(cls)s_t *
1687%(cls)s_%(ver_name)s_dup(
1688 %(cls)s_t *src)
1689{
1690""" % dict(cls=cls, ver_name=ver_name))
1691
1692 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001693 sub_classes = type_maps.sub_class_map(cls, version)
1694 for (_, sub_cls) in sub_classes:
1695 sub_enum = sub_cls.upper()
Rich Lanea06d0c32013-03-25 08:52:03 -07001696 out.write("""
1697 if (src->header.object_id == %(sub_enum)s) {
Rich Lane10daa5b2014-10-12 11:36:50 -07001698 return (%(cls)s_t *)%(sub_cls)s_%(ver_name)s_dup(
1699 (of_object_t *)src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001700 }
1701""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1702
1703 out.write("""
1704 return NULL;
1705}
1706""")
1707
1708
1709def gen_dup_cls(out, cls, version):
1710 """
1711 Generate duplication routine for class cls
1712 """
1713 ver_name = loxi_utils.version_to_name(version)
1714
1715 out.write("""
1716/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001717 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001718 * using accessor functions
1719 * @param src Pointer to object to be duplicated
1720 * @returns A new object of type %(cls)s.
1721 *
1722 * The caller is responsible for deleting the returned value
1723 */
1724%(cls)s_t *
1725%(cls)s_%(ver_name)s_dup(
1726 %(cls)s_t *src)
1727{
1728 %(cls)s_t *dst;
1729""" % dict(cls=cls, ver_name=ver_name))
1730
1731 # Get members and types for the class
1732 members, member_types = loxi_utils.all_member_types_get(cls, version)
1733
1734 # Add declarations for each member type
1735 for m_type in member_types:
1736 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1737 # Declare instance of these
1738 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001739 elif m_type in embedded_subclasses:
1740 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001741 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001742 %(sub_cls)s_t src_%(v_name)s;
1743 %(sub_cls)s_t *dst_%(v_name)s;
1744""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001745 else:
1746 out.write("""
1747 %(m_type)s src_%(v_name)s;
1748 %(m_type)s *dst_%(v_name)s;
1749""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1750
1751 out.write("""
1752 if ((dst = %(cls)s_new(src->version)) == NULL) {
1753 return NULL;
1754 }
1755""" % dict(cls=cls))
1756
1757 for member in members:
1758 m_type = member["m_type"]
1759 m_name = member["name"]
1760 if loxi_utils.skip_member_name(m_name):
1761 continue
1762 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1763 out.write("""
1764 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1765 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1766""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1767 elif m_type in ["of_match_t", "of_octets_t"]:
1768 out.write("""
1769 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1770 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1771""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001772 elif m_type in embedded_subclasses:
1773 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001774 out.write("""
1775 %(cls)s_%(m_name)s_bind(
1776 src, &src_%(v_name)s);
1777 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1778 if (dst_%(v_name)s == NULL) {
1779 %(cls)s_delete(dst);
1780 return NULL;
1781 }
1782 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1783 %(sub_cls)s_delete(dst_%(v_name)s);
1784""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1785 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001786 else:
1787 sub_cls = m_type[:-2] # Trim _t
1788 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);
Andreas Wundsam53256162013-05-02 14:05:53 -07001798""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001799 v_name=var_name_map(m_type), ver_name=ver_name))
1800
1801 out.write("""
1802 return dst;
1803}
1804""")
1805
1806def gen_version_dup(out=sys.stdout):
1807 """
1808 Generate duplication routines for each object type
1809 """
1810 out.write("""
1811/* Special try macro for duplicating */
1812#define _TRY_FREE(op, obj, rv) do { \\
1813 int _rv; \\
1814 if ((_rv = (op)) < 0) { \\
1815 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1816 of_object_delete((of_object_t *)(obj)); \\
1817 return (rv); \\
1818 } \\
1819 } while (0)
1820""")
1821
1822 for version in of_g.of_version_range:
1823 for cls in of_g.standard_class_order:
1824 if not loxi_utils.class_in_version(cls, version):
1825 continue
Rich Lane8841f352014-10-12 19:18:36 -07001826 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001827 gen_dup_inheritance(out, cls, version)
1828 elif loxi_utils.class_is_list(cls):
1829 gen_dup_list(out, cls, version)
1830 else:
1831 gen_dup_cls(out, cls, version)
1832
1833def gen_dup(out=sys.stdout):
1834 """
1835 Generate non-version specific duplication routines for each object type
1836 """
1837
1838 for cls in of_g.standard_class_order:
1839 out.write("""
1840%(cls)s_t *
1841%(cls)s_dup(
1842 %(cls)s_t *src)
1843{
1844""" % dict(cls=cls))
1845 for version in of_g.of_version_range:
1846 if not loxi_utils.class_in_version(cls, version):
1847 continue
Rich Lane8841f352014-10-12 19:18:36 -07001848 hdr = "header." if type_maps.class_is_inheritance_root(cls) else ""
Rich Lanea06d0c32013-03-25 08:52:03 -07001849
1850 ver_name = loxi_utils.version_to_name(version)
1851 out.write("""
1852 if (src->%(hdr)sversion == %(ver_name)s) {
1853 return %(cls)s_%(ver_name)s_dup(src);
1854 }
1855""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1856
1857 out.write("""
1858 /* Class not supported in given version */
1859 return NULL;
1860}
1861""")
1862
1863def dup_c_gen(out, name):
1864 """
1865 Generate the C file for duplication functions
1866 """
1867 loxi_utils.gen_c_copy_license(out)
1868 out.write("""\
1869/*
1870 * Duplication functions for all OF objects
1871 *
1872 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1873 *
1874 * These are test functions for exercising accessors. You can call
1875 * of_object_dup for an efficient duplication.
1876 */
1877
1878#define DISABLE_WARN_UNUSED_RESULT
1879#include "loci_log.h"
1880#include <locitest/of_dup.h>
1881
1882""")
1883
1884 gen_version_dup(out)
1885 gen_dup(out)
1886
1887
1888def dup_h_gen(out, name):
1889 """
1890 Generate the header file for duplication functions
1891 """
1892
1893 loxi_utils.gen_c_copy_license(out)
1894 out.write("""
1895/*
1896 * Duplication function header file
1897 *
1898 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1899 */
1900
1901#if !defined(_OF_DUP_H_)
1902#define _OF_DUP_H_
1903
1904#include <loci/loci.h>
1905""")
1906
1907 for cls in of_g.standard_class_order:
1908 out.write("""
1909extern %(cls)s_t *
1910 %(cls)s_dup(
1911 %(cls)s_t *src);
1912""" % dict(cls=cls))
1913
1914 for version in of_g.of_version_range:
1915 for cls in of_g.standard_class_order:
1916 if not loxi_utils.class_in_version(cls, version):
1917 continue
1918 ver_name = loxi_utils.version_to_name(version)
1919 out.write("""
1920extern %(cls)s_t *
1921 %(cls)s_%(ver_name)s_dup(
1922 %(cls)s_t *src);
1923""" % dict(cls=cls, ver_name=ver_name))
1924
1925 out.write("\n#endif /* _OF_DUP_H_ */\n")
1926
1927def gen_log_test(out):
1928 """
1929 Generate test for obj log calls
1930
1931 Define a trivial handler for object logging; call all obj log fns
1932 """
1933 out.write("""
1934
1935/**
1936 * Test object dump functions
1937 */
1938
1939int
1940test_dump_objs(void)
1941{
1942 of_object_t *obj;
1943
1944 FILE *out = fopen("/dev/null", "w");
1945
1946 /* Call each obj dump function */
1947""")
1948 for version in of_g.of_version_range:
1949 for j, cls in enumerate(of_g.all_class_order):
1950 if not loxi_utils.class_in_version(cls, version):
1951 continue
Rich Lane8841f352014-10-12 19:18:36 -07001952 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001953 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001954 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1955 out.write("""
1956 obj = (of_object_t *)%(cls)s_new(%(version)s);
1957 {
1958 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1959 %(cls)s_vport_set(obj, vport);
1960 of_object_delete(vport);
1961 }
1962 of_object_dump((loci_writer_f)fprintf, out, obj);
1963 of_object_delete(obj);
1964""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1965 else:
1966 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001967 obj = (of_object_t *)%(cls)s_new(%(version)s);
1968 of_object_dump((loci_writer_f)fprintf, out, obj);
1969 of_object_delete(obj);
1970""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001971
Rich Lanea06d0c32013-03-25 08:52:03 -07001972 out.write("""
1973 fclose(out);
1974 return TEST_PASS;
1975}
1976""")
1977
1978def gen_ident_tests(out):
1979 """
1980 Generate tests for identifiers
1981
1982 For all idents, instantiate, test version supported macros
1983 For flags, set it, test it, clear it, test it.
1984 """
1985 out.write("""
1986/**
1987 * Test cases for all flag accessor macros
1988 * These only test self consistency (and that they compile)
1989 */
1990int
1991test_ident_macros(void)
1992{
1993 int value __attribute__((unused));
1994 uint32_t flags;
1995
1996""")
1997
1998 for ident, info in of_g.identifiers.items():
1999 if not identifiers.defined_versions_agree(of_g.identifiers,
2000 of_g.target_version_list,
2001 ident):
2002 # @fixme
2003 continue
2004 out.write(" value = %s;\n" % ident)
2005 for version in of_g.target_version_list:
2006 if version in info["values_by_version"].keys():
2007 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2008 (ident, of_g.of_version_wire2name[version]))
2009 else:
2010 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2011 (ident, of_g.of_version_wire2name[version]))
2012 if flags.ident_is_flag(ident):
2013 # Grab first supported version
2014 for version in info["values_by_version"]:
2015 break
2016 out.write("""
2017 flags = 0;
2018 %(ident)s_SET(flags, %(ver_name)s);
2019 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2020 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2021 %(ident)s_CLEAR(flags, %(ver_name)s);
2022 TEST_ASSERT(flags == 0);
2023 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2024""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2025
2026 out.write("""
2027 return TEST_PASS;
2028}
2029""")
2030
Rich Laneccae0312013-07-21 23:34:13 -07002031def gen_datafiles_tests(out, name):
2032 tests = []
2033 for filename in test_data.list_files():
2034 data = test_data.read(filename)
2035 if not 'c' in data:
2036 continue
2037 name = filename[:-5].replace("/", "_")
2038 tests.append(dict(name=name,
2039 filename=filename,
2040 c=data['c'],
2041 binary=data['binary']))
2042
2043 util.render_template(out, "test_data.c", tests=tests)