blob: f2f24dcc942395c317f3f6ba25d7dcf16b256b76 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Test case generation functions
30
31@fixme Update the following
32The following components are generated.
33
34test_common.[ch]: A collection of common code for tests. Currently
35this includes the ability to set the scalar members of an object with
36incrementing values and then similarly verify those values
37
38test_scalar_acc.c: Instantiate each type of object, then set and get
39scalar values in the objects.
40
41test_list.c: Instantiate each type of list, add an element of each
42type the list supports, setting scalar values of the elements.
43
44test_match.c: Various tests for match objects
45
46test_msg.c: Instantiate top level messages
47
48These will move towards unified tests that do the following:
49
50Create or init an object.
51Populate the object with incrementing values.
52Possibly transform the object in some way (e.g., run the underlying
53wire buffer through a parse routine).
54Verify that the members all have the appropriate value
55
56Through out, checking the consistency of memory and memory operations
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +090057is done with mcheck (if available).
Rich Lanea06d0c32013-03-25 08:52:03 -070058
59"""
60
61import sys
Andreas Wundsam76db0062013-11-15 13:34:41 -080062import c_gen.of_g_legacy as of_g
Andreas Wundsam542a13c2013-11-15 13:28:55 -080063import c_gen.match as match
64import c_gen.flags as flags
Rich Lanea06d0c32013-03-25 08:52:03 -070065from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080066import c_gen.type_maps as type_maps
67import c_gen.loxi_utils_legacy as loxi_utils
68import c_gen.identifiers as identifiers
Rich Laneccae0312013-07-21 23:34:13 -070069import util
70import test_data
Rich Lane79c87192014-03-04 10:56:59 -080071import loxi_globals
72from loxi_ir import *
Rich Lanea06d0c32013-03-25 08:52:03 -070073
74def var_name_map(m_type):
75 """
76 Map a type to a generic variable name for the type.
77 @param m_type The data type
78
79 Used mostly in test code generation, but also for the dup functions.
80 """
81 _var_name_map= dict(
82 uint8_t="val8",
83 uint16_t="val16",
84 uint32_t="val32",
85 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070086 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_port_no_t="port_no",
88 of_fm_cmd_t="fm_cmd",
89 of_wc_bmap_t="wc_bmap",
90 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070091 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070092 of_table_name_t="table_name",
93 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070094 of_serial_num_t="ser_num",
Rich Lanef8a3d002014-03-19 13:33:52 -070095 of_str64_t="str64",
Andreas Wundsam53256162013-05-02 14:05:53 -070096 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070097 of_ipv6_t="ipv6",
98 # Non-scalars; more TBD
99 of_octets_t="octets",
100 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700101 of_match_t="match",
Rich Lane90020b42014-04-07 12:05:45 -0700102 of_oxm_header_t="oxm",
Wilson Ngd6181882014-04-14 16:28:35 -0700103 of_bsn_vport_header_t="bsn_vport",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700104 # BSN extensions
105 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700106 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800107 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700108 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700109
110 if m_type.find("of_list_") == 0:
111 return "list"
112 if m_type in of_g.of_mixed_types:
113 return of_g.of_mixed_types[m_type]["short_name"]
114 return _var_name_map[m_type]
115
116integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
117 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700118 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700119string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700120 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700121 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
122 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700123
124scalar_types = integer_types[:]
125scalar_types.extend(string_types)
126
127def ignore_member(cls, version, m_name, m_type):
128 """
129 Filter out names or types that either don't have accessors
130 or those that should not be messed with
131 or whose types we're not ready to deal with yet.
132 """
Rich Lane79c87192014-03-04 10:56:59 -0800133
134 uclass = loxi_globals.unified.class_by_name(cls)
135 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700136 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800137
Rich Lane79c87192014-03-04 10:56:59 -0800138 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800139 return True
Rich Lane79c87192014-03-04 10:56:59 -0800140
Rich Lanea06d0c32013-03-25 08:52:03 -0700141 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
142
143def gen_fill_string(out):
144 out.write("""
145
146/**
147 * The increment to use on values inside a string
148 */
149#define OF_TEST_STR_INCR 3
150
151/**
152 * Fill in a buffer with incrementing values starting
153 * at the given offset with the given value
154 * @param buf The buffer to fill
155 * @param value The value to use for data
156 * @param len The number of bytes to fill
157 */
158
159void
160of_test_str_fill(uint8_t *buf, int value, int len)
161{
162 int i;
163
164 for (i = 0; i < len; i++) {
165 *buf = value;
166 value += OF_TEST_STR_INCR;
167 buf++;
168 }
169}
170
171/**
172 * Given a buffer, verify that it's filled as above
173 * @param buf The buffer to check
174 * @param value The value to use for data
175 * @param len The number of bytes to fill
176 * @return Boolean True on equality (success)
177 */
178
179int
180of_test_str_check(uint8_t *buf, int value, int len)
181{
182 int i;
183 uint8_t val8;
184
185 val8 = value;
186
187 for (i = 0; i < len; i++) {
188 if (*buf != val8) {
189 return 0;
190 }
191 val8 += OF_TEST_STR_INCR;
192 buf++;
193 }
194
195 return 1;
196}
197
198/**
199 * Global that determines how octets should be populated
200 * -1 means use value % MAX (below) to determine length
201 * 0, 1, ... means used that fixed length
202 *
203 * Note: Was 16K, but that made objects too big. May add flexibility
204 * to call populate with a max parameter for length
205 */
206int octets_pop_style = -1;
207#define OCTETS_MAX_VALUE (128) /* 16K was too big */
208#define OCTETS_MULTIPLIER 6367 /* A prime */
209
210int
211of_octets_populate(of_octets_t *octets, int value)
212{
213 if (octets_pop_style < 0) {
214 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
215 } else {
216 octets->bytes = octets_pop_style;
217 }
218
219 if (octets->bytes != 0) {
220 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
221 return 0;
222 }
223 of_test_str_fill(octets->data, value, octets->bytes);
224 value += 1;
225 }
226
227 return value;
228}
229
230int
231of_octets_check(of_octets_t *octets, int value)
232{
233 int len;
234
235 if (octets_pop_style < 0) {
236 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
237 TEST_ASSERT(octets->bytes == len);
238 } else {
239 TEST_ASSERT(octets->bytes == octets_pop_style);
240 }
241
242 if (octets->bytes != 0) {
243 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
244 == 1);
245 value += 1;
246 }
247
248 return value;
249}
250
251int
252of_match_populate(of_match_t *match, of_version_t version, int value)
253{
254 MEMSET(match, 0, sizeof(*match));
255 match->version = version;
256""")
257
Rich Laned56f8d22014-05-06 14:52:55 -0700258 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700259 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700260 if (version == %d) {\
261""" % wire_version)
262 for key in keys:
263 entry = match.of_match_members[key]
264 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700265 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
266 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
267 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700268""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
269 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700270 }
271
Rich Laned56f8d22014-05-06 14:52:55 -0700272""")
273
274 populate_match_version(1, match.of_v1_keys)
275 populate_match_version(2, match.of_v2_keys)
276 populate_match_version(3, match.match_keys_sorted)
277 populate_match_version(4, match.match_keys_sorted)
Rich Lanea06d0c32013-03-25 08:52:03 -0700278
279 out.write("""
280 if (value % 2) {
281 /* Sometimes set ipv4 addr masks to non-exact */
282 match->masks.ipv4_src = 0xffff0000;
283 match->masks.ipv4_dst = 0xfffff800;
284 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700285
286 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700287 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700288 return value;
289}
290
291int
292of_match_check(of_match_t *match, of_version_t version, int value)
293{
294 of_match_t check;
295
296 value = of_match_populate(&check, match->version, value);
297 TEST_ASSERT(value != 0);
298 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
299
300 return value;
301}
302""")
303
304def gen_common_test_header(out, name):
305 loxi_utils.gen_c_copy_license(out)
306 out.write("""
307/*
308 * Test header file
309 *
310 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
311 */
312
313#if !defined(_TEST_COMMON_H_)
314#define _TEST_COMMON_H_
315
316#define DISABLE_WARN_UNUSED_RESULT
317#include <loci/loci.h>
318#include <locitest/of_dup.h>
319#include <locitest/unittest.h>
320
321extern int global_error;
322extern int exit_on_error;
323
324/* @todo Make option for -k to continue tests if errors */
325#define RUN_TEST(test) do { \\
326 int rv; \\
327 TESTCASE(test, rv); \\
328 if (rv != TEST_PASS) { \\
329 global_error=1; \\
330 if (exit_on_error) return(1); \\
331 } \\
332 } while(0)
333
334#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
335#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
336
337/*
338 * Declarations of functions to populate scalar values in a a class
339 */
340
341extern void of_test_str_fill(uint8_t *buf, int value, int len);
342extern int of_test_str_check(uint8_t *buf, int value, int len);
343
344
345extern int of_octets_populate(of_octets_t *octets, int value);
346extern int of_octets_check(of_octets_t *octets, int value);
347extern int of_match_populate(of_match_t *match, of_version_t version,
348 int value);
349extern int of_match_check(of_match_t *match, of_version_t version, int value);
350extern int test_ident_macros(void);
351extern int test_dump_objs(void);
352
353/* In test_match_utils.c */
354extern int test_match_utils(void);
355
356extern int run_unified_accessor_tests(void);
357extern int run_match_tests(void);
358extern int run_utility_tests(void);
359
360extern int run_scalar_acc_tests(void);
361extern int run_list_tests(void);
362extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700363
364extern int run_validator_tests(void);
365
366extern int run_list_limits_tests(void);
367
368extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700369extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700370
371""")
372
373 for version in of_g.of_version_range:
374 for cls in of_g.standard_class_order:
375 if not loxi_utils.class_in_version(cls, version):
376 continue
377 if cls in type_maps.inheritance_map:
378 continue
379 out.write("""
380extern int %(cls)s_%(v_name)s_populate(
381 %(cls)s_t *obj, int value);
382extern int %(cls)s_%(v_name)s_check(
383 %(cls)s_t *obj, int value);
384extern int %(cls)s_%(v_name)s_populate_scalars(
385 %(cls)s_t *obj, int value);
386extern int %(cls)s_%(v_name)s_check_scalars(
387 %(cls)s_t *obj, int value);
388""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
389
390 out.write("""
391/*
392 * Declarations for list population and check primitives
393 */
394""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700395
Rich Lanea06d0c32013-03-25 08:52:03 -0700396 for version in of_g.of_version_range:
397 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700398 if version in of_g.unified[cls]:
399 out.write("""
400extern int
401 list_setup_%(cls)s_%(v_name)s(
402 %(cls)s_t *list, int value);
403extern int
404 list_check_%(cls)s_%(v_name)s(
405 %(cls)s_t *list, int value);
406""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
407
408 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
409
410def gen_common_test(out, name):
411 """
412 Generate common test content including main
413 """
414 loxi_utils.gen_c_copy_license(out)
415 out.write("""
416/*
417 * Common test code for LOCI
418 *
419 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
420 */
421
422#define DISABLE_WARN_UNUSED_RESULT
423#include "loci_log.h"
424#include <loci/loci_obj_dump.h>
425#include <locitest/unittest.h>
426#include <locitest/test_common.h>
427
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900428/* mcheck is a glibc extension */
429#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700430#include <mcheck.h>
431#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900432#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700433#define MCHECK_INIT do { } while (0)
434#endif
435
436/**
437 * Exit on error if set to 1
438 */
439int exit_on_error = 1;
440
441/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700442 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700443 */
444int global_error = 0;
445
446extern int run_unified_accessor_tests(void);
447extern int run_match_tests(void);
448extern int run_utility_tests(void);
449
450extern int run_scalar_acc_tests(void);
451extern int run_list_tests(void);
452extern int run_message_tests(void);
453
454/**
455 * Macros for initializing and checking scalar types
456 *
457 * @param var The variable being initialized or checked
458 * @param val The integer value to set/check against, see below
459 *
460 * Note that equality means something special for strings. Each byte
461 * is initialized to an incrementing value. So check is done against that.
462 *
463 */
464
465""")
466 for t in scalar_types:
467 if t in integer_types:
468 out.write("""
469#define VAR_%s_INIT(var, val) var = (%s)(val)
470#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
471""" % (t.upper(), t, t.upper(), t))
472 else:
473 out.write("""
474#define VAR_%s_INIT(var, val) \\
475 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
476#define VAR_%s_CHECK(var, val) \\
477 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
478""" % (t.upper(), t.upper()))
479
480 gen_fill_string(out)
481 gen_scalar_set_check_funs(out)
482 gen_list_set_check_funs(out)
483 gen_unified_accessor_funs(out)
484
485 gen_ident_tests(out)
486 gen_log_test(out)
487
488def gen_message_scalar_test(out, name):
489 """
490 Generate test cases for message objects, scalar accessors
491 """
492
493 loxi_utils.gen_c_copy_license(out)
494 out.write("""
495/**
496 *
497 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
498 *
499 * Message-scalar tests for all versions
500 */
501
502#include <locitest/test_common.h>
503""")
504 for version in of_g.of_version_range:
505 v_name = loxi_utils.version_to_name(version)
506 out.write("""
507/**
508 * Message-scalar tests for version %s
509 */
510""" % v_name)
511 for cls in of_g.standard_class_order:
512 if cls in type_maps.inheritance_map:
513 continue
514 if version in of_g.unified[cls]:
515 message_scalar_test(out, version, cls)
516
517 out.write("""
518int
519run_scalar_acc_tests(void)
520{
521""")
522 for version in of_g.of_version_range:
523 v_name = loxi_utils.version_to_name(version)
524 for cls in of_g.standard_class_order:
525 if cls in type_maps.inheritance_map:
526 continue
527 if version in of_g.unified[cls]:
528 test_name = "%s_%s" % (cls, v_name)
529 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
530
531 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700532
Rich Lanea06d0c32013-03-25 08:52:03 -0700533def message_scalar_test(out, version, cls):
534 """
535 Generate one test case for the given version and class
536 """
537
538 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700539 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700540 v_name = loxi_utils.version_to_name(version)
541
542 out.write("""
543static int
544test_%(cls)s_%(v_name)s_scalar(void)
545{
546 %(cls)s_t *obj;
547
548 obj = %(cls)s_new(%(v_name)s);
549 TEST_ASSERT(obj != NULL);
550 TEST_ASSERT(obj->version == %(v_name)s);
551 TEST_ASSERT(obj->length == %(length)d);
552 TEST_ASSERT(obj->parent == NULL);
553 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700554""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700555 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700556
557 # If this class is a concrete member of an inheritance hierarchy,
558 # run the hierarchy's root wire type parser and assert it returns
559 # the expected object id.
560 ofclass = loxi_globals.unified.class_by_name(cls)
561 if ofclass and not ofclass.virtual:
562 root = ofclass
563 while root.superclass:
564 root = root.superclass
565 if root.virtual:
566 out.write("""
567 {
568 of_object_id_t object_id;
569 %(root_cls)s_wire_object_id_get(obj, &object_id);
570 TEST_ASSERT(object_id == %(u_cls)s);
571 }
572""" % dict(root_cls=root.name, u_cls=cls.upper()))
573
Rich Lanea06d0c32013-03-25 08:52:03 -0700574 if not type_maps.class_is_virtual(cls):
575 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700576 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700577 int length;
578
Rich Lanedc46fe22014-04-03 15:10:38 -0700579 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 TEST_ASSERT(length == %(length)d);
581 }
582
583 /* Set up incrementing values for scalar members */
584 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
585
586 /* Check values just set */
587 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700588""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700589 v_name=v_name, length=length, version=version))
590
591 out.write("""
592 %(cls)s_delete(obj);
593
594 /* To do: Check memory */
595 return TEST_PASS;
596}
597""" % dict(cls=cls))
598
599# Get the members and list of scalar types for members of a given class
600def scalar_member_types_get(cls, version):
601 member_types = []
602
603 if not version in of_g.unified[cls]:
604 return ([], [])
605
606 if "use_version" in of_g.unified[cls][version]:
607 v = of_g.unified[cls][version]["use_version"]
608 members = of_g.unified[cls][v]["members"]
609 else:
610 members = of_g.unified[cls][version]["members"]
611 # Accumulate variables that are supported
612 for member in members:
613 m_type = member["m_type"]
614 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700615 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700616 ignore_member(cls, version, m_name, m_type)):
617 continue
618 if not m_type in member_types:
619 member_types.append(m_type)
620
621 return (members, member_types)
622
623def scalar_funs_instance(out, cls, version, members, member_types):
624 """
625 Generate one instance of scalar set/check functions
626 """
627 out.write("""
628/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700629 * Populate the scalar values in obj of type %(cls)s,
630 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700631 * @param obj Pointer to an object to populate
632 * @param value The seed value to use in populating the object
633 * @returns The value after increments for this object's values
634 */
635int %(cls)s_%(v_name)s_populate_scalars(
636 %(cls)s_t *obj, int value) {
637""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
638 # Declare string types
639 for t in member_types:
640 out.write(" %s %s;\n" % (t, var_name_map(t)))
641 for member in members:
642 m_type = member["m_type"]
643 m_name = member["name"]
644 if (not loxi_utils.type_is_scalar(m_type) or
645 ignore_member(cls, version, m_name, m_type)):
646 continue
647 v_name = var_name_map(m_type);
648 out.write("""
649 VAR_%(u_type)s_INIT(%(v_name)s, value);
650 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
651 value += 1;
652""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
653 out.write("""
654 return value;
655}
656""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700657
Rich Lanea06d0c32013-03-25 08:52:03 -0700658 out.write("""
659/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700660 * Check scalar values in obj of type %(cls)s,
661 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700662 * @param obj Pointer to an object to check
663 * @param value Starting value for checking
664 * @returns The value after increments for this object's values
665 */
666int %(cls)s_%(v_name)s_check_scalars(
667 %(cls)s_t *obj, int value) {
668""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
669
670 for t in member_types:
671 out.write(" %s %s;\n" % (t, var_name_map(t)))
672 for member in members:
673 m_type = member["m_type"]
674 m_name = member["name"]
675 if (not loxi_utils.type_is_scalar(m_type) or
676 ignore_member(cls, version, m_name, m_type)):
677 continue
678 v_name = var_name_map(m_type);
679 out.write("""
680 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
681 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
682 value += 1;
683""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
684
685 out.write("""
686 return value;
687}
688
689""")
690
691def gen_scalar_set_check_funs(out):
692 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700693 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700694 set and check their values
695 """
696 for version in of_g.of_version_range:
697 for cls in of_g.standard_class_order:
698 (members, member_types) = scalar_member_types_get(cls, version)
699 scalar_funs_instance(out, cls, version, members, member_types)
700
701
702# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700703def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700704 base_type = loxi_utils.list_to_entry_type(cls)
705 setup_template = """
706 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700707 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700708 (%(base_type)s_t *)%(inst)s);
709 value = %(subcls)s_%(v_name)s_populate(
710 %(inst)s, value);
711 cur_len += %(inst)s->length;
712 TEST_ASSERT(list->length == cur_len);
713"""
714 out.write("""
715 /* Append two instances of type %s */
716""" % subcls)
717 for i in range(2):
718 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700719 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700720 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700721 version=version))
722
Rich Lane9afc3b92014-04-09 22:55:53 -0700723def check_instance(out, cls, subcls, instance, v_name, version, last):
724 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700725 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
726 value = %(subcls)s_%(v_name)s_check(
727 %(inst)s, value);
728 TEST_ASSERT(value != 0);
729"""
730 out.write("\n /* Check two instances of type %s */" % instance)
731
Andreas Wundsam53256162013-05-02 14:05:53 -0700732 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700733 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700734 inst=instance, subcls=subcls,
735 v_name=loxi_utils.version_to_name(version)))
736 out.write("""\
737 TEST_OK(%(cls)s_next(list, &elt));
738""" % dict(cls=cls))
739
Andreas Wundsam53256162013-05-02 14:05:53 -0700740 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700741 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700742 inst=instance, subcls=subcls,
743 v_name=loxi_utils.version_to_name(version)))
744 if last:
745 out.write("""\
746 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
747""" % dict(cls=cls))
748 else:
749 out.write("""\
750 TEST_OK(%(cls)s_next(list, &elt));
751""" % dict(cls=cls))
752
753def setup_list_fn(out, version, cls):
754 """
755 Generate a helper function that populates a list with two
756 of each type of subclass it supports
757 """
758 out.write("""
759/**
760 * Set up a list of type %(cls)s with two of each type of subclass
761 */
762int
763list_setup_%(cls)s_%(v_name)s(
764 %(cls)s_t *list, int value)
765{
766""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
767 base_type = loxi_utils.list_to_entry_type(cls)
768 out.write("""
769 %(base_type)s_t elt;
770 int cur_len = 0;
771""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700772
Rich Lanea06d0c32013-03-25 08:52:03 -0700773 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700774 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 -0700775 v_name = loxi_utils.version_to_name(version)
776
777 if len(sub_classes) == 0:
778 out.write(" /* No subclasses for %s */\n"% base_type)
779 out.write(" %s_t *elt_p;\n" % base_type)
780 out.write("\n elt_p = &elt;\n")
781 else:
782 out.write(" /* Declare pointers for each subclass */\n")
783 for instance, subcls in sub_classes:
784 out.write(" %s_t *%s;\n" % (subcls, instance))
785 out.write("\n /* Instantiate pointers for each subclass */\n")
786 for instance, subcls in sub_classes:
787 out.write(" %s = &elt.%s;\n" % (instance, instance))
788
789 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700790 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700791 else:
792 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700793 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700794 out.write("""
795
796 return value;
797}
798""")
799
800def check_list_fn(out, version, cls):
801 """
802 Generate a helper function that checks a list populated by above fn
803 """
804 out.write("""
805/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700806 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700807 * list_setup_%(cls)s_%(v_name)s
808 */
809int
810list_check_%(cls)s_%(v_name)s(
811 %(cls)s_t *list, int value)
812{
813""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
814 base_type = loxi_utils.list_to_entry_type(cls)
815 out.write("""
816 %(base_type)s_t elt;
817""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700818
Rich Lanea06d0c32013-03-25 08:52:03 -0700819 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700820 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 -0700821 v_name = loxi_utils.version_to_name(version)
822
823 if len(sub_classes) == 0:
824 out.write(" /* No subclasses for %s */\n"% base_type)
825 out.write(" %s_t *elt_p;\n" % base_type)
826 out.write("\n elt_p = &elt;\n")
827 else:
828 out.write(" /* Declare pointers for each subclass */\n")
829 for instance, subcls in sub_classes:
830 out.write(" %s_t *%s;\n" % (subcls, instance))
831 out.write("\n /* Instantiate pointers for each subclass */\n")
832 for instance, subcls in sub_classes:
833 out.write(" %s = &elt.%s;\n" % (instance, instance))
834
835 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
836 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700837 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700838 else:
839 count = 0
840 for instance, subcls in sub_classes:
841 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700842 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700843 version, count==len(sub_classes))
844
845 out.write("""
846 return value;
847}
848""" % dict(base_type=base_type))
849
850def gen_list_set_check_funs(out):
851 for version in of_g.of_version_range:
852 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700853 if version in of_g.unified[cls]:
854 setup_list_fn(out, version, cls)
855 check_list_fn(out, version, cls)
856
857# Maybe: Get a map from list class to parent, mem_name of container
858
859def list_test(out, version, cls):
860 out.write("""
861static int
862test_%(cls)s_%(v_name)s(void)
863{
864""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
865 base_type = loxi_utils.list_to_entry_type(cls)
866
867 out.write(""" %(cls)s_t *list;
868 int value = 1;
869""" % dict(cls=cls, base_type=base_type))
870
871 out.write("""
872 list = %(cls)s_new(%(v_name)s);
873 TEST_ASSERT(list != NULL);
874 TEST_ASSERT(list->version == %(v_name)s);
875 TEST_ASSERT(list->length == 0);
876 TEST_ASSERT(list->parent == NULL);
877 TEST_ASSERT(list->object_id == %(enum_cls)s);
878
879 value = list_setup_%(cls)s_%(v_name)s(list, value);
880 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700881""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700882 enum_cls=loxi_utils.enum_name(cls)))
883
884 out.write("""
885 /* Now check values */
886 value = 1;
887 value = list_check_%(cls)s_%(v_name)s(list, value);
888 TEST_ASSERT(value != 0);
889""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
890
891 out.write("""
892 %(cls)s_delete(list);
893
894 return TEST_PASS;
895}
896""" % dict(cls=cls))
897
898def gen_list_test(out, name):
899 """
900 Generate base line test cases for lists
901 @param out The file handle to write to
902 """
903
904 loxi_utils.gen_c_copy_license(out)
905 out.write("""
906/**
907 *
908 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
909 *
910 * Message-scalar tests for all versions
911 */
912
913#include <locitest/test_common.h>
914""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700915
Rich Lanea06d0c32013-03-25 08:52:03 -0700916 for version in of_g.of_version_range:
917 v_name = loxi_utils.version_to_name(version)
918 out.write("""
919/**
920 * Baseline list tests for version %s
921 */
922""" % v_name)
923 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700924 if version in of_g.unified[cls]:
925 list_test(out, version, cls)
926
927 out.write("""
928int
929run_list_tests(void)
930{
931""")
932 for version in of_g.of_version_range:
933 v_name = loxi_utils.version_to_name(version)
934 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700935 if version in of_g.unified[cls]:
936 test_name = "%s_%s" % (cls, v_name)
937 out.write(" RUN_TEST(%s);\n" % test_name)
938
939 out.write("\n return TEST_PASS;\n}\n");
940
941def gen_match_test(out, name):
942 """
943 Generate baseline tests for match functions
944 """
945
946 loxi_utils.gen_c_copy_license(out)
947 out.write("""\
948/**
949 *
950 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
951 *
952 * Message-scalar tests for all versions
953 * @fixme These are mostly hard coded now.
954 */
955
956#include <locitest/test_common.h>
957
958static int
959test_match_1(void)
960{
961 of_match_v1_t *m_v1;
962 of_match_v2_t *m_v2;
963 of_match_v3_t *m_v3;
964 of_match_v4_t *m_v4;
965 of_match_t match;
966 int value = 1;
967 int idx;
968 uint32_t exp_value;
969
970 /* Verify default values for ip mask map */
971 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
972 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
973 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
974 if (idx < 32) {
975 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
976 }
977 }
978
979 TEST_ASSERT(of_ip_mask_map_set(17, 0xabcdef00) == OF_ERROR_NONE);
980 TEST_ASSERT(of_ip_mask_to_index(0xabcdef00) == 17);
981 TEST_ASSERT(of_ip_index_to_mask(17) == 0xabcdef00);
982
983 TEST_ASSERT(of_ip_mask_map_set(62, 0xabcdefff) == OF_ERROR_NONE);
984 TEST_ASSERT(of_ip_mask_to_index(0xabcdefff) == 62);
985 TEST_ASSERT(of_ip_index_to_mask(62) == 0xabcdefff);
986
987 /* Test re-init */
988 of_ip_mask_map_init();
989 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
990 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
991 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
992 if (idx < 32) {
993 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
994 }
995 }
996""")
997
998 for version in of_g.of_version_range:
999 out.write("""
1000 /* Create/populate/convert and delete for version %(v_name)s */
1001 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1002 TEST_ASSERT(m_v%(version)d != NULL);
1003 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
1004 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
1005 of_match_v%(version)d_delete(m_v%(version)d);
1006""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1007
1008 out.write("""
1009 return TEST_PASS;
1010}
1011""")
1012
1013 out.write("""
1014static int
1015test_match_2(void)
1016{
1017 of_match_v1_t *m_v1;
1018 of_match_v2_t *m_v2;
1019 of_match_v3_t *m_v3;
1020 of_match_v3_t *m_v4;
1021 of_match_t match1;
1022 of_match_t match2;
1023 int value = 1;
1024""")
1025
1026 for version in of_g.of_version_range:
1027 out.write("""
1028 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1029 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1030 TEST_ASSERT(m_v%(version)d != NULL);
1031 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1032 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1033 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1034 of_match_v%(version)d_delete(m_v%(version)d);
1035""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1036
1037 out.write("""
1038 return TEST_PASS;
1039}
1040""")
1041
1042 out.write("""
1043static int
1044test_match_3(void)
1045{
1046 of_match_t match1;
1047 of_match_t match2;
1048 int value = 1;
1049 of_octets_t octets;
1050""")
1051 for version in of_g.of_version_range:
1052 out.write("""
1053 /* Serialize to version %(v_name)s */
1054 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001055 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001056 OF_ERROR_NONE);
Andreas Wundsam53256162013-05-02 14:05:53 -07001057 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001058 OF_ERROR_NONE);
1059 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1060 FREE(octets.data);
1061""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1062
1063 out.write("""
1064 return TEST_PASS;
1065}
1066""")
1067
1068 out.write("""
1069int run_match_tests(void)
1070{
1071 RUN_TEST(match_1);
1072 RUN_TEST(match_2);
1073 RUN_TEST(match_3);
1074 RUN_TEST(match_utils);
1075
1076 return TEST_PASS;
1077}
1078""")
1079
1080def gen_msg_test(out, name):
1081 loxi_utils.gen_c_copy_license(out)
1082 out.write("""
1083/**
1084 *
1085 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1086 *
1087 * Message-scalar tests for all versions
1088 */
1089
1090#include <locitest/test_common.h>
1091""")
1092 for version in of_g.of_version_range:
1093 for cls in of_g.ordered_messages:
1094 if not (cls, version) in of_g.base_length:
1095 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001096 if type_maps.class_is_virtual(cls):
1097 continue
Rich Lanef70be942013-07-18 13:33:14 -07001098 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001099 out.write("""
1100static int
1101test_%(cls)s_create_%(v_name)s(void)
1102{
1103 %(cls)s_t *obj;
1104 uint8_t *msg_buf;
1105 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001106 of_object_id_t object_id;
Rich Lanea06d0c32013-03-25 08:52:03 -07001107
1108 obj = %(cls)s_new(%(v_name)s);
1109 TEST_ASSERT(obj != NULL);
1110 TEST_ASSERT(obj->version == %(v_name)s);
1111 TEST_ASSERT(obj->length == %(bytes)d);
1112 TEST_ASSERT(obj->parent == NULL);
1113 TEST_ASSERT(obj->object_id == %(enum)s);
1114
Rich Lanea4b68302014-03-12 15:17:58 -07001115 of_header_wire_object_id_get(obj, &object_id);
1116 TEST_ASSERT(object_id == %(enum)s);
1117
Rich Lanea06d0c32013-03-25 08:52:03 -07001118 /* Set up incrementing values for scalar members */
1119 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1120 TEST_ASSERT(value != 0);
1121
1122 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001123 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1124 TEST_ASSERT(msg_buf != NULL);
1125 %(cls)s_delete(obj);
Rich Lanea06d0c32013-03-25 08:52:03 -07001126 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1127
1128 TEST_ASSERT(obj != NULL);
1129
1130 /* @fixme Set up all message objects (recursively?) */
1131
1132 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1133 TEST_ASSERT(value != 0);
1134
1135 %(cls)s_delete(obj);
1136
1137 return TEST_PASS;
1138}
1139""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1140 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1141
1142 out.write("""
1143int
1144run_message_tests(void)
1145{
1146""")
1147 for version in of_g.of_version_range:
1148 for cls in of_g.ordered_messages:
1149 if not (cls, version) in of_g.base_length:
1150 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001151 if type_maps.class_is_virtual(cls):
1152 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001153 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1154 out.write(" RUN_TEST(%s);\n" % test_name)
1155
1156 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001157
Rich Lanea06d0c32013-03-25 08:52:03 -07001158
1159def gen_list_setup_check(out, cls, version):
1160 """
1161 Generate functions that populate and check a list with two
1162 of each type of subclass it supports
1163 """
1164 out.write("""
1165/**
1166 * Populate a list of type %(cls)s with two of each type of subclass
1167 * @param list Pointer to the list to be populated
1168 * @param value The seed value to use in populating the list
1169 * @returns The value after increments for this object's values
1170 */
1171int
1172%(cls)s_%(v_name)s_populate(
1173 %(cls)s_t *list, int value)
1174{
1175""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1176 base_type = loxi_utils.list_to_entry_type(cls)
1177 out.write("""
1178 %(base_type)s_t elt;
1179 int cur_len = 0;
1180""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001181
Rich Lanea06d0c32013-03-25 08:52:03 -07001182 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001183 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 -07001184 v_name = loxi_utils.version_to_name(version)
1185
1186 if len(sub_classes) == 0:
1187 out.write(" /* No subclasses for %s */\n"% base_type)
1188 out.write(" %s_t *elt_p;\n" % base_type)
1189 out.write("\n elt_p = &elt;\n")
1190 else:
1191 out.write(" /* Declare pointers for each subclass */\n")
1192 for instance, subcls in sub_classes:
1193 out.write(" %s_t *%s;\n" % (subcls, instance))
1194 out.write("\n /* Instantiate pointers for each subclass */\n")
1195 for instance, subcls in sub_classes:
1196 out.write(" %s = &elt.%s;\n" % (instance, instance))
1197
Rich Lanea06d0c32013-03-25 08:52:03 -07001198 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001199 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001200 else:
1201 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001202 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001203 out.write("""
1204 return value;
1205}
1206""")
1207 out.write("""
1208/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001209 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001210 * %(cls)s_%(v_name)s_populate
1211 * @param list Pointer to the list that was populated
1212 * @param value Starting value for checking
1213 * @returns The value after increments for this object's values
1214 */
1215int
1216%(cls)s_%(v_name)s_check(
1217 %(cls)s_t *list, int value)
1218{
1219""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1220 base_type = loxi_utils.list_to_entry_type(cls)
1221 out.write("""
1222 %(base_type)s_t elt;
1223 int count = 0;
1224 int rv;
1225""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001226
Rich Lanea06d0c32013-03-25 08:52:03 -07001227
1228 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001229 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 -07001230 v_name = loxi_utils.version_to_name(version)
1231
1232 if len(sub_classes) == 0:
1233 entry_count = 2
1234 out.write(" /* No subclasses for %s */\n"% base_type)
1235 out.write(" %s_t *elt_p;\n" % base_type)
1236 out.write("\n elt_p = &elt;\n")
1237 else:
1238 entry_count = 2 * len(sub_classes) # Two of each type appended
1239 out.write(" /* Declare pointers for each subclass */\n")
1240 for instance, subcls in sub_classes:
1241 out.write(" %s_t *%s;\n" % (subcls, instance))
1242 out.write("\n /* Instantiate pointers for each subclass */\n")
1243 for instance, subcls in sub_classes:
1244 out.write(" %s = &elt.%s;\n" % (instance, instance))
1245
1246 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1247 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001248 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001249 version, True)
1250 else:
1251 count = 0
1252 for instance, subcls in sub_classes:
1253 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001254 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001255 version, count==len(sub_classes))
1256 out.write("""
1257""" % dict(base_type=base_type))
1258
1259 out.write("""
1260 /* Do an iterate to test the iterator */
1261 %(u_cls)s_ITER(list, &elt, rv) {
1262 count += 1;
1263 }
1264
1265 TEST_ASSERT(rv == OF_ERROR_RANGE);
1266 TEST_ASSERT(count == %(entry_count)d);
1267
1268 /* We shoehorn a test of the dup functions here */
1269 {
1270 %(cls)s_t *dup;
1271
1272 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1273 TEST_ASSERT(dup->length == list->length);
1274 TEST_ASSERT(dup->object_id == list->object_id);
1275 TEST_ASSERT(dup->version == list->version);
1276 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1277 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1278 of_object_delete((of_object_t *)dup);
1279
1280 /* And now for the generic dup function */
1281 TEST_ASSERT((dup = (%(cls)s_t *)
1282 of_object_dup(list)) != NULL);
1283 TEST_ASSERT(dup->length == list->length);
1284 TEST_ASSERT(dup->object_id == list->object_id);
1285 TEST_ASSERT(dup->version == list->version);
1286 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1287 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1288 of_object_delete((of_object_t *)dup);
1289 }
1290
1291 return value;
1292}
1293""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1294
1295
1296def gen_class_setup_check(out, cls, version):
1297 out.write("""
1298/**
1299 * Populate all members of an object of type %(cls)s
1300 * with incrementing values
1301 * @param obj Pointer to an object to populate
1302 * @param value The seed value to use in populating the object
1303 * @returns The value after increments for this object's values
1304 */
1305
1306int
1307%(cls)s_%(v_name)s_populate(
1308 %(cls)s_t *obj, int value)
1309{
1310""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1311 members, member_types = loxi_utils.all_member_types_get(cls, version)
1312 for m_type in member_types:
1313 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1314 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001315 elif m_type == "of_bsn_vport_header_t":
1316 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001317 else:
1318 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1319 out.write("""
1320 /* Run thru accessors after new to ensure okay */
1321""")
1322 for member in members:
1323 m_type = member["m_type"]
1324 m_name = member["name"]
1325 if loxi_utils.skip_member_name(m_name):
1326 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001327 if m_type == "of_bsn_vport_header_t":
1328 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001329 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1330 out.write("""\
1331 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1332""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1333 else:
1334 sub_cls = m_type[:-2] # Trim _t
1335 out.write("""\
1336 {
1337 %(sub_cls)s_t sub_cls;
1338
1339 /* Test bind */
1340 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1341 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001342""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001343 m_name=m_name, sub_cls=sub_cls,
1344 v_name=loxi_utils.version_to_name(version)))
1345
1346 out.write("""
1347 value = %(cls)s_%(v_name)s_populate_scalars(
1348 obj, value);
1349 TEST_ASSERT(value != 0);
1350""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1351
1352 for member in members:
1353 m_type = member["m_type"]
1354 m_name = member["name"]
1355 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1356 continue
1357 if loxi_utils.skip_member_name(m_name):
1358 continue
1359 if m_type == "of_match_t":
1360 out.write("""\
1361 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1362 TEST_ASSERT(value != 0);
1363 %(cls)s_%(m_name)s_set(
1364 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001365""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001366 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1367 elif m_type == "of_octets_t":
1368 out.write("""\
1369 value = of_octets_populate(&%(var_name)s, value);
1370 TEST_ASSERT(value != 0);
1371 %(cls)s_%(m_name)s_set(
1372 obj, &%(var_name)s);
1373 if (octets.bytes) {
1374 FREE(octets.data);
1375 }
1376""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001377 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1378 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001379 out.write("""\
1380 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1381 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001382 value = %(sub_cls)s_%(v_name)s_populate(
1383 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001384 TEST_ASSERT(value != 0);
1385 %(cls)s_%(m_name)s_set(
1386 obj, %(var_name)s);
1387 %(sub_cls)s_delete(%(var_name)s);
1388""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1389 var_name=var_name_map(m_type),
1390 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001391 else:
1392 sub_cls = m_type[:-2] # Trim _t
1393 out.write("""
1394 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1395 TEST_ASSERT(%(var_name)s != NULL);
1396 value = %(sub_cls)s_%(v_name)s_populate(
1397 %(var_name)s, value);
1398 TEST_ASSERT(value != 0);
1399 %(cls)s_%(m_name)s_set(
1400 obj, %(var_name)s);
1401 %(sub_cls)s_delete(%(var_name)s);
1402""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1403 var_name=var_name_map(m_type),
1404 v_name=loxi_utils.version_to_name(version)))
1405
1406 out.write("""
1407 return value;
1408}
1409""")
1410
1411 out.write("""
1412/**
1413 * Check all members of an object of type %(cls)s
1414 * populated by the above function
1415 * @param obj Pointer to an object to check
1416 * @param value Starting value for checking
1417 * @returns The value after increments for this object's values
1418 */
1419
1420int
1421%(cls)s_%(v_name)s_check(
1422 %(cls)s_t *obj, int value)
1423{
1424""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1425 members, member_types = loxi_utils.all_member_types_get(cls, version)
1426 for m_type in member_types:
1427 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1428 continue
1429 if loxi_utils.type_is_of_object(m_type):
1430 continue
1431 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1432 out.write("""
1433 value = %(cls)s_%(v_name)s_check_scalars(
1434 obj, value);
1435 TEST_ASSERT(value != 0);
1436""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1437
1438 for member in members:
1439 m_type = member["m_type"]
1440 m_name = member["name"]
1441 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1442 continue
1443 if loxi_utils.skip_member_name(m_name):
1444 continue
1445 if m_type == "of_match_t":
1446 out.write("""\
1447 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1448 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1449""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1450 v_name=loxi_utils.version_to_name(version)))
1451 elif m_type == "of_octets_t":
1452 out.write("""\
1453 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1454 value = of_octets_check(&%(var_name)s, value);
1455""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1456 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001457 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1458 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001459 out.write("""
1460 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001461 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001462
1463 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1464 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001465 value = %(sub_cls)s_%(v_name)s_check(
1466 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001467 TEST_ASSERT(value != 0);
1468 %(sub_cls)s_delete(%(m_name)s_ptr);
1469 }
1470""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1471 var_name=var_name_map(m_type),
1472 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001473 else:
1474 sub_cls = m_type[:-2] # Trim _t
1475 out.write("""
1476 { /* Use get/delete to access on check */
1477 %(m_type)s *%(m_name)s_ptr;
1478
1479 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1480 TEST_ASSERT(%(m_name)s_ptr != NULL);
1481 value = %(sub_cls)s_%(v_name)s_check(
1482 %(m_name)s_ptr, value);
1483 TEST_ASSERT(value != 0);
1484 %(sub_cls)s_delete(%(m_name)s_ptr);
1485 }
1486""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1487 var_name=var_name_map(m_type),
1488 v_name=loxi_utils.version_to_name(version)))
1489
1490 out.write("""
1491 /* We shoehorn a test of the dup functions here */
1492 {
1493 %(cls)s_t *dup;
1494
1495 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1496 TEST_ASSERT(dup->length == obj->length);
1497 TEST_ASSERT(dup->object_id == obj->object_id);
1498 TEST_ASSERT(dup->version == obj->version);
1499 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1500 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1501 of_object_delete((of_object_t *)dup);
1502
1503 /* And now for the generic dup function */
1504 TEST_ASSERT((dup = (%(cls)s_t *)
1505 of_object_dup(obj)) != NULL);
1506 TEST_ASSERT(dup->length == obj->length);
1507 TEST_ASSERT(dup->object_id == obj->object_id);
1508 TEST_ASSERT(dup->version == obj->version);
1509 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1510 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1511 of_object_delete((of_object_t *)dup);
1512 }
1513
1514 return value;
1515}
1516""" % dict(cls=cls))
1517
1518def unified_accessor_test_case(out, cls, version):
1519 """
1520 Generate one test case for the given version and class
1521 """
1522
1523 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001524 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001525 v_name = loxi_utils.version_to_name(version)
1526
1527 out.write("""
1528static int
1529test_%(cls)s_%(v_name)s(void)
1530{
1531 %(cls)s_t *obj;
1532 obj = %(cls)s_new(%(v_name)s);
1533 TEST_ASSERT(obj != NULL);
1534 TEST_ASSERT(obj->version == %(v_name)s);
1535 TEST_ASSERT(obj->length == %(length)d);
1536 TEST_ASSERT(obj->parent == NULL);
1537 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001538""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001539 v_name=v_name, length=length, version=version))
1540 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1541 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001542 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001543 int length;
1544
Rich Lanedc46fe22014-04-03 15:10:38 -07001545 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001546 TEST_ASSERT(length == %(length)d);
1547 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001548 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001549 of_object_id_t obj_id;
1550
Rich Lanedc46fe22014-04-03 15:10:38 -07001551 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001552 TEST_ASSERT(obj_id == %(u_cls)s);
1553 }
1554
1555 /* Set up incrementing values for members */
1556 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1557 obj, 1) != 0);
1558
1559 /* Check values just set */
1560 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1561 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001562""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001563 v_name=v_name, length=length, version=version))
1564
1565 out.write("""
1566 %(cls)s_delete(obj);
1567
1568 /* To do: Check memory */
1569 return TEST_PASS;
1570}
1571""" % dict(cls=cls))
1572
1573
1574def gen_unified_accessor_funs(out):
1575 for version in of_g.of_version_range:
1576 for cls in of_g.standard_class_order:
1577 if not loxi_utils.class_in_version(cls, version):
1578 continue
1579 if cls in type_maps.inheritance_map:
1580 continue
1581 elif loxi_utils.class_is_list(cls):
1582 gen_list_setup_check(out, cls, version)
1583 else:
1584 gen_class_setup_check(out, cls, version)
1585
1586def gen_unified_accessor_tests(out, name):
1587 loxi_utils.gen_c_copy_license(out)
1588 out.write("""
1589/**
1590 *
1591 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1592 *
1593 * Unified simple class instantiation tests for all versions
1594 */
1595
1596#include <locitest/test_common.h>
1597""")
1598 for version in of_g.of_version_range:
1599 for cls in of_g.standard_class_order:
1600 if not loxi_utils.class_in_version(cls, version):
1601 continue
1602 if cls in type_maps.inheritance_map:
1603 continue
1604 unified_accessor_test_case(out, cls, version)
1605
1606 out.write("""
1607int
1608run_unified_accessor_tests(void)
1609{
1610""")
1611 for version in of_g.of_version_range:
1612 v_name = loxi_utils.version_to_name(version)
1613 for cls in of_g.standard_class_order:
1614 if not loxi_utils.class_in_version(cls, version):
1615 continue
1616 if cls in type_maps.inheritance_map:
1617 continue
1618 test_name = "%s_%s" % (cls, v_name)
1619 out.write(" RUN_TEST(%s);\n" % test_name)
1620
1621 out.write(" return TEST_PASS;\n}\n");
1622
1623
1624
1625################################################################
1626#
1627# Object duplication functions
1628#
1629# These exercise the accessors to create duplicate objects.
1630# They are used in the LOCI test shim which sits in an OF
1631# protocol stream.
1632#
1633# TODO
1634# Resolve version stuff
1635# Complete list dup
1636
1637def gen_dup_list(out, cls, version):
1638 ver_name = loxi_utils.version_to_name(version)
1639 elt_type = loxi_utils.list_to_entry_type(cls)
1640 out.write("""
1641/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001642 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001643 * using accessor functions
1644 * @param src Pointer to object to be duplicated
1645 * @returns A new object of type %(cls)s.
1646 *
1647 * The caller is responsible for deleting the returned value
1648 */
1649%(cls)s_t *
1650%(cls)s_%(ver_name)s_dup(
1651 %(cls)s_t *src)
1652{
1653 %(elt_type)s_t src_elt;
1654 %(elt_type)s_t *dst_elt;
1655 int rv;
1656 %(cls)s_t *dst;
1657
1658 if ((dst = %(cls)s_new(src->version)) == NULL) {
1659 return NULL;
1660 }
1661""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1662
1663 out.write("""
1664 %(u_cls)s_ITER(src, &src_elt, rv) {
1665 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1666 of_object_delete((of_object_t *)dst);
1667 return NULL;
1668 }
1669 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1670 dst, NULL);
1671 of_object_delete((of_object_t *)dst_elt);
1672 }
1673
1674 return dst;
1675}
1676""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1677
1678
1679def gen_dup_inheritance(out, cls, version):
1680 ver_name = loxi_utils.version_to_name(version)
1681 out.write("""
1682/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001683 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001684 * @param src Pointer to object to be duplicated
1685 * @returns A new object of type %(cls)s.
1686 *
1687 * The caller is responsible for deleting the returned value
1688 */
1689%(cls)s_t *
1690%(cls)s_%(ver_name)s_dup(
1691 %(cls)s_t *src)
1692{
1693""" % dict(cls=cls, ver_name=ver_name))
1694
1695 # For each subclass, check if this is an instance of that subclass
1696 version_classes = type_maps.inheritance_data[cls][version]
1697 for sub_cls in version_classes:
1698 sub_enum = (cls + "_" + sub_cls).upper()
1699 out.write("""
1700 if (src->header.object_id == %(sub_enum)s) {
1701 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1702 &src->%(sub_cls)s);
1703 }
1704""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1705
1706 out.write("""
1707 return NULL;
1708}
1709""")
1710
1711
1712def gen_dup_cls(out, cls, version):
1713 """
1714 Generate duplication routine for class cls
1715 """
1716 ver_name = loxi_utils.version_to_name(version)
1717
1718 out.write("""
1719/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001720 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001721 * using accessor functions
1722 * @param src Pointer to object to be duplicated
1723 * @returns A new object of type %(cls)s.
1724 *
1725 * The caller is responsible for deleting the returned value
1726 */
1727%(cls)s_t *
1728%(cls)s_%(ver_name)s_dup(
1729 %(cls)s_t *src)
1730{
1731 %(cls)s_t *dst;
1732""" % dict(cls=cls, ver_name=ver_name))
1733
1734 # Get members and types for the class
1735 members, member_types = loxi_utils.all_member_types_get(cls, version)
1736
1737 # Add declarations for each member type
1738 for m_type in member_types:
1739 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1740 # Declare instance of these
1741 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001742 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1743 out.write("""
1744 of_bsn_vport_q_in_q_t src_%(v_name)s;
1745 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1746""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001747 else:
1748 out.write("""
1749 %(m_type)s src_%(v_name)s;
1750 %(m_type)s *dst_%(v_name)s;
1751""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1752
1753 out.write("""
1754 if ((dst = %(cls)s_new(src->version)) == NULL) {
1755 return NULL;
1756 }
1757""" % dict(cls=cls))
1758
1759 for member in members:
1760 m_type = member["m_type"]
1761 m_name = member["name"]
1762 if loxi_utils.skip_member_name(m_name):
1763 continue
1764 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1765 out.write("""
1766 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1767 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1768""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1769 elif m_type in ["of_match_t", "of_octets_t"]:
1770 out.write("""
1771 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1772 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1773""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001774 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1775 sub_cls = "of_bsn_vport_q_in_q"
1776 out.write("""
1777 %(cls)s_%(m_name)s_bind(
1778 src, &src_%(v_name)s);
1779 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1780 if (dst_%(v_name)s == NULL) {
1781 %(cls)s_delete(dst);
1782 return NULL;
1783 }
1784 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1785 %(sub_cls)s_delete(dst_%(v_name)s);
1786""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1787 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001788 else:
1789 sub_cls = m_type[:-2] # Trim _t
1790 out.write("""
1791 %(cls)s_%(m_name)s_bind(
1792 src, &src_%(v_name)s);
1793 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1794 if (dst_%(v_name)s == NULL) {
1795 %(cls)s_delete(dst);
1796 return NULL;
1797 }
1798 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1799 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001800""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001801 v_name=var_name_map(m_type), ver_name=ver_name))
1802
1803 out.write("""
1804 return dst;
1805}
1806""")
1807
1808def gen_version_dup(out=sys.stdout):
1809 """
1810 Generate duplication routines for each object type
1811 """
1812 out.write("""
1813/* Special try macro for duplicating */
1814#define _TRY_FREE(op, obj, rv) do { \\
1815 int _rv; \\
1816 if ((_rv = (op)) < 0) { \\
1817 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1818 of_object_delete((of_object_t *)(obj)); \\
1819 return (rv); \\
1820 } \\
1821 } while (0)
1822""")
1823
1824 for version in of_g.of_version_range:
1825 for cls in of_g.standard_class_order:
1826 if not loxi_utils.class_in_version(cls, version):
1827 continue
1828 if cls in type_maps.inheritance_map:
1829 gen_dup_inheritance(out, cls, version)
1830 elif loxi_utils.class_is_list(cls):
1831 gen_dup_list(out, cls, version)
1832 else:
1833 gen_dup_cls(out, cls, version)
1834
1835def gen_dup(out=sys.stdout):
1836 """
1837 Generate non-version specific duplication routines for each object type
1838 """
1839
1840 for cls in of_g.standard_class_order:
1841 out.write("""
1842%(cls)s_t *
1843%(cls)s_dup(
1844 %(cls)s_t *src)
1845{
1846""" % dict(cls=cls))
1847 for version in of_g.of_version_range:
1848 if not loxi_utils.class_in_version(cls, version):
1849 continue
1850 hdr = "header." if cls in type_maps.inheritance_map else ""
1851
1852 ver_name = loxi_utils.version_to_name(version)
1853 out.write("""
1854 if (src->%(hdr)sversion == %(ver_name)s) {
1855 return %(cls)s_%(ver_name)s_dup(src);
1856 }
1857""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1858
1859 out.write("""
1860 /* Class not supported in given version */
1861 return NULL;
1862}
1863""")
1864
1865def dup_c_gen(out, name):
1866 """
1867 Generate the C file for duplication functions
1868 """
1869 loxi_utils.gen_c_copy_license(out)
1870 out.write("""\
1871/*
1872 * Duplication functions for all OF objects
1873 *
1874 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1875 *
1876 * These are test functions for exercising accessors. You can call
1877 * of_object_dup for an efficient duplication.
1878 */
1879
1880#define DISABLE_WARN_UNUSED_RESULT
1881#include "loci_log.h"
1882#include <locitest/of_dup.h>
1883
1884""")
1885
1886 gen_version_dup(out)
1887 gen_dup(out)
1888
1889
1890def dup_h_gen(out, name):
1891 """
1892 Generate the header file for duplication functions
1893 """
1894
1895 loxi_utils.gen_c_copy_license(out)
1896 out.write("""
1897/*
1898 * Duplication function header file
1899 *
1900 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1901 */
1902
1903#if !defined(_OF_DUP_H_)
1904#define _OF_DUP_H_
1905
1906#include <loci/loci.h>
1907""")
1908
1909 for cls in of_g.standard_class_order:
1910 out.write("""
1911extern %(cls)s_t *
1912 %(cls)s_dup(
1913 %(cls)s_t *src);
1914""" % dict(cls=cls))
1915
1916 for version in of_g.of_version_range:
1917 for cls in of_g.standard_class_order:
1918 if not loxi_utils.class_in_version(cls, version):
1919 continue
1920 ver_name = loxi_utils.version_to_name(version)
1921 out.write("""
1922extern %(cls)s_t *
1923 %(cls)s_%(ver_name)s_dup(
1924 %(cls)s_t *src);
1925""" % dict(cls=cls, ver_name=ver_name))
1926
1927 out.write("\n#endif /* _OF_DUP_H_ */\n")
1928
1929def gen_log_test(out):
1930 """
1931 Generate test for obj log calls
1932
1933 Define a trivial handler for object logging; call all obj log fns
1934 """
1935 out.write("""
1936
1937/**
1938 * Test object dump functions
1939 */
1940
1941int
1942test_dump_objs(void)
1943{
1944 of_object_t *obj;
1945
1946 FILE *out = fopen("/dev/null", "w");
1947
1948 /* Call each obj dump function */
1949""")
1950 for version in of_g.of_version_range:
1951 for j, cls in enumerate(of_g.all_class_order):
1952 if not loxi_utils.class_in_version(cls, version):
1953 continue
1954 if cls in type_maps.inheritance_map:
1955 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001956 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1957 out.write("""
1958 obj = (of_object_t *)%(cls)s_new(%(version)s);
1959 {
1960 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1961 %(cls)s_vport_set(obj, vport);
1962 of_object_delete(vport);
1963 }
1964 of_object_dump((loci_writer_f)fprintf, out, obj);
1965 of_object_delete(obj);
1966""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1967 else:
1968 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001969 obj = (of_object_t *)%(cls)s_new(%(version)s);
1970 of_object_dump((loci_writer_f)fprintf, out, obj);
1971 of_object_delete(obj);
1972""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001973
Rich Lanea06d0c32013-03-25 08:52:03 -07001974 out.write("""
1975 fclose(out);
1976 return TEST_PASS;
1977}
1978""")
1979
1980def gen_ident_tests(out):
1981 """
1982 Generate tests for identifiers
1983
1984 For all idents, instantiate, test version supported macros
1985 For flags, set it, test it, clear it, test it.
1986 """
1987 out.write("""
1988/**
1989 * Test cases for all flag accessor macros
1990 * These only test self consistency (and that they compile)
1991 */
1992int
1993test_ident_macros(void)
1994{
1995 int value __attribute__((unused));
1996 uint32_t flags;
1997
1998""")
1999
2000 for ident, info in of_g.identifiers.items():
2001 if not identifiers.defined_versions_agree(of_g.identifiers,
2002 of_g.target_version_list,
2003 ident):
2004 # @fixme
2005 continue
2006 out.write(" value = %s;\n" % ident)
2007 for version in of_g.target_version_list:
2008 if version in info["values_by_version"].keys():
2009 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2010 (ident, of_g.of_version_wire2name[version]))
2011 else:
2012 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2013 (ident, of_g.of_version_wire2name[version]))
2014 if flags.ident_is_flag(ident):
2015 # Grab first supported version
2016 for version in info["values_by_version"]:
2017 break
2018 out.write("""
2019 flags = 0;
2020 %(ident)s_SET(flags, %(ver_name)s);
2021 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2022 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2023 %(ident)s_CLEAR(flags, %(ver_name)s);
2024 TEST_ASSERT(flags == 0);
2025 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2026""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2027
2028 out.write("""
2029 return TEST_PASS;
2030}
2031""")
2032
Rich Laneccae0312013-07-21 23:34:13 -07002033def gen_datafiles_tests(out, name):
2034 tests = []
2035 for filename in test_data.list_files():
2036 data = test_data.read(filename)
2037 if not 'c' in data:
2038 continue
2039 name = filename[:-5].replace("/", "_")
2040 tests.append(dict(name=name,
2041 filename=filename,
2042 c=data['c'],
2043 binary=data['binary']))
2044
2045 util.render_template(out, "test_data.c", tests=tests)