blob: 74db717d18b71bab6b846570fe94cfb9feb2b749 [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;
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{
971 of_match_v1_t *m_v1;
972 of_match_v2_t *m_v2;
973 of_match_v3_t *m_v3;
974 of_match_v4_t *m_v4;
975 of_match_t match;
976 int value = 1;
977 int idx;
978 uint32_t exp_value;
979
980 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700981 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700982 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
983 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
984 if (idx < 32) {
985 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
986 }
987 }
988""")
989
990 for version in of_g.of_version_range:
991 out.write("""
992 /* Create/populate/convert and delete for version %(v_name)s */
993 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
994 TEST_ASSERT(m_v%(version)d != NULL);
995 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
996 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
997 of_match_v%(version)d_delete(m_v%(version)d);
998""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
999
1000 out.write("""
1001 return TEST_PASS;
1002}
1003""")
1004
1005 out.write("""
1006static int
1007test_match_2(void)
1008{
1009 of_match_v1_t *m_v1;
1010 of_match_v2_t *m_v2;
1011 of_match_v3_t *m_v3;
1012 of_match_v3_t *m_v4;
1013 of_match_t match1;
1014 of_match_t match2;
1015 int value = 1;
1016""")
1017
1018 for version in of_g.of_version_range:
1019 out.write("""
1020 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1021 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1022 TEST_ASSERT(m_v%(version)d != NULL);
1023 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1024 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1025 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1026 of_match_v%(version)d_delete(m_v%(version)d);
1027""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1028
1029 out.write("""
1030 return TEST_PASS;
1031}
1032""")
1033
1034 out.write("""
1035static int
1036test_match_3(void)
1037{
1038 of_match_t match1;
1039 of_match_t match2;
1040 int value = 1;
1041 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001042 of_object_storage_t storage;
1043 memset(&storage, 0, sizeof(storage));
1044 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001045""")
1046 for version in of_g.of_version_range:
1047 out.write("""
1048 /* Serialize to version %(v_name)s */
1049 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001050 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001051 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001052 storage.obj.wbuf->buf = octets.data;
1053 storage.obj.wbuf->alloc_bytes = octets.bytes;
1054 storage.obj.wbuf->current_bytes = octets.bytes;
1055 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001056 OF_ERROR_NONE);
1057 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1058 FREE(octets.data);
1059""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1060
1061 out.write("""
1062 return TEST_PASS;
1063}
1064""")
1065
1066 out.write("""
1067int run_match_tests(void)
1068{
1069 RUN_TEST(match_1);
1070 RUN_TEST(match_2);
1071 RUN_TEST(match_3);
1072 RUN_TEST(match_utils);
1073
1074 return TEST_PASS;
1075}
1076""")
1077
1078def gen_msg_test(out, name):
1079 loxi_utils.gen_c_copy_license(out)
1080 out.write("""
1081/**
1082 *
1083 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1084 *
1085 * Message-scalar tests for all versions
1086 */
1087
1088#include <locitest/test_common.h>
1089""")
1090 for version in of_g.of_version_range:
1091 for cls in of_g.ordered_messages:
1092 if not (cls, version) in of_g.base_length:
1093 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001094 if type_maps.class_is_virtual(cls):
1095 continue
Rich Lanef70be942013-07-18 13:33:14 -07001096 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001097 out.write("""
1098static int
1099test_%(cls)s_create_%(v_name)s(void)
1100{
1101 %(cls)s_t *obj;
1102 uint8_t *msg_buf;
1103 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001104 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001105 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001106
1107 obj = %(cls)s_new(%(v_name)s);
1108 TEST_ASSERT(obj != NULL);
1109 TEST_ASSERT(obj->version == %(v_name)s);
1110 TEST_ASSERT(obj->length == %(bytes)d);
1111 TEST_ASSERT(obj->parent == NULL);
1112 TEST_ASSERT(obj->object_id == %(enum)s);
1113
Rich Lanea4b68302014-03-12 15:17:58 -07001114 of_header_wire_object_id_get(obj, &object_id);
1115 TEST_ASSERT(object_id == %(enum)s);
1116
Rich Lanea06d0c32013-03-25 08:52:03 -07001117 /* Set up incrementing values for scalar members */
1118 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1119 TEST_ASSERT(value != 0);
1120
Rich Lanebb8f17c2014-06-12 13:14:09 -07001121 len = obj->length;
1122
Rich Lanea06d0c32013-03-25 08:52:03 -07001123 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001124 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1125 TEST_ASSERT(msg_buf != NULL);
1126 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001127 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001128
1129 TEST_ASSERT(obj != NULL);
1130
1131 /* @fixme Set up all message objects (recursively?) */
1132
1133 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1134 TEST_ASSERT(value != 0);
1135
1136 %(cls)s_delete(obj);
1137
1138 return TEST_PASS;
1139}
1140""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1141 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1142
1143 out.write("""
1144int
1145run_message_tests(void)
1146{
1147""")
1148 for version in of_g.of_version_range:
1149 for cls in of_g.ordered_messages:
1150 if not (cls, version) in of_g.base_length:
1151 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001152 if type_maps.class_is_virtual(cls):
1153 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001154 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1155 out.write(" RUN_TEST(%s);\n" % test_name)
1156
1157 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001158
Rich Lanea06d0c32013-03-25 08:52:03 -07001159
1160def gen_list_setup_check(out, cls, version):
1161 """
1162 Generate functions that populate and check a list with two
1163 of each type of subclass it supports
1164 """
1165 out.write("""
1166/**
1167 * Populate a list of type %(cls)s with two of each type of subclass
1168 * @param list Pointer to the list to be populated
1169 * @param value The seed value to use in populating the list
1170 * @returns The value after increments for this object's values
1171 */
1172int
1173%(cls)s_%(v_name)s_populate(
1174 %(cls)s_t *list, int value)
1175{
1176""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1177 base_type = loxi_utils.list_to_entry_type(cls)
1178 out.write("""
1179 %(base_type)s_t elt;
1180 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001181 (void) elt;
1182 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001183""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001184
Rich Lanea06d0c32013-03-25 08:52:03 -07001185 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001186 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 -07001187 v_name = loxi_utils.version_to_name(version)
1188
Rich Lanee98ee5d2014-10-14 10:43:44 -07001189 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001190 out.write(" /* No subclasses for %s */\n"% base_type)
1191 out.write(" %s_t *elt_p;\n" % base_type)
1192 out.write("\n elt_p = &elt;\n")
1193 else:
1194 out.write(" /* Declare pointers for each subclass */\n")
1195 for instance, subcls in sub_classes:
1196 out.write(" %s_t *%s;\n" % (subcls, instance))
1197 out.write("\n /* Instantiate pointers for each subclass */\n")
1198 for instance, subcls in sub_classes:
1199 out.write(" %s = &elt.%s;\n" % (instance, instance))
1200
Rich Lanee98ee5d2014-10-14 10:43:44 -07001201 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001202 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001203 else:
1204 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001205 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001206 out.write("""
1207 return value;
1208}
1209""")
1210 out.write("""
1211/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001212 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001213 * %(cls)s_%(v_name)s_populate
1214 * @param list Pointer to the list that was populated
1215 * @param value Starting value for checking
1216 * @returns The value after increments for this object's values
1217 */
1218int
1219%(cls)s_%(v_name)s_check(
1220 %(cls)s_t *list, int value)
1221{
1222""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1223 base_type = loxi_utils.list_to_entry_type(cls)
1224 out.write("""
1225 %(base_type)s_t elt;
1226 int count = 0;
1227 int rv;
1228""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001229
Rich Lanea06d0c32013-03-25 08:52:03 -07001230
1231 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001232 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 -07001233 v_name = loxi_utils.version_to_name(version)
1234
Rich Lanee98ee5d2014-10-14 10:43:44 -07001235 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001236 entry_count = 2
1237 out.write(" /* No subclasses for %s */\n"% base_type)
1238 out.write(" %s_t *elt_p;\n" % base_type)
1239 out.write("\n elt_p = &elt;\n")
1240 else:
1241 entry_count = 2 * len(sub_classes) # Two of each type appended
1242 out.write(" /* Declare pointers for each subclass */\n")
1243 for instance, subcls in sub_classes:
1244 out.write(" %s_t *%s;\n" % (subcls, instance))
1245 out.write("\n /* Instantiate pointers for each subclass */\n")
1246 for instance, subcls in sub_classes:
1247 out.write(" %s = &elt.%s;\n" % (instance, instance))
1248
Rich Lanee98ee5d2014-10-14 10:43:44 -07001249 if not type_maps.class_is_virtual(base_type) or sub_classes:
1250 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1251
1252 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001253 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001254 version, True)
1255 else:
1256 count = 0
1257 for instance, subcls in sub_classes:
1258 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001259 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001260 version, count==len(sub_classes))
1261 out.write("""
1262""" % dict(base_type=base_type))
1263
1264 out.write("""
1265 /* Do an iterate to test the iterator */
1266 %(u_cls)s_ITER(list, &elt, rv) {
1267 count += 1;
1268 }
1269
1270 TEST_ASSERT(rv == OF_ERROR_RANGE);
1271 TEST_ASSERT(count == %(entry_count)d);
1272
1273 /* We shoehorn a test of the dup functions here */
1274 {
1275 %(cls)s_t *dup;
1276
1277 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1278 TEST_ASSERT(dup->length == list->length);
1279 TEST_ASSERT(dup->object_id == list->object_id);
1280 TEST_ASSERT(dup->version == list->version);
1281 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1282 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1283 of_object_delete((of_object_t *)dup);
1284
1285 /* And now for the generic dup function */
1286 TEST_ASSERT((dup = (%(cls)s_t *)
1287 of_object_dup(list)) != NULL);
1288 TEST_ASSERT(dup->length == list->length);
1289 TEST_ASSERT(dup->object_id == list->object_id);
1290 TEST_ASSERT(dup->version == list->version);
1291 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1292 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1293 of_object_delete((of_object_t *)dup);
1294 }
1295
1296 return value;
1297}
1298""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1299
1300
1301def gen_class_setup_check(out, cls, version):
1302 out.write("""
1303/**
1304 * Populate all members of an object of type %(cls)s
1305 * with incrementing values
1306 * @param obj Pointer to an object to populate
1307 * @param value The seed value to use in populating the object
1308 * @returns The value after increments for this object's values
1309 */
1310
1311int
1312%(cls)s_%(v_name)s_populate(
1313 %(cls)s_t *obj, int value)
1314{
1315""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1316 members, member_types = loxi_utils.all_member_types_get(cls, version)
1317 for m_type in member_types:
1318 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1319 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001320 elif m_type in embedded_subclasses:
1321 subcls = embedded_subclasses[m_type]
1322 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001323 else:
1324 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1325 out.write("""
1326 /* Run thru accessors after new to ensure okay */
1327""")
1328 for member in members:
1329 m_type = member["m_type"]
1330 m_name = member["name"]
1331 if loxi_utils.skip_member_name(m_name):
1332 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001333 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001334 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001335 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1336 out.write("""\
1337 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1338""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1339 else:
1340 sub_cls = m_type[:-2] # Trim _t
1341 out.write("""\
1342 {
1343 %(sub_cls)s_t sub_cls;
1344
1345 /* Test bind */
1346 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1347 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001348""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001349 m_name=m_name, sub_cls=sub_cls,
1350 v_name=loxi_utils.version_to_name(version)))
1351
1352 out.write("""
1353 value = %(cls)s_%(v_name)s_populate_scalars(
1354 obj, value);
1355 TEST_ASSERT(value != 0);
1356""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1357
1358 for member in members:
1359 m_type = member["m_type"]
1360 m_name = member["name"]
1361 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1362 continue
1363 if loxi_utils.skip_member_name(m_name):
1364 continue
1365 if m_type == "of_match_t":
1366 out.write("""\
1367 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1368 TEST_ASSERT(value != 0);
1369 %(cls)s_%(m_name)s_set(
1370 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001371""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001372 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1373 elif m_type == "of_octets_t":
1374 out.write("""\
1375 value = of_octets_populate(&%(var_name)s, value);
1376 TEST_ASSERT(value != 0);
1377 %(cls)s_%(m_name)s_set(
1378 obj, &%(var_name)s);
1379 if (octets.bytes) {
1380 FREE(octets.data);
1381 }
1382""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001383 elif m_type in embedded_subclasses:
1384 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001385 out.write("""\
1386 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1387 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001388 value = %(sub_cls)s_%(v_name)s_populate(
1389 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001390 TEST_ASSERT(value != 0);
1391 %(cls)s_%(m_name)s_set(
1392 obj, %(var_name)s);
1393 %(sub_cls)s_delete(%(var_name)s);
1394""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1395 var_name=var_name_map(m_type),
1396 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001397 else:
1398 sub_cls = m_type[:-2] # Trim _t
1399 out.write("""
1400 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1401 TEST_ASSERT(%(var_name)s != NULL);
1402 value = %(sub_cls)s_%(v_name)s_populate(
1403 %(var_name)s, value);
1404 TEST_ASSERT(value != 0);
1405 %(cls)s_%(m_name)s_set(
1406 obj, %(var_name)s);
1407 %(sub_cls)s_delete(%(var_name)s);
1408""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1409 var_name=var_name_map(m_type),
1410 v_name=loxi_utils.version_to_name(version)))
1411
1412 out.write("""
1413 return value;
1414}
1415""")
1416
1417 out.write("""
1418/**
1419 * Check all members of an object of type %(cls)s
1420 * populated by the above function
1421 * @param obj Pointer to an object to check
1422 * @param value Starting value for checking
1423 * @returns The value after increments for this object's values
1424 */
1425
1426int
1427%(cls)s_%(v_name)s_check(
1428 %(cls)s_t *obj, int value)
1429{
1430""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1431 members, member_types = loxi_utils.all_member_types_get(cls, version)
1432 for m_type in member_types:
1433 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1434 continue
1435 if loxi_utils.type_is_of_object(m_type):
1436 continue
1437 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1438 out.write("""
1439 value = %(cls)s_%(v_name)s_check_scalars(
1440 obj, value);
1441 TEST_ASSERT(value != 0);
1442""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1443
1444 for member in members:
1445 m_type = member["m_type"]
1446 m_name = member["name"]
1447 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1448 continue
1449 if loxi_utils.skip_member_name(m_name):
1450 continue
1451 if m_type == "of_match_t":
1452 out.write("""\
1453 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1454 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1455""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1456 v_name=loxi_utils.version_to_name(version)))
1457 elif m_type == "of_octets_t":
1458 out.write("""\
1459 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1460 value = of_octets_check(&%(var_name)s, value);
1461""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1462 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001463 elif m_type in embedded_subclasses:
1464 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001465 out.write("""
1466 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001467 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001468
1469 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1470 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001471 value = %(sub_cls)s_%(v_name)s_check(
1472 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001473 TEST_ASSERT(value != 0);
1474 %(sub_cls)s_delete(%(m_name)s_ptr);
1475 }
1476""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1477 var_name=var_name_map(m_type),
1478 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001479 else:
1480 sub_cls = m_type[:-2] # Trim _t
1481 out.write("""
1482 { /* Use get/delete to access on check */
1483 %(m_type)s *%(m_name)s_ptr;
1484
1485 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1486 TEST_ASSERT(%(m_name)s_ptr != NULL);
1487 value = %(sub_cls)s_%(v_name)s_check(
1488 %(m_name)s_ptr, value);
1489 TEST_ASSERT(value != 0);
1490 %(sub_cls)s_delete(%(m_name)s_ptr);
1491 }
1492""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1493 var_name=var_name_map(m_type),
1494 v_name=loxi_utils.version_to_name(version)))
1495
1496 out.write("""
1497 /* We shoehorn a test of the dup functions here */
1498 {
1499 %(cls)s_t *dup;
1500
1501 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1502 TEST_ASSERT(dup->length == obj->length);
1503 TEST_ASSERT(dup->object_id == obj->object_id);
1504 TEST_ASSERT(dup->version == obj->version);
1505 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1506 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1507 of_object_delete((of_object_t *)dup);
1508
1509 /* And now for the generic dup function */
1510 TEST_ASSERT((dup = (%(cls)s_t *)
1511 of_object_dup(obj)) != NULL);
1512 TEST_ASSERT(dup->length == obj->length);
1513 TEST_ASSERT(dup->object_id == obj->object_id);
1514 TEST_ASSERT(dup->version == obj->version);
1515 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1516 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1517 of_object_delete((of_object_t *)dup);
1518 }
1519
1520 return value;
1521}
1522""" % dict(cls=cls))
1523
1524def unified_accessor_test_case(out, cls, version):
1525 """
1526 Generate one test case for the given version and class
1527 """
1528
1529 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001530 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001531 v_name = loxi_utils.version_to_name(version)
1532
1533 out.write("""
1534static int
1535test_%(cls)s_%(v_name)s(void)
1536{
1537 %(cls)s_t *obj;
1538 obj = %(cls)s_new(%(v_name)s);
1539 TEST_ASSERT(obj != NULL);
1540 TEST_ASSERT(obj->version == %(v_name)s);
1541 TEST_ASSERT(obj->length == %(length)d);
1542 TEST_ASSERT(obj->parent == NULL);
1543 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001544""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001545 v_name=v_name, length=length, version=version))
1546 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1547 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001548 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001549 int length;
1550
Rich Lanedc46fe22014-04-03 15:10:38 -07001551 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001552 TEST_ASSERT(length == %(length)d);
1553 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001554 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001555 of_object_id_t obj_id;
1556
Rich Lanedc46fe22014-04-03 15:10:38 -07001557 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001558 TEST_ASSERT(obj_id == %(u_cls)s);
1559 }
1560
1561 /* Set up incrementing values for members */
1562 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1563 obj, 1) != 0);
1564
1565 /* Check values just set */
1566 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1567 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001568""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001569 v_name=v_name, length=length, version=version))
1570
1571 out.write("""
1572 %(cls)s_delete(obj);
1573
1574 /* To do: Check memory */
1575 return TEST_PASS;
1576}
1577""" % dict(cls=cls))
1578
1579
1580def gen_unified_accessor_funs(out):
1581 for version in of_g.of_version_range:
1582 for cls in of_g.standard_class_order:
1583 if not loxi_utils.class_in_version(cls, version):
1584 continue
Rich Lane8841f352014-10-12 19:18:36 -07001585 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001586 continue
1587 elif loxi_utils.class_is_list(cls):
1588 gen_list_setup_check(out, cls, version)
1589 else:
1590 gen_class_setup_check(out, cls, version)
1591
1592def gen_unified_accessor_tests(out, name):
1593 loxi_utils.gen_c_copy_license(out)
1594 out.write("""
1595/**
1596 *
1597 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1598 *
1599 * Unified simple class instantiation tests for all versions
1600 */
1601
1602#include <locitest/test_common.h>
1603""")
1604 for version in of_g.of_version_range:
1605 for cls in of_g.standard_class_order:
1606 if not loxi_utils.class_in_version(cls, version):
1607 continue
Rich Lane8841f352014-10-12 19:18:36 -07001608 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001609 continue
1610 unified_accessor_test_case(out, cls, version)
1611
1612 out.write("""
1613int
1614run_unified_accessor_tests(void)
1615{
1616""")
1617 for version in of_g.of_version_range:
1618 v_name = loxi_utils.version_to_name(version)
1619 for cls in of_g.standard_class_order:
1620 if not loxi_utils.class_in_version(cls, version):
1621 continue
Rich Lane8841f352014-10-12 19:18:36 -07001622 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001623 continue
1624 test_name = "%s_%s" % (cls, v_name)
1625 out.write(" RUN_TEST(%s);\n" % test_name)
1626
1627 out.write(" return TEST_PASS;\n}\n");
1628
1629
1630
1631################################################################
1632#
1633# Object duplication functions
1634#
1635# These exercise the accessors to create duplicate objects.
1636# They are used in the LOCI test shim which sits in an OF
1637# protocol stream.
1638#
1639# TODO
1640# Resolve version stuff
1641# Complete list dup
1642
1643def gen_dup_list(out, cls, version):
1644 ver_name = loxi_utils.version_to_name(version)
1645 elt_type = loxi_utils.list_to_entry_type(cls)
1646 out.write("""
1647/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001648 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001649 * using accessor functions
1650 * @param src Pointer to object to be duplicated
1651 * @returns A new object of type %(cls)s.
1652 *
1653 * The caller is responsible for deleting the returned value
1654 */
1655%(cls)s_t *
1656%(cls)s_%(ver_name)s_dup(
1657 %(cls)s_t *src)
1658{
1659 %(elt_type)s_t src_elt;
1660 %(elt_type)s_t *dst_elt;
1661 int rv;
1662 %(cls)s_t *dst;
1663
1664 if ((dst = %(cls)s_new(src->version)) == NULL) {
1665 return NULL;
1666 }
1667""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1668
1669 out.write("""
1670 %(u_cls)s_ITER(src, &src_elt, rv) {
1671 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1672 of_object_delete((of_object_t *)dst);
1673 return NULL;
1674 }
1675 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1676 dst, NULL);
1677 of_object_delete((of_object_t *)dst_elt);
1678 }
1679
1680 return dst;
1681}
1682""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1683
1684
1685def gen_dup_inheritance(out, cls, version):
1686 ver_name = loxi_utils.version_to_name(version)
1687 out.write("""
1688/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001689 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001690 * @param src Pointer to object to be duplicated
1691 * @returns A new object of type %(cls)s.
1692 *
1693 * The caller is responsible for deleting the returned value
1694 */
1695%(cls)s_t *
1696%(cls)s_%(ver_name)s_dup(
1697 %(cls)s_t *src)
1698{
1699""" % dict(cls=cls, ver_name=ver_name))
1700
1701 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001702 sub_classes = type_maps.sub_class_map(cls, version)
1703 for (_, sub_cls) in sub_classes:
1704 sub_enum = sub_cls.upper()
Rich Lanea06d0c32013-03-25 08:52:03 -07001705 out.write("""
1706 if (src->header.object_id == %(sub_enum)s) {
Rich Lane10daa5b2014-10-12 11:36:50 -07001707 return (%(cls)s_t *)%(sub_cls)s_%(ver_name)s_dup(
1708 (of_object_t *)src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001709 }
1710""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1711
1712 out.write("""
1713 return NULL;
1714}
1715""")
1716
1717
1718def gen_dup_cls(out, cls, version):
1719 """
1720 Generate duplication routine for class cls
1721 """
1722 ver_name = loxi_utils.version_to_name(version)
1723
1724 out.write("""
1725/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001726 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001727 * using accessor functions
1728 * @param src Pointer to object to be duplicated
1729 * @returns A new object of type %(cls)s.
1730 *
1731 * The caller is responsible for deleting the returned value
1732 */
1733%(cls)s_t *
1734%(cls)s_%(ver_name)s_dup(
1735 %(cls)s_t *src)
1736{
1737 %(cls)s_t *dst;
1738""" % dict(cls=cls, ver_name=ver_name))
1739
1740 # Get members and types for the class
1741 members, member_types = loxi_utils.all_member_types_get(cls, version)
1742
1743 # Add declarations for each member type
1744 for m_type in member_types:
1745 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1746 # Declare instance of these
1747 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001748 elif m_type in embedded_subclasses:
1749 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001750 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001751 %(sub_cls)s_t src_%(v_name)s;
1752 %(sub_cls)s_t *dst_%(v_name)s;
1753""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001754 else:
1755 out.write("""
1756 %(m_type)s src_%(v_name)s;
1757 %(m_type)s *dst_%(v_name)s;
1758""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1759
1760 out.write("""
1761 if ((dst = %(cls)s_new(src->version)) == NULL) {
1762 return NULL;
1763 }
1764""" % dict(cls=cls))
1765
1766 for member in members:
1767 m_type = member["m_type"]
1768 m_name = member["name"]
1769 if loxi_utils.skip_member_name(m_name):
1770 continue
1771 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1772 out.write("""
1773 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1774 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1775""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1776 elif m_type in ["of_match_t", "of_octets_t"]:
1777 out.write("""
1778 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1779 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1780""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001781 elif m_type in embedded_subclasses:
1782 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001783 out.write("""
1784 %(cls)s_%(m_name)s_bind(
1785 src, &src_%(v_name)s);
1786 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1787 if (dst_%(v_name)s == NULL) {
1788 %(cls)s_delete(dst);
1789 return NULL;
1790 }
1791 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1792 %(sub_cls)s_delete(dst_%(v_name)s);
1793""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1794 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001795 else:
1796 sub_cls = m_type[:-2] # Trim _t
1797 out.write("""
1798 %(cls)s_%(m_name)s_bind(
1799 src, &src_%(v_name)s);
1800 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1801 if (dst_%(v_name)s == NULL) {
1802 %(cls)s_delete(dst);
1803 return NULL;
1804 }
1805 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1806 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001807""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001808 v_name=var_name_map(m_type), ver_name=ver_name))
1809
1810 out.write("""
1811 return dst;
1812}
1813""")
1814
1815def gen_version_dup(out=sys.stdout):
1816 """
1817 Generate duplication routines for each object type
1818 """
1819 out.write("""
1820/* Special try macro for duplicating */
1821#define _TRY_FREE(op, obj, rv) do { \\
1822 int _rv; \\
1823 if ((_rv = (op)) < 0) { \\
1824 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1825 of_object_delete((of_object_t *)(obj)); \\
1826 return (rv); \\
1827 } \\
1828 } while (0)
1829""")
1830
1831 for version in of_g.of_version_range:
1832 for cls in of_g.standard_class_order:
1833 if not loxi_utils.class_in_version(cls, version):
1834 continue
Rich Lane8841f352014-10-12 19:18:36 -07001835 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001836 gen_dup_inheritance(out, cls, version)
1837 elif loxi_utils.class_is_list(cls):
1838 gen_dup_list(out, cls, version)
1839 else:
1840 gen_dup_cls(out, cls, version)
1841
1842def gen_dup(out=sys.stdout):
1843 """
1844 Generate non-version specific duplication routines for each object type
1845 """
1846
1847 for cls in of_g.standard_class_order:
1848 out.write("""
1849%(cls)s_t *
1850%(cls)s_dup(
1851 %(cls)s_t *src)
1852{
1853""" % dict(cls=cls))
1854 for version in of_g.of_version_range:
1855 if not loxi_utils.class_in_version(cls, version):
1856 continue
Rich Lane8841f352014-10-12 19:18:36 -07001857 hdr = "header." if type_maps.class_is_inheritance_root(cls) else ""
Rich Lanea06d0c32013-03-25 08:52:03 -07001858
1859 ver_name = loxi_utils.version_to_name(version)
1860 out.write("""
1861 if (src->%(hdr)sversion == %(ver_name)s) {
1862 return %(cls)s_%(ver_name)s_dup(src);
1863 }
1864""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1865
1866 out.write("""
1867 /* Class not supported in given version */
1868 return NULL;
1869}
1870""")
1871
1872def dup_c_gen(out, name):
1873 """
1874 Generate the C file for duplication functions
1875 """
1876 loxi_utils.gen_c_copy_license(out)
1877 out.write("""\
1878/*
1879 * Duplication functions for all OF objects
1880 *
1881 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1882 *
1883 * These are test functions for exercising accessors. You can call
1884 * of_object_dup for an efficient duplication.
1885 */
1886
1887#define DISABLE_WARN_UNUSED_RESULT
1888#include "loci_log.h"
1889#include <locitest/of_dup.h>
1890
1891""")
1892
1893 gen_version_dup(out)
1894 gen_dup(out)
1895
1896
1897def dup_h_gen(out, name):
1898 """
1899 Generate the header file for duplication functions
1900 """
1901
1902 loxi_utils.gen_c_copy_license(out)
1903 out.write("""
1904/*
1905 * Duplication function header file
1906 *
1907 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1908 */
1909
1910#if !defined(_OF_DUP_H_)
1911#define _OF_DUP_H_
1912
1913#include <loci/loci.h>
1914""")
1915
1916 for cls in of_g.standard_class_order:
1917 out.write("""
1918extern %(cls)s_t *
1919 %(cls)s_dup(
1920 %(cls)s_t *src);
1921""" % dict(cls=cls))
1922
1923 for version in of_g.of_version_range:
1924 for cls in of_g.standard_class_order:
1925 if not loxi_utils.class_in_version(cls, version):
1926 continue
1927 ver_name = loxi_utils.version_to_name(version)
1928 out.write("""
1929extern %(cls)s_t *
1930 %(cls)s_%(ver_name)s_dup(
1931 %(cls)s_t *src);
1932""" % dict(cls=cls, ver_name=ver_name))
1933
1934 out.write("\n#endif /* _OF_DUP_H_ */\n")
1935
1936def gen_log_test(out):
1937 """
1938 Generate test for obj log calls
1939
1940 Define a trivial handler for object logging; call all obj log fns
1941 """
1942 out.write("""
1943
1944/**
1945 * Test object dump functions
1946 */
1947
1948int
1949test_dump_objs(void)
1950{
1951 of_object_t *obj;
1952
1953 FILE *out = fopen("/dev/null", "w");
1954
1955 /* Call each obj dump function */
1956""")
1957 for version in of_g.of_version_range:
1958 for j, cls in enumerate(of_g.all_class_order):
1959 if not loxi_utils.class_in_version(cls, version):
1960 continue
Rich Lane8841f352014-10-12 19:18:36 -07001961 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001962 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001963 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1964 out.write("""
1965 obj = (of_object_t *)%(cls)s_new(%(version)s);
1966 {
1967 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1968 %(cls)s_vport_set(obj, vport);
1969 of_object_delete(vport);
1970 }
1971 of_object_dump((loci_writer_f)fprintf, out, obj);
1972 of_object_delete(obj);
1973""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1974 else:
1975 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001976 obj = (of_object_t *)%(cls)s_new(%(version)s);
1977 of_object_dump((loci_writer_f)fprintf, out, obj);
1978 of_object_delete(obj);
1979""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001980
Rich Lanea06d0c32013-03-25 08:52:03 -07001981 out.write("""
1982 fclose(out);
1983 return TEST_PASS;
1984}
1985""")
1986
1987def gen_ident_tests(out):
1988 """
1989 Generate tests for identifiers
1990
1991 For all idents, instantiate, test version supported macros
1992 For flags, set it, test it, clear it, test it.
1993 """
1994 out.write("""
1995/**
1996 * Test cases for all flag accessor macros
1997 * These only test self consistency (and that they compile)
1998 */
1999int
2000test_ident_macros(void)
2001{
2002 int value __attribute__((unused));
2003 uint32_t flags;
2004
2005""")
2006
2007 for ident, info in of_g.identifiers.items():
2008 if not identifiers.defined_versions_agree(of_g.identifiers,
2009 of_g.target_version_list,
2010 ident):
2011 # @fixme
2012 continue
2013 out.write(" value = %s;\n" % ident)
2014 for version in of_g.target_version_list:
2015 if version in info["values_by_version"].keys():
2016 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2017 (ident, of_g.of_version_wire2name[version]))
2018 else:
2019 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2020 (ident, of_g.of_version_wire2name[version]))
2021 if flags.ident_is_flag(ident):
2022 # Grab first supported version
2023 for version in info["values_by_version"]:
2024 break
2025 out.write("""
2026 flags = 0;
2027 %(ident)s_SET(flags, %(ver_name)s);
2028 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2029 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2030 %(ident)s_CLEAR(flags, %(ver_name)s);
2031 TEST_ASSERT(flags == 0);
2032 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2033""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2034
2035 out.write("""
2036 return TEST_PASS;
2037}
2038""")
2039
Rich Laneccae0312013-07-21 23:34:13 -07002040def gen_datafiles_tests(out, name):
2041 tests = []
2042 for filename in test_data.list_files():
2043 data = test_data.read(filename)
2044 if not 'c' in data:
2045 continue
2046 name = filename[:-5].replace("/", "_")
2047 tests.append(dict(name=name,
2048 filename=filename,
2049 c=data['c'],
2050 binary=data['binary']))
2051
2052 util.render_template(out, "test_data.c", tests=tests)