blob: 05ff8e23f4bc4282da9fdce96a8e35eba5dfa338 [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",
Praseed Balakrishnanf78068b2014-09-04 10:30:40 -0700110 #Circuit extensions
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700111 of_app_code_t="app_code",
Praseed Balakrishnan2ed6da02014-09-18 17:02:48 -0700112 of_sig_id_t="sig_id",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700113 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700114
115 if m_type.find("of_list_") == 0:
116 return "list"
117 if m_type in of_g.of_mixed_types:
118 return of_g.of_mixed_types[m_type]["short_name"]
119 return _var_name_map[m_type]
120
121integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
122 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700123 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700124string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700125 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700126 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700127 "of_str64_t","of_app_code_t"]
Rich Lane119289c2014-12-01 13:44:08 -0800128 "of_str64_t", "of_bitmap_512_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700129
130scalar_types = integer_types[:]
131scalar_types.extend(string_types)
132
Rich Lane1f315aa2014-10-13 17:11:35 -0700133# When embedding an object inside of another object we have to pick a single
134# subclass to use, unlike lists where we use all subclasses.
135embedded_subclasses = {
Rich Lanec247ade2014-11-07 09:33:24 -0800136 'of_oxm_t': 'of_oxm_eth_type',
137 'of_bsn_vport_t': 'of_bsn_vport_q_in_q',
Rich Lane1f315aa2014-10-13 17:11:35 -0700138}
139
Rich Lanea06d0c32013-03-25 08:52:03 -0700140def ignore_member(cls, version, m_name, m_type):
141 """
142 Filter out names or types that either don't have accessors
143 or those that should not be messed with
144 or whose types we're not ready to deal with yet.
145 """
Rich Lane79c87192014-03-04 10:56:59 -0800146
147 uclass = loxi_globals.unified.class_by_name(cls)
148 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800150
Rich Lane79c87192014-03-04 10:56:59 -0800151 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800152 return True
Rich Lane79c87192014-03-04 10:56:59 -0800153
Rich Lanea06d0c32013-03-25 08:52:03 -0700154 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
155
156def gen_fill_string(out):
157 out.write("""
158
159/**
160 * The increment to use on values inside a string
161 */
162#define OF_TEST_STR_INCR 3
163
164/**
165 * Fill in a buffer with incrementing values starting
166 * at the given offset with the given value
167 * @param buf The buffer to fill
168 * @param value The value to use for data
169 * @param len The number of bytes to fill
170 */
171
172void
173of_test_str_fill(uint8_t *buf, int value, int len)
174{
175 int i;
176
177 for (i = 0; i < len; i++) {
178 *buf = value;
179 value += OF_TEST_STR_INCR;
180 buf++;
181 }
182}
183
184/**
185 * Given a buffer, verify that it's filled as above
186 * @param buf The buffer to check
187 * @param value The value to use for data
188 * @param len The number of bytes to fill
189 * @return Boolean True on equality (success)
190 */
191
192int
193of_test_str_check(uint8_t *buf, int value, int len)
194{
195 int i;
196 uint8_t val8;
197
198 val8 = value;
199
200 for (i = 0; i < len; i++) {
201 if (*buf != val8) {
202 return 0;
203 }
204 val8 += OF_TEST_STR_INCR;
205 buf++;
206 }
207
208 return 1;
209}
210
211/**
212 * Global that determines how octets should be populated
213 * -1 means use value % MAX (below) to determine length
214 * 0, 1, ... means used that fixed length
215 *
216 * Note: Was 16K, but that made objects too big. May add flexibility
217 * to call populate with a max parameter for length
218 */
219int octets_pop_style = -1;
220#define OCTETS_MAX_VALUE (128) /* 16K was too big */
221#define OCTETS_MULTIPLIER 6367 /* A prime */
222
223int
224of_octets_populate(of_octets_t *octets, int value)
225{
226 if (octets_pop_style < 0) {
227 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
228 } else {
229 octets->bytes = octets_pop_style;
230 }
231
232 if (octets->bytes != 0) {
233 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
234 return 0;
235 }
236 of_test_str_fill(octets->data, value, octets->bytes);
237 value += 1;
238 }
239
240 return value;
241}
242
243int
244of_octets_check(of_octets_t *octets, int value)
245{
246 int len;
247
248 if (octets_pop_style < 0) {
249 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
250 TEST_ASSERT(octets->bytes == len);
251 } else {
252 TEST_ASSERT(octets->bytes == octets_pop_style);
253 }
254
255 if (octets->bytes != 0) {
256 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
257 == 1);
258 value += 1;
259 }
260
261 return value;
262}
263
264int
265of_match_populate(of_match_t *match, of_version_t version, int value)
266{
267 MEMSET(match, 0, sizeof(*match));
268 match->version = version;
269""")
270
Rich Laned56f8d22014-05-06 14:52:55 -0700271 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700272 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700273 if (version == %d) {\
274""" % wire_version)
275 for key in keys:
276 entry = match.of_match_members[key]
277 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700278 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
279 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
280 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700281""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
282 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700283 }
284
Rich Laned56f8d22014-05-06 14:52:55 -0700285""")
286
Rich Laneb4a63a52014-05-22 14:41:57 -0700287 for wire_version, match_keys in match.match_keys.items():
288 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700289
290 out.write("""
291 if (value % 2) {
292 /* Sometimes set ipv4 addr masks to non-exact */
293 match->masks.ipv4_src = 0xffff0000;
294 match->masks.ipv4_dst = 0xfffff800;
295 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700296
297 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700298 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700299 return value;
300}
301
302int
303of_match_check(of_match_t *match, of_version_t version, int value)
304{
305 of_match_t check;
306
307 value = of_match_populate(&check, match->version, value);
308 TEST_ASSERT(value != 0);
309 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
310
311 return value;
312}
313""")
314
315def gen_common_test_header(out, name):
316 loxi_utils.gen_c_copy_license(out)
317 out.write("""
318/*
319 * Test header file
320 *
321 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
322 */
323
324#if !defined(_TEST_COMMON_H_)
325#define _TEST_COMMON_H_
326
327#define DISABLE_WARN_UNUSED_RESULT
328#include <loci/loci.h>
329#include <locitest/of_dup.h>
330#include <locitest/unittest.h>
331
332extern int global_error;
333extern int exit_on_error;
334
335/* @todo Make option for -k to continue tests if errors */
336#define RUN_TEST(test) do { \\
337 int rv; \\
338 TESTCASE(test, rv); \\
339 if (rv != TEST_PASS) { \\
340 global_error=1; \\
341 if (exit_on_error) return(1); \\
342 } \\
343 } while(0)
344
345#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
346#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
347
348/*
349 * Declarations of functions to populate scalar values in a a class
350 */
351
352extern void of_test_str_fill(uint8_t *buf, int value, int len);
353extern int of_test_str_check(uint8_t *buf, int value, int len);
354
355
356extern int of_octets_populate(of_octets_t *octets, int value);
357extern int of_octets_check(of_octets_t *octets, int value);
358extern int of_match_populate(of_match_t *match, of_version_t version,
359 int value);
360extern int of_match_check(of_match_t *match, of_version_t version, int value);
361extern int test_ident_macros(void);
362extern int test_dump_objs(void);
363
364/* In test_match_utils.c */
365extern int test_match_utils(void);
366
367extern int run_unified_accessor_tests(void);
368extern int run_match_tests(void);
369extern int run_utility_tests(void);
370
371extern int run_scalar_acc_tests(void);
372extern int run_list_tests(void);
373extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700374
375extern int run_validator_tests(void);
376
377extern int run_list_limits_tests(void);
378
379extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700380extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700381
382""")
383
384 for version in of_g.of_version_range:
385 for cls in of_g.standard_class_order:
386 if not loxi_utils.class_in_version(cls, version):
387 continue
Rich Lane6171e632014-11-07 10:23:38 -0800388 if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700389 continue
390 out.write("""
391extern int %(cls)s_%(v_name)s_populate(
392 %(cls)s_t *obj, int value);
393extern int %(cls)s_%(v_name)s_check(
394 %(cls)s_t *obj, int value);
395extern int %(cls)s_%(v_name)s_populate_scalars(
396 %(cls)s_t *obj, int value);
397extern int %(cls)s_%(v_name)s_check_scalars(
398 %(cls)s_t *obj, int value);
399""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
400
Rich Lanea06d0c32013-03-25 08:52:03 -0700401 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
402
403def gen_common_test(out, name):
404 """
405 Generate common test content including main
406 """
407 loxi_utils.gen_c_copy_license(out)
408 out.write("""
409/*
410 * Common test code for LOCI
411 *
412 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
413 */
414
415#define DISABLE_WARN_UNUSED_RESULT
416#include "loci_log.h"
417#include <loci/loci_obj_dump.h>
418#include <locitest/unittest.h>
419#include <locitest/test_common.h>
420
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900421/* mcheck is a glibc extension */
422#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700423#include <mcheck.h>
424#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900425#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700426#define MCHECK_INIT do { } while (0)
427#endif
428
429/**
430 * Exit on error if set to 1
431 */
432int exit_on_error = 1;
433
434/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700435 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700436 */
437int global_error = 0;
438
439extern int run_unified_accessor_tests(void);
440extern int run_match_tests(void);
441extern int run_utility_tests(void);
442
443extern int run_scalar_acc_tests(void);
444extern int run_list_tests(void);
445extern int run_message_tests(void);
446
447/**
448 * Macros for initializing and checking scalar types
449 *
450 * @param var The variable being initialized or checked
451 * @param val The integer value to set/check against, see below
452 *
453 * Note that equality means something special for strings. Each byte
454 * is initialized to an incrementing value. So check is done against that.
455 *
456 */
457
458""")
459 for t in scalar_types:
460 if t in integer_types:
461 out.write("""
462#define VAR_%s_INIT(var, val) var = (%s)(val)
463#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
464""" % (t.upper(), t, t.upper(), t))
465 else:
466 out.write("""
467#define VAR_%s_INIT(var, val) \\
468 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
469#define VAR_%s_CHECK(var, val) \\
470 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
471""" % (t.upper(), t.upper()))
472
473 gen_fill_string(out)
474 gen_scalar_set_check_funs(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700475 gen_unified_accessor_funs(out)
476
477 gen_ident_tests(out)
478 gen_log_test(out)
479
480def gen_message_scalar_test(out, name):
481 """
482 Generate test cases for message objects, scalar accessors
483 """
484
485 loxi_utils.gen_c_copy_license(out)
486 out.write("""
487/**
488 *
489 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
490 *
491 * Message-scalar tests for all versions
492 */
493
494#include <locitest/test_common.h>
495""")
496 for version in of_g.of_version_range:
497 v_name = loxi_utils.version_to_name(version)
498 out.write("""
499/**
500 * Message-scalar tests for version %s
501 */
502""" % v_name)
503 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800504 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700505 continue
506 if version in of_g.unified[cls]:
507 message_scalar_test(out, version, cls)
508
509 out.write("""
510int
511run_scalar_acc_tests(void)
512{
513""")
514 for version in of_g.of_version_range:
515 v_name = loxi_utils.version_to_name(version)
516 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800517 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700518 continue
519 if version in of_g.unified[cls]:
520 test_name = "%s_%s" % (cls, v_name)
521 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
522
523 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700524
Rich Lanea06d0c32013-03-25 08:52:03 -0700525def message_scalar_test(out, version, cls):
526 """
527 Generate one test case for the given version and class
528 """
529
530 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700531 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700532 v_name = loxi_utils.version_to_name(version)
533
534 out.write("""
535static int
536test_%(cls)s_%(v_name)s_scalar(void)
537{
538 %(cls)s_t *obj;
539
540 obj = %(cls)s_new(%(v_name)s);
541 TEST_ASSERT(obj != NULL);
542 TEST_ASSERT(obj->version == %(v_name)s);
543 TEST_ASSERT(obj->length == %(length)d);
544 TEST_ASSERT(obj->parent == NULL);
545 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700546""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700547 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700548
549 # If this class is a concrete member of an inheritance hierarchy,
550 # run the hierarchy's root wire type parser and assert it returns
551 # the expected object id.
552 ofclass = loxi_globals.unified.class_by_name(cls)
553 if ofclass and not ofclass.virtual:
554 root = ofclass
555 while root.superclass:
556 root = root.superclass
557 if root.virtual:
558 out.write("""
559 {
560 of_object_id_t object_id;
561 %(root_cls)s_wire_object_id_get(obj, &object_id);
562 TEST_ASSERT(object_id == %(u_cls)s);
563 }
564""" % dict(root_cls=root.name, u_cls=cls.upper()))
565
Rich Lanea06d0c32013-03-25 08:52:03 -0700566 if not type_maps.class_is_virtual(cls):
567 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700568 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700569 int length;
570
Rich Lanedc46fe22014-04-03 15:10:38 -0700571 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700572 TEST_ASSERT(length == %(length)d);
573 }
574
575 /* Set up incrementing values for scalar members */
576 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
577
578 /* Check values just set */
579 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700580""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700581 v_name=v_name, length=length, version=version))
582
583 out.write("""
584 %(cls)s_delete(obj);
585
586 /* To do: Check memory */
587 return TEST_PASS;
588}
589""" % dict(cls=cls))
590
591# Get the members and list of scalar types for members of a given class
592def scalar_member_types_get(cls, version):
593 member_types = []
594
595 if not version in of_g.unified[cls]:
596 return ([], [])
597
598 if "use_version" in of_g.unified[cls][version]:
599 v = of_g.unified[cls][version]["use_version"]
600 members = of_g.unified[cls][v]["members"]
601 else:
602 members = of_g.unified[cls][version]["members"]
603 # Accumulate variables that are supported
604 for member in members:
605 m_type = member["m_type"]
606 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700607 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700608 ignore_member(cls, version, m_name, m_type)):
609 continue
610 if not m_type in member_types:
611 member_types.append(m_type)
612
613 return (members, member_types)
614
615def scalar_funs_instance(out, cls, version, members, member_types):
616 """
617 Generate one instance of scalar set/check functions
618 """
619 out.write("""
620/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700621 * Populate the scalar values in obj of type %(cls)s,
622 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700623 * @param obj Pointer to an object to populate
624 * @param value The seed value to use in populating the object
625 * @returns The value after increments for this object's values
626 */
627int %(cls)s_%(v_name)s_populate_scalars(
628 %(cls)s_t *obj, int value) {
629""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
630 # Declare string types
631 for t in member_types:
632 out.write(" %s %s;\n" % (t, var_name_map(t)))
633 for member in members:
634 m_type = member["m_type"]
635 m_name = member["name"]
636 if (not loxi_utils.type_is_scalar(m_type) or
637 ignore_member(cls, version, m_name, m_type)):
638 continue
639 v_name = var_name_map(m_type);
640 out.write("""
641 VAR_%(u_type)s_INIT(%(v_name)s, value);
642 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
643 value += 1;
644""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
645 out.write("""
646 return value;
647}
648""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700649
Rich Lanea06d0c32013-03-25 08:52:03 -0700650 out.write("""
651/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700652 * Check scalar values in obj of type %(cls)s,
653 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700654 * @param obj Pointer to an object to check
655 * @param value Starting value for checking
656 * @returns The value after increments for this object's values
657 */
658int %(cls)s_%(v_name)s_check_scalars(
659 %(cls)s_t *obj, int value) {
660""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
661
662 for t in member_types:
663 out.write(" %s %s;\n" % (t, var_name_map(t)))
664 for member in members:
665 m_type = member["m_type"]
666 m_name = member["name"]
667 if (not loxi_utils.type_is_scalar(m_type) or
668 ignore_member(cls, version, m_name, m_type)):
669 continue
670 v_name = var_name_map(m_type);
671 out.write("""
672 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
673 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
674 value += 1;
675""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
676
677 out.write("""
678 return value;
679}
680
681""")
682
683def gen_scalar_set_check_funs(out):
684 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700685 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700686 set and check their values
687 """
688 for version in of_g.of_version_range:
689 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800690 if type_maps.class_is_virtual(cls):
Rich Lanee499bd12014-10-28 15:25:09 -0700691 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700692 (members, member_types) = scalar_member_types_get(cls, version)
693 scalar_funs_instance(out, cls, version, members, member_types)
694
695
696# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700697def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700698 base_type = loxi_utils.list_to_entry_type(cls)
699 setup_template = """
700 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700701 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700702 value = %(subcls)s_%(v_name)s_populate(
703 %(inst)s, value);
704 cur_len += %(inst)s->length;
705 TEST_ASSERT(list->length == cur_len);
706"""
707 out.write("""
708 /* Append two instances of type %s */
709""" % subcls)
710 for i in range(2):
711 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700712 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700713 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700714 version=version))
715
Rich Lane9afc3b92014-04-09 22:55:53 -0700716def check_instance(out, cls, subcls, instance, v_name, version, last):
717 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700718 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
719 value = %(subcls)s_%(v_name)s_check(
720 %(inst)s, value);
721 TEST_ASSERT(value != 0);
722"""
723 out.write("\n /* Check two instances of type %s */" % instance)
724
Andreas Wundsam53256162013-05-02 14:05:53 -0700725 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700726 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700727 inst=instance, subcls=subcls,
728 v_name=loxi_utils.version_to_name(version)))
729 out.write("""\
730 TEST_OK(%(cls)s_next(list, &elt));
731""" % dict(cls=cls))
732
Andreas Wundsam53256162013-05-02 14:05:53 -0700733 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700734 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700735 inst=instance, subcls=subcls,
736 v_name=loxi_utils.version_to_name(version)))
737 if last:
738 out.write("""\
739 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
740""" % dict(cls=cls))
741 else:
742 out.write("""\
743 TEST_OK(%(cls)s_next(list, &elt));
744""" % dict(cls=cls))
745
Rich Lanea06d0c32013-03-25 08:52:03 -0700746# Maybe: Get a map from list class to parent, mem_name of container
747
748def list_test(out, version, cls):
749 out.write("""
750static int
751test_%(cls)s_%(v_name)s(void)
752{
753""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
754 base_type = loxi_utils.list_to_entry_type(cls)
755
756 out.write(""" %(cls)s_t *list;
757 int value = 1;
758""" % dict(cls=cls, base_type=base_type))
759
760 out.write("""
761 list = %(cls)s_new(%(v_name)s);
762 TEST_ASSERT(list != NULL);
763 TEST_ASSERT(list->version == %(v_name)s);
764 TEST_ASSERT(list->length == 0);
765 TEST_ASSERT(list->parent == NULL);
766 TEST_ASSERT(list->object_id == %(enum_cls)s);
767
Rich Lanec6e97f72014-12-03 12:08:25 -0800768 value = %(cls)s_%(v_name)s_populate(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700769 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700770""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700771 enum_cls=loxi_utils.enum_name(cls)))
772
773 out.write("""
774 /* Now check values */
775 value = 1;
Rich Lanec6e97f72014-12-03 12:08:25 -0800776 value = %(cls)s_%(v_name)s_check(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700777 TEST_ASSERT(value != 0);
778""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
779
780 out.write("""
781 %(cls)s_delete(list);
782
783 return TEST_PASS;
784}
785""" % dict(cls=cls))
786
787def gen_list_test(out, name):
788 """
789 Generate base line test cases for lists
790 @param out The file handle to write to
791 """
792
793 loxi_utils.gen_c_copy_license(out)
794 out.write("""
795/**
796 *
797 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
798 *
799 * Message-scalar tests for all versions
800 */
801
802#include <locitest/test_common.h>
803""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700804
Rich Lanea06d0c32013-03-25 08:52:03 -0700805 for version in of_g.of_version_range:
806 v_name = loxi_utils.version_to_name(version)
807 out.write("""
808/**
809 * Baseline list tests for version %s
810 */
811""" % v_name)
812 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700813 if version in of_g.unified[cls]:
814 list_test(out, version, cls)
815
816 out.write("""
817int
818run_list_tests(void)
819{
820""")
821 for version in of_g.of_version_range:
822 v_name = loxi_utils.version_to_name(version)
823 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700824 if version in of_g.unified[cls]:
825 test_name = "%s_%s" % (cls, v_name)
826 out.write(" RUN_TEST(%s);\n" % test_name)
827
828 out.write("\n return TEST_PASS;\n}\n");
829
830def gen_match_test(out, name):
831 """
832 Generate baseline tests for match functions
833 """
834
835 loxi_utils.gen_c_copy_license(out)
836 out.write("""\
837/**
838 *
839 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
840 *
841 * Message-scalar tests for all versions
842 * @fixme These are mostly hard coded now.
843 */
844
845#include <locitest/test_common.h>
846
847static int
848test_match_1(void)
849{
Rich Lanef87f4c32014-10-14 11:56:02 -0700850""")
851
852 for version in of_g.of_version_range:
853 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
854
855 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700856 of_match_t match;
857 int value = 1;
858 int idx;
859 uint32_t exp_value;
860
861 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700862 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700863 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
864 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
865 if (idx < 32) {
866 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
867 }
868 }
869""")
870
871 for version in of_g.of_version_range:
872 out.write("""
873 /* Create/populate/convert and delete for version %(v_name)s */
874 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
875 TEST_ASSERT(m_v%(version)d != NULL);
876 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
877 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
878 of_match_v%(version)d_delete(m_v%(version)d);
879""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
880
881 out.write("""
882 return TEST_PASS;
883}
884""")
885
886 out.write("""
887static int
888test_match_2(void)
889{
Rich Lanef87f4c32014-10-14 11:56:02 -0700890""")
891
892 for version in of_g.of_version_range:
893 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
894
895 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700896 of_match_t match1;
897 of_match_t match2;
898 int value = 1;
899""")
900
901 for version in of_g.of_version_range:
902 out.write("""
903 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
904 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
905 TEST_ASSERT(m_v%(version)d != NULL);
906 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
907 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
908 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
909 of_match_v%(version)d_delete(m_v%(version)d);
910""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
911
912 out.write("""
913 return TEST_PASS;
914}
915""")
916
917 out.write("""
918static int
919test_match_3(void)
920{
921 of_match_t match1;
922 of_match_t match2;
923 int value = 1;
924 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -0700925 of_object_storage_t storage;
926 memset(&storage, 0, sizeof(storage));
927 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700928""")
929 for version in of_g.of_version_range:
930 out.write("""
931 /* Serialize to version %(v_name)s */
932 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700933 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700934 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -0700935 storage.obj.wbuf->buf = octets.data;
936 storage.obj.wbuf->alloc_bytes = octets.bytes;
937 storage.obj.wbuf->current_bytes = octets.bytes;
938 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700939 OF_ERROR_NONE);
940 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
941 FREE(octets.data);
942""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
943
944 out.write("""
945 return TEST_PASS;
946}
947""")
948
949 out.write("""
950int run_match_tests(void)
951{
952 RUN_TEST(match_1);
953 RUN_TEST(match_2);
954 RUN_TEST(match_3);
955 RUN_TEST(match_utils);
956
957 return TEST_PASS;
958}
959""")
960
961def gen_msg_test(out, name):
962 loxi_utils.gen_c_copy_license(out)
963 out.write("""
964/**
965 *
966 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
967 *
968 * Message-scalar tests for all versions
969 */
970
971#include <locitest/test_common.h>
972""")
973 for version in of_g.of_version_range:
974 for cls in of_g.ordered_messages:
975 if not (cls, version) in of_g.base_length:
976 continue
Rich Lane488b3c52013-06-21 18:11:02 -0700977 if type_maps.class_is_virtual(cls):
978 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -0700979 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700980 out.write("""
981static int
982test_%(cls)s_create_%(v_name)s(void)
983{
984 %(cls)s_t *obj;
985 uint8_t *msg_buf;
986 int value;
Rich Lanea4b68302014-03-12 15:17:58 -0700987 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -0700988 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700989
990 obj = %(cls)s_new(%(v_name)s);
991 TEST_ASSERT(obj != NULL);
992 TEST_ASSERT(obj->version == %(v_name)s);
993 TEST_ASSERT(obj->length == %(bytes)d);
994 TEST_ASSERT(obj->parent == NULL);
995 TEST_ASSERT(obj->object_id == %(enum)s);
996
Rich Lanea4b68302014-03-12 15:17:58 -0700997 of_header_wire_object_id_get(obj, &object_id);
998 TEST_ASSERT(object_id == %(enum)s);
999
Rich Lanea06d0c32013-03-25 08:52:03 -07001000 /* Set up incrementing values for scalar members */
1001 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1002 TEST_ASSERT(value != 0);
1003
Rich Lanebb8f17c2014-06-12 13:14:09 -07001004 len = obj->length;
1005
Rich Lanea06d0c32013-03-25 08:52:03 -07001006 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001007 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1008 TEST_ASSERT(msg_buf != NULL);
1009 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001010 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001011
1012 TEST_ASSERT(obj != NULL);
1013
1014 /* @fixme Set up all message objects (recursively?) */
1015
1016 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1017 TEST_ASSERT(value != 0);
1018
1019 %(cls)s_delete(obj);
1020
1021 return TEST_PASS;
1022}
1023""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1024 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1025
1026 out.write("""
1027int
1028run_message_tests(void)
1029{
1030""")
1031 for version in of_g.of_version_range:
1032 for cls in of_g.ordered_messages:
1033 if not (cls, version) in of_g.base_length:
1034 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001035 if type_maps.class_is_virtual(cls):
1036 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001037 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1038 out.write(" RUN_TEST(%s);\n" % test_name)
1039
1040 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001041
Rich Lanea06d0c32013-03-25 08:52:03 -07001042
1043def gen_list_setup_check(out, cls, version):
1044 """
1045 Generate functions that populate and check a list with two
1046 of each type of subclass it supports
1047 """
1048 out.write("""
1049/**
1050 * Populate a list of type %(cls)s with two of each type of subclass
1051 * @param list Pointer to the list to be populated
1052 * @param value The seed value to use in populating the list
1053 * @returns The value after increments for this object's values
1054 */
1055int
1056%(cls)s_%(v_name)s_populate(
1057 %(cls)s_t *list, int value)
1058{
1059""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1060 base_type = loxi_utils.list_to_entry_type(cls)
1061 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001062 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001063 int cur_len = 0;
Rich Lanead708032014-12-03 12:40:58 -08001064 static int recursion;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001065 (void) elt;
1066 (void) cur_len;
Rich Lanead708032014-12-03 12:40:58 -08001067
1068 if (recursion > 0) {
1069 return value;
1070 }
1071
1072 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001073""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001074
Rich Lanea06d0c32013-03-25 08:52:03 -07001075 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001076 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 -07001077 v_name = loxi_utils.version_to_name(version)
1078
Rich Lanee98ee5d2014-10-14 10:43:44 -07001079 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001080 out.write(" /* No subclasses for %s */\n"% base_type)
1081 out.write(" %s_t *elt_p;\n" % base_type)
1082 out.write("\n elt_p = &elt;\n")
1083 else:
1084 out.write(" /* Declare pointers for each subclass */\n")
1085 for instance, subcls in sub_classes:
1086 out.write(" %s_t *%s;\n" % (subcls, instance))
1087 out.write("\n /* Instantiate pointers for each subclass */\n")
1088 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001089 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001090
Rich Lanee98ee5d2014-10-14 10:43:44 -07001091 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001092 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001093 else:
1094 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001095 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001096 out.write("""
Rich Lanead708032014-12-03 12:40:58 -08001097 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001098 return value;
1099}
1100""")
1101 out.write("""
1102/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001103 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001104 * %(cls)s_%(v_name)s_populate
1105 * @param list Pointer to the list that was populated
1106 * @param value Starting value for checking
1107 * @returns The value after increments for this object's values
1108 */
1109int
1110%(cls)s_%(v_name)s_check(
1111 %(cls)s_t *list, int value)
1112{
1113""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1114 base_type = loxi_utils.list_to_entry_type(cls)
1115 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001116 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001117 int count = 0;
1118 int rv;
Rich Lanead708032014-12-03 12:40:58 -08001119 static int recursion;
1120
1121 if (recursion > 0) {
1122 return value;
1123 }
1124
1125 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001126""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001127
Rich Lanea06d0c32013-03-25 08:52:03 -07001128
1129 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001130 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 -07001131 v_name = loxi_utils.version_to_name(version)
1132
Rich Lanee98ee5d2014-10-14 10:43:44 -07001133 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001134 entry_count = 2
1135 out.write(" /* No subclasses for %s */\n"% base_type)
1136 out.write(" %s_t *elt_p;\n" % base_type)
1137 out.write("\n elt_p = &elt;\n")
1138 else:
1139 entry_count = 2 * len(sub_classes) # Two of each type appended
1140 out.write(" /* Declare pointers for each subclass */\n")
1141 for instance, subcls in sub_classes:
1142 out.write(" %s_t *%s;\n" % (subcls, instance))
1143 out.write("\n /* Instantiate pointers for each subclass */\n")
1144 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001145 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001146
Rich Lanee98ee5d2014-10-14 10:43:44 -07001147 if not type_maps.class_is_virtual(base_type) or sub_classes:
1148 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1149
1150 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001151 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001152 version, True)
1153 else:
1154 count = 0
1155 for instance, subcls in sub_classes:
1156 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001157 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001158 version, count==len(sub_classes))
1159 out.write("""
1160""" % dict(base_type=base_type))
1161
1162 out.write("""
1163 /* Do an iterate to test the iterator */
1164 %(u_cls)s_ITER(list, &elt, rv) {
1165 count += 1;
1166 }
1167
1168 TEST_ASSERT(rv == OF_ERROR_RANGE);
1169 TEST_ASSERT(count == %(entry_count)d);
1170
1171 /* We shoehorn a test of the dup functions here */
1172 {
1173 %(cls)s_t *dup;
1174
1175 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1176 TEST_ASSERT(dup->length == list->length);
1177 TEST_ASSERT(dup->object_id == list->object_id);
1178 TEST_ASSERT(dup->version == list->version);
1179 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1180 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1181 of_object_delete((of_object_t *)dup);
1182
1183 /* And now for the generic dup function */
1184 TEST_ASSERT((dup = (%(cls)s_t *)
1185 of_object_dup(list)) != NULL);
1186 TEST_ASSERT(dup->length == list->length);
1187 TEST_ASSERT(dup->object_id == list->object_id);
1188 TEST_ASSERT(dup->version == list->version);
1189 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1190 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1191 of_object_delete((of_object_t *)dup);
1192 }
1193
Rich Lanead708032014-12-03 12:40:58 -08001194 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001195 return value;
1196}
1197""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1198
1199
1200def gen_class_setup_check(out, cls, version):
1201 out.write("""
1202/**
1203 * Populate all members of an object of type %(cls)s
1204 * with incrementing values
1205 * @param obj Pointer to an object to populate
1206 * @param value The seed value to use in populating the object
1207 * @returns The value after increments for this object's values
1208 */
1209
1210int
1211%(cls)s_%(v_name)s_populate(
1212 %(cls)s_t *obj, int value)
1213{
1214""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1215 members, member_types = loxi_utils.all_member_types_get(cls, version)
1216 for m_type in member_types:
1217 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1218 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001219 elif m_type in embedded_subclasses:
1220 subcls = embedded_subclasses[m_type]
1221 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001222 else:
1223 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1224 out.write("""
1225 /* Run thru accessors after new to ensure okay */
1226""")
1227 for member in members:
1228 m_type = member["m_type"]
1229 m_name = member["name"]
1230 if loxi_utils.skip_member_name(m_name):
1231 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001232 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001233 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001234 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1235 out.write("""\
1236 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1237""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1238 else:
1239 sub_cls = m_type[:-2] # Trim _t
1240 out.write("""\
1241 {
1242 %(sub_cls)s_t sub_cls;
1243
1244 /* Test bind */
1245 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1246 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001247""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001248 m_name=m_name, sub_cls=sub_cls,
1249 v_name=loxi_utils.version_to_name(version)))
1250
1251 out.write("""
1252 value = %(cls)s_%(v_name)s_populate_scalars(
1253 obj, value);
1254 TEST_ASSERT(value != 0);
1255""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1256
1257 for member in members:
1258 m_type = member["m_type"]
1259 m_name = member["name"]
1260 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1261 continue
1262 if loxi_utils.skip_member_name(m_name):
1263 continue
1264 if m_type == "of_match_t":
1265 out.write("""\
1266 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1267 TEST_ASSERT(value != 0);
1268 %(cls)s_%(m_name)s_set(
1269 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001270""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001271 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1272 elif m_type == "of_octets_t":
1273 out.write("""\
1274 value = of_octets_populate(&%(var_name)s, value);
1275 TEST_ASSERT(value != 0);
1276 %(cls)s_%(m_name)s_set(
1277 obj, &%(var_name)s);
1278 if (octets.bytes) {
1279 FREE(octets.data);
1280 }
1281""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001282 elif m_type in embedded_subclasses:
1283 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001284 out.write("""\
1285 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1286 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001287 value = %(sub_cls)s_%(v_name)s_populate(
1288 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001289 TEST_ASSERT(value != 0);
1290 %(cls)s_%(m_name)s_set(
1291 obj, %(var_name)s);
1292 %(sub_cls)s_delete(%(var_name)s);
1293""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1294 var_name=var_name_map(m_type),
1295 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001296 else:
1297 sub_cls = m_type[:-2] # Trim _t
1298 out.write("""
1299 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1300 TEST_ASSERT(%(var_name)s != NULL);
1301 value = %(sub_cls)s_%(v_name)s_populate(
1302 %(var_name)s, value);
1303 TEST_ASSERT(value != 0);
1304 %(cls)s_%(m_name)s_set(
1305 obj, %(var_name)s);
1306 %(sub_cls)s_delete(%(var_name)s);
1307""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1308 var_name=var_name_map(m_type),
1309 v_name=loxi_utils.version_to_name(version)))
1310
1311 out.write("""
1312 return value;
1313}
1314""")
1315
1316 out.write("""
1317/**
1318 * Check all members of an object of type %(cls)s
1319 * populated by the above function
1320 * @param obj Pointer to an object to check
1321 * @param value Starting value for checking
1322 * @returns The value after increments for this object's values
1323 */
1324
1325int
1326%(cls)s_%(v_name)s_check(
1327 %(cls)s_t *obj, int value)
1328{
1329""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1330 members, member_types = loxi_utils.all_member_types_get(cls, version)
1331 for m_type in member_types:
1332 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1333 continue
1334 if loxi_utils.type_is_of_object(m_type):
1335 continue
1336 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1337 out.write("""
1338 value = %(cls)s_%(v_name)s_check_scalars(
1339 obj, value);
1340 TEST_ASSERT(value != 0);
1341""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1342
1343 for member in members:
1344 m_type = member["m_type"]
1345 m_name = member["name"]
1346 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1347 continue
1348 if loxi_utils.skip_member_name(m_name):
1349 continue
1350 if m_type == "of_match_t":
1351 out.write("""\
1352 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1353 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1354""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1355 v_name=loxi_utils.version_to_name(version)))
1356 elif m_type == "of_octets_t":
1357 out.write("""\
1358 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1359 value = of_octets_check(&%(var_name)s, value);
1360""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1361 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001362 elif m_type in embedded_subclasses:
1363 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001364 out.write("""
1365 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001366 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001367
1368 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1369 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001370 value = %(sub_cls)s_%(v_name)s_check(
1371 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001372 TEST_ASSERT(value != 0);
1373 %(sub_cls)s_delete(%(m_name)s_ptr);
1374 }
1375""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1376 var_name=var_name_map(m_type),
1377 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001378 else:
1379 sub_cls = m_type[:-2] # Trim _t
1380 out.write("""
1381 { /* Use get/delete to access on check */
1382 %(m_type)s *%(m_name)s_ptr;
1383
1384 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1385 TEST_ASSERT(%(m_name)s_ptr != NULL);
1386 value = %(sub_cls)s_%(v_name)s_check(
1387 %(m_name)s_ptr, value);
1388 TEST_ASSERT(value != 0);
1389 %(sub_cls)s_delete(%(m_name)s_ptr);
1390 }
1391""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1392 var_name=var_name_map(m_type),
1393 v_name=loxi_utils.version_to_name(version)))
1394
1395 out.write("""
1396 /* We shoehorn a test of the dup functions here */
1397 {
1398 %(cls)s_t *dup;
1399
1400 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1401 TEST_ASSERT(dup->length == obj->length);
1402 TEST_ASSERT(dup->object_id == obj->object_id);
1403 TEST_ASSERT(dup->version == obj->version);
1404 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1405 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1406 of_object_delete((of_object_t *)dup);
1407
1408 /* And now for the generic dup function */
1409 TEST_ASSERT((dup = (%(cls)s_t *)
1410 of_object_dup(obj)) != NULL);
1411 TEST_ASSERT(dup->length == obj->length);
1412 TEST_ASSERT(dup->object_id == obj->object_id);
1413 TEST_ASSERT(dup->version == obj->version);
1414 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1415 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1416 of_object_delete((of_object_t *)dup);
1417 }
1418
1419 return value;
1420}
1421""" % dict(cls=cls))
1422
1423def unified_accessor_test_case(out, cls, version):
1424 """
1425 Generate one test case for the given version and class
1426 """
1427
1428 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001429 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001430 v_name = loxi_utils.version_to_name(version)
1431
1432 out.write("""
1433static int
1434test_%(cls)s_%(v_name)s(void)
1435{
1436 %(cls)s_t *obj;
1437 obj = %(cls)s_new(%(v_name)s);
1438 TEST_ASSERT(obj != NULL);
1439 TEST_ASSERT(obj->version == %(v_name)s);
1440 TEST_ASSERT(obj->length == %(length)d);
1441 TEST_ASSERT(obj->parent == NULL);
1442 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001443""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001444 v_name=v_name, length=length, version=version))
1445 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1446 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001447 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001448 int length;
1449
Rich Lanedc46fe22014-04-03 15:10:38 -07001450 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001451 TEST_ASSERT(length == %(length)d);
1452 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001453 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001454 of_object_id_t obj_id;
1455
Rich Lanedc46fe22014-04-03 15:10:38 -07001456 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001457 TEST_ASSERT(obj_id == %(u_cls)s);
1458 }
1459
1460 /* Set up incrementing values for members */
1461 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1462 obj, 1) != 0);
1463
1464 /* Check values just set */
1465 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1466 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001467""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001468 v_name=v_name, length=length, version=version))
1469
1470 out.write("""
1471 %(cls)s_delete(obj);
1472
1473 /* To do: Check memory */
1474 return TEST_PASS;
1475}
1476""" % dict(cls=cls))
1477
1478
1479def gen_unified_accessor_funs(out):
1480 for version in of_g.of_version_range:
1481 for cls in of_g.standard_class_order:
1482 if not loxi_utils.class_in_version(cls, version):
1483 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001484 elif loxi_utils.class_is_list(cls):
1485 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001486 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001487 gen_class_setup_check(out, cls, version)
1488
1489def gen_unified_accessor_tests(out, name):
1490 loxi_utils.gen_c_copy_license(out)
1491 out.write("""
1492/**
1493 *
1494 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1495 *
1496 * Unified simple class instantiation tests for all versions
1497 */
1498
1499#include <locitest/test_common.h>
1500""")
1501 for version in of_g.of_version_range:
1502 for cls in of_g.standard_class_order:
1503 if not loxi_utils.class_in_version(cls, version):
1504 continue
Rich Lane6171e632014-11-07 10:23:38 -08001505 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001506 continue
1507 unified_accessor_test_case(out, cls, version)
1508
1509 out.write("""
1510int
1511run_unified_accessor_tests(void)
1512{
1513""")
1514 for version in of_g.of_version_range:
1515 v_name = loxi_utils.version_to_name(version)
1516 for cls in of_g.standard_class_order:
1517 if not loxi_utils.class_in_version(cls, version):
1518 continue
Rich Lane6171e632014-11-07 10:23:38 -08001519 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001520 continue
1521 test_name = "%s_%s" % (cls, v_name)
1522 out.write(" RUN_TEST(%s);\n" % test_name)
1523
1524 out.write(" return TEST_PASS;\n}\n");
1525
1526
1527
1528################################################################
1529#
1530# Object duplication functions
1531#
1532# These exercise the accessors to create duplicate objects.
1533# They are used in the LOCI test shim which sits in an OF
1534# protocol stream.
1535#
1536# TODO
1537# Resolve version stuff
1538# Complete list dup
1539
1540def gen_dup_list(out, cls, version):
1541 ver_name = loxi_utils.version_to_name(version)
1542 elt_type = loxi_utils.list_to_entry_type(cls)
1543 out.write("""
1544/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001545 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001546 * using accessor functions
1547 * @param src Pointer to object to be duplicated
1548 * @returns A new object of type %(cls)s.
1549 *
1550 * The caller is responsible for deleting the returned value
1551 */
1552%(cls)s_t *
1553%(cls)s_%(ver_name)s_dup(
1554 %(cls)s_t *src)
1555{
Rich Lanee499bd12014-10-28 15:25:09 -07001556 of_object_t src_elt;
1557 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001558 int rv;
1559 %(cls)s_t *dst;
1560
1561 if ((dst = %(cls)s_new(src->version)) == NULL) {
1562 return NULL;
1563 }
1564""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1565
1566 out.write("""
1567 %(u_cls)s_ITER(src, &src_elt, rv) {
1568 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1569 of_object_delete((of_object_t *)dst);
1570 return NULL;
1571 }
1572 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1573 dst, NULL);
1574 of_object_delete((of_object_t *)dst_elt);
1575 }
1576
1577 return dst;
1578}
1579""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1580
1581
1582def gen_dup_inheritance(out, cls, version):
1583 ver_name = loxi_utils.version_to_name(version)
1584 out.write("""
1585/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001586 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001587 * @param src Pointer to object to be duplicated
1588 * @returns A new object of type %(cls)s.
1589 *
1590 * The caller is responsible for deleting the returned value
1591 */
Rich Lanee499bd12014-10-28 15:25:09 -07001592of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001593%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001594 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001595{
1596""" % dict(cls=cls, ver_name=ver_name))
1597
1598 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001599 sub_classes = type_maps.sub_class_map(cls, version)
1600 for (_, sub_cls) in sub_classes:
1601 sub_enum = sub_cls.upper()
Rich Lane6171e632014-11-07 10:23:38 -08001602 if type_maps.class_is_virtual(sub_cls):
1603 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001604 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001605 if (src->object_id == %(sub_enum)s) {
1606 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001607 }
1608""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1609
1610 out.write("""
1611 return NULL;
1612}
1613""")
1614
1615
1616def gen_dup_cls(out, cls, version):
1617 """
1618 Generate duplication routine for class cls
1619 """
1620 ver_name = loxi_utils.version_to_name(version)
1621
1622 out.write("""
1623/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001624 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001625 * using accessor functions
1626 * @param src Pointer to object to be duplicated
1627 * @returns A new object of type %(cls)s.
1628 *
1629 * The caller is responsible for deleting the returned value
1630 */
1631%(cls)s_t *
1632%(cls)s_%(ver_name)s_dup(
1633 %(cls)s_t *src)
1634{
1635 %(cls)s_t *dst;
1636""" % dict(cls=cls, ver_name=ver_name))
1637
1638 # Get members and types for the class
1639 members, member_types = loxi_utils.all_member_types_get(cls, version)
1640
1641 # Add declarations for each member type
1642 for m_type in member_types:
1643 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1644 # Declare instance of these
1645 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001646 elif m_type in embedded_subclasses:
1647 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001648 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001649 %(sub_cls)s_t src_%(v_name)s;
1650 %(sub_cls)s_t *dst_%(v_name)s;
1651""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001652 else:
1653 out.write("""
1654 %(m_type)s src_%(v_name)s;
1655 %(m_type)s *dst_%(v_name)s;
1656""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1657
1658 out.write("""
1659 if ((dst = %(cls)s_new(src->version)) == NULL) {
1660 return NULL;
1661 }
1662""" % dict(cls=cls))
1663
1664 for member in members:
1665 m_type = member["m_type"]
1666 m_name = member["name"]
1667 if loxi_utils.skip_member_name(m_name):
1668 continue
1669 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1670 out.write("""
1671 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1672 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1673""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1674 elif m_type in ["of_match_t", "of_octets_t"]:
1675 out.write("""
1676 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1677 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1678""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001679 elif m_type in embedded_subclasses:
1680 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001681 out.write("""
1682 %(cls)s_%(m_name)s_bind(
1683 src, &src_%(v_name)s);
1684 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1685 if (dst_%(v_name)s == NULL) {
1686 %(cls)s_delete(dst);
1687 return NULL;
1688 }
1689 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1690 %(sub_cls)s_delete(dst_%(v_name)s);
1691""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1692 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001693 else:
1694 sub_cls = m_type[:-2] # Trim _t
1695 out.write("""
1696 %(cls)s_%(m_name)s_bind(
1697 src, &src_%(v_name)s);
1698 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1699 if (dst_%(v_name)s == NULL) {
1700 %(cls)s_delete(dst);
1701 return NULL;
1702 }
1703 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1704 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001705""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001706 v_name=var_name_map(m_type), ver_name=ver_name))
1707
1708 out.write("""
1709 return dst;
1710}
1711""")
1712
1713def gen_version_dup(out=sys.stdout):
1714 """
1715 Generate duplication routines for each object type
1716 """
1717 out.write("""
1718/* Special try macro for duplicating */
1719#define _TRY_FREE(op, obj, rv) do { \\
1720 int _rv; \\
1721 if ((_rv = (op)) < 0) { \\
1722 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1723 of_object_delete((of_object_t *)(obj)); \\
1724 return (rv); \\
1725 } \\
1726 } while (0)
1727""")
1728
1729 for version in of_g.of_version_range:
1730 for cls in of_g.standard_class_order:
1731 if not loxi_utils.class_in_version(cls, version):
1732 continue
Rich Lane8841f352014-10-12 19:18:36 -07001733 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001734 gen_dup_inheritance(out, cls, version)
1735 elif loxi_utils.class_is_list(cls):
1736 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001737 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001738 gen_dup_cls(out, cls, version)
1739
1740def gen_dup(out=sys.stdout):
1741 """
1742 Generate non-version specific duplication routines for each object type
1743 """
1744
1745 for cls in of_g.standard_class_order:
1746 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001747of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001748%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001749 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001750{
1751""" % dict(cls=cls))
1752 for version in of_g.of_version_range:
1753 if not loxi_utils.class_in_version(cls, version):
1754 continue
Rich Lane6171e632014-11-07 10:23:38 -08001755 elif type_maps.class_is_inheritance_root(cls):
1756 pass
1757 elif loxi_utils.class_is_list(cls):
1758 pass
1759 elif type_maps.class_is_virtual(cls):
1760 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001761 ver_name = loxi_utils.version_to_name(version)
1762 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001763 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001764 return %(cls)s_%(ver_name)s_dup(src);
1765 }
Rich Lanee499bd12014-10-28 15:25:09 -07001766""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001767
1768 out.write("""
1769 /* Class not supported in given version */
1770 return NULL;
1771}
1772""")
1773
1774def dup_c_gen(out, name):
1775 """
1776 Generate the C file for duplication functions
1777 """
1778 loxi_utils.gen_c_copy_license(out)
1779 out.write("""\
1780/*
1781 * Duplication functions for all OF objects
1782 *
1783 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1784 *
1785 * These are test functions for exercising accessors. You can call
1786 * of_object_dup for an efficient duplication.
1787 */
1788
1789#define DISABLE_WARN_UNUSED_RESULT
1790#include "loci_log.h"
1791#include <locitest/of_dup.h>
1792
1793""")
1794
1795 gen_version_dup(out)
1796 gen_dup(out)
1797
1798
1799def dup_h_gen(out, name):
1800 """
1801 Generate the header file for duplication functions
1802 """
1803
1804 loxi_utils.gen_c_copy_license(out)
1805 out.write("""
1806/*
1807 * Duplication function header file
1808 *
1809 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1810 */
1811
1812#if !defined(_OF_DUP_H_)
1813#define _OF_DUP_H_
1814
1815#include <loci/loci.h>
1816""")
1817
1818 for cls in of_g.standard_class_order:
1819 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001820extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001821 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001822 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001823""" % dict(cls=cls))
1824
1825 for version in of_g.of_version_range:
1826 for cls in of_g.standard_class_order:
1827 if not loxi_utils.class_in_version(cls, version):
1828 continue
Rich Lane6171e632014-11-07 10:23:38 -08001829 elif type_maps.class_is_inheritance_root(cls):
1830 pass
1831 elif loxi_utils.class_is_list(cls):
1832 pass
1833 elif type_maps.class_is_virtual(cls):
1834 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001835 ver_name = loxi_utils.version_to_name(version)
1836 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001837extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001838 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001839 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001840""" % dict(cls=cls, ver_name=ver_name))
1841
1842 out.write("\n#endif /* _OF_DUP_H_ */\n")
1843
1844def gen_log_test(out):
1845 """
1846 Generate test for obj log calls
1847
1848 Define a trivial handler for object logging; call all obj log fns
1849 """
1850 out.write("""
1851
1852/**
1853 * Test object dump functions
1854 */
1855
1856int
1857test_dump_objs(void)
1858{
1859 of_object_t *obj;
1860
1861 FILE *out = fopen("/dev/null", "w");
1862
1863 /* Call each obj dump function */
1864""")
1865 for version in of_g.of_version_range:
1866 for j, cls in enumerate(of_g.all_class_order):
1867 if not loxi_utils.class_in_version(cls, version):
1868 continue
Rich Lane6171e632014-11-07 10:23:38 -08001869 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001870 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001871 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1872 out.write("""
1873 obj = (of_object_t *)%(cls)s_new(%(version)s);
1874 {
1875 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1876 %(cls)s_vport_set(obj, vport);
1877 of_object_delete(vport);
1878 }
1879 of_object_dump((loci_writer_f)fprintf, out, obj);
1880 of_object_delete(obj);
1881""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1882 else:
1883 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001884 obj = (of_object_t *)%(cls)s_new(%(version)s);
1885 of_object_dump((loci_writer_f)fprintf, out, obj);
1886 of_object_delete(obj);
1887""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001888
Rich Lanea06d0c32013-03-25 08:52:03 -07001889 out.write("""
1890 fclose(out);
1891 return TEST_PASS;
1892}
1893""")
1894
1895def gen_ident_tests(out):
1896 """
1897 Generate tests for identifiers
1898
1899 For all idents, instantiate, test version supported macros
1900 For flags, set it, test it, clear it, test it.
1901 """
1902 out.write("""
1903/**
1904 * Test cases for all flag accessor macros
1905 * These only test self consistency (and that they compile)
1906 */
1907int
1908test_ident_macros(void)
1909{
1910 int value __attribute__((unused));
1911 uint32_t flags;
1912
1913""")
1914
1915 for ident, info in of_g.identifiers.items():
1916 if not identifiers.defined_versions_agree(of_g.identifiers,
1917 of_g.target_version_list,
1918 ident):
1919 # @fixme
1920 continue
1921 out.write(" value = %s;\n" % ident)
1922 for version in of_g.target_version_list:
1923 if version in info["values_by_version"].keys():
1924 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1925 (ident, of_g.of_version_wire2name[version]))
1926 else:
1927 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1928 (ident, of_g.of_version_wire2name[version]))
1929 if flags.ident_is_flag(ident):
1930 # Grab first supported version
1931 for version in info["values_by_version"]:
1932 break
1933 out.write("""
1934 flags = 0;
1935 %(ident)s_SET(flags, %(ver_name)s);
1936 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1937 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1938 %(ident)s_CLEAR(flags, %(ver_name)s);
1939 TEST_ASSERT(flags == 0);
1940 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1941""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1942
1943 out.write("""
1944 return TEST_PASS;
1945}
1946""")
1947
Rich Laneccae0312013-07-21 23:34:13 -07001948def gen_datafiles_tests(out, name):
1949 tests = []
1950 for filename in test_data.list_files():
1951 data = test_data.read(filename)
1952 if not 'c' in data:
1953 continue
1954 name = filename[:-5].replace("/", "_")
1955 tests.append(dict(name=name,
1956 filename=filename,
1957 c=data['c'],
1958 binary=data['binary']))
1959
1960 util.render_template(out, "test_data.c", tests=tests)