blob: 955f34f6e002ca34cc735b949edb85971ff01589 [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
Rich Lanea06d0c32013-03-25 08:52:03 -0700397 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
398
399def gen_common_test(out, name):
400 """
401 Generate common test content including main
402 """
403 loxi_utils.gen_c_copy_license(out)
404 out.write("""
405/*
406 * Common test code for LOCI
407 *
408 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
409 */
410
411#define DISABLE_WARN_UNUSED_RESULT
412#include "loci_log.h"
413#include <loci/loci_obj_dump.h>
414#include <locitest/unittest.h>
415#include <locitest/test_common.h>
416
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900417/* mcheck is a glibc extension */
418#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700419#include <mcheck.h>
420#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900421#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700422#define MCHECK_INIT do { } while (0)
423#endif
424
425/**
426 * Exit on error if set to 1
427 */
428int exit_on_error = 1;
429
430/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700431 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700432 */
433int global_error = 0;
434
435extern int run_unified_accessor_tests(void);
436extern int run_match_tests(void);
437extern int run_utility_tests(void);
438
439extern int run_scalar_acc_tests(void);
440extern int run_list_tests(void);
441extern int run_message_tests(void);
442
443/**
444 * Macros for initializing and checking scalar types
445 *
446 * @param var The variable being initialized or checked
447 * @param val The integer value to set/check against, see below
448 *
449 * Note that equality means something special for strings. Each byte
450 * is initialized to an incrementing value. So check is done against that.
451 *
452 */
453
454""")
455 for t in scalar_types:
456 if t in integer_types:
457 out.write("""
458#define VAR_%s_INIT(var, val) var = (%s)(val)
459#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
460""" % (t.upper(), t, t.upper(), t))
461 else:
462 out.write("""
463#define VAR_%s_INIT(var, val) \\
464 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
465#define VAR_%s_CHECK(var, val) \\
466 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
467""" % (t.upper(), t.upper()))
468
469 gen_fill_string(out)
470 gen_scalar_set_check_funs(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700471 gen_unified_accessor_funs(out)
472
473 gen_ident_tests(out)
474 gen_log_test(out)
475
476def gen_message_scalar_test(out, name):
477 """
478 Generate test cases for message objects, scalar accessors
479 """
480
481 loxi_utils.gen_c_copy_license(out)
482 out.write("""
483/**
484 *
485 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
486 *
487 * Message-scalar tests for all versions
488 */
489
490#include <locitest/test_common.h>
491""")
492 for version in of_g.of_version_range:
493 v_name = loxi_utils.version_to_name(version)
494 out.write("""
495/**
496 * Message-scalar tests for version %s
497 */
498""" % v_name)
499 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800500 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700501 continue
502 if version in of_g.unified[cls]:
503 message_scalar_test(out, version, cls)
504
505 out.write("""
506int
507run_scalar_acc_tests(void)
508{
509""")
510 for version in of_g.of_version_range:
511 v_name = loxi_utils.version_to_name(version)
512 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800513 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700514 continue
515 if version in of_g.unified[cls]:
516 test_name = "%s_%s" % (cls, v_name)
517 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
518
519 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700520
Rich Lanea06d0c32013-03-25 08:52:03 -0700521def message_scalar_test(out, version, cls):
522 """
523 Generate one test case for the given version and class
524 """
525
526 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700527 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700528 v_name = loxi_utils.version_to_name(version)
529
530 out.write("""
531static int
532test_%(cls)s_%(v_name)s_scalar(void)
533{
534 %(cls)s_t *obj;
535
536 obj = %(cls)s_new(%(v_name)s);
537 TEST_ASSERT(obj != NULL);
538 TEST_ASSERT(obj->version == %(v_name)s);
539 TEST_ASSERT(obj->length == %(length)d);
540 TEST_ASSERT(obj->parent == NULL);
541 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700542""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700543 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700544
545 # If this class is a concrete member of an inheritance hierarchy,
546 # run the hierarchy's root wire type parser and assert it returns
547 # the expected object id.
548 ofclass = loxi_globals.unified.class_by_name(cls)
549 if ofclass and not ofclass.virtual:
550 root = ofclass
551 while root.superclass:
552 root = root.superclass
553 if root.virtual:
554 out.write("""
555 {
556 of_object_id_t object_id;
557 %(root_cls)s_wire_object_id_get(obj, &object_id);
558 TEST_ASSERT(object_id == %(u_cls)s);
559 }
560""" % dict(root_cls=root.name, u_cls=cls.upper()))
561
Rich Lanea06d0c32013-03-25 08:52:03 -0700562 if not type_maps.class_is_virtual(cls):
563 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700564 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700565 int length;
566
Rich Lanedc46fe22014-04-03 15:10:38 -0700567 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700568 TEST_ASSERT(length == %(length)d);
569 }
570
571 /* Set up incrementing values for scalar members */
572 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
573
574 /* Check values just set */
575 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700576""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700577 v_name=v_name, length=length, version=version))
578
579 out.write("""
580 %(cls)s_delete(obj);
581
582 /* To do: Check memory */
583 return TEST_PASS;
584}
585""" % dict(cls=cls))
586
587# Get the members and list of scalar types for members of a given class
588def scalar_member_types_get(cls, version):
589 member_types = []
590
591 if not version in of_g.unified[cls]:
592 return ([], [])
593
594 if "use_version" in of_g.unified[cls][version]:
595 v = of_g.unified[cls][version]["use_version"]
596 members = of_g.unified[cls][v]["members"]
597 else:
598 members = of_g.unified[cls][version]["members"]
599 # Accumulate variables that are supported
600 for member in members:
601 m_type = member["m_type"]
602 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700603 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700604 ignore_member(cls, version, m_name, m_type)):
605 continue
606 if not m_type in member_types:
607 member_types.append(m_type)
608
609 return (members, member_types)
610
611def scalar_funs_instance(out, cls, version, members, member_types):
612 """
613 Generate one instance of scalar set/check functions
614 """
615 out.write("""
616/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700617 * Populate the scalar values in obj of type %(cls)s,
618 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700619 * @param obj Pointer to an object to populate
620 * @param value The seed value to use in populating the object
621 * @returns The value after increments for this object's values
622 */
623int %(cls)s_%(v_name)s_populate_scalars(
624 %(cls)s_t *obj, int value) {
625""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
626 # Declare string types
627 for t in member_types:
628 out.write(" %s %s;\n" % (t, var_name_map(t)))
629 for member in members:
630 m_type = member["m_type"]
631 m_name = member["name"]
632 if (not loxi_utils.type_is_scalar(m_type) or
633 ignore_member(cls, version, m_name, m_type)):
634 continue
635 v_name = var_name_map(m_type);
636 out.write("""
637 VAR_%(u_type)s_INIT(%(v_name)s, value);
638 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
639 value += 1;
640""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
641 out.write("""
642 return value;
643}
644""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700645
Rich Lanea06d0c32013-03-25 08:52:03 -0700646 out.write("""
647/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700648 * Check scalar values in obj of type %(cls)s,
649 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700650 * @param obj Pointer to an object to check
651 * @param value Starting value for checking
652 * @returns The value after increments for this object's values
653 */
654int %(cls)s_%(v_name)s_check_scalars(
655 %(cls)s_t *obj, int value) {
656""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
657
658 for t in member_types:
659 out.write(" %s %s;\n" % (t, var_name_map(t)))
660 for member in members:
661 m_type = member["m_type"]
662 m_name = member["name"]
663 if (not loxi_utils.type_is_scalar(m_type) or
664 ignore_member(cls, version, m_name, m_type)):
665 continue
666 v_name = var_name_map(m_type);
667 out.write("""
668 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
669 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
670 value += 1;
671""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
672
673 out.write("""
674 return value;
675}
676
677""")
678
679def gen_scalar_set_check_funs(out):
680 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700681 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700682 set and check their values
683 """
684 for version in of_g.of_version_range:
685 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800686 if type_maps.class_is_virtual(cls):
Rich Lanee499bd12014-10-28 15:25:09 -0700687 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700688 (members, member_types) = scalar_member_types_get(cls, version)
689 scalar_funs_instance(out, cls, version, members, member_types)
690
691
692# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700693def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700694 base_type = loxi_utils.list_to_entry_type(cls)
695 setup_template = """
696 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700697 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700698 value = %(subcls)s_%(v_name)s_populate(
699 %(inst)s, value);
700 cur_len += %(inst)s->length;
701 TEST_ASSERT(list->length == cur_len);
702"""
703 out.write("""
704 /* Append two instances of type %s */
705""" % subcls)
706 for i in range(2):
707 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700708 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700709 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700710 version=version))
711
Rich Lane9afc3b92014-04-09 22:55:53 -0700712def check_instance(out, cls, subcls, instance, v_name, version, last):
713 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700714 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
715 value = %(subcls)s_%(v_name)s_check(
716 %(inst)s, value);
717 TEST_ASSERT(value != 0);
718"""
719 out.write("\n /* Check two instances of type %s */" % instance)
720
Andreas Wundsam53256162013-05-02 14:05:53 -0700721 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700722 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700723 inst=instance, subcls=subcls,
724 v_name=loxi_utils.version_to_name(version)))
725 out.write("""\
726 TEST_OK(%(cls)s_next(list, &elt));
727""" % dict(cls=cls))
728
Andreas Wundsam53256162013-05-02 14:05:53 -0700729 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700730 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700731 inst=instance, subcls=subcls,
732 v_name=loxi_utils.version_to_name(version)))
733 if last:
734 out.write("""\
735 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
736""" % dict(cls=cls))
737 else:
738 out.write("""\
739 TEST_OK(%(cls)s_next(list, &elt));
740""" % dict(cls=cls))
741
Rich Lanea06d0c32013-03-25 08:52:03 -0700742# Maybe: Get a map from list class to parent, mem_name of container
743
744def list_test(out, version, cls):
745 out.write("""
746static int
747test_%(cls)s_%(v_name)s(void)
748{
749""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
750 base_type = loxi_utils.list_to_entry_type(cls)
751
752 out.write(""" %(cls)s_t *list;
753 int value = 1;
754""" % dict(cls=cls, base_type=base_type))
755
756 out.write("""
757 list = %(cls)s_new(%(v_name)s);
758 TEST_ASSERT(list != NULL);
759 TEST_ASSERT(list->version == %(v_name)s);
760 TEST_ASSERT(list->length == 0);
761 TEST_ASSERT(list->parent == NULL);
762 TEST_ASSERT(list->object_id == %(enum_cls)s);
763
Rich Lanec6e97f72014-12-03 12:08:25 -0800764 value = %(cls)s_%(v_name)s_populate(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700765 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700766""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700767 enum_cls=loxi_utils.enum_name(cls)))
768
769 out.write("""
770 /* Now check values */
771 value = 1;
Rich Lanec6e97f72014-12-03 12:08:25 -0800772 value = %(cls)s_%(v_name)s_check(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700773 TEST_ASSERT(value != 0);
774""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
775
776 out.write("""
777 %(cls)s_delete(list);
778
779 return TEST_PASS;
780}
781""" % dict(cls=cls))
782
783def gen_list_test(out, name):
784 """
785 Generate base line test cases for lists
786 @param out The file handle to write to
787 """
788
789 loxi_utils.gen_c_copy_license(out)
790 out.write("""
791/**
792 *
793 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
794 *
795 * Message-scalar tests for all versions
796 */
797
798#include <locitest/test_common.h>
799""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700800
Rich Lanea06d0c32013-03-25 08:52:03 -0700801 for version in of_g.of_version_range:
802 v_name = loxi_utils.version_to_name(version)
803 out.write("""
804/**
805 * Baseline list tests for version %s
806 */
807""" % v_name)
808 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700809 if version in of_g.unified[cls]:
810 list_test(out, version, cls)
811
812 out.write("""
813int
814run_list_tests(void)
815{
816""")
817 for version in of_g.of_version_range:
818 v_name = loxi_utils.version_to_name(version)
819 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700820 if version in of_g.unified[cls]:
821 test_name = "%s_%s" % (cls, v_name)
822 out.write(" RUN_TEST(%s);\n" % test_name)
823
824 out.write("\n return TEST_PASS;\n}\n");
825
826def gen_match_test(out, name):
827 """
828 Generate baseline tests for match functions
829 """
830
831 loxi_utils.gen_c_copy_license(out)
832 out.write("""\
833/**
834 *
835 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
836 *
837 * Message-scalar tests for all versions
838 * @fixme These are mostly hard coded now.
839 */
840
841#include <locitest/test_common.h>
842
843static int
844test_match_1(void)
845{
Rich Lanef87f4c32014-10-14 11:56:02 -0700846""")
847
848 for version in of_g.of_version_range:
849 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
850
851 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700852 of_match_t match;
853 int value = 1;
854 int idx;
855 uint32_t exp_value;
856
857 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700858 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700859 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
860 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
861 if (idx < 32) {
862 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
863 }
864 }
865""")
866
867 for version in of_g.of_version_range:
868 out.write("""
869 /* Create/populate/convert and delete for version %(v_name)s */
870 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
871 TEST_ASSERT(m_v%(version)d != NULL);
872 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
873 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
874 of_match_v%(version)d_delete(m_v%(version)d);
875""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
876
877 out.write("""
878 return TEST_PASS;
879}
880""")
881
882 out.write("""
883static int
884test_match_2(void)
885{
Rich Lanef87f4c32014-10-14 11:56:02 -0700886""")
887
888 for version in of_g.of_version_range:
889 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
890
891 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700892 of_match_t match1;
893 of_match_t match2;
894 int value = 1;
895""")
896
897 for version in of_g.of_version_range:
898 out.write("""
899 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
900 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
901 TEST_ASSERT(m_v%(version)d != NULL);
902 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
903 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
904 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
905 of_match_v%(version)d_delete(m_v%(version)d);
906""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
907
908 out.write("""
909 return TEST_PASS;
910}
911""")
912
913 out.write("""
914static int
915test_match_3(void)
916{
917 of_match_t match1;
918 of_match_t match2;
919 int value = 1;
920 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -0700921 of_object_storage_t storage;
922 memset(&storage, 0, sizeof(storage));
923 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700924""")
925 for version in of_g.of_version_range:
926 out.write("""
927 /* Serialize to version %(v_name)s */
928 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700929 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700930 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -0700931 storage.obj.wbuf->buf = octets.data;
932 storage.obj.wbuf->alloc_bytes = octets.bytes;
933 storage.obj.wbuf->current_bytes = octets.bytes;
934 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700935 OF_ERROR_NONE);
936 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
937 FREE(octets.data);
938""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
939
940 out.write("""
941 return TEST_PASS;
942}
943""")
944
945 out.write("""
946int run_match_tests(void)
947{
948 RUN_TEST(match_1);
949 RUN_TEST(match_2);
950 RUN_TEST(match_3);
951 RUN_TEST(match_utils);
952
953 return TEST_PASS;
954}
955""")
956
957def gen_msg_test(out, name):
958 loxi_utils.gen_c_copy_license(out)
959 out.write("""
960/**
961 *
962 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
963 *
964 * Message-scalar tests for all versions
965 */
966
967#include <locitest/test_common.h>
968""")
969 for version in of_g.of_version_range:
970 for cls in of_g.ordered_messages:
971 if not (cls, version) in of_g.base_length:
972 continue
Rich Lane488b3c52013-06-21 18:11:02 -0700973 if type_maps.class_is_virtual(cls):
974 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -0700975 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700976 out.write("""
977static int
978test_%(cls)s_create_%(v_name)s(void)
979{
980 %(cls)s_t *obj;
981 uint8_t *msg_buf;
982 int value;
Rich Lanea4b68302014-03-12 15:17:58 -0700983 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -0700984 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700985
986 obj = %(cls)s_new(%(v_name)s);
987 TEST_ASSERT(obj != NULL);
988 TEST_ASSERT(obj->version == %(v_name)s);
989 TEST_ASSERT(obj->length == %(bytes)d);
990 TEST_ASSERT(obj->parent == NULL);
991 TEST_ASSERT(obj->object_id == %(enum)s);
992
Rich Lanea4b68302014-03-12 15:17:58 -0700993 of_header_wire_object_id_get(obj, &object_id);
994 TEST_ASSERT(object_id == %(enum)s);
995
Rich Lanea06d0c32013-03-25 08:52:03 -0700996 /* Set up incrementing values for scalar members */
997 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
998 TEST_ASSERT(value != 0);
999
Rich Lanebb8f17c2014-06-12 13:14:09 -07001000 len = obj->length;
1001
Rich Lanea06d0c32013-03-25 08:52:03 -07001002 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001003 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1004 TEST_ASSERT(msg_buf != NULL);
1005 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001006 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001007
1008 TEST_ASSERT(obj != NULL);
1009
1010 /* @fixme Set up all message objects (recursively?) */
1011
1012 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1013 TEST_ASSERT(value != 0);
1014
1015 %(cls)s_delete(obj);
1016
1017 return TEST_PASS;
1018}
1019""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1020 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1021
1022 out.write("""
1023int
1024run_message_tests(void)
1025{
1026""")
1027 for version in of_g.of_version_range:
1028 for cls in of_g.ordered_messages:
1029 if not (cls, version) in of_g.base_length:
1030 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001031 if type_maps.class_is_virtual(cls):
1032 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001033 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1034 out.write(" RUN_TEST(%s);\n" % test_name)
1035
1036 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001037
Rich Lanea06d0c32013-03-25 08:52:03 -07001038
1039def gen_list_setup_check(out, cls, version):
1040 """
1041 Generate functions that populate and check a list with two
1042 of each type of subclass it supports
1043 """
1044 out.write("""
1045/**
1046 * Populate a list of type %(cls)s with two of each type of subclass
1047 * @param list Pointer to the list to be populated
1048 * @param value The seed value to use in populating the list
1049 * @returns The value after increments for this object's values
1050 */
1051int
1052%(cls)s_%(v_name)s_populate(
1053 %(cls)s_t *list, int value)
1054{
1055""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1056 base_type = loxi_utils.list_to_entry_type(cls)
1057 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001058 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001059 int cur_len = 0;
Rich Lanead708032014-12-03 12:40:58 -08001060 static int recursion;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001061 (void) elt;
1062 (void) cur_len;
Rich Lanead708032014-12-03 12:40:58 -08001063
1064 if (recursion > 0) {
1065 return value;
1066 }
1067
1068 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001069""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001070
Rich Lanea06d0c32013-03-25 08:52:03 -07001071 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001072 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 -07001073 v_name = loxi_utils.version_to_name(version)
1074
Rich Lanee98ee5d2014-10-14 10:43:44 -07001075 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001076 out.write(" /* No subclasses for %s */\n"% base_type)
1077 out.write(" %s_t *elt_p;\n" % base_type)
1078 out.write("\n elt_p = &elt;\n")
1079 else:
1080 out.write(" /* Declare pointers for each subclass */\n")
1081 for instance, subcls in sub_classes:
1082 out.write(" %s_t *%s;\n" % (subcls, instance))
1083 out.write("\n /* Instantiate pointers for each subclass */\n")
1084 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001085 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001086
Rich Lanee98ee5d2014-10-14 10:43:44 -07001087 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001088 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001089 else:
1090 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001091 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001092 out.write("""
Rich Lanead708032014-12-03 12:40:58 -08001093 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001094 return value;
1095}
1096""")
1097 out.write("""
1098/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001099 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001100 * %(cls)s_%(v_name)s_populate
1101 * @param list Pointer to the list that was populated
1102 * @param value Starting value for checking
1103 * @returns The value after increments for this object's values
1104 */
1105int
1106%(cls)s_%(v_name)s_check(
1107 %(cls)s_t *list, int value)
1108{
1109""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1110 base_type = loxi_utils.list_to_entry_type(cls)
1111 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001112 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001113 int count = 0;
1114 int rv;
Rich Lanead708032014-12-03 12:40:58 -08001115 static int recursion;
1116
1117 if (recursion > 0) {
1118 return value;
1119 }
1120
1121 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001122""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001123
Rich Lanea06d0c32013-03-25 08:52:03 -07001124
1125 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001126 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 -07001127 v_name = loxi_utils.version_to_name(version)
1128
Rich Lanee98ee5d2014-10-14 10:43:44 -07001129 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001130 entry_count = 2
1131 out.write(" /* No subclasses for %s */\n"% base_type)
1132 out.write(" %s_t *elt_p;\n" % base_type)
1133 out.write("\n elt_p = &elt;\n")
1134 else:
1135 entry_count = 2 * len(sub_classes) # Two of each type appended
1136 out.write(" /* Declare pointers for each subclass */\n")
1137 for instance, subcls in sub_classes:
1138 out.write(" %s_t *%s;\n" % (subcls, instance))
1139 out.write("\n /* Instantiate pointers for each subclass */\n")
1140 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001141 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001142
Rich Lanee98ee5d2014-10-14 10:43:44 -07001143 if not type_maps.class_is_virtual(base_type) or sub_classes:
1144 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1145
1146 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001147 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001148 version, True)
1149 else:
1150 count = 0
1151 for instance, subcls in sub_classes:
1152 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001153 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001154 version, count==len(sub_classes))
1155 out.write("""
1156""" % dict(base_type=base_type))
1157
1158 out.write("""
1159 /* Do an iterate to test the iterator */
1160 %(u_cls)s_ITER(list, &elt, rv) {
1161 count += 1;
1162 }
1163
1164 TEST_ASSERT(rv == OF_ERROR_RANGE);
1165 TEST_ASSERT(count == %(entry_count)d);
1166
1167 /* We shoehorn a test of the dup functions here */
1168 {
1169 %(cls)s_t *dup;
1170
1171 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1172 TEST_ASSERT(dup->length == list->length);
1173 TEST_ASSERT(dup->object_id == list->object_id);
1174 TEST_ASSERT(dup->version == list->version);
1175 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1176 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1177 of_object_delete((of_object_t *)dup);
1178
1179 /* And now for the generic dup function */
1180 TEST_ASSERT((dup = (%(cls)s_t *)
1181 of_object_dup(list)) != NULL);
1182 TEST_ASSERT(dup->length == list->length);
1183 TEST_ASSERT(dup->object_id == list->object_id);
1184 TEST_ASSERT(dup->version == list->version);
1185 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1186 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1187 of_object_delete((of_object_t *)dup);
1188 }
1189
Rich Lanead708032014-12-03 12:40:58 -08001190 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001191 return value;
1192}
1193""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1194
1195
1196def gen_class_setup_check(out, cls, version):
1197 out.write("""
1198/**
1199 * Populate all members of an object of type %(cls)s
1200 * with incrementing values
1201 * @param obj Pointer to an object to populate
1202 * @param value The seed value to use in populating the object
1203 * @returns The value after increments for this object's values
1204 */
1205
1206int
1207%(cls)s_%(v_name)s_populate(
1208 %(cls)s_t *obj, int value)
1209{
1210""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1211 members, member_types = loxi_utils.all_member_types_get(cls, version)
1212 for m_type in member_types:
1213 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1214 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001215 elif m_type in embedded_subclasses:
1216 subcls = embedded_subclasses[m_type]
1217 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001218 else:
1219 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1220 out.write("""
1221 /* Run thru accessors after new to ensure okay */
1222""")
1223 for member in members:
1224 m_type = member["m_type"]
1225 m_name = member["name"]
1226 if loxi_utils.skip_member_name(m_name):
1227 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001228 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001229 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001230 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1231 out.write("""\
1232 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1233""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1234 else:
1235 sub_cls = m_type[:-2] # Trim _t
1236 out.write("""\
1237 {
1238 %(sub_cls)s_t sub_cls;
1239
1240 /* Test bind */
1241 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1242 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001243""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001244 m_name=m_name, sub_cls=sub_cls,
1245 v_name=loxi_utils.version_to_name(version)))
1246
1247 out.write("""
1248 value = %(cls)s_%(v_name)s_populate_scalars(
1249 obj, value);
1250 TEST_ASSERT(value != 0);
1251""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1252
1253 for member in members:
1254 m_type = member["m_type"]
1255 m_name = member["name"]
1256 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1257 continue
1258 if loxi_utils.skip_member_name(m_name):
1259 continue
1260 if m_type == "of_match_t":
1261 out.write("""\
1262 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1263 TEST_ASSERT(value != 0);
1264 %(cls)s_%(m_name)s_set(
1265 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001266""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001267 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1268 elif m_type == "of_octets_t":
1269 out.write("""\
1270 value = of_octets_populate(&%(var_name)s, value);
1271 TEST_ASSERT(value != 0);
1272 %(cls)s_%(m_name)s_set(
1273 obj, &%(var_name)s);
1274 if (octets.bytes) {
1275 FREE(octets.data);
1276 }
1277""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001278 elif m_type in embedded_subclasses:
1279 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001280 out.write("""\
1281 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1282 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001283 value = %(sub_cls)s_%(v_name)s_populate(
1284 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001285 TEST_ASSERT(value != 0);
1286 %(cls)s_%(m_name)s_set(
1287 obj, %(var_name)s);
1288 %(sub_cls)s_delete(%(var_name)s);
1289""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1290 var_name=var_name_map(m_type),
1291 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001292 else:
1293 sub_cls = m_type[:-2] # Trim _t
1294 out.write("""
1295 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1296 TEST_ASSERT(%(var_name)s != NULL);
1297 value = %(sub_cls)s_%(v_name)s_populate(
1298 %(var_name)s, value);
1299 TEST_ASSERT(value != 0);
1300 %(cls)s_%(m_name)s_set(
1301 obj, %(var_name)s);
1302 %(sub_cls)s_delete(%(var_name)s);
1303""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1304 var_name=var_name_map(m_type),
1305 v_name=loxi_utils.version_to_name(version)))
1306
1307 out.write("""
1308 return value;
1309}
1310""")
1311
1312 out.write("""
1313/**
1314 * Check all members of an object of type %(cls)s
1315 * populated by the above function
1316 * @param obj Pointer to an object to check
1317 * @param value Starting value for checking
1318 * @returns The value after increments for this object's values
1319 */
1320
1321int
1322%(cls)s_%(v_name)s_check(
1323 %(cls)s_t *obj, int value)
1324{
1325""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1326 members, member_types = loxi_utils.all_member_types_get(cls, version)
1327 for m_type in member_types:
1328 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1329 continue
1330 if loxi_utils.type_is_of_object(m_type):
1331 continue
1332 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1333 out.write("""
1334 value = %(cls)s_%(v_name)s_check_scalars(
1335 obj, value);
1336 TEST_ASSERT(value != 0);
1337""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1338
1339 for member in members:
1340 m_type = member["m_type"]
1341 m_name = member["name"]
1342 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1343 continue
1344 if loxi_utils.skip_member_name(m_name):
1345 continue
1346 if m_type == "of_match_t":
1347 out.write("""\
1348 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1349 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1350""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1351 v_name=loxi_utils.version_to_name(version)))
1352 elif m_type == "of_octets_t":
1353 out.write("""\
1354 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1355 value = of_octets_check(&%(var_name)s, value);
1356""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1357 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001358 elif m_type in embedded_subclasses:
1359 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001360 out.write("""
1361 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001362 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001363
1364 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1365 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001366 value = %(sub_cls)s_%(v_name)s_check(
1367 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001368 TEST_ASSERT(value != 0);
1369 %(sub_cls)s_delete(%(m_name)s_ptr);
1370 }
1371""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1372 var_name=var_name_map(m_type),
1373 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001374 else:
1375 sub_cls = m_type[:-2] # Trim _t
1376 out.write("""
1377 { /* Use get/delete to access on check */
1378 %(m_type)s *%(m_name)s_ptr;
1379
1380 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1381 TEST_ASSERT(%(m_name)s_ptr != NULL);
1382 value = %(sub_cls)s_%(v_name)s_check(
1383 %(m_name)s_ptr, value);
1384 TEST_ASSERT(value != 0);
1385 %(sub_cls)s_delete(%(m_name)s_ptr);
1386 }
1387""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1388 var_name=var_name_map(m_type),
1389 v_name=loxi_utils.version_to_name(version)))
1390
1391 out.write("""
1392 /* We shoehorn a test of the dup functions here */
1393 {
1394 %(cls)s_t *dup;
1395
1396 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1397 TEST_ASSERT(dup->length == obj->length);
1398 TEST_ASSERT(dup->object_id == obj->object_id);
1399 TEST_ASSERT(dup->version == obj->version);
1400 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1401 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1402 of_object_delete((of_object_t *)dup);
1403
1404 /* And now for the generic dup function */
1405 TEST_ASSERT((dup = (%(cls)s_t *)
1406 of_object_dup(obj)) != NULL);
1407 TEST_ASSERT(dup->length == obj->length);
1408 TEST_ASSERT(dup->object_id == obj->object_id);
1409 TEST_ASSERT(dup->version == obj->version);
1410 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1411 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1412 of_object_delete((of_object_t *)dup);
1413 }
1414
1415 return value;
1416}
1417""" % dict(cls=cls))
1418
1419def unified_accessor_test_case(out, cls, version):
1420 """
1421 Generate one test case for the given version and class
1422 """
1423
1424 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001425 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001426 v_name = loxi_utils.version_to_name(version)
1427
1428 out.write("""
1429static int
1430test_%(cls)s_%(v_name)s(void)
1431{
1432 %(cls)s_t *obj;
1433 obj = %(cls)s_new(%(v_name)s);
1434 TEST_ASSERT(obj != NULL);
1435 TEST_ASSERT(obj->version == %(v_name)s);
1436 TEST_ASSERT(obj->length == %(length)d);
1437 TEST_ASSERT(obj->parent == NULL);
1438 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001439""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001440 v_name=v_name, length=length, version=version))
1441 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1442 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001443 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001444 int length;
1445
Rich Lanedc46fe22014-04-03 15:10:38 -07001446 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001447 TEST_ASSERT(length == %(length)d);
1448 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001449 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001450 of_object_id_t obj_id;
1451
Rich Lanedc46fe22014-04-03 15:10:38 -07001452 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001453 TEST_ASSERT(obj_id == %(u_cls)s);
1454 }
1455
1456 /* Set up incrementing values for members */
1457 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1458 obj, 1) != 0);
1459
1460 /* Check values just set */
1461 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1462 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001463""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001464 v_name=v_name, length=length, version=version))
1465
1466 out.write("""
1467 %(cls)s_delete(obj);
1468
1469 /* To do: Check memory */
1470 return TEST_PASS;
1471}
1472""" % dict(cls=cls))
1473
1474
1475def gen_unified_accessor_funs(out):
1476 for version in of_g.of_version_range:
1477 for cls in of_g.standard_class_order:
1478 if not loxi_utils.class_in_version(cls, version):
1479 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001480 elif loxi_utils.class_is_list(cls):
1481 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001482 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001483 gen_class_setup_check(out, cls, version)
1484
1485def gen_unified_accessor_tests(out, name):
1486 loxi_utils.gen_c_copy_license(out)
1487 out.write("""
1488/**
1489 *
1490 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1491 *
1492 * Unified simple class instantiation tests for all versions
1493 */
1494
1495#include <locitest/test_common.h>
1496""")
1497 for version in of_g.of_version_range:
1498 for cls in of_g.standard_class_order:
1499 if not loxi_utils.class_in_version(cls, version):
1500 continue
Rich Lane6171e632014-11-07 10:23:38 -08001501 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001502 continue
1503 unified_accessor_test_case(out, cls, version)
1504
1505 out.write("""
1506int
1507run_unified_accessor_tests(void)
1508{
1509""")
1510 for version in of_g.of_version_range:
1511 v_name = loxi_utils.version_to_name(version)
1512 for cls in of_g.standard_class_order:
1513 if not loxi_utils.class_in_version(cls, version):
1514 continue
Rich Lane6171e632014-11-07 10:23:38 -08001515 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001516 continue
1517 test_name = "%s_%s" % (cls, v_name)
1518 out.write(" RUN_TEST(%s);\n" % test_name)
1519
1520 out.write(" return TEST_PASS;\n}\n");
1521
1522
1523
1524################################################################
1525#
1526# Object duplication functions
1527#
1528# These exercise the accessors to create duplicate objects.
1529# They are used in the LOCI test shim which sits in an OF
1530# protocol stream.
1531#
1532# TODO
1533# Resolve version stuff
1534# Complete list dup
1535
1536def gen_dup_list(out, cls, version):
1537 ver_name = loxi_utils.version_to_name(version)
1538 elt_type = loxi_utils.list_to_entry_type(cls)
1539 out.write("""
1540/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001541 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001542 * using accessor functions
1543 * @param src Pointer to object to be duplicated
1544 * @returns A new object of type %(cls)s.
1545 *
1546 * The caller is responsible for deleting the returned value
1547 */
1548%(cls)s_t *
1549%(cls)s_%(ver_name)s_dup(
1550 %(cls)s_t *src)
1551{
Rich Lanee499bd12014-10-28 15:25:09 -07001552 of_object_t src_elt;
1553 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001554 int rv;
1555 %(cls)s_t *dst;
1556
1557 if ((dst = %(cls)s_new(src->version)) == NULL) {
1558 return NULL;
1559 }
1560""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1561
1562 out.write("""
1563 %(u_cls)s_ITER(src, &src_elt, rv) {
1564 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1565 of_object_delete((of_object_t *)dst);
1566 return NULL;
1567 }
1568 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1569 dst, NULL);
1570 of_object_delete((of_object_t *)dst_elt);
1571 }
1572
1573 return dst;
1574}
1575""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1576
1577
1578def gen_dup_inheritance(out, cls, version):
1579 ver_name = loxi_utils.version_to_name(version)
1580 out.write("""
1581/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001582 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001583 * @param src Pointer to object to be duplicated
1584 * @returns A new object of type %(cls)s.
1585 *
1586 * The caller is responsible for deleting the returned value
1587 */
Rich Lanee499bd12014-10-28 15:25:09 -07001588of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001589%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001590 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001591{
1592""" % dict(cls=cls, ver_name=ver_name))
1593
1594 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001595 sub_classes = type_maps.sub_class_map(cls, version)
1596 for (_, sub_cls) in sub_classes:
1597 sub_enum = sub_cls.upper()
Rich Lane6171e632014-11-07 10:23:38 -08001598 if type_maps.class_is_virtual(sub_cls):
1599 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001600 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001601 if (src->object_id == %(sub_enum)s) {
1602 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001603 }
1604""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1605
1606 out.write("""
1607 return NULL;
1608}
1609""")
1610
1611
1612def gen_dup_cls(out, cls, version):
1613 """
1614 Generate duplication routine for class cls
1615 """
1616 ver_name = loxi_utils.version_to_name(version)
1617
1618 out.write("""
1619/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001620 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001621 * using accessor functions
1622 * @param src Pointer to object to be duplicated
1623 * @returns A new object of type %(cls)s.
1624 *
1625 * The caller is responsible for deleting the returned value
1626 */
1627%(cls)s_t *
1628%(cls)s_%(ver_name)s_dup(
1629 %(cls)s_t *src)
1630{
1631 %(cls)s_t *dst;
1632""" % dict(cls=cls, ver_name=ver_name))
1633
1634 # Get members and types for the class
1635 members, member_types = loxi_utils.all_member_types_get(cls, version)
1636
1637 # Add declarations for each member type
1638 for m_type in member_types:
1639 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1640 # Declare instance of these
1641 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001642 elif m_type in embedded_subclasses:
1643 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001644 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001645 %(sub_cls)s_t src_%(v_name)s;
1646 %(sub_cls)s_t *dst_%(v_name)s;
1647""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001648 else:
1649 out.write("""
1650 %(m_type)s src_%(v_name)s;
1651 %(m_type)s *dst_%(v_name)s;
1652""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1653
1654 out.write("""
1655 if ((dst = %(cls)s_new(src->version)) == NULL) {
1656 return NULL;
1657 }
1658""" % dict(cls=cls))
1659
1660 for member in members:
1661 m_type = member["m_type"]
1662 m_name = member["name"]
1663 if loxi_utils.skip_member_name(m_name):
1664 continue
1665 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1666 out.write("""
1667 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1668 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1669""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1670 elif m_type in ["of_match_t", "of_octets_t"]:
1671 out.write("""
1672 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1673 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1674""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001675 elif m_type in embedded_subclasses:
1676 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001677 out.write("""
1678 %(cls)s_%(m_name)s_bind(
1679 src, &src_%(v_name)s);
1680 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1681 if (dst_%(v_name)s == NULL) {
1682 %(cls)s_delete(dst);
1683 return NULL;
1684 }
1685 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1686 %(sub_cls)s_delete(dst_%(v_name)s);
1687""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1688 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001689 else:
1690 sub_cls = m_type[:-2] # Trim _t
1691 out.write("""
1692 %(cls)s_%(m_name)s_bind(
1693 src, &src_%(v_name)s);
1694 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1695 if (dst_%(v_name)s == NULL) {
1696 %(cls)s_delete(dst);
1697 return NULL;
1698 }
1699 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1700 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001701""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001702 v_name=var_name_map(m_type), ver_name=ver_name))
1703
1704 out.write("""
1705 return dst;
1706}
1707""")
1708
1709def gen_version_dup(out=sys.stdout):
1710 """
1711 Generate duplication routines for each object type
1712 """
1713 out.write("""
1714/* Special try macro for duplicating */
1715#define _TRY_FREE(op, obj, rv) do { \\
1716 int _rv; \\
1717 if ((_rv = (op)) < 0) { \\
1718 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1719 of_object_delete((of_object_t *)(obj)); \\
1720 return (rv); \\
1721 } \\
1722 } while (0)
1723""")
1724
1725 for version in of_g.of_version_range:
1726 for cls in of_g.standard_class_order:
1727 if not loxi_utils.class_in_version(cls, version):
1728 continue
Rich Lane8841f352014-10-12 19:18:36 -07001729 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001730 gen_dup_inheritance(out, cls, version)
1731 elif loxi_utils.class_is_list(cls):
1732 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001733 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001734 gen_dup_cls(out, cls, version)
1735
1736def gen_dup(out=sys.stdout):
1737 """
1738 Generate non-version specific duplication routines for each object type
1739 """
1740
1741 for cls in of_g.standard_class_order:
1742 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001743of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001744%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001745 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001746{
1747""" % dict(cls=cls))
1748 for version in of_g.of_version_range:
1749 if not loxi_utils.class_in_version(cls, version):
1750 continue
Rich Lane6171e632014-11-07 10:23:38 -08001751 elif type_maps.class_is_inheritance_root(cls):
1752 pass
1753 elif loxi_utils.class_is_list(cls):
1754 pass
1755 elif type_maps.class_is_virtual(cls):
1756 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001757 ver_name = loxi_utils.version_to_name(version)
1758 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001759 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001760 return %(cls)s_%(ver_name)s_dup(src);
1761 }
Rich Lanee499bd12014-10-28 15:25:09 -07001762""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001763
1764 out.write("""
1765 /* Class not supported in given version */
1766 return NULL;
1767}
1768""")
1769
1770def dup_c_gen(out, name):
1771 """
1772 Generate the C file for duplication functions
1773 """
1774 loxi_utils.gen_c_copy_license(out)
1775 out.write("""\
1776/*
1777 * Duplication functions for all OF objects
1778 *
1779 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1780 *
1781 * These are test functions for exercising accessors. You can call
1782 * of_object_dup for an efficient duplication.
1783 */
1784
1785#define DISABLE_WARN_UNUSED_RESULT
1786#include "loci_log.h"
1787#include <locitest/of_dup.h>
1788
1789""")
1790
1791 gen_version_dup(out)
1792 gen_dup(out)
1793
1794
1795def dup_h_gen(out, name):
1796 """
1797 Generate the header file for duplication functions
1798 """
1799
1800 loxi_utils.gen_c_copy_license(out)
1801 out.write("""
1802/*
1803 * Duplication function header file
1804 *
1805 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1806 */
1807
1808#if !defined(_OF_DUP_H_)
1809#define _OF_DUP_H_
1810
1811#include <loci/loci.h>
1812""")
1813
1814 for cls in of_g.standard_class_order:
1815 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001816extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001817 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001818 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001819""" % dict(cls=cls))
1820
1821 for version in of_g.of_version_range:
1822 for cls in of_g.standard_class_order:
1823 if not loxi_utils.class_in_version(cls, version):
1824 continue
Rich Lane6171e632014-11-07 10:23:38 -08001825 elif type_maps.class_is_inheritance_root(cls):
1826 pass
1827 elif loxi_utils.class_is_list(cls):
1828 pass
1829 elif type_maps.class_is_virtual(cls):
1830 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001831 ver_name = loxi_utils.version_to_name(version)
1832 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001833extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001834 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001835 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001836""" % dict(cls=cls, ver_name=ver_name))
1837
1838 out.write("\n#endif /* _OF_DUP_H_ */\n")
1839
1840def gen_log_test(out):
1841 """
1842 Generate test for obj log calls
1843
1844 Define a trivial handler for object logging; call all obj log fns
1845 """
1846 out.write("""
1847
1848/**
1849 * Test object dump functions
1850 */
1851
1852int
1853test_dump_objs(void)
1854{
1855 of_object_t *obj;
1856
1857 FILE *out = fopen("/dev/null", "w");
1858
1859 /* Call each obj dump function */
1860""")
1861 for version in of_g.of_version_range:
1862 for j, cls in enumerate(of_g.all_class_order):
1863 if not loxi_utils.class_in_version(cls, version):
1864 continue
Rich Lane6171e632014-11-07 10:23:38 -08001865 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001866 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001867 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1868 out.write("""
1869 obj = (of_object_t *)%(cls)s_new(%(version)s);
1870 {
1871 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1872 %(cls)s_vport_set(obj, vport);
1873 of_object_delete(vport);
1874 }
1875 of_object_dump((loci_writer_f)fprintf, out, obj);
1876 of_object_delete(obj);
1877""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1878 else:
1879 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001880 obj = (of_object_t *)%(cls)s_new(%(version)s);
1881 of_object_dump((loci_writer_f)fprintf, out, obj);
1882 of_object_delete(obj);
1883""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001884
Rich Lanea06d0c32013-03-25 08:52:03 -07001885 out.write("""
1886 fclose(out);
1887 return TEST_PASS;
1888}
1889""")
1890
1891def gen_ident_tests(out):
1892 """
1893 Generate tests for identifiers
1894
1895 For all idents, instantiate, test version supported macros
1896 For flags, set it, test it, clear it, test it.
1897 """
1898 out.write("""
1899/**
1900 * Test cases for all flag accessor macros
1901 * These only test self consistency (and that they compile)
1902 */
1903int
1904test_ident_macros(void)
1905{
1906 int value __attribute__((unused));
1907 uint32_t flags;
1908
1909""")
1910
1911 for ident, info in of_g.identifiers.items():
1912 if not identifiers.defined_versions_agree(of_g.identifiers,
1913 of_g.target_version_list,
1914 ident):
1915 # @fixme
1916 continue
1917 out.write(" value = %s;\n" % ident)
1918 for version in of_g.target_version_list:
1919 if version in info["values_by_version"].keys():
1920 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1921 (ident, of_g.of_version_wire2name[version]))
1922 else:
1923 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1924 (ident, of_g.of_version_wire2name[version]))
1925 if flags.ident_is_flag(ident):
1926 # Grab first supported version
1927 for version in info["values_by_version"]:
1928 break
1929 out.write("""
1930 flags = 0;
1931 %(ident)s_SET(flags, %(ver_name)s);
1932 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1933 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1934 %(ident)s_CLEAR(flags, %(ver_name)s);
1935 TEST_ASSERT(flags == 0);
1936 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1937""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1938
1939 out.write("""
1940 return TEST_PASS;
1941}
1942""")
1943
Rich Laneccae0312013-07-21 23:34:13 -07001944def gen_datafiles_tests(out, name):
1945 tests = []
1946 for filename in test_data.list_files():
1947 data = test_data.read(filename)
1948 if not 'c' in data:
1949 continue
1950 name = filename[:-5].replace("/", "_")
1951 tests.append(dict(name=name,
1952 filename=filename,
1953 c=data['c'],
1954 binary=data['binary']))
1955
1956 util.render_template(out, "test_data.c", tests=tests)