blob: db7ca2894e2405d167da958b1519adaab9d093b8 [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",
Rich Lane41b278f2014-10-17 18:29:56 -0700104 of_table_desc_t="table_desc",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700105 # BSN extensions
106 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700107 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800108 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700109 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700110
111 if m_type.find("of_list_") == 0:
112 return "list"
113 if m_type in of_g.of_mixed_types:
114 return of_g.of_mixed_types[m_type]["short_name"]
115 return _var_name_map[m_type]
116
117integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
118 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700119 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700120string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700121 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700122 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
123 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700124
125scalar_types = integer_types[:]
126scalar_types.extend(string_types)
127
Rich Lane1f315aa2014-10-13 17:11:35 -0700128# When embedding an object inside of another object we have to pick a single
129# subclass to use, unlike lists where we use all subclasses.
130embedded_subclasses = {
131 'of_oxm_header_t': 'of_oxm_eth_type',
132 'of_bsn_vport_header_t': 'of_bsn_vport_q_in_q',
133}
134
Rich Lanea06d0c32013-03-25 08:52:03 -0700135def ignore_member(cls, version, m_name, m_type):
136 """
137 Filter out names or types that either don't have accessors
138 or those that should not be messed with
139 or whose types we're not ready to deal with yet.
140 """
Rich Lane79c87192014-03-04 10:56:59 -0800141
142 uclass = loxi_globals.unified.class_by_name(cls)
143 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700144 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800145
Rich Lane79c87192014-03-04 10:56:59 -0800146 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800147 return True
Rich Lane79c87192014-03-04 10:56:59 -0800148
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
150
151def gen_fill_string(out):
152 out.write("""
153
154/**
155 * The increment to use on values inside a string
156 */
157#define OF_TEST_STR_INCR 3
158
159/**
160 * Fill in a buffer with incrementing values starting
161 * at the given offset with the given value
162 * @param buf The buffer to fill
163 * @param value The value to use for data
164 * @param len The number of bytes to fill
165 */
166
167void
168of_test_str_fill(uint8_t *buf, int value, int len)
169{
170 int i;
171
172 for (i = 0; i < len; i++) {
173 *buf = value;
174 value += OF_TEST_STR_INCR;
175 buf++;
176 }
177}
178
179/**
180 * Given a buffer, verify that it's filled as above
181 * @param buf The buffer to check
182 * @param value The value to use for data
183 * @param len The number of bytes to fill
184 * @return Boolean True on equality (success)
185 */
186
187int
188of_test_str_check(uint8_t *buf, int value, int len)
189{
190 int i;
191 uint8_t val8;
192
193 val8 = value;
194
195 for (i = 0; i < len; i++) {
196 if (*buf != val8) {
197 return 0;
198 }
199 val8 += OF_TEST_STR_INCR;
200 buf++;
201 }
202
203 return 1;
204}
205
206/**
207 * Global that determines how octets should be populated
208 * -1 means use value % MAX (below) to determine length
209 * 0, 1, ... means used that fixed length
210 *
211 * Note: Was 16K, but that made objects too big. May add flexibility
212 * to call populate with a max parameter for length
213 */
214int octets_pop_style = -1;
215#define OCTETS_MAX_VALUE (128) /* 16K was too big */
216#define OCTETS_MULTIPLIER 6367 /* A prime */
217
218int
219of_octets_populate(of_octets_t *octets, int value)
220{
221 if (octets_pop_style < 0) {
222 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
223 } else {
224 octets->bytes = octets_pop_style;
225 }
226
227 if (octets->bytes != 0) {
228 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
229 return 0;
230 }
231 of_test_str_fill(octets->data, value, octets->bytes);
232 value += 1;
233 }
234
235 return value;
236}
237
238int
239of_octets_check(of_octets_t *octets, int value)
240{
241 int len;
242
243 if (octets_pop_style < 0) {
244 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
245 TEST_ASSERT(octets->bytes == len);
246 } else {
247 TEST_ASSERT(octets->bytes == octets_pop_style);
248 }
249
250 if (octets->bytes != 0) {
251 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
252 == 1);
253 value += 1;
254 }
255
256 return value;
257}
258
259int
260of_match_populate(of_match_t *match, of_version_t version, int value)
261{
262 MEMSET(match, 0, sizeof(*match));
263 match->version = version;
264""")
265
Rich Laned56f8d22014-05-06 14:52:55 -0700266 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700267 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700268 if (version == %d) {\
269""" % wire_version)
270 for key in keys:
271 entry = match.of_match_members[key]
272 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700273 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
274 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
275 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700276""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
277 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700278 }
279
Rich Laned56f8d22014-05-06 14:52:55 -0700280""")
281
Rich Laneb4a63a52014-05-22 14:41:57 -0700282 for wire_version, match_keys in match.match_keys.items():
283 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700284
285 out.write("""
286 if (value % 2) {
287 /* Sometimes set ipv4 addr masks to non-exact */
288 match->masks.ipv4_src = 0xffff0000;
289 match->masks.ipv4_dst = 0xfffff800;
290 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700291
292 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700293 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700294 return value;
295}
296
297int
298of_match_check(of_match_t *match, of_version_t version, int value)
299{
300 of_match_t check;
301
302 value = of_match_populate(&check, match->version, value);
303 TEST_ASSERT(value != 0);
304 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
305
306 return value;
307}
308""")
309
310def gen_common_test_header(out, name):
311 loxi_utils.gen_c_copy_license(out)
312 out.write("""
313/*
314 * Test header file
315 *
316 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
317 */
318
319#if !defined(_TEST_COMMON_H_)
320#define _TEST_COMMON_H_
321
322#define DISABLE_WARN_UNUSED_RESULT
323#include <loci/loci.h>
324#include <locitest/of_dup.h>
325#include <locitest/unittest.h>
326
327extern int global_error;
328extern int exit_on_error;
329
330/* @todo Make option for -k to continue tests if errors */
331#define RUN_TEST(test) do { \\
332 int rv; \\
333 TESTCASE(test, rv); \\
334 if (rv != TEST_PASS) { \\
335 global_error=1; \\
336 if (exit_on_error) return(1); \\
337 } \\
338 } while(0)
339
340#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
341#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
342
343/*
344 * Declarations of functions to populate scalar values in a a class
345 */
346
347extern void of_test_str_fill(uint8_t *buf, int value, int len);
348extern int of_test_str_check(uint8_t *buf, int value, int len);
349
350
351extern int of_octets_populate(of_octets_t *octets, int value);
352extern int of_octets_check(of_octets_t *octets, int value);
353extern int of_match_populate(of_match_t *match, of_version_t version,
354 int value);
355extern int of_match_check(of_match_t *match, of_version_t version, int value);
356extern int test_ident_macros(void);
357extern int test_dump_objs(void);
358
359/* In test_match_utils.c */
360extern int test_match_utils(void);
361
362extern int run_unified_accessor_tests(void);
363extern int run_match_tests(void);
364extern int run_utility_tests(void);
365
366extern int run_scalar_acc_tests(void);
367extern int run_list_tests(void);
368extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700369
370extern int run_validator_tests(void);
371
372extern int run_list_limits_tests(void);
373
374extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700375extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700376
377""")
378
379 for version in of_g.of_version_range:
380 for cls in of_g.standard_class_order:
381 if not loxi_utils.class_in_version(cls, version):
382 continue
Rich Lane8841f352014-10-12 19:18:36 -0700383 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700384 continue
385 out.write("""
386extern int %(cls)s_%(v_name)s_populate(
387 %(cls)s_t *obj, int value);
388extern int %(cls)s_%(v_name)s_check(
389 %(cls)s_t *obj, int value);
390extern int %(cls)s_%(v_name)s_populate_scalars(
391 %(cls)s_t *obj, int value);
392extern int %(cls)s_%(v_name)s_check_scalars(
393 %(cls)s_t *obj, int value);
394""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
395
396 out.write("""
397/*
398 * Declarations for list population and check primitives
399 */
400""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700401
Rich Lanea06d0c32013-03-25 08:52:03 -0700402 for version in of_g.of_version_range:
403 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700404 if version in of_g.unified[cls]:
405 out.write("""
406extern int
407 list_setup_%(cls)s_%(v_name)s(
408 %(cls)s_t *list, int value);
409extern int
410 list_check_%(cls)s_%(v_name)s(
411 %(cls)s_t *list, int value);
412""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
413
414 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
415
416def gen_common_test(out, name):
417 """
418 Generate common test content including main
419 """
420 loxi_utils.gen_c_copy_license(out)
421 out.write("""
422/*
423 * Common test code for LOCI
424 *
425 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
426 */
427
428#define DISABLE_WARN_UNUSED_RESULT
429#include "loci_log.h"
430#include <loci/loci_obj_dump.h>
431#include <locitest/unittest.h>
432#include <locitest/test_common.h>
433
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900434/* mcheck is a glibc extension */
435#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700436#include <mcheck.h>
437#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900438#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700439#define MCHECK_INIT do { } while (0)
440#endif
441
442/**
443 * Exit on error if set to 1
444 */
445int exit_on_error = 1;
446
447/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700448 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700449 */
450int global_error = 0;
451
452extern int run_unified_accessor_tests(void);
453extern int run_match_tests(void);
454extern int run_utility_tests(void);
455
456extern int run_scalar_acc_tests(void);
457extern int run_list_tests(void);
458extern int run_message_tests(void);
459
460/**
461 * Macros for initializing and checking scalar types
462 *
463 * @param var The variable being initialized or checked
464 * @param val The integer value to set/check against, see below
465 *
466 * Note that equality means something special for strings. Each byte
467 * is initialized to an incrementing value. So check is done against that.
468 *
469 */
470
471""")
472 for t in scalar_types:
473 if t in integer_types:
474 out.write("""
475#define VAR_%s_INIT(var, val) var = (%s)(val)
476#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
477""" % (t.upper(), t, t.upper(), t))
478 else:
479 out.write("""
480#define VAR_%s_INIT(var, val) \\
481 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
482#define VAR_%s_CHECK(var, val) \\
483 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
484""" % (t.upper(), t.upper()))
485
486 gen_fill_string(out)
487 gen_scalar_set_check_funs(out)
488 gen_list_set_check_funs(out)
489 gen_unified_accessor_funs(out)
490
491 gen_ident_tests(out)
492 gen_log_test(out)
493
494def gen_message_scalar_test(out, name):
495 """
496 Generate test cases for message objects, scalar accessors
497 """
498
499 loxi_utils.gen_c_copy_license(out)
500 out.write("""
501/**
502 *
503 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
504 *
505 * Message-scalar tests for all versions
506 */
507
508#include <locitest/test_common.h>
509""")
510 for version in of_g.of_version_range:
511 v_name = loxi_utils.version_to_name(version)
512 out.write("""
513/**
514 * Message-scalar tests for version %s
515 */
516""" % v_name)
517 for cls in of_g.standard_class_order:
Rich Lane8841f352014-10-12 19:18:36 -0700518 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700519 continue
520 if version in of_g.unified[cls]:
521 message_scalar_test(out, version, cls)
522
523 out.write("""
524int
525run_scalar_acc_tests(void)
526{
527""")
528 for version in of_g.of_version_range:
529 v_name = loxi_utils.version_to_name(version)
530 for cls in of_g.standard_class_order:
Rich Lane8841f352014-10-12 19:18:36 -0700531 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700532 continue
533 if version in of_g.unified[cls]:
534 test_name = "%s_%s" % (cls, v_name)
535 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
536
537 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700538
Rich Lanea06d0c32013-03-25 08:52:03 -0700539def message_scalar_test(out, version, cls):
540 """
541 Generate one test case for the given version and class
542 """
543
544 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700545 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700546 v_name = loxi_utils.version_to_name(version)
547
548 out.write("""
549static int
550test_%(cls)s_%(v_name)s_scalar(void)
551{
552 %(cls)s_t *obj;
553
554 obj = %(cls)s_new(%(v_name)s);
555 TEST_ASSERT(obj != NULL);
556 TEST_ASSERT(obj->version == %(v_name)s);
557 TEST_ASSERT(obj->length == %(length)d);
558 TEST_ASSERT(obj->parent == NULL);
559 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700560""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700561 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700562
563 # If this class is a concrete member of an inheritance hierarchy,
564 # run the hierarchy's root wire type parser and assert it returns
565 # the expected object id.
566 ofclass = loxi_globals.unified.class_by_name(cls)
567 if ofclass and not ofclass.virtual:
568 root = ofclass
569 while root.superclass:
570 root = root.superclass
571 if root.virtual:
572 out.write("""
573 {
574 of_object_id_t object_id;
575 %(root_cls)s_wire_object_id_get(obj, &object_id);
576 TEST_ASSERT(object_id == %(u_cls)s);
577 }
578""" % dict(root_cls=root.name, u_cls=cls.upper()))
579
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 if not type_maps.class_is_virtual(cls):
581 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700582 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700583 int length;
584
Rich Lanedc46fe22014-04-03 15:10:38 -0700585 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700586 TEST_ASSERT(length == %(length)d);
587 }
588
589 /* Set up incrementing values for scalar members */
590 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
591
592 /* Check values just set */
593 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700594""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700595 v_name=v_name, length=length, version=version))
596
597 out.write("""
598 %(cls)s_delete(obj);
599
600 /* To do: Check memory */
601 return TEST_PASS;
602}
603""" % dict(cls=cls))
604
605# Get the members and list of scalar types for members of a given class
606def scalar_member_types_get(cls, version):
607 member_types = []
608
609 if not version in of_g.unified[cls]:
610 return ([], [])
611
612 if "use_version" in of_g.unified[cls][version]:
613 v = of_g.unified[cls][version]["use_version"]
614 members = of_g.unified[cls][v]["members"]
615 else:
616 members = of_g.unified[cls][version]["members"]
617 # Accumulate variables that are supported
618 for member in members:
619 m_type = member["m_type"]
620 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700621 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700622 ignore_member(cls, version, m_name, m_type)):
623 continue
624 if not m_type in member_types:
625 member_types.append(m_type)
626
627 return (members, member_types)
628
629def scalar_funs_instance(out, cls, version, members, member_types):
630 """
631 Generate one instance of scalar set/check functions
632 """
633 out.write("""
634/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700635 * Populate the scalar values in obj of type %(cls)s,
636 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700637 * @param obj Pointer to an object to populate
638 * @param value The seed value to use in populating the object
639 * @returns The value after increments for this object's values
640 */
641int %(cls)s_%(v_name)s_populate_scalars(
642 %(cls)s_t *obj, int value) {
643""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
644 # Declare string types
645 for t in member_types:
646 out.write(" %s %s;\n" % (t, var_name_map(t)))
647 for member in members:
648 m_type = member["m_type"]
649 m_name = member["name"]
650 if (not loxi_utils.type_is_scalar(m_type) or
651 ignore_member(cls, version, m_name, m_type)):
652 continue
653 v_name = var_name_map(m_type);
654 out.write("""
655 VAR_%(u_type)s_INIT(%(v_name)s, value);
656 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
657 value += 1;
658""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
659 out.write("""
660 return value;
661}
662""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700663
Rich Lanea06d0c32013-03-25 08:52:03 -0700664 out.write("""
665/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700666 * Check scalar values in obj of type %(cls)s,
667 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700668 * @param obj Pointer to an object to check
669 * @param value Starting value for checking
670 * @returns The value after increments for this object's values
671 */
672int %(cls)s_%(v_name)s_check_scalars(
673 %(cls)s_t *obj, int value) {
674""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
675
676 for t in member_types:
677 out.write(" %s %s;\n" % (t, var_name_map(t)))
678 for member in members:
679 m_type = member["m_type"]
680 m_name = member["name"]
681 if (not loxi_utils.type_is_scalar(m_type) or
682 ignore_member(cls, version, m_name, m_type)):
683 continue
684 v_name = var_name_map(m_type);
685 out.write("""
686 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
687 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
688 value += 1;
689""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
690
691 out.write("""
692 return value;
693}
694
695""")
696
697def gen_scalar_set_check_funs(out):
698 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700699 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700700 set and check their values
701 """
702 for version in of_g.of_version_range:
703 for cls in of_g.standard_class_order:
704 (members, member_types) = scalar_member_types_get(cls, version)
705 scalar_funs_instance(out, cls, version, members, member_types)
706
707
708# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700709def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700710 base_type = loxi_utils.list_to_entry_type(cls)
711 setup_template = """
712 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700713 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700714 (%(base_type)s_t *)%(inst)s);
715 value = %(subcls)s_%(v_name)s_populate(
716 %(inst)s, value);
717 cur_len += %(inst)s->length;
718 TEST_ASSERT(list->length == cur_len);
719"""
720 out.write("""
721 /* Append two instances of type %s */
722""" % subcls)
723 for i in range(2):
724 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700725 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700726 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700727 version=version))
728
Rich Lane9afc3b92014-04-09 22:55:53 -0700729def check_instance(out, cls, subcls, instance, v_name, version, last):
730 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700731 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
732 value = %(subcls)s_%(v_name)s_check(
733 %(inst)s, value);
734 TEST_ASSERT(value != 0);
735"""
736 out.write("\n /* Check two instances of type %s */" % instance)
737
Andreas Wundsam53256162013-05-02 14:05:53 -0700738 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700739 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700740 inst=instance, subcls=subcls,
741 v_name=loxi_utils.version_to_name(version)))
742 out.write("""\
743 TEST_OK(%(cls)s_next(list, &elt));
744""" % dict(cls=cls))
745
Andreas Wundsam53256162013-05-02 14:05:53 -0700746 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700747 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700748 inst=instance, subcls=subcls,
749 v_name=loxi_utils.version_to_name(version)))
750 if last:
751 out.write("""\
752 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
753""" % dict(cls=cls))
754 else:
755 out.write("""\
756 TEST_OK(%(cls)s_next(list, &elt));
757""" % dict(cls=cls))
758
759def setup_list_fn(out, version, cls):
760 """
761 Generate a helper function that populates a list with two
762 of each type of subclass it supports
763 """
764 out.write("""
765/**
766 * Set up a list of type %(cls)s with two of each type of subclass
767 */
768int
769list_setup_%(cls)s_%(v_name)s(
770 %(cls)s_t *list, int value)
771{
772""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
773 base_type = loxi_utils.list_to_entry_type(cls)
774 out.write("""
775 %(base_type)s_t elt;
776 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700777 (void) elt;
778 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700779""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700780
Rich Lanea06d0c32013-03-25 08:52:03 -0700781 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700782 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 -0700783 v_name = loxi_utils.version_to_name(version)
784
Rich Lanee98ee5d2014-10-14 10:43:44 -0700785 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700786 out.write(" /* No subclasses for %s */\n"% base_type)
787 out.write(" %s_t *elt_p;\n" % base_type)
788 out.write("\n elt_p = &elt;\n")
789 else:
790 out.write(" /* Declare pointers for each subclass */\n")
791 for instance, subcls in sub_classes:
792 out.write(" %s_t *%s;\n" % (subcls, instance))
793 out.write("\n /* Instantiate pointers for each subclass */\n")
794 for instance, subcls in sub_classes:
795 out.write(" %s = &elt.%s;\n" % (instance, instance))
796
Rich Lanee98ee5d2014-10-14 10:43:44 -0700797 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700798 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700799 else:
800 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700801 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700802 out.write("""
803
804 return value;
805}
806""")
807
808def check_list_fn(out, version, cls):
809 """
810 Generate a helper function that checks a list populated by above fn
811 """
812 out.write("""
813/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700814 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700815 * list_setup_%(cls)s_%(v_name)s
816 */
817int
818list_check_%(cls)s_%(v_name)s(
819 %(cls)s_t *list, int value)
820{
821""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
822 base_type = loxi_utils.list_to_entry_type(cls)
823 out.write("""
824 %(base_type)s_t elt;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700825 (void) elt;
Rich Lanea06d0c32013-03-25 08:52:03 -0700826""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700827
Rich Lanea06d0c32013-03-25 08:52:03 -0700828 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700829 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 -0700830 v_name = loxi_utils.version_to_name(version)
831
Rich Lanee98ee5d2014-10-14 10:43:44 -0700832 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700833 out.write(" /* No subclasses for %s */\n"% base_type)
834 out.write(" %s_t *elt_p;\n" % base_type)
835 out.write("\n elt_p = &elt;\n")
836 else:
837 out.write(" /* Declare pointers for each subclass */\n")
838 for instance, subcls in sub_classes:
839 out.write(" %s_t *%s;\n" % (subcls, instance))
840 out.write("\n /* Instantiate pointers for each subclass */\n")
841 for instance, subcls in sub_classes:
842 out.write(" %s = &elt.%s;\n" % (instance, instance))
843
Rich Lanee98ee5d2014-10-14 10:43:44 -0700844 if not type_maps.class_is_virtual(base_type) or sub_classes:
845 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
846
847 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700848 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700849 else:
850 count = 0
851 for instance, subcls in sub_classes:
852 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700853 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700854 version, count==len(sub_classes))
855
856 out.write("""
857 return value;
858}
859""" % dict(base_type=base_type))
860
861def gen_list_set_check_funs(out):
862 for version in of_g.of_version_range:
863 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700864 if version in of_g.unified[cls]:
865 setup_list_fn(out, version, cls)
866 check_list_fn(out, version, cls)
867
868# Maybe: Get a map from list class to parent, mem_name of container
869
870def list_test(out, version, cls):
871 out.write("""
872static int
873test_%(cls)s_%(v_name)s(void)
874{
875""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
876 base_type = loxi_utils.list_to_entry_type(cls)
877
878 out.write(""" %(cls)s_t *list;
879 int value = 1;
880""" % dict(cls=cls, base_type=base_type))
881
882 out.write("""
883 list = %(cls)s_new(%(v_name)s);
884 TEST_ASSERT(list != NULL);
885 TEST_ASSERT(list->version == %(v_name)s);
886 TEST_ASSERT(list->length == 0);
887 TEST_ASSERT(list->parent == NULL);
888 TEST_ASSERT(list->object_id == %(enum_cls)s);
889
890 value = list_setup_%(cls)s_%(v_name)s(list, value);
891 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700892""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700893 enum_cls=loxi_utils.enum_name(cls)))
894
895 out.write("""
896 /* Now check values */
897 value = 1;
898 value = list_check_%(cls)s_%(v_name)s(list, value);
899 TEST_ASSERT(value != 0);
900""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
901
902 out.write("""
903 %(cls)s_delete(list);
904
905 return TEST_PASS;
906}
907""" % dict(cls=cls))
908
909def gen_list_test(out, name):
910 """
911 Generate base line test cases for lists
912 @param out The file handle to write to
913 """
914
915 loxi_utils.gen_c_copy_license(out)
916 out.write("""
917/**
918 *
919 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
920 *
921 * Message-scalar tests for all versions
922 */
923
924#include <locitest/test_common.h>
925""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700926
Rich Lanea06d0c32013-03-25 08:52:03 -0700927 for version in of_g.of_version_range:
928 v_name = loxi_utils.version_to_name(version)
929 out.write("""
930/**
931 * Baseline list tests for version %s
932 */
933""" % v_name)
934 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700935 if version in of_g.unified[cls]:
936 list_test(out, version, cls)
937
938 out.write("""
939int
940run_list_tests(void)
941{
942""")
943 for version in of_g.of_version_range:
944 v_name = loxi_utils.version_to_name(version)
945 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700946 if version in of_g.unified[cls]:
947 test_name = "%s_%s" % (cls, v_name)
948 out.write(" RUN_TEST(%s);\n" % test_name)
949
950 out.write("\n return TEST_PASS;\n}\n");
951
952def gen_match_test(out, name):
953 """
954 Generate baseline tests for match functions
955 """
956
957 loxi_utils.gen_c_copy_license(out)
958 out.write("""\
959/**
960 *
961 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
962 *
963 * Message-scalar tests for all versions
964 * @fixme These are mostly hard coded now.
965 */
966
967#include <locitest/test_common.h>
968
969static int
970test_match_1(void)
971{
Rich Lanef87f4c32014-10-14 11:56:02 -0700972""")
973
974 for version in of_g.of_version_range:
975 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
976
977 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700978 of_match_t match;
979 int value = 1;
980 int idx;
981 uint32_t exp_value;
982
983 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700984 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700985 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
986 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
987 if (idx < 32) {
988 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
989 }
990 }
991""")
992
993 for version in of_g.of_version_range:
994 out.write("""
995 /* Create/populate/convert and delete for version %(v_name)s */
996 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
997 TEST_ASSERT(m_v%(version)d != NULL);
998 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
999 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
1000 of_match_v%(version)d_delete(m_v%(version)d);
1001""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1002
1003 out.write("""
1004 return TEST_PASS;
1005}
1006""")
1007
1008 out.write("""
1009static int
1010test_match_2(void)
1011{
Rich Lanef87f4c32014-10-14 11:56:02 -07001012""")
1013
1014 for version in of_g.of_version_range:
1015 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
1016
1017 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -07001018 of_match_t match1;
1019 of_match_t match2;
1020 int value = 1;
1021""")
1022
1023 for version in of_g.of_version_range:
1024 out.write("""
1025 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1026 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1027 TEST_ASSERT(m_v%(version)d != NULL);
1028 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1029 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1030 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1031 of_match_v%(version)d_delete(m_v%(version)d);
1032""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1033
1034 out.write("""
1035 return TEST_PASS;
1036}
1037""")
1038
1039 out.write("""
1040static int
1041test_match_3(void)
1042{
1043 of_match_t match1;
1044 of_match_t match2;
1045 int value = 1;
1046 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001047 of_object_storage_t storage;
1048 memset(&storage, 0, sizeof(storage));
1049 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001050""")
1051 for version in of_g.of_version_range:
1052 out.write("""
1053 /* Serialize to version %(v_name)s */
1054 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001055 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001056 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001057 storage.obj.wbuf->buf = octets.data;
1058 storage.obj.wbuf->alloc_bytes = octets.bytes;
1059 storage.obj.wbuf->current_bytes = octets.bytes;
1060 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001061 OF_ERROR_NONE);
1062 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1063 FREE(octets.data);
1064""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1065
1066 out.write("""
1067 return TEST_PASS;
1068}
1069""")
1070
1071 out.write("""
1072int run_match_tests(void)
1073{
1074 RUN_TEST(match_1);
1075 RUN_TEST(match_2);
1076 RUN_TEST(match_3);
1077 RUN_TEST(match_utils);
1078
1079 return TEST_PASS;
1080}
1081""")
1082
1083def gen_msg_test(out, name):
1084 loxi_utils.gen_c_copy_license(out)
1085 out.write("""
1086/**
1087 *
1088 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1089 *
1090 * Message-scalar tests for all versions
1091 */
1092
1093#include <locitest/test_common.h>
1094""")
1095 for version in of_g.of_version_range:
1096 for cls in of_g.ordered_messages:
1097 if not (cls, version) in of_g.base_length:
1098 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001099 if type_maps.class_is_virtual(cls):
1100 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -07001101 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001102 out.write("""
1103static int
1104test_%(cls)s_create_%(v_name)s(void)
1105{
1106 %(cls)s_t *obj;
1107 uint8_t *msg_buf;
1108 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001109 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001110 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001111
1112 obj = %(cls)s_new(%(v_name)s);
1113 TEST_ASSERT(obj != NULL);
1114 TEST_ASSERT(obj->version == %(v_name)s);
1115 TEST_ASSERT(obj->length == %(bytes)d);
1116 TEST_ASSERT(obj->parent == NULL);
1117 TEST_ASSERT(obj->object_id == %(enum)s);
1118
Rich Lanea4b68302014-03-12 15:17:58 -07001119 of_header_wire_object_id_get(obj, &object_id);
1120 TEST_ASSERT(object_id == %(enum)s);
1121
Rich Lanea06d0c32013-03-25 08:52:03 -07001122 /* Set up incrementing values for scalar members */
1123 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1124 TEST_ASSERT(value != 0);
1125
Rich Lanebb8f17c2014-06-12 13:14:09 -07001126 len = obj->length;
1127
Rich Lanea06d0c32013-03-25 08:52:03 -07001128 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001129 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1130 TEST_ASSERT(msg_buf != NULL);
1131 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001132 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001133
1134 TEST_ASSERT(obj != NULL);
1135
1136 /* @fixme Set up all message objects (recursively?) */
1137
1138 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1139 TEST_ASSERT(value != 0);
1140
1141 %(cls)s_delete(obj);
1142
1143 return TEST_PASS;
1144}
1145""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1146 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1147
1148 out.write("""
1149int
1150run_message_tests(void)
1151{
1152""")
1153 for version in of_g.of_version_range:
1154 for cls in of_g.ordered_messages:
1155 if not (cls, version) in of_g.base_length:
1156 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001157 if type_maps.class_is_virtual(cls):
1158 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001159 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1160 out.write(" RUN_TEST(%s);\n" % test_name)
1161
1162 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001163
Rich Lanea06d0c32013-03-25 08:52:03 -07001164
1165def gen_list_setup_check(out, cls, version):
1166 """
1167 Generate functions that populate and check a list with two
1168 of each type of subclass it supports
1169 """
1170 out.write("""
1171/**
1172 * Populate a list of type %(cls)s with two of each type of subclass
1173 * @param list Pointer to the list to be populated
1174 * @param value The seed value to use in populating the list
1175 * @returns The value after increments for this object's values
1176 */
1177int
1178%(cls)s_%(v_name)s_populate(
1179 %(cls)s_t *list, int value)
1180{
1181""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1182 base_type = loxi_utils.list_to_entry_type(cls)
1183 out.write("""
1184 %(base_type)s_t elt;
1185 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001186 (void) elt;
1187 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001188""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001189
Rich Lanea06d0c32013-03-25 08:52:03 -07001190 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001191 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 -07001192 v_name = loxi_utils.version_to_name(version)
1193
Rich Lanee98ee5d2014-10-14 10:43:44 -07001194 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001195 out.write(" /* No subclasses for %s */\n"% base_type)
1196 out.write(" %s_t *elt_p;\n" % base_type)
1197 out.write("\n elt_p = &elt;\n")
1198 else:
1199 out.write(" /* Declare pointers for each subclass */\n")
1200 for instance, subcls in sub_classes:
1201 out.write(" %s_t *%s;\n" % (subcls, instance))
1202 out.write("\n /* Instantiate pointers for each subclass */\n")
1203 for instance, subcls in sub_classes:
1204 out.write(" %s = &elt.%s;\n" % (instance, instance))
1205
Rich Lanee98ee5d2014-10-14 10:43:44 -07001206 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001207 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001208 else:
1209 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001210 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001211 out.write("""
1212 return value;
1213}
1214""")
1215 out.write("""
1216/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001217 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001218 * %(cls)s_%(v_name)s_populate
1219 * @param list Pointer to the list that was populated
1220 * @param value Starting value for checking
1221 * @returns The value after increments for this object's values
1222 */
1223int
1224%(cls)s_%(v_name)s_check(
1225 %(cls)s_t *list, int value)
1226{
1227""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1228 base_type = loxi_utils.list_to_entry_type(cls)
1229 out.write("""
1230 %(base_type)s_t elt;
1231 int count = 0;
1232 int rv;
1233""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001234
Rich Lanea06d0c32013-03-25 08:52:03 -07001235
1236 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001237 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 -07001238 v_name = loxi_utils.version_to_name(version)
1239
Rich Lanee98ee5d2014-10-14 10:43:44 -07001240 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001241 entry_count = 2
1242 out.write(" /* No subclasses for %s */\n"% base_type)
1243 out.write(" %s_t *elt_p;\n" % base_type)
1244 out.write("\n elt_p = &elt;\n")
1245 else:
1246 entry_count = 2 * len(sub_classes) # Two of each type appended
1247 out.write(" /* Declare pointers for each subclass */\n")
1248 for instance, subcls in sub_classes:
1249 out.write(" %s_t *%s;\n" % (subcls, instance))
1250 out.write("\n /* Instantiate pointers for each subclass */\n")
1251 for instance, subcls in sub_classes:
1252 out.write(" %s = &elt.%s;\n" % (instance, instance))
1253
Rich Lanee98ee5d2014-10-14 10:43:44 -07001254 if not type_maps.class_is_virtual(base_type) or sub_classes:
1255 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1256
1257 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001258 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001259 version, True)
1260 else:
1261 count = 0
1262 for instance, subcls in sub_classes:
1263 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001264 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001265 version, count==len(sub_classes))
1266 out.write("""
1267""" % dict(base_type=base_type))
1268
1269 out.write("""
1270 /* Do an iterate to test the iterator */
1271 %(u_cls)s_ITER(list, &elt, rv) {
1272 count += 1;
1273 }
1274
1275 TEST_ASSERT(rv == OF_ERROR_RANGE);
1276 TEST_ASSERT(count == %(entry_count)d);
1277
1278 /* We shoehorn a test of the dup functions here */
1279 {
1280 %(cls)s_t *dup;
1281
1282 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1283 TEST_ASSERT(dup->length == list->length);
1284 TEST_ASSERT(dup->object_id == list->object_id);
1285 TEST_ASSERT(dup->version == list->version);
1286 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1287 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1288 of_object_delete((of_object_t *)dup);
1289
1290 /* And now for the generic dup function */
1291 TEST_ASSERT((dup = (%(cls)s_t *)
1292 of_object_dup(list)) != NULL);
1293 TEST_ASSERT(dup->length == list->length);
1294 TEST_ASSERT(dup->object_id == list->object_id);
1295 TEST_ASSERT(dup->version == list->version);
1296 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1297 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1298 of_object_delete((of_object_t *)dup);
1299 }
1300
1301 return value;
1302}
1303""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1304
1305
1306def gen_class_setup_check(out, cls, version):
1307 out.write("""
1308/**
1309 * Populate all members of an object of type %(cls)s
1310 * with incrementing values
1311 * @param obj Pointer to an object to populate
1312 * @param value The seed value to use in populating the object
1313 * @returns The value after increments for this object's values
1314 */
1315
1316int
1317%(cls)s_%(v_name)s_populate(
1318 %(cls)s_t *obj, int value)
1319{
1320""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1321 members, member_types = loxi_utils.all_member_types_get(cls, version)
1322 for m_type in member_types:
1323 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1324 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001325 elif m_type in embedded_subclasses:
1326 subcls = embedded_subclasses[m_type]
1327 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001328 else:
1329 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1330 out.write("""
1331 /* Run thru accessors after new to ensure okay */
1332""")
1333 for member in members:
1334 m_type = member["m_type"]
1335 m_name = member["name"]
1336 if loxi_utils.skip_member_name(m_name):
1337 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001338 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001339 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001340 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1341 out.write("""\
1342 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1343""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1344 else:
1345 sub_cls = m_type[:-2] # Trim _t
1346 out.write("""\
1347 {
1348 %(sub_cls)s_t sub_cls;
1349
1350 /* Test bind */
1351 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1352 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001353""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001354 m_name=m_name, sub_cls=sub_cls,
1355 v_name=loxi_utils.version_to_name(version)))
1356
1357 out.write("""
1358 value = %(cls)s_%(v_name)s_populate_scalars(
1359 obj, value);
1360 TEST_ASSERT(value != 0);
1361""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1362
1363 for member in members:
1364 m_type = member["m_type"]
1365 m_name = member["name"]
1366 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1367 continue
1368 if loxi_utils.skip_member_name(m_name):
1369 continue
1370 if m_type == "of_match_t":
1371 out.write("""\
1372 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1373 TEST_ASSERT(value != 0);
1374 %(cls)s_%(m_name)s_set(
1375 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001376""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001377 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1378 elif m_type == "of_octets_t":
1379 out.write("""\
1380 value = of_octets_populate(&%(var_name)s, value);
1381 TEST_ASSERT(value != 0);
1382 %(cls)s_%(m_name)s_set(
1383 obj, &%(var_name)s);
1384 if (octets.bytes) {
1385 FREE(octets.data);
1386 }
1387""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001388 elif m_type in embedded_subclasses:
1389 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001390 out.write("""\
1391 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1392 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001393 value = %(sub_cls)s_%(v_name)s_populate(
1394 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001395 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)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001402 else:
1403 sub_cls = m_type[:-2] # Trim _t
1404 out.write("""
1405 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1406 TEST_ASSERT(%(var_name)s != NULL);
1407 value = %(sub_cls)s_%(v_name)s_populate(
1408 %(var_name)s, value);
1409 TEST_ASSERT(value != 0);
1410 %(cls)s_%(m_name)s_set(
1411 obj, %(var_name)s);
1412 %(sub_cls)s_delete(%(var_name)s);
1413""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1414 var_name=var_name_map(m_type),
1415 v_name=loxi_utils.version_to_name(version)))
1416
1417 out.write("""
1418 return value;
1419}
1420""")
1421
1422 out.write("""
1423/**
1424 * Check all members of an object of type %(cls)s
1425 * populated by the above function
1426 * @param obj Pointer to an object to check
1427 * @param value Starting value for checking
1428 * @returns The value after increments for this object's values
1429 */
1430
1431int
1432%(cls)s_%(v_name)s_check(
1433 %(cls)s_t *obj, int value)
1434{
1435""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1436 members, member_types = loxi_utils.all_member_types_get(cls, version)
1437 for m_type in member_types:
1438 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1439 continue
1440 if loxi_utils.type_is_of_object(m_type):
1441 continue
1442 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1443 out.write("""
1444 value = %(cls)s_%(v_name)s_check_scalars(
1445 obj, value);
1446 TEST_ASSERT(value != 0);
1447""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1448
1449 for member in members:
1450 m_type = member["m_type"]
1451 m_name = member["name"]
1452 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1453 continue
1454 if loxi_utils.skip_member_name(m_name):
1455 continue
1456 if m_type == "of_match_t":
1457 out.write("""\
1458 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1459 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1460""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1461 v_name=loxi_utils.version_to_name(version)))
1462 elif m_type == "of_octets_t":
1463 out.write("""\
1464 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1465 value = of_octets_check(&%(var_name)s, value);
1466""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1467 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001468 elif m_type in embedded_subclasses:
1469 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001470 out.write("""
1471 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001472 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001473
1474 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1475 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001476 value = %(sub_cls)s_%(v_name)s_check(
1477 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001478 TEST_ASSERT(value != 0);
1479 %(sub_cls)s_delete(%(m_name)s_ptr);
1480 }
1481""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1482 var_name=var_name_map(m_type),
1483 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001484 else:
1485 sub_cls = m_type[:-2] # Trim _t
1486 out.write("""
1487 { /* Use get/delete to access on check */
1488 %(m_type)s *%(m_name)s_ptr;
1489
1490 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1491 TEST_ASSERT(%(m_name)s_ptr != NULL);
1492 value = %(sub_cls)s_%(v_name)s_check(
1493 %(m_name)s_ptr, value);
1494 TEST_ASSERT(value != 0);
1495 %(sub_cls)s_delete(%(m_name)s_ptr);
1496 }
1497""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1498 var_name=var_name_map(m_type),
1499 v_name=loxi_utils.version_to_name(version)))
1500
1501 out.write("""
1502 /* We shoehorn a test of the dup functions here */
1503 {
1504 %(cls)s_t *dup;
1505
1506 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1507 TEST_ASSERT(dup->length == obj->length);
1508 TEST_ASSERT(dup->object_id == obj->object_id);
1509 TEST_ASSERT(dup->version == obj->version);
1510 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1511 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1512 of_object_delete((of_object_t *)dup);
1513
1514 /* And now for the generic dup function */
1515 TEST_ASSERT((dup = (%(cls)s_t *)
1516 of_object_dup(obj)) != NULL);
1517 TEST_ASSERT(dup->length == obj->length);
1518 TEST_ASSERT(dup->object_id == obj->object_id);
1519 TEST_ASSERT(dup->version == obj->version);
1520 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1521 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1522 of_object_delete((of_object_t *)dup);
1523 }
1524
1525 return value;
1526}
1527""" % dict(cls=cls))
1528
1529def unified_accessor_test_case(out, cls, version):
1530 """
1531 Generate one test case for the given version and class
1532 """
1533
1534 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001535 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001536 v_name = loxi_utils.version_to_name(version)
1537
1538 out.write("""
1539static int
1540test_%(cls)s_%(v_name)s(void)
1541{
1542 %(cls)s_t *obj;
1543 obj = %(cls)s_new(%(v_name)s);
1544 TEST_ASSERT(obj != NULL);
1545 TEST_ASSERT(obj->version == %(v_name)s);
1546 TEST_ASSERT(obj->length == %(length)d);
1547 TEST_ASSERT(obj->parent == NULL);
1548 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001549""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001550 v_name=v_name, length=length, version=version))
1551 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1552 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001553 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001554 int length;
1555
Rich Lanedc46fe22014-04-03 15:10:38 -07001556 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001557 TEST_ASSERT(length == %(length)d);
1558 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001559 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001560 of_object_id_t obj_id;
1561
Rich Lanedc46fe22014-04-03 15:10:38 -07001562 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001563 TEST_ASSERT(obj_id == %(u_cls)s);
1564 }
1565
1566 /* Set up incrementing values for members */
1567 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1568 obj, 1) != 0);
1569
1570 /* Check values just set */
1571 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1572 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001573""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001574 v_name=v_name, length=length, version=version))
1575
1576 out.write("""
1577 %(cls)s_delete(obj);
1578
1579 /* To do: Check memory */
1580 return TEST_PASS;
1581}
1582""" % dict(cls=cls))
1583
1584
1585def gen_unified_accessor_funs(out):
1586 for version in of_g.of_version_range:
1587 for cls in of_g.standard_class_order:
1588 if not loxi_utils.class_in_version(cls, version):
1589 continue
Rich Lane8841f352014-10-12 19:18:36 -07001590 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001591 continue
1592 elif loxi_utils.class_is_list(cls):
1593 gen_list_setup_check(out, cls, version)
1594 else:
1595 gen_class_setup_check(out, cls, version)
1596
1597def gen_unified_accessor_tests(out, name):
1598 loxi_utils.gen_c_copy_license(out)
1599 out.write("""
1600/**
1601 *
1602 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1603 *
1604 * Unified simple class instantiation tests for all versions
1605 */
1606
1607#include <locitest/test_common.h>
1608""")
1609 for version in of_g.of_version_range:
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 unified_accessor_test_case(out, cls, version)
1616
1617 out.write("""
1618int
1619run_unified_accessor_tests(void)
1620{
1621""")
1622 for version in of_g.of_version_range:
1623 v_name = loxi_utils.version_to_name(version)
1624 for cls in of_g.standard_class_order:
1625 if not loxi_utils.class_in_version(cls, version):
1626 continue
Rich Lane8841f352014-10-12 19:18:36 -07001627 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001628 continue
1629 test_name = "%s_%s" % (cls, v_name)
1630 out.write(" RUN_TEST(%s);\n" % test_name)
1631
1632 out.write(" return TEST_PASS;\n}\n");
1633
1634
1635
1636################################################################
1637#
1638# Object duplication functions
1639#
1640# These exercise the accessors to create duplicate objects.
1641# They are used in the LOCI test shim which sits in an OF
1642# protocol stream.
1643#
1644# TODO
1645# Resolve version stuff
1646# Complete list dup
1647
1648def gen_dup_list(out, cls, version):
1649 ver_name = loxi_utils.version_to_name(version)
1650 elt_type = loxi_utils.list_to_entry_type(cls)
1651 out.write("""
1652/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001653 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001654 * using accessor functions
1655 * @param src Pointer to object to be duplicated
1656 * @returns A new object of type %(cls)s.
1657 *
1658 * The caller is responsible for deleting the returned value
1659 */
1660%(cls)s_t *
1661%(cls)s_%(ver_name)s_dup(
1662 %(cls)s_t *src)
1663{
1664 %(elt_type)s_t src_elt;
1665 %(elt_type)s_t *dst_elt;
1666 int rv;
1667 %(cls)s_t *dst;
1668
1669 if ((dst = %(cls)s_new(src->version)) == NULL) {
1670 return NULL;
1671 }
1672""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1673
1674 out.write("""
1675 %(u_cls)s_ITER(src, &src_elt, rv) {
1676 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1677 of_object_delete((of_object_t *)dst);
1678 return NULL;
1679 }
1680 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1681 dst, NULL);
1682 of_object_delete((of_object_t *)dst_elt);
1683 }
1684
1685 return dst;
1686}
1687""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1688
1689
1690def gen_dup_inheritance(out, cls, version):
1691 ver_name = loxi_utils.version_to_name(version)
1692 out.write("""
1693/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001694 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001695 * @param src Pointer to object to be duplicated
1696 * @returns A new object of type %(cls)s.
1697 *
1698 * The caller is responsible for deleting the returned value
1699 */
1700%(cls)s_t *
1701%(cls)s_%(ver_name)s_dup(
1702 %(cls)s_t *src)
1703{
1704""" % dict(cls=cls, ver_name=ver_name))
1705
1706 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001707 sub_classes = type_maps.sub_class_map(cls, version)
1708 for (_, sub_cls) in sub_classes:
1709 sub_enum = sub_cls.upper()
Rich Lanea06d0c32013-03-25 08:52:03 -07001710 out.write("""
1711 if (src->header.object_id == %(sub_enum)s) {
Rich Lane10daa5b2014-10-12 11:36:50 -07001712 return (%(cls)s_t *)%(sub_cls)s_%(ver_name)s_dup(
1713 (of_object_t *)src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001714 }
1715""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1716
1717 out.write("""
1718 return NULL;
1719}
1720""")
1721
1722
1723def gen_dup_cls(out, cls, version):
1724 """
1725 Generate duplication routine for class cls
1726 """
1727 ver_name = loxi_utils.version_to_name(version)
1728
1729 out.write("""
1730/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001731 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001732 * using accessor functions
1733 * @param src Pointer to object to be duplicated
1734 * @returns A new object of type %(cls)s.
1735 *
1736 * The caller is responsible for deleting the returned value
1737 */
1738%(cls)s_t *
1739%(cls)s_%(ver_name)s_dup(
1740 %(cls)s_t *src)
1741{
1742 %(cls)s_t *dst;
1743""" % dict(cls=cls, ver_name=ver_name))
1744
1745 # Get members and types for the class
1746 members, member_types = loxi_utils.all_member_types_get(cls, version)
1747
1748 # Add declarations for each member type
1749 for m_type in member_types:
1750 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1751 # Declare instance of these
1752 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001753 elif m_type in embedded_subclasses:
1754 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001755 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001756 %(sub_cls)s_t src_%(v_name)s;
1757 %(sub_cls)s_t *dst_%(v_name)s;
1758""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001759 else:
1760 out.write("""
1761 %(m_type)s src_%(v_name)s;
1762 %(m_type)s *dst_%(v_name)s;
1763""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1764
1765 out.write("""
1766 if ((dst = %(cls)s_new(src->version)) == NULL) {
1767 return NULL;
1768 }
1769""" % dict(cls=cls))
1770
1771 for member in members:
1772 m_type = member["m_type"]
1773 m_name = member["name"]
1774 if loxi_utils.skip_member_name(m_name):
1775 continue
1776 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1777 out.write("""
1778 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1779 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1780""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1781 elif m_type in ["of_match_t", "of_octets_t"]:
1782 out.write("""
1783 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1784 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1785""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001786 elif m_type in embedded_subclasses:
1787 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001788 out.write("""
1789 %(cls)s_%(m_name)s_bind(
1790 src, &src_%(v_name)s);
1791 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1792 if (dst_%(v_name)s == NULL) {
1793 %(cls)s_delete(dst);
1794 return NULL;
1795 }
1796 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1797 %(sub_cls)s_delete(dst_%(v_name)s);
1798""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1799 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001800 else:
1801 sub_cls = m_type[:-2] # Trim _t
1802 out.write("""
1803 %(cls)s_%(m_name)s_bind(
1804 src, &src_%(v_name)s);
1805 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1806 if (dst_%(v_name)s == NULL) {
1807 %(cls)s_delete(dst);
1808 return NULL;
1809 }
1810 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1811 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001812""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001813 v_name=var_name_map(m_type), ver_name=ver_name))
1814
1815 out.write("""
1816 return dst;
1817}
1818""")
1819
1820def gen_version_dup(out=sys.stdout):
1821 """
1822 Generate duplication routines for each object type
1823 """
1824 out.write("""
1825/* Special try macro for duplicating */
1826#define _TRY_FREE(op, obj, rv) do { \\
1827 int _rv; \\
1828 if ((_rv = (op)) < 0) { \\
1829 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1830 of_object_delete((of_object_t *)(obj)); \\
1831 return (rv); \\
1832 } \\
1833 } while (0)
1834""")
1835
1836 for version in of_g.of_version_range:
1837 for cls in of_g.standard_class_order:
1838 if not loxi_utils.class_in_version(cls, version):
1839 continue
Rich Lane8841f352014-10-12 19:18:36 -07001840 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001841 gen_dup_inheritance(out, cls, version)
1842 elif loxi_utils.class_is_list(cls):
1843 gen_dup_list(out, cls, version)
1844 else:
1845 gen_dup_cls(out, cls, version)
1846
1847def gen_dup(out=sys.stdout):
1848 """
1849 Generate non-version specific duplication routines for each object type
1850 """
1851
1852 for cls in of_g.standard_class_order:
1853 out.write("""
1854%(cls)s_t *
1855%(cls)s_dup(
1856 %(cls)s_t *src)
1857{
1858""" % dict(cls=cls))
1859 for version in of_g.of_version_range:
1860 if not loxi_utils.class_in_version(cls, version):
1861 continue
Rich Lane8841f352014-10-12 19:18:36 -07001862 hdr = "header." if type_maps.class_is_inheritance_root(cls) else ""
Rich Lanea06d0c32013-03-25 08:52:03 -07001863
1864 ver_name = loxi_utils.version_to_name(version)
1865 out.write("""
1866 if (src->%(hdr)sversion == %(ver_name)s) {
1867 return %(cls)s_%(ver_name)s_dup(src);
1868 }
1869""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1870
1871 out.write("""
1872 /* Class not supported in given version */
1873 return NULL;
1874}
1875""")
1876
1877def dup_c_gen(out, name):
1878 """
1879 Generate the C file for duplication functions
1880 """
1881 loxi_utils.gen_c_copy_license(out)
1882 out.write("""\
1883/*
1884 * Duplication functions for all OF objects
1885 *
1886 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1887 *
1888 * These are test functions for exercising accessors. You can call
1889 * of_object_dup for an efficient duplication.
1890 */
1891
1892#define DISABLE_WARN_UNUSED_RESULT
1893#include "loci_log.h"
1894#include <locitest/of_dup.h>
1895
1896""")
1897
1898 gen_version_dup(out)
1899 gen_dup(out)
1900
1901
1902def dup_h_gen(out, name):
1903 """
1904 Generate the header file for duplication functions
1905 """
1906
1907 loxi_utils.gen_c_copy_license(out)
1908 out.write("""
1909/*
1910 * Duplication function header file
1911 *
1912 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1913 */
1914
1915#if !defined(_OF_DUP_H_)
1916#define _OF_DUP_H_
1917
1918#include <loci/loci.h>
1919""")
1920
1921 for cls in of_g.standard_class_order:
1922 out.write("""
1923extern %(cls)s_t *
1924 %(cls)s_dup(
1925 %(cls)s_t *src);
1926""" % dict(cls=cls))
1927
1928 for version in of_g.of_version_range:
1929 for cls in of_g.standard_class_order:
1930 if not loxi_utils.class_in_version(cls, version):
1931 continue
1932 ver_name = loxi_utils.version_to_name(version)
1933 out.write("""
1934extern %(cls)s_t *
1935 %(cls)s_%(ver_name)s_dup(
1936 %(cls)s_t *src);
1937""" % dict(cls=cls, ver_name=ver_name))
1938
1939 out.write("\n#endif /* _OF_DUP_H_ */\n")
1940
1941def gen_log_test(out):
1942 """
1943 Generate test for obj log calls
1944
1945 Define a trivial handler for object logging; call all obj log fns
1946 """
1947 out.write("""
1948
1949/**
1950 * Test object dump functions
1951 */
1952
1953int
1954test_dump_objs(void)
1955{
1956 of_object_t *obj;
1957
1958 FILE *out = fopen("/dev/null", "w");
1959
1960 /* Call each obj dump function */
1961""")
1962 for version in of_g.of_version_range:
1963 for j, cls in enumerate(of_g.all_class_order):
1964 if not loxi_utils.class_in_version(cls, version):
1965 continue
Rich Lane8841f352014-10-12 19:18:36 -07001966 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001967 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001968 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1969 out.write("""
1970 obj = (of_object_t *)%(cls)s_new(%(version)s);
1971 {
1972 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1973 %(cls)s_vport_set(obj, vport);
1974 of_object_delete(vport);
1975 }
1976 of_object_dump((loci_writer_f)fprintf, out, obj);
1977 of_object_delete(obj);
1978""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1979 else:
1980 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001981 obj = (of_object_t *)%(cls)s_new(%(version)s);
1982 of_object_dump((loci_writer_f)fprintf, out, obj);
1983 of_object_delete(obj);
1984""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001985
Rich Lanea06d0c32013-03-25 08:52:03 -07001986 out.write("""
1987 fclose(out);
1988 return TEST_PASS;
1989}
1990""")
1991
1992def gen_ident_tests(out):
1993 """
1994 Generate tests for identifiers
1995
1996 For all idents, instantiate, test version supported macros
1997 For flags, set it, test it, clear it, test it.
1998 """
1999 out.write("""
2000/**
2001 * Test cases for all flag accessor macros
2002 * These only test self consistency (and that they compile)
2003 */
2004int
2005test_ident_macros(void)
2006{
2007 int value __attribute__((unused));
2008 uint32_t flags;
2009
2010""")
2011
2012 for ident, info in of_g.identifiers.items():
2013 if not identifiers.defined_versions_agree(of_g.identifiers,
2014 of_g.target_version_list,
2015 ident):
2016 # @fixme
2017 continue
2018 out.write(" value = %s;\n" % ident)
2019 for version in of_g.target_version_list:
2020 if version in info["values_by_version"].keys():
2021 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2022 (ident, of_g.of_version_wire2name[version]))
2023 else:
2024 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2025 (ident, of_g.of_version_wire2name[version]))
2026 if flags.ident_is_flag(ident):
2027 # Grab first supported version
2028 for version in info["values_by_version"]:
2029 break
2030 out.write("""
2031 flags = 0;
2032 %(ident)s_SET(flags, %(ver_name)s);
2033 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2034 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2035 %(ident)s_CLEAR(flags, %(ver_name)s);
2036 TEST_ASSERT(flags == 0);
2037 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2038""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2039
2040 out.write("""
2041 return TEST_PASS;
2042}
2043""")
2044
Rich Laneccae0312013-07-21 23:34:13 -07002045def gen_datafiles_tests(out, name):
2046 tests = []
2047 for filename in test_data.list_files():
2048 data = test_data.read(filename)
2049 if not 'c' in data:
2050 continue
2051 name = filename[:-5].replace("/", "_")
2052 tests.append(dict(name=name,
2053 filename=filename,
2054 c=data['c'],
2055 binary=data['binary']))
2056
2057 util.render_template(out, "test_data.c", tests=tests)