blob: 6e88d6ddf22aa3cc6867cbab7d0deec95dd4d3c7 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Test case generation functions
30
31@fixme Update the following
32The following components are generated.
33
34test_common.[ch]: A collection of common code for tests. Currently
35this includes the ability to set the scalar members of an object with
36incrementing values and then similarly verify those values
37
38test_scalar_acc.c: Instantiate each type of object, then set and get
39scalar values in the objects.
40
41test_list.c: Instantiate each type of list, add an element of each
42type the list supports, setting scalar values of the elements.
43
44test_match.c: Various tests for match objects
45
46test_msg.c: Instantiate top level messages
47
48These will move towards unified tests that do the following:
49
50Create or init an object.
51Populate the object with incrementing values.
52Possibly transform the object in some way (e.g., run the underlying
53wire buffer through a parse routine).
54Verify that the members all have the appropriate value
55
56Through out, checking the consistency of memory and memory operations
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +090057is done with mcheck (if available).
Rich Lanea06d0c32013-03-25 08:52:03 -070058
59"""
60
61import sys
Andreas Wundsam76db0062013-11-15 13:34:41 -080062import c_gen.of_g_legacy as of_g
Andreas Wundsam542a13c2013-11-15 13:28:55 -080063import c_gen.match as match
64import c_gen.flags as flags
Rich Lanea06d0c32013-03-25 08:52:03 -070065from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080066import c_gen.type_maps as type_maps
67import c_gen.loxi_utils_legacy as loxi_utils
68import c_gen.identifiers as identifiers
Rich Laneccae0312013-07-21 23:34:13 -070069import util
70import test_data
Rich Lane79c87192014-03-04 10:56:59 -080071import loxi_globals
72from loxi_ir import *
Rich Lanea06d0c32013-03-25 08:52:03 -070073
74def var_name_map(m_type):
75 """
76 Map a type to a generic variable name for the type.
77 @param m_type The data type
78
79 Used mostly in test code generation, but also for the dup functions.
80 """
81 _var_name_map= dict(
82 uint8_t="val8",
83 uint16_t="val16",
84 uint32_t="val32",
85 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070086 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_port_no_t="port_no",
88 of_fm_cmd_t="fm_cmd",
89 of_wc_bmap_t="wc_bmap",
90 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070091 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070092 of_table_name_t="table_name",
93 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070094 of_serial_num_t="ser_num",
Rich Lanef8a3d002014-03-19 13:33:52 -070095 of_str64_t="str64",
Andreas Wundsam53256162013-05-02 14:05:53 -070096 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070097 of_ipv6_t="ipv6",
98 # Non-scalars; more TBD
99 of_octets_t="octets",
100 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700101 of_match_t="match",
Rich Lanec247ade2014-11-07 09:33:24 -0800102 of_oxm_t="oxm",
103 of_bsn_vport_t="bsn_vport",
Rich Lane41b278f2014-10-17 18:29:56 -0700104 of_table_desc_t="table_desc",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700105 # BSN extensions
106 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700107 of_bitmap_128_t="bitmap_128",
Rich Lane119289c2014-12-01 13:44:08 -0800108 of_bitmap_512_t="bitmap_512",
Rich Lanefab0c822013-12-30 11:46:48 -0800109 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700110 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700111
112 if m_type.find("of_list_") == 0:
113 return "list"
114 if m_type in of_g.of_mixed_types:
115 return of_g.of_mixed_types[m_type]["short_name"]
116 return _var_name_map[m_type]
117
118integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
119 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700120 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700121string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700122 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700123 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
Rich Lane119289c2014-12-01 13:44:08 -0800124 "of_str64_t", "of_bitmap_512_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700125
126scalar_types = integer_types[:]
127scalar_types.extend(string_types)
128
Rich Lane1f315aa2014-10-13 17:11:35 -0700129# When embedding an object inside of another object we have to pick a single
130# subclass to use, unlike lists where we use all subclasses.
131embedded_subclasses = {
Rich Lanec247ade2014-11-07 09:33:24 -0800132 'of_oxm_t': 'of_oxm_eth_type',
133 'of_bsn_vport_t': 'of_bsn_vport_q_in_q',
Rich Lane1f315aa2014-10-13 17:11:35 -0700134}
135
Rich Lanea06d0c32013-03-25 08:52:03 -0700136def ignore_member(cls, version, m_name, m_type):
137 """
138 Filter out names or types that either don't have accessors
139 or those that should not be messed with
140 or whose types we're not ready to deal with yet.
141 """
Rich Lane79c87192014-03-04 10:56:59 -0800142
143 uclass = loxi_globals.unified.class_by_name(cls)
144 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700145 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800146
Rich Lane79c87192014-03-04 10:56:59 -0800147 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800148 return True
Rich Lane79c87192014-03-04 10:56:59 -0800149
Rich Lanea06d0c32013-03-25 08:52:03 -0700150 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
151
152def gen_fill_string(out):
153 out.write("""
154
155/**
156 * The increment to use on values inside a string
157 */
158#define OF_TEST_STR_INCR 3
159
160/**
161 * Fill in a buffer with incrementing values starting
162 * at the given offset with the given value
163 * @param buf The buffer to fill
164 * @param value The value to use for data
165 * @param len The number of bytes to fill
166 */
167
168void
169of_test_str_fill(uint8_t *buf, int value, int len)
170{
171 int i;
172
173 for (i = 0; i < len; i++) {
174 *buf = value;
175 value += OF_TEST_STR_INCR;
176 buf++;
177 }
178}
179
180/**
181 * Given a buffer, verify that it's filled as above
182 * @param buf The buffer to check
183 * @param value The value to use for data
184 * @param len The number of bytes to fill
185 * @return Boolean True on equality (success)
186 */
187
188int
189of_test_str_check(uint8_t *buf, int value, int len)
190{
191 int i;
192 uint8_t val8;
193
194 val8 = value;
195
196 for (i = 0; i < len; i++) {
197 if (*buf != val8) {
198 return 0;
199 }
200 val8 += OF_TEST_STR_INCR;
201 buf++;
202 }
203
204 return 1;
205}
206
207/**
208 * Global that determines how octets should be populated
209 * -1 means use value % MAX (below) to determine length
210 * 0, 1, ... means used that fixed length
211 *
212 * Note: Was 16K, but that made objects too big. May add flexibility
213 * to call populate with a max parameter for length
214 */
215int octets_pop_style = -1;
216#define OCTETS_MAX_VALUE (128) /* 16K was too big */
217#define OCTETS_MULTIPLIER 6367 /* A prime */
218
219int
220of_octets_populate(of_octets_t *octets, int value)
221{
222 if (octets_pop_style < 0) {
223 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
224 } else {
225 octets->bytes = octets_pop_style;
226 }
227
228 if (octets->bytes != 0) {
229 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
230 return 0;
231 }
232 of_test_str_fill(octets->data, value, octets->bytes);
233 value += 1;
234 }
235
236 return value;
237}
238
239int
240of_octets_check(of_octets_t *octets, int value)
241{
242 int len;
243
244 if (octets_pop_style < 0) {
245 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
246 TEST_ASSERT(octets->bytes == len);
247 } else {
248 TEST_ASSERT(octets->bytes == octets_pop_style);
249 }
250
251 if (octets->bytes != 0) {
252 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
253 == 1);
254 value += 1;
255 }
256
257 return value;
258}
259
260int
261of_match_populate(of_match_t *match, of_version_t version, int value)
262{
263 MEMSET(match, 0, sizeof(*match));
264 match->version = version;
265""")
266
Rich Laned56f8d22014-05-06 14:52:55 -0700267 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700268 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700269 if (version == %d) {\
270""" % wire_version)
271 for key in keys:
272 entry = match.of_match_members[key]
273 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700274 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
275 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
276 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700277""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
278 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700279 }
280
Rich Laned56f8d22014-05-06 14:52:55 -0700281""")
282
Rich Laneb4a63a52014-05-22 14:41:57 -0700283 for wire_version, match_keys in match.match_keys.items():
284 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700285
286 out.write("""
287 if (value % 2) {
288 /* Sometimes set ipv4 addr masks to non-exact */
289 match->masks.ipv4_src = 0xffff0000;
290 match->masks.ipv4_dst = 0xfffff800;
291 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700292
293 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700294 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700295 return value;
296}
297
298int
299of_match_check(of_match_t *match, of_version_t version, int value)
300{
301 of_match_t check;
302
303 value = of_match_populate(&check, match->version, value);
304 TEST_ASSERT(value != 0);
305 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
306
307 return value;
308}
309""")
310
311def gen_common_test_header(out, name):
312 loxi_utils.gen_c_copy_license(out)
313 out.write("""
314/*
315 * Test header file
316 *
317 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
318 */
319
320#if !defined(_TEST_COMMON_H_)
321#define _TEST_COMMON_H_
322
323#define DISABLE_WARN_UNUSED_RESULT
324#include <loci/loci.h>
325#include <locitest/of_dup.h>
326#include <locitest/unittest.h>
327
328extern int global_error;
329extern int exit_on_error;
330
331/* @todo Make option for -k to continue tests if errors */
332#define RUN_TEST(test) do { \\
333 int rv; \\
334 TESTCASE(test, rv); \\
335 if (rv != TEST_PASS) { \\
336 global_error=1; \\
337 if (exit_on_error) return(1); \\
338 } \\
339 } while(0)
340
341#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
342#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
343
344/*
345 * Declarations of functions to populate scalar values in a a class
346 */
347
348extern void of_test_str_fill(uint8_t *buf, int value, int len);
349extern int of_test_str_check(uint8_t *buf, int value, int len);
350
351
352extern int of_octets_populate(of_octets_t *octets, int value);
353extern int of_octets_check(of_octets_t *octets, int value);
354extern int of_match_populate(of_match_t *match, of_version_t version,
355 int value);
356extern int of_match_check(of_match_t *match, of_version_t version, int value);
357extern int test_ident_macros(void);
358extern int test_dump_objs(void);
359
360/* In test_match_utils.c */
361extern int test_match_utils(void);
362
363extern int run_unified_accessor_tests(void);
364extern int run_match_tests(void);
365extern int run_utility_tests(void);
366
367extern int run_scalar_acc_tests(void);
368extern int run_list_tests(void);
369extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700370
371extern int run_validator_tests(void);
372
373extern int run_list_limits_tests(void);
374
375extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700376extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700377
378""")
379
380 for version in of_g.of_version_range:
381 for cls in of_g.standard_class_order:
382 if not loxi_utils.class_in_version(cls, version):
383 continue
Rich Lane6171e632014-11-07 10:23:38 -0800384 if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700385 continue
386 out.write("""
387extern int %(cls)s_%(v_name)s_populate(
388 %(cls)s_t *obj, int value);
389extern int %(cls)s_%(v_name)s_check(
390 %(cls)s_t *obj, int value);
391extern int %(cls)s_%(v_name)s_populate_scalars(
392 %(cls)s_t *obj, int value);
393extern int %(cls)s_%(v_name)s_check_scalars(
394 %(cls)s_t *obj, int value);
395""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
396
397 out.write("""
398/*
399 * Declarations for list population and check primitives
400 */
401""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700402
Rich Lanea06d0c32013-03-25 08:52:03 -0700403 for version in of_g.of_version_range:
404 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700405 if version in of_g.unified[cls]:
406 out.write("""
407extern int
408 list_setup_%(cls)s_%(v_name)s(
409 %(cls)s_t *list, int value);
410extern int
411 list_check_%(cls)s_%(v_name)s(
412 %(cls)s_t *list, int value);
413""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
414
415 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
416
417def gen_common_test(out, name):
418 """
419 Generate common test content including main
420 """
421 loxi_utils.gen_c_copy_license(out)
422 out.write("""
423/*
424 * Common test code for LOCI
425 *
426 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
427 */
428
429#define DISABLE_WARN_UNUSED_RESULT
430#include "loci_log.h"
431#include <loci/loci_obj_dump.h>
432#include <locitest/unittest.h>
433#include <locitest/test_common.h>
434
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900435/* mcheck is a glibc extension */
436#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700437#include <mcheck.h>
438#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900439#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700440#define MCHECK_INIT do { } while (0)
441#endif
442
443/**
444 * Exit on error if set to 1
445 */
446int exit_on_error = 1;
447
448/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700449 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700450 */
451int global_error = 0;
452
453extern int run_unified_accessor_tests(void);
454extern int run_match_tests(void);
455extern int run_utility_tests(void);
456
457extern int run_scalar_acc_tests(void);
458extern int run_list_tests(void);
459extern int run_message_tests(void);
460
461/**
462 * Macros for initializing and checking scalar types
463 *
464 * @param var The variable being initialized or checked
465 * @param val The integer value to set/check against, see below
466 *
467 * Note that equality means something special for strings. Each byte
468 * is initialized to an incrementing value. So check is done against that.
469 *
470 */
471
472""")
473 for t in scalar_types:
474 if t in integer_types:
475 out.write("""
476#define VAR_%s_INIT(var, val) var = (%s)(val)
477#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
478""" % (t.upper(), t, t.upper(), t))
479 else:
480 out.write("""
481#define VAR_%s_INIT(var, val) \\
482 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
483#define VAR_%s_CHECK(var, val) \\
484 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
485""" % (t.upper(), t.upper()))
486
487 gen_fill_string(out)
488 gen_scalar_set_check_funs(out)
489 gen_list_set_check_funs(out)
490 gen_unified_accessor_funs(out)
491
492 gen_ident_tests(out)
493 gen_log_test(out)
494
495def gen_message_scalar_test(out, name):
496 """
497 Generate test cases for message objects, scalar accessors
498 """
499
500 loxi_utils.gen_c_copy_license(out)
501 out.write("""
502/**
503 *
504 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
505 *
506 * Message-scalar tests for all versions
507 */
508
509#include <locitest/test_common.h>
510""")
511 for version in of_g.of_version_range:
512 v_name = loxi_utils.version_to_name(version)
513 out.write("""
514/**
515 * Message-scalar tests for version %s
516 */
517""" % v_name)
518 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800519 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700520 continue
521 if version in of_g.unified[cls]:
522 message_scalar_test(out, version, cls)
523
524 out.write("""
525int
526run_scalar_acc_tests(void)
527{
528""")
529 for version in of_g.of_version_range:
530 v_name = loxi_utils.version_to_name(version)
531 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800532 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700533 continue
534 if version in of_g.unified[cls]:
535 test_name = "%s_%s" % (cls, v_name)
536 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
537
538 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700539
Rich Lanea06d0c32013-03-25 08:52:03 -0700540def message_scalar_test(out, version, cls):
541 """
542 Generate one test case for the given version and class
543 """
544
545 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700546 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700547 v_name = loxi_utils.version_to_name(version)
548
549 out.write("""
550static int
551test_%(cls)s_%(v_name)s_scalar(void)
552{
553 %(cls)s_t *obj;
554
555 obj = %(cls)s_new(%(v_name)s);
556 TEST_ASSERT(obj != NULL);
557 TEST_ASSERT(obj->version == %(v_name)s);
558 TEST_ASSERT(obj->length == %(length)d);
559 TEST_ASSERT(obj->parent == NULL);
560 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700561""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700562 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700563
564 # If this class is a concrete member of an inheritance hierarchy,
565 # run the hierarchy's root wire type parser and assert it returns
566 # the expected object id.
567 ofclass = loxi_globals.unified.class_by_name(cls)
568 if ofclass and not ofclass.virtual:
569 root = ofclass
570 while root.superclass:
571 root = root.superclass
572 if root.virtual:
573 out.write("""
574 {
575 of_object_id_t object_id;
576 %(root_cls)s_wire_object_id_get(obj, &object_id);
577 TEST_ASSERT(object_id == %(u_cls)s);
578 }
579""" % dict(root_cls=root.name, u_cls=cls.upper()))
580
Rich Lanea06d0c32013-03-25 08:52:03 -0700581 if not type_maps.class_is_virtual(cls):
582 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700583 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700584 int length;
585
Rich Lanedc46fe22014-04-03 15:10:38 -0700586 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700587 TEST_ASSERT(length == %(length)d);
588 }
589
590 /* Set up incrementing values for scalar members */
591 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
592
593 /* Check values just set */
594 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700595""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700596 v_name=v_name, length=length, version=version))
597
598 out.write("""
599 %(cls)s_delete(obj);
600
601 /* To do: Check memory */
602 return TEST_PASS;
603}
604""" % dict(cls=cls))
605
606# Get the members and list of scalar types for members of a given class
607def scalar_member_types_get(cls, version):
608 member_types = []
609
610 if not version in of_g.unified[cls]:
611 return ([], [])
612
613 if "use_version" in of_g.unified[cls][version]:
614 v = of_g.unified[cls][version]["use_version"]
615 members = of_g.unified[cls][v]["members"]
616 else:
617 members = of_g.unified[cls][version]["members"]
618 # Accumulate variables that are supported
619 for member in members:
620 m_type = member["m_type"]
621 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700622 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700623 ignore_member(cls, version, m_name, m_type)):
624 continue
625 if not m_type in member_types:
626 member_types.append(m_type)
627
628 return (members, member_types)
629
630def scalar_funs_instance(out, cls, version, members, member_types):
631 """
632 Generate one instance of scalar set/check functions
633 """
634 out.write("""
635/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700636 * Populate the scalar values in obj of type %(cls)s,
637 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700638 * @param obj Pointer to an object to populate
639 * @param value The seed value to use in populating the object
640 * @returns The value after increments for this object's values
641 */
642int %(cls)s_%(v_name)s_populate_scalars(
643 %(cls)s_t *obj, int value) {
644""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
645 # Declare string types
646 for t in member_types:
647 out.write(" %s %s;\n" % (t, var_name_map(t)))
648 for member in members:
649 m_type = member["m_type"]
650 m_name = member["name"]
651 if (not loxi_utils.type_is_scalar(m_type) or
652 ignore_member(cls, version, m_name, m_type)):
653 continue
654 v_name = var_name_map(m_type);
655 out.write("""
656 VAR_%(u_type)s_INIT(%(v_name)s, value);
657 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
658 value += 1;
659""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
660 out.write("""
661 return value;
662}
663""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700664
Rich Lanea06d0c32013-03-25 08:52:03 -0700665 out.write("""
666/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700667 * Check scalar values in obj of type %(cls)s,
668 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700669 * @param obj Pointer to an object to check
670 * @param value Starting value for checking
671 * @returns The value after increments for this object's values
672 */
673int %(cls)s_%(v_name)s_check_scalars(
674 %(cls)s_t *obj, int value) {
675""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
676
677 for t in member_types:
678 out.write(" %s %s;\n" % (t, var_name_map(t)))
679 for member in members:
680 m_type = member["m_type"]
681 m_name = member["name"]
682 if (not loxi_utils.type_is_scalar(m_type) or
683 ignore_member(cls, version, m_name, m_type)):
684 continue
685 v_name = var_name_map(m_type);
686 out.write("""
687 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
688 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
689 value += 1;
690""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
691
692 out.write("""
693 return value;
694}
695
696""")
697
698def gen_scalar_set_check_funs(out):
699 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700700 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700701 set and check their values
702 """
703 for version in of_g.of_version_range:
704 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800705 if type_maps.class_is_virtual(cls):
Rich Lanee499bd12014-10-28 15:25:09 -0700706 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700707 (members, member_types) = scalar_member_types_get(cls, version)
708 scalar_funs_instance(out, cls, version, members, member_types)
709
710
711# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700712def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700713 base_type = loxi_utils.list_to_entry_type(cls)
714 setup_template = """
715 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700716 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700717 value = %(subcls)s_%(v_name)s_populate(
718 %(inst)s, value);
719 cur_len += %(inst)s->length;
720 TEST_ASSERT(list->length == cur_len);
721"""
722 out.write("""
723 /* Append two instances of type %s */
724""" % subcls)
725 for i in range(2):
726 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700727 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700728 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700729 version=version))
730
Rich Lane9afc3b92014-04-09 22:55:53 -0700731def check_instance(out, cls, subcls, instance, v_name, version, last):
732 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700733 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
734 value = %(subcls)s_%(v_name)s_check(
735 %(inst)s, value);
736 TEST_ASSERT(value != 0);
737"""
738 out.write("\n /* Check two instances of type %s */" % instance)
739
Andreas Wundsam53256162013-05-02 14:05:53 -0700740 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700741 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700742 inst=instance, subcls=subcls,
743 v_name=loxi_utils.version_to_name(version)))
744 out.write("""\
745 TEST_OK(%(cls)s_next(list, &elt));
746""" % dict(cls=cls))
747
Andreas Wundsam53256162013-05-02 14:05:53 -0700748 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700749 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700750 inst=instance, subcls=subcls,
751 v_name=loxi_utils.version_to_name(version)))
752 if last:
753 out.write("""\
754 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
755""" % dict(cls=cls))
756 else:
757 out.write("""\
758 TEST_OK(%(cls)s_next(list, &elt));
759""" % dict(cls=cls))
760
761def setup_list_fn(out, version, cls):
762 """
763 Generate a helper function that populates a list with two
764 of each type of subclass it supports
765 """
766 out.write("""
767/**
768 * Set up a list of type %(cls)s with two of each type of subclass
769 */
770int
771list_setup_%(cls)s_%(v_name)s(
772 %(cls)s_t *list, int value)
773{
774""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
775 base_type = loxi_utils.list_to_entry_type(cls)
776 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -0700777 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -0700778 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700779 (void) elt;
780 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700781""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700782
Rich Lanea06d0c32013-03-25 08:52:03 -0700783 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700784 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 -0700785 v_name = loxi_utils.version_to_name(version)
786
Rich Lanee98ee5d2014-10-14 10:43:44 -0700787 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700788 out.write(" /* No subclasses for %s */\n"% base_type)
789 out.write(" %s_t *elt_p;\n" % base_type)
790 out.write("\n elt_p = &elt;\n")
791 else:
792 out.write(" /* Declare pointers for each subclass */\n")
793 for instance, subcls in sub_classes:
794 out.write(" %s_t *%s;\n" % (subcls, instance))
795 out.write("\n /* Instantiate pointers for each subclass */\n")
796 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -0700797 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -0700798
Rich Lanee98ee5d2014-10-14 10:43:44 -0700799 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700800 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700801 else:
802 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700803 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700804 out.write("""
805
806 return value;
807}
808""")
809
810def check_list_fn(out, version, cls):
811 """
812 Generate a helper function that checks a list populated by above fn
813 """
814 out.write("""
815/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700816 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700817 * list_setup_%(cls)s_%(v_name)s
818 */
819int
820list_check_%(cls)s_%(v_name)s(
821 %(cls)s_t *list, int value)
822{
823""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
824 base_type = loxi_utils.list_to_entry_type(cls)
825 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -0700826 of_object_t elt;
Rich Lanee98ee5d2014-10-14 10:43:44 -0700827 (void) elt;
Rich Lanea06d0c32013-03-25 08:52:03 -0700828""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700829
Rich Lanea06d0c32013-03-25 08:52:03 -0700830 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700831 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 -0700832 v_name = loxi_utils.version_to_name(version)
833
Rich Lanee98ee5d2014-10-14 10:43:44 -0700834 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -0700835 out.write(" /* No subclasses for %s */\n"% base_type)
836 out.write(" %s_t *elt_p;\n" % base_type)
837 out.write("\n elt_p = &elt;\n")
838 else:
839 out.write(" /* Declare pointers for each subclass */\n")
840 for instance, subcls in sub_classes:
841 out.write(" %s_t *%s;\n" % (subcls, instance))
842 out.write("\n /* Instantiate pointers for each subclass */\n")
843 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -0700844 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -0700845
Rich Lanee98ee5d2014-10-14 10:43:44 -0700846 if not type_maps.class_is_virtual(base_type) or sub_classes:
847 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
848
849 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700850 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700851 else:
852 count = 0
853 for instance, subcls in sub_classes:
854 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700855 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700856 version, count==len(sub_classes))
857
858 out.write("""
859 return value;
860}
861""" % dict(base_type=base_type))
862
863def gen_list_set_check_funs(out):
864 for version in of_g.of_version_range:
865 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700866 if version in of_g.unified[cls]:
867 setup_list_fn(out, version, cls)
868 check_list_fn(out, version, cls)
869
870# Maybe: Get a map from list class to parent, mem_name of container
871
872def list_test(out, version, cls):
873 out.write("""
874static int
875test_%(cls)s_%(v_name)s(void)
876{
877""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
878 base_type = loxi_utils.list_to_entry_type(cls)
879
880 out.write(""" %(cls)s_t *list;
881 int value = 1;
882""" % dict(cls=cls, base_type=base_type))
883
884 out.write("""
885 list = %(cls)s_new(%(v_name)s);
886 TEST_ASSERT(list != NULL);
887 TEST_ASSERT(list->version == %(v_name)s);
888 TEST_ASSERT(list->length == 0);
889 TEST_ASSERT(list->parent == NULL);
890 TEST_ASSERT(list->object_id == %(enum_cls)s);
891
892 value = list_setup_%(cls)s_%(v_name)s(list, value);
893 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700894""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700895 enum_cls=loxi_utils.enum_name(cls)))
896
897 out.write("""
898 /* Now check values */
899 value = 1;
900 value = list_check_%(cls)s_%(v_name)s(list, value);
901 TEST_ASSERT(value != 0);
902""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
903
904 out.write("""
905 %(cls)s_delete(list);
906
907 return TEST_PASS;
908}
909""" % dict(cls=cls))
910
911def gen_list_test(out, name):
912 """
913 Generate base line test cases for lists
914 @param out The file handle to write to
915 """
916
917 loxi_utils.gen_c_copy_license(out)
918 out.write("""
919/**
920 *
921 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
922 *
923 * Message-scalar tests for all versions
924 */
925
926#include <locitest/test_common.h>
927""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700928
Rich Lanea06d0c32013-03-25 08:52:03 -0700929 for version in of_g.of_version_range:
930 v_name = loxi_utils.version_to_name(version)
931 out.write("""
932/**
933 * Baseline list tests for version %s
934 */
935""" % v_name)
936 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700937 if version in of_g.unified[cls]:
938 list_test(out, version, cls)
939
940 out.write("""
941int
942run_list_tests(void)
943{
944""")
945 for version in of_g.of_version_range:
946 v_name = loxi_utils.version_to_name(version)
947 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700948 if version in of_g.unified[cls]:
949 test_name = "%s_%s" % (cls, v_name)
950 out.write(" RUN_TEST(%s);\n" % test_name)
951
952 out.write("\n return TEST_PASS;\n}\n");
953
954def gen_match_test(out, name):
955 """
956 Generate baseline tests for match functions
957 """
958
959 loxi_utils.gen_c_copy_license(out)
960 out.write("""\
961/**
962 *
963 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
964 *
965 * Message-scalar tests for all versions
966 * @fixme These are mostly hard coded now.
967 */
968
969#include <locitest/test_common.h>
970
971static int
972test_match_1(void)
973{
Rich Lanef87f4c32014-10-14 11:56:02 -0700974""")
975
976 for version in of_g.of_version_range:
977 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
978
979 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700980 of_match_t match;
981 int value = 1;
982 int idx;
983 uint32_t exp_value;
984
985 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700986 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700987 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
988 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
989 if (idx < 32) {
990 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
991 }
992 }
993""")
994
995 for version in of_g.of_version_range:
996 out.write("""
997 /* Create/populate/convert and delete for version %(v_name)s */
998 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
999 TEST_ASSERT(m_v%(version)d != NULL);
1000 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
1001 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
1002 of_match_v%(version)d_delete(m_v%(version)d);
1003""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1004
1005 out.write("""
1006 return TEST_PASS;
1007}
1008""")
1009
1010 out.write("""
1011static int
1012test_match_2(void)
1013{
Rich Lanef87f4c32014-10-14 11:56:02 -07001014""")
1015
1016 for version in of_g.of_version_range:
1017 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
1018
1019 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -07001020 of_match_t match1;
1021 of_match_t match2;
1022 int value = 1;
1023""")
1024
1025 for version in of_g.of_version_range:
1026 out.write("""
1027 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1028 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1029 TEST_ASSERT(m_v%(version)d != NULL);
1030 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1031 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1032 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1033 of_match_v%(version)d_delete(m_v%(version)d);
1034""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1035
1036 out.write("""
1037 return TEST_PASS;
1038}
1039""")
1040
1041 out.write("""
1042static int
1043test_match_3(void)
1044{
1045 of_match_t match1;
1046 of_match_t match2;
1047 int value = 1;
1048 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001049 of_object_storage_t storage;
1050 memset(&storage, 0, sizeof(storage));
1051 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001052""")
1053 for version in of_g.of_version_range:
1054 out.write("""
1055 /* Serialize to version %(v_name)s */
1056 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001057 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001058 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001059 storage.obj.wbuf->buf = octets.data;
1060 storage.obj.wbuf->alloc_bytes = octets.bytes;
1061 storage.obj.wbuf->current_bytes = octets.bytes;
1062 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001063 OF_ERROR_NONE);
1064 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1065 FREE(octets.data);
1066""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1067
1068 out.write("""
1069 return TEST_PASS;
1070}
1071""")
1072
1073 out.write("""
1074int run_match_tests(void)
1075{
1076 RUN_TEST(match_1);
1077 RUN_TEST(match_2);
1078 RUN_TEST(match_3);
1079 RUN_TEST(match_utils);
1080
1081 return TEST_PASS;
1082}
1083""")
1084
1085def gen_msg_test(out, name):
1086 loxi_utils.gen_c_copy_license(out)
1087 out.write("""
1088/**
1089 *
1090 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1091 *
1092 * Message-scalar tests for all versions
1093 */
1094
1095#include <locitest/test_common.h>
1096""")
1097 for version in of_g.of_version_range:
1098 for cls in of_g.ordered_messages:
1099 if not (cls, version) in of_g.base_length:
1100 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001101 if type_maps.class_is_virtual(cls):
1102 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -07001103 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001104 out.write("""
1105static int
1106test_%(cls)s_create_%(v_name)s(void)
1107{
1108 %(cls)s_t *obj;
1109 uint8_t *msg_buf;
1110 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001111 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001112 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001113
1114 obj = %(cls)s_new(%(v_name)s);
1115 TEST_ASSERT(obj != NULL);
1116 TEST_ASSERT(obj->version == %(v_name)s);
1117 TEST_ASSERT(obj->length == %(bytes)d);
1118 TEST_ASSERT(obj->parent == NULL);
1119 TEST_ASSERT(obj->object_id == %(enum)s);
1120
Rich Lanea4b68302014-03-12 15:17:58 -07001121 of_header_wire_object_id_get(obj, &object_id);
1122 TEST_ASSERT(object_id == %(enum)s);
1123
Rich Lanea06d0c32013-03-25 08:52:03 -07001124 /* Set up incrementing values for scalar members */
1125 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1126 TEST_ASSERT(value != 0);
1127
Rich Lanebb8f17c2014-06-12 13:14:09 -07001128 len = obj->length;
1129
Rich Lanea06d0c32013-03-25 08:52:03 -07001130 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001131 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1132 TEST_ASSERT(msg_buf != NULL);
1133 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001134 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001135
1136 TEST_ASSERT(obj != NULL);
1137
1138 /* @fixme Set up all message objects (recursively?) */
1139
1140 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1141 TEST_ASSERT(value != 0);
1142
1143 %(cls)s_delete(obj);
1144
1145 return TEST_PASS;
1146}
1147""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1148 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1149
1150 out.write("""
1151int
1152run_message_tests(void)
1153{
1154""")
1155 for version in of_g.of_version_range:
1156 for cls in of_g.ordered_messages:
1157 if not (cls, version) in of_g.base_length:
1158 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001159 if type_maps.class_is_virtual(cls):
1160 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001161 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1162 out.write(" RUN_TEST(%s);\n" % test_name)
1163
1164 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001165
Rich Lanea06d0c32013-03-25 08:52:03 -07001166
1167def gen_list_setup_check(out, cls, version):
1168 """
1169 Generate functions that populate and check a list with two
1170 of each type of subclass it supports
1171 """
1172 out.write("""
1173/**
1174 * Populate a list of type %(cls)s with two of each type of subclass
1175 * @param list Pointer to the list to be populated
1176 * @param value The seed value to use in populating the list
1177 * @returns The value after increments for this object's values
1178 */
1179int
1180%(cls)s_%(v_name)s_populate(
1181 %(cls)s_t *list, int value)
1182{
1183""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1184 base_type = loxi_utils.list_to_entry_type(cls)
1185 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001186 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001187 int cur_len = 0;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001188 (void) elt;
1189 (void) cur_len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001190""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001191
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001193 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 -07001194 v_name = loxi_utils.version_to_name(version)
1195
Rich Lanee98ee5d2014-10-14 10:43:44 -07001196 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001197 out.write(" /* No subclasses for %s */\n"% base_type)
1198 out.write(" %s_t *elt_p;\n" % base_type)
1199 out.write("\n elt_p = &elt;\n")
1200 else:
1201 out.write(" /* Declare pointers for each subclass */\n")
1202 for instance, subcls in sub_classes:
1203 out.write(" %s_t *%s;\n" % (subcls, instance))
1204 out.write("\n /* Instantiate pointers for each subclass */\n")
1205 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001206 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001207
Rich Lanee98ee5d2014-10-14 10:43:44 -07001208 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001209 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001210 else:
1211 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001212 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001213 out.write("""
1214 return value;
1215}
1216""")
1217 out.write("""
1218/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001219 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001220 * %(cls)s_%(v_name)s_populate
1221 * @param list Pointer to the list that was populated
1222 * @param value Starting value for checking
1223 * @returns The value after increments for this object's values
1224 */
1225int
1226%(cls)s_%(v_name)s_check(
1227 %(cls)s_t *list, int value)
1228{
1229""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1230 base_type = loxi_utils.list_to_entry_type(cls)
1231 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001232 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001233 int count = 0;
1234 int rv;
1235""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001236
Rich Lanea06d0c32013-03-25 08:52:03 -07001237
1238 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001239 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 -07001240 v_name = loxi_utils.version_to_name(version)
1241
Rich Lanee98ee5d2014-10-14 10:43:44 -07001242 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001243 entry_count = 2
1244 out.write(" /* No subclasses for %s */\n"% base_type)
1245 out.write(" %s_t *elt_p;\n" % base_type)
1246 out.write("\n elt_p = &elt;\n")
1247 else:
1248 entry_count = 2 * len(sub_classes) # Two of each type appended
1249 out.write(" /* Declare pointers for each subclass */\n")
1250 for instance, subcls in sub_classes:
1251 out.write(" %s_t *%s;\n" % (subcls, instance))
1252 out.write("\n /* Instantiate pointers for each subclass */\n")
1253 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001254 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001255
Rich Lanee98ee5d2014-10-14 10:43:44 -07001256 if not type_maps.class_is_virtual(base_type) or sub_classes:
1257 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1258
1259 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001260 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001261 version, True)
1262 else:
1263 count = 0
1264 for instance, subcls in sub_classes:
1265 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001266 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001267 version, count==len(sub_classes))
1268 out.write("""
1269""" % dict(base_type=base_type))
1270
1271 out.write("""
1272 /* Do an iterate to test the iterator */
1273 %(u_cls)s_ITER(list, &elt, rv) {
1274 count += 1;
1275 }
1276
1277 TEST_ASSERT(rv == OF_ERROR_RANGE);
1278 TEST_ASSERT(count == %(entry_count)d);
1279
1280 /* We shoehorn a test of the dup functions here */
1281 {
1282 %(cls)s_t *dup;
1283
1284 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1285 TEST_ASSERT(dup->length == list->length);
1286 TEST_ASSERT(dup->object_id == list->object_id);
1287 TEST_ASSERT(dup->version == list->version);
1288 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1289 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1290 of_object_delete((of_object_t *)dup);
1291
1292 /* And now for the generic dup function */
1293 TEST_ASSERT((dup = (%(cls)s_t *)
1294 of_object_dup(list)) != NULL);
1295 TEST_ASSERT(dup->length == list->length);
1296 TEST_ASSERT(dup->object_id == list->object_id);
1297 TEST_ASSERT(dup->version == list->version);
1298 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1299 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1300 of_object_delete((of_object_t *)dup);
1301 }
1302
1303 return value;
1304}
1305""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1306
1307
1308def gen_class_setup_check(out, cls, version):
1309 out.write("""
1310/**
1311 * Populate all members of an object of type %(cls)s
1312 * with incrementing values
1313 * @param obj Pointer to an object to populate
1314 * @param value The seed value to use in populating the object
1315 * @returns The value after increments for this object's values
1316 */
1317
1318int
1319%(cls)s_%(v_name)s_populate(
1320 %(cls)s_t *obj, int value)
1321{
1322""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1323 members, member_types = loxi_utils.all_member_types_get(cls, version)
1324 for m_type in member_types:
1325 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1326 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001327 elif m_type in embedded_subclasses:
1328 subcls = embedded_subclasses[m_type]
1329 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001330 else:
1331 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1332 out.write("""
1333 /* Run thru accessors after new to ensure okay */
1334""")
1335 for member in members:
1336 m_type = member["m_type"]
1337 m_name = member["name"]
1338 if loxi_utils.skip_member_name(m_name):
1339 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001340 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001341 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001342 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1343 out.write("""\
1344 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1345""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1346 else:
1347 sub_cls = m_type[:-2] # Trim _t
1348 out.write("""\
1349 {
1350 %(sub_cls)s_t sub_cls;
1351
1352 /* Test bind */
1353 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1354 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001355""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001356 m_name=m_name, sub_cls=sub_cls,
1357 v_name=loxi_utils.version_to_name(version)))
1358
1359 out.write("""
1360 value = %(cls)s_%(v_name)s_populate_scalars(
1361 obj, value);
1362 TEST_ASSERT(value != 0);
1363""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1364
1365 for member in members:
1366 m_type = member["m_type"]
1367 m_name = member["name"]
1368 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1369 continue
1370 if loxi_utils.skip_member_name(m_name):
1371 continue
1372 if m_type == "of_match_t":
1373 out.write("""\
1374 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1375 TEST_ASSERT(value != 0);
1376 %(cls)s_%(m_name)s_set(
1377 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001378""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001379 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1380 elif m_type == "of_octets_t":
1381 out.write("""\
1382 value = of_octets_populate(&%(var_name)s, value);
1383 TEST_ASSERT(value != 0);
1384 %(cls)s_%(m_name)s_set(
1385 obj, &%(var_name)s);
1386 if (octets.bytes) {
1387 FREE(octets.data);
1388 }
1389""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001390 elif m_type in embedded_subclasses:
1391 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001392 out.write("""\
1393 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1394 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001395 value = %(sub_cls)s_%(v_name)s_populate(
1396 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001397 TEST_ASSERT(value != 0);
1398 %(cls)s_%(m_name)s_set(
1399 obj, %(var_name)s);
1400 %(sub_cls)s_delete(%(var_name)s);
1401""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1402 var_name=var_name_map(m_type),
1403 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001404 else:
1405 sub_cls = m_type[:-2] # Trim _t
1406 out.write("""
1407 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1408 TEST_ASSERT(%(var_name)s != NULL);
1409 value = %(sub_cls)s_%(v_name)s_populate(
1410 %(var_name)s, value);
1411 TEST_ASSERT(value != 0);
1412 %(cls)s_%(m_name)s_set(
1413 obj, %(var_name)s);
1414 %(sub_cls)s_delete(%(var_name)s);
1415""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1416 var_name=var_name_map(m_type),
1417 v_name=loxi_utils.version_to_name(version)))
1418
1419 out.write("""
1420 return value;
1421}
1422""")
1423
1424 out.write("""
1425/**
1426 * Check all members of an object of type %(cls)s
1427 * populated by the above function
1428 * @param obj Pointer to an object to check
1429 * @param value Starting value for checking
1430 * @returns The value after increments for this object's values
1431 */
1432
1433int
1434%(cls)s_%(v_name)s_check(
1435 %(cls)s_t *obj, int value)
1436{
1437""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1438 members, member_types = loxi_utils.all_member_types_get(cls, version)
1439 for m_type in member_types:
1440 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1441 continue
1442 if loxi_utils.type_is_of_object(m_type):
1443 continue
1444 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1445 out.write("""
1446 value = %(cls)s_%(v_name)s_check_scalars(
1447 obj, value);
1448 TEST_ASSERT(value != 0);
1449""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1450
1451 for member in members:
1452 m_type = member["m_type"]
1453 m_name = member["name"]
1454 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1455 continue
1456 if loxi_utils.skip_member_name(m_name):
1457 continue
1458 if m_type == "of_match_t":
1459 out.write("""\
1460 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1461 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1462""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1463 v_name=loxi_utils.version_to_name(version)))
1464 elif m_type == "of_octets_t":
1465 out.write("""\
1466 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1467 value = of_octets_check(&%(var_name)s, value);
1468""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1469 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001470 elif m_type in embedded_subclasses:
1471 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001472 out.write("""
1473 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001474 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001475
1476 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1477 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001478 value = %(sub_cls)s_%(v_name)s_check(
1479 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001480 TEST_ASSERT(value != 0);
1481 %(sub_cls)s_delete(%(m_name)s_ptr);
1482 }
1483""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1484 var_name=var_name_map(m_type),
1485 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001486 else:
1487 sub_cls = m_type[:-2] # Trim _t
1488 out.write("""
1489 { /* Use get/delete to access on check */
1490 %(m_type)s *%(m_name)s_ptr;
1491
1492 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1493 TEST_ASSERT(%(m_name)s_ptr != NULL);
1494 value = %(sub_cls)s_%(v_name)s_check(
1495 %(m_name)s_ptr, value);
1496 TEST_ASSERT(value != 0);
1497 %(sub_cls)s_delete(%(m_name)s_ptr);
1498 }
1499""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1500 var_name=var_name_map(m_type),
1501 v_name=loxi_utils.version_to_name(version)))
1502
1503 out.write("""
1504 /* We shoehorn a test of the dup functions here */
1505 {
1506 %(cls)s_t *dup;
1507
1508 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1509 TEST_ASSERT(dup->length == obj->length);
1510 TEST_ASSERT(dup->object_id == obj->object_id);
1511 TEST_ASSERT(dup->version == obj->version);
1512 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1513 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1514 of_object_delete((of_object_t *)dup);
1515
1516 /* And now for the generic dup function */
1517 TEST_ASSERT((dup = (%(cls)s_t *)
1518 of_object_dup(obj)) != NULL);
1519 TEST_ASSERT(dup->length == obj->length);
1520 TEST_ASSERT(dup->object_id == obj->object_id);
1521 TEST_ASSERT(dup->version == obj->version);
1522 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1523 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1524 of_object_delete((of_object_t *)dup);
1525 }
1526
1527 return value;
1528}
1529""" % dict(cls=cls))
1530
1531def unified_accessor_test_case(out, cls, version):
1532 """
1533 Generate one test case for the given version and class
1534 """
1535
1536 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001537 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001538 v_name = loxi_utils.version_to_name(version)
1539
1540 out.write("""
1541static int
1542test_%(cls)s_%(v_name)s(void)
1543{
1544 %(cls)s_t *obj;
1545 obj = %(cls)s_new(%(v_name)s);
1546 TEST_ASSERT(obj != NULL);
1547 TEST_ASSERT(obj->version == %(v_name)s);
1548 TEST_ASSERT(obj->length == %(length)d);
1549 TEST_ASSERT(obj->parent == NULL);
1550 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001551""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001552 v_name=v_name, length=length, version=version))
1553 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1554 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001555 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001556 int length;
1557
Rich Lanedc46fe22014-04-03 15:10:38 -07001558 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001559 TEST_ASSERT(length == %(length)d);
1560 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001561 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001562 of_object_id_t obj_id;
1563
Rich Lanedc46fe22014-04-03 15:10:38 -07001564 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001565 TEST_ASSERT(obj_id == %(u_cls)s);
1566 }
1567
1568 /* Set up incrementing values for members */
1569 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1570 obj, 1) != 0);
1571
1572 /* Check values just set */
1573 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1574 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001575""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001576 v_name=v_name, length=length, version=version))
1577
1578 out.write("""
1579 %(cls)s_delete(obj);
1580
1581 /* To do: Check memory */
1582 return TEST_PASS;
1583}
1584""" % dict(cls=cls))
1585
1586
1587def gen_unified_accessor_funs(out):
1588 for version in of_g.of_version_range:
1589 for cls in of_g.standard_class_order:
1590 if not loxi_utils.class_in_version(cls, version):
1591 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001592 elif loxi_utils.class_is_list(cls):
1593 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001594 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001595 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 Lane6171e632014-11-07 10:23:38 -08001613 if type_maps.class_is_virtual(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 Lane6171e632014-11-07 10:23:38 -08001627 if type_maps.class_is_virtual(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{
Rich Lanee499bd12014-10-28 15:25:09 -07001664 of_object_t src_elt;
1665 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001666 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 */
Rich Lanee499bd12014-10-28 15:25:09 -07001700of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001701%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001702 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001703{
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 Lane6171e632014-11-07 10:23:38 -08001710 if type_maps.class_is_virtual(sub_cls):
1711 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001712 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001713 if (src->object_id == %(sub_enum)s) {
1714 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001715 }
1716""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1717
1718 out.write("""
1719 return NULL;
1720}
1721""")
1722
1723
1724def gen_dup_cls(out, cls, version):
1725 """
1726 Generate duplication routine for class cls
1727 """
1728 ver_name = loxi_utils.version_to_name(version)
1729
1730 out.write("""
1731/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001732 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001733 * using accessor functions
1734 * @param src Pointer to object to be duplicated
1735 * @returns A new object of type %(cls)s.
1736 *
1737 * The caller is responsible for deleting the returned value
1738 */
1739%(cls)s_t *
1740%(cls)s_%(ver_name)s_dup(
1741 %(cls)s_t *src)
1742{
1743 %(cls)s_t *dst;
1744""" % dict(cls=cls, ver_name=ver_name))
1745
1746 # Get members and types for the class
1747 members, member_types = loxi_utils.all_member_types_get(cls, version)
1748
1749 # Add declarations for each member type
1750 for m_type in member_types:
1751 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1752 # Declare instance of these
1753 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001754 elif m_type in embedded_subclasses:
1755 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001756 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001757 %(sub_cls)s_t src_%(v_name)s;
1758 %(sub_cls)s_t *dst_%(v_name)s;
1759""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001760 else:
1761 out.write("""
1762 %(m_type)s src_%(v_name)s;
1763 %(m_type)s *dst_%(v_name)s;
1764""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1765
1766 out.write("""
1767 if ((dst = %(cls)s_new(src->version)) == NULL) {
1768 return NULL;
1769 }
1770""" % dict(cls=cls))
1771
1772 for member in members:
1773 m_type = member["m_type"]
1774 m_name = member["name"]
1775 if loxi_utils.skip_member_name(m_name):
1776 continue
1777 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1778 out.write("""
1779 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1780 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1781""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1782 elif m_type in ["of_match_t", "of_octets_t"]:
1783 out.write("""
1784 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1785 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1786""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001787 elif m_type in embedded_subclasses:
1788 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001789 out.write("""
1790 %(cls)s_%(m_name)s_bind(
1791 src, &src_%(v_name)s);
1792 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1793 if (dst_%(v_name)s == NULL) {
1794 %(cls)s_delete(dst);
1795 return NULL;
1796 }
1797 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1798 %(sub_cls)s_delete(dst_%(v_name)s);
1799""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1800 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001801 else:
1802 sub_cls = m_type[:-2] # Trim _t
1803 out.write("""
1804 %(cls)s_%(m_name)s_bind(
1805 src, &src_%(v_name)s);
1806 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1807 if (dst_%(v_name)s == NULL) {
1808 %(cls)s_delete(dst);
1809 return NULL;
1810 }
1811 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1812 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001813""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001814 v_name=var_name_map(m_type), ver_name=ver_name))
1815
1816 out.write("""
1817 return dst;
1818}
1819""")
1820
1821def gen_version_dup(out=sys.stdout):
1822 """
1823 Generate duplication routines for each object type
1824 """
1825 out.write("""
1826/* Special try macro for duplicating */
1827#define _TRY_FREE(op, obj, rv) do { \\
1828 int _rv; \\
1829 if ((_rv = (op)) < 0) { \\
1830 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1831 of_object_delete((of_object_t *)(obj)); \\
1832 return (rv); \\
1833 } \\
1834 } while (0)
1835""")
1836
1837 for version in of_g.of_version_range:
1838 for cls in of_g.standard_class_order:
1839 if not loxi_utils.class_in_version(cls, version):
1840 continue
Rich Lane8841f352014-10-12 19:18:36 -07001841 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001842 gen_dup_inheritance(out, cls, version)
1843 elif loxi_utils.class_is_list(cls):
1844 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001845 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001846 gen_dup_cls(out, cls, version)
1847
1848def gen_dup(out=sys.stdout):
1849 """
1850 Generate non-version specific duplication routines for each object type
1851 """
1852
1853 for cls in of_g.standard_class_order:
1854 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001855of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001856%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001857 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001858{
1859""" % dict(cls=cls))
1860 for version in of_g.of_version_range:
1861 if not loxi_utils.class_in_version(cls, version):
1862 continue
Rich Lane6171e632014-11-07 10:23:38 -08001863 elif type_maps.class_is_inheritance_root(cls):
1864 pass
1865 elif loxi_utils.class_is_list(cls):
1866 pass
1867 elif type_maps.class_is_virtual(cls):
1868 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001869 ver_name = loxi_utils.version_to_name(version)
1870 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001871 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001872 return %(cls)s_%(ver_name)s_dup(src);
1873 }
Rich Lanee499bd12014-10-28 15:25:09 -07001874""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001875
1876 out.write("""
1877 /* Class not supported in given version */
1878 return NULL;
1879}
1880""")
1881
1882def dup_c_gen(out, name):
1883 """
1884 Generate the C file for duplication functions
1885 """
1886 loxi_utils.gen_c_copy_license(out)
1887 out.write("""\
1888/*
1889 * Duplication functions for all OF objects
1890 *
1891 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1892 *
1893 * These are test functions for exercising accessors. You can call
1894 * of_object_dup for an efficient duplication.
1895 */
1896
1897#define DISABLE_WARN_UNUSED_RESULT
1898#include "loci_log.h"
1899#include <locitest/of_dup.h>
1900
1901""")
1902
1903 gen_version_dup(out)
1904 gen_dup(out)
1905
1906
1907def dup_h_gen(out, name):
1908 """
1909 Generate the header file for duplication functions
1910 """
1911
1912 loxi_utils.gen_c_copy_license(out)
1913 out.write("""
1914/*
1915 * Duplication function header file
1916 *
1917 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1918 */
1919
1920#if !defined(_OF_DUP_H_)
1921#define _OF_DUP_H_
1922
1923#include <loci/loci.h>
1924""")
1925
1926 for cls in of_g.standard_class_order:
1927 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001928extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001929 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001930 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001931""" % dict(cls=cls))
1932
1933 for version in of_g.of_version_range:
1934 for cls in of_g.standard_class_order:
1935 if not loxi_utils.class_in_version(cls, version):
1936 continue
Rich Lane6171e632014-11-07 10:23:38 -08001937 elif type_maps.class_is_inheritance_root(cls):
1938 pass
1939 elif loxi_utils.class_is_list(cls):
1940 pass
1941 elif type_maps.class_is_virtual(cls):
1942 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001943 ver_name = loxi_utils.version_to_name(version)
1944 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001945extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001946 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001947 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001948""" % dict(cls=cls, ver_name=ver_name))
1949
1950 out.write("\n#endif /* _OF_DUP_H_ */\n")
1951
1952def gen_log_test(out):
1953 """
1954 Generate test for obj log calls
1955
1956 Define a trivial handler for object logging; call all obj log fns
1957 """
1958 out.write("""
1959
1960/**
1961 * Test object dump functions
1962 */
1963
1964int
1965test_dump_objs(void)
1966{
1967 of_object_t *obj;
1968
1969 FILE *out = fopen("/dev/null", "w");
1970
1971 /* Call each obj dump function */
1972""")
1973 for version in of_g.of_version_range:
1974 for j, cls in enumerate(of_g.all_class_order):
1975 if not loxi_utils.class_in_version(cls, version):
1976 continue
Rich Lane6171e632014-11-07 10:23:38 -08001977 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001978 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001979 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1980 out.write("""
1981 obj = (of_object_t *)%(cls)s_new(%(version)s);
1982 {
1983 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1984 %(cls)s_vport_set(obj, vport);
1985 of_object_delete(vport);
1986 }
1987 of_object_dump((loci_writer_f)fprintf, out, obj);
1988 of_object_delete(obj);
1989""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1990 else:
1991 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001992 obj = (of_object_t *)%(cls)s_new(%(version)s);
1993 of_object_dump((loci_writer_f)fprintf, out, obj);
1994 of_object_delete(obj);
1995""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001996
Rich Lanea06d0c32013-03-25 08:52:03 -07001997 out.write("""
1998 fclose(out);
1999 return TEST_PASS;
2000}
2001""")
2002
2003def gen_ident_tests(out):
2004 """
2005 Generate tests for identifiers
2006
2007 For all idents, instantiate, test version supported macros
2008 For flags, set it, test it, clear it, test it.
2009 """
2010 out.write("""
2011/**
2012 * Test cases for all flag accessor macros
2013 * These only test self consistency (and that they compile)
2014 */
2015int
2016test_ident_macros(void)
2017{
2018 int value __attribute__((unused));
2019 uint32_t flags;
2020
2021""")
2022
2023 for ident, info in of_g.identifiers.items():
2024 if not identifiers.defined_versions_agree(of_g.identifiers,
2025 of_g.target_version_list,
2026 ident):
2027 # @fixme
2028 continue
2029 out.write(" value = %s;\n" % ident)
2030 for version in of_g.target_version_list:
2031 if version in info["values_by_version"].keys():
2032 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2033 (ident, of_g.of_version_wire2name[version]))
2034 else:
2035 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2036 (ident, of_g.of_version_wire2name[version]))
2037 if flags.ident_is_flag(ident):
2038 # Grab first supported version
2039 for version in info["values_by_version"]:
2040 break
2041 out.write("""
2042 flags = 0;
2043 %(ident)s_SET(flags, %(ver_name)s);
2044 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2045 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2046 %(ident)s_CLEAR(flags, %(ver_name)s);
2047 TEST_ASSERT(flags == 0);
2048 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2049""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2050
2051 out.write("""
2052 return TEST_PASS;
2053}
2054""")
2055
Rich Laneccae0312013-07-21 23:34:13 -07002056def gen_datafiles_tests(out, name):
2057 tests = []
2058 for filename in test_data.list_files():
2059 data = test_data.read(filename)
2060 if not 'c' in data:
2061 continue
2062 name = filename[:-5].replace("/", "_")
2063 tests.append(dict(name=name,
2064 filename=filename,
2065 c=data['c'],
2066 binary=data['binary']))
2067
2068 util.render_template(out, "test_data.c", tests=tests)