blob: 8cd73c50edc042e67ed7303edf7c9cc76f1e9565 [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",
Praseed Balakrishnanf78068b2014-09-04 10:30:40 -0700108 #Circuit extensions
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700109 oxm_of_och_sig_id_t="sig_id",
110 of_app_code_t="app_code",
111 #of_port_optical_transport_application_code_t="tappcode",
112 of_port_desc_prop_optical_transport_t="desc1",
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 Lanea06d0c32013-03-25 08:52:03 -0700128
129scalar_types = integer_types[:]
130scalar_types.extend(string_types)
131
132def ignore_member(cls, version, m_name, m_type):
133 """
134 Filter out names or types that either don't have accessors
135 or those that should not be messed with
136 or whose types we're not ready to deal with yet.
137 """
Rich Lane79c87192014-03-04 10:56:59 -0800138
139 uclass = loxi_globals.unified.class_by_name(cls)
140 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700141 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800142
Rich Lane79c87192014-03-04 10:56:59 -0800143 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800144 return True
Rich Lane79c87192014-03-04 10:56:59 -0800145
Rich Lanea06d0c32013-03-25 08:52:03 -0700146 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
147
148def gen_fill_string(out):
149 out.write("""
150
151/**
152 * The increment to use on values inside a string
153 */
154#define OF_TEST_STR_INCR 3
155
156/**
157 * Fill in a buffer with incrementing values starting
158 * at the given offset with the given value
159 * @param buf The buffer to fill
160 * @param value The value to use for data
161 * @param len The number of bytes to fill
162 */
163
164void
165of_test_str_fill(uint8_t *buf, int value, int len)
166{
167 int i;
168
169 for (i = 0; i < len; i++) {
170 *buf = value;
171 value += OF_TEST_STR_INCR;
172 buf++;
173 }
174}
175
176/**
177 * Given a buffer, verify that it's filled as above
178 * @param buf The buffer to check
179 * @param value The value to use for data
180 * @param len The number of bytes to fill
181 * @return Boolean True on equality (success)
182 */
183
184int
185of_test_str_check(uint8_t *buf, int value, int len)
186{
187 int i;
188 uint8_t val8;
189
190 val8 = value;
191
192 for (i = 0; i < len; i++) {
193 if (*buf != val8) {
194 return 0;
195 }
196 val8 += OF_TEST_STR_INCR;
197 buf++;
198 }
199
200 return 1;
201}
202
203/**
204 * Global that determines how octets should be populated
205 * -1 means use value % MAX (below) to determine length
206 * 0, 1, ... means used that fixed length
207 *
208 * Note: Was 16K, but that made objects too big. May add flexibility
209 * to call populate with a max parameter for length
210 */
211int octets_pop_style = -1;
212#define OCTETS_MAX_VALUE (128) /* 16K was too big */
213#define OCTETS_MULTIPLIER 6367 /* A prime */
214
215int
216of_octets_populate(of_octets_t *octets, int value)
217{
218 if (octets_pop_style < 0) {
219 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
220 } else {
221 octets->bytes = octets_pop_style;
222 }
223
224 if (octets->bytes != 0) {
225 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
226 return 0;
227 }
228 of_test_str_fill(octets->data, value, octets->bytes);
229 value += 1;
230 }
231
232 return value;
233}
234
235int
236of_octets_check(of_octets_t *octets, int value)
237{
238 int len;
239
240 if (octets_pop_style < 0) {
241 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
242 TEST_ASSERT(octets->bytes == len);
243 } else {
244 TEST_ASSERT(octets->bytes == octets_pop_style);
245 }
246
247 if (octets->bytes != 0) {
248 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
249 == 1);
250 value += 1;
251 }
252
253 return value;
254}
255
256int
257of_match_populate(of_match_t *match, of_version_t version, int value)
258{
259 MEMSET(match, 0, sizeof(*match));
260 match->version = version;
261""")
262
Rich Laned56f8d22014-05-06 14:52:55 -0700263 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700264 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700265 if (version == %d) {\
266""" % wire_version)
267 for key in keys:
268 entry = match.of_match_members[key]
269 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700270 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
271 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
272 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700273""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
274 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700275 }
276
Rich Laned56f8d22014-05-06 14:52:55 -0700277""")
278
Rich Laneb4a63a52014-05-22 14:41:57 -0700279 for wire_version, match_keys in match.match_keys.items():
280 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700281
282 out.write("""
283 if (value % 2) {
284 /* Sometimes set ipv4 addr masks to non-exact */
285 match->masks.ipv4_src = 0xffff0000;
286 match->masks.ipv4_dst = 0xfffff800;
287 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700288
289 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700290 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700291 return value;
292}
293
294int
295of_match_check(of_match_t *match, of_version_t version, int value)
296{
297 of_match_t check;
298
299 value = of_match_populate(&check, match->version, value);
300 TEST_ASSERT(value != 0);
301 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
302
303 return value;
304}
305""")
306
307def gen_common_test_header(out, name):
308 loxi_utils.gen_c_copy_license(out)
309 out.write("""
310/*
311 * Test header file
312 *
313 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
314 */
315
316#if !defined(_TEST_COMMON_H_)
317#define _TEST_COMMON_H_
318
319#define DISABLE_WARN_UNUSED_RESULT
320#include <loci/loci.h>
321#include <locitest/of_dup.h>
322#include <locitest/unittest.h>
323
324extern int global_error;
325extern int exit_on_error;
326
327/* @todo Make option for -k to continue tests if errors */
328#define RUN_TEST(test) do { \\
329 int rv; \\
330 TESTCASE(test, rv); \\
331 if (rv != TEST_PASS) { \\
332 global_error=1; \\
333 if (exit_on_error) return(1); \\
334 } \\
335 } while(0)
336
337#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
338#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
339
340/*
341 * Declarations of functions to populate scalar values in a a class
342 */
343
344extern void of_test_str_fill(uint8_t *buf, int value, int len);
345extern int of_test_str_check(uint8_t *buf, int value, int len);
346
347
348extern int of_octets_populate(of_octets_t *octets, int value);
349extern int of_octets_check(of_octets_t *octets, int value);
350extern int of_match_populate(of_match_t *match, of_version_t version,
351 int value);
352extern int of_match_check(of_match_t *match, of_version_t version, int value);
353extern int test_ident_macros(void);
354extern int test_dump_objs(void);
355
356/* In test_match_utils.c */
357extern int test_match_utils(void);
358
359extern int run_unified_accessor_tests(void);
360extern int run_match_tests(void);
361extern int run_utility_tests(void);
362
363extern int run_scalar_acc_tests(void);
364extern int run_list_tests(void);
365extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700366
367extern int run_validator_tests(void);
368
369extern int run_list_limits_tests(void);
370
371extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700372extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700373
374""")
375
376 for version in of_g.of_version_range:
377 for cls in of_g.standard_class_order:
378 if not loxi_utils.class_in_version(cls, version):
379 continue
380 if cls in type_maps.inheritance_map:
381 continue
382 out.write("""
383extern int %(cls)s_%(v_name)s_populate(
384 %(cls)s_t *obj, int value);
385extern int %(cls)s_%(v_name)s_check(
386 %(cls)s_t *obj, int value);
387extern int %(cls)s_%(v_name)s_populate_scalars(
388 %(cls)s_t *obj, int value);
389extern int %(cls)s_%(v_name)s_check_scalars(
390 %(cls)s_t *obj, int value);
391""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
392
393 out.write("""
394/*
395 * Declarations for list population and check primitives
396 */
397""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700398
Rich Lanea06d0c32013-03-25 08:52:03 -0700399 for version in of_g.of_version_range:
400 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700401 if version in of_g.unified[cls]:
402 out.write("""
403extern int
404 list_setup_%(cls)s_%(v_name)s(
405 %(cls)s_t *list, int value);
406extern int
407 list_check_%(cls)s_%(v_name)s(
408 %(cls)s_t *list, int value);
409""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
410
411 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
412
413def gen_common_test(out, name):
414 """
415 Generate common test content including main
416 """
417 loxi_utils.gen_c_copy_license(out)
418 out.write("""
419/*
420 * Common test code for LOCI
421 *
422 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
423 */
424
425#define DISABLE_WARN_UNUSED_RESULT
426#include "loci_log.h"
427#include <loci/loci_obj_dump.h>
428#include <locitest/unittest.h>
429#include <locitest/test_common.h>
430
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900431/* mcheck is a glibc extension */
432#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700433#include <mcheck.h>
434#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900435#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700436#define MCHECK_INIT do { } while (0)
437#endif
438
439/**
440 * Exit on error if set to 1
441 */
442int exit_on_error = 1;
443
444/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700445 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700446 */
447int global_error = 0;
448
449extern int run_unified_accessor_tests(void);
450extern int run_match_tests(void);
451extern int run_utility_tests(void);
452
453extern int run_scalar_acc_tests(void);
454extern int run_list_tests(void);
455extern int run_message_tests(void);
456
457/**
458 * Macros for initializing and checking scalar types
459 *
460 * @param var The variable being initialized or checked
461 * @param val The integer value to set/check against, see below
462 *
463 * Note that equality means something special for strings. Each byte
464 * is initialized to an incrementing value. So check is done against that.
465 *
466 */
467
468""")
469 for t in scalar_types:
470 if t in integer_types:
471 out.write("""
472#define VAR_%s_INIT(var, val) var = (%s)(val)
473#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
474""" % (t.upper(), t, t.upper(), t))
475 else:
476 out.write("""
477#define VAR_%s_INIT(var, val) \\
478 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
479#define VAR_%s_CHECK(var, val) \\
480 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
481""" % (t.upper(), t.upper()))
482
483 gen_fill_string(out)
484 gen_scalar_set_check_funs(out)
485 gen_list_set_check_funs(out)
486 gen_unified_accessor_funs(out)
487
488 gen_ident_tests(out)
489 gen_log_test(out)
490
491def gen_message_scalar_test(out, name):
492 """
493 Generate test cases for message objects, scalar accessors
494 """
495
496 loxi_utils.gen_c_copy_license(out)
497 out.write("""
498/**
499 *
500 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
501 *
502 * Message-scalar tests for all versions
503 */
504
505#include <locitest/test_common.h>
506""")
507 for version in of_g.of_version_range:
508 v_name = loxi_utils.version_to_name(version)
509 out.write("""
510/**
511 * Message-scalar tests for version %s
512 */
513""" % v_name)
514 for cls in of_g.standard_class_order:
515 if cls in type_maps.inheritance_map:
516 continue
517 if version in of_g.unified[cls]:
518 message_scalar_test(out, version, cls)
519
520 out.write("""
521int
522run_scalar_acc_tests(void)
523{
524""")
525 for version in of_g.of_version_range:
526 v_name = loxi_utils.version_to_name(version)
527 for cls in of_g.standard_class_order:
528 if cls in type_maps.inheritance_map:
529 continue
530 if version in of_g.unified[cls]:
531 test_name = "%s_%s" % (cls, v_name)
532 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
533
534 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700535
Rich Lanea06d0c32013-03-25 08:52:03 -0700536def message_scalar_test(out, version, cls):
537 """
538 Generate one test case for the given version and class
539 """
540
541 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700542 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700543 v_name = loxi_utils.version_to_name(version)
544
545 out.write("""
546static int
547test_%(cls)s_%(v_name)s_scalar(void)
548{
549 %(cls)s_t *obj;
550
551 obj = %(cls)s_new(%(v_name)s);
552 TEST_ASSERT(obj != NULL);
553 TEST_ASSERT(obj->version == %(v_name)s);
554 TEST_ASSERT(obj->length == %(length)d);
555 TEST_ASSERT(obj->parent == NULL);
556 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700557""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700558 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700559
560 # If this class is a concrete member of an inheritance hierarchy,
561 # run the hierarchy's root wire type parser and assert it returns
562 # the expected object id.
563 ofclass = loxi_globals.unified.class_by_name(cls)
564 if ofclass and not ofclass.virtual:
565 root = ofclass
566 while root.superclass:
567 root = root.superclass
568 if root.virtual:
569 out.write("""
570 {
571 of_object_id_t object_id;
572 %(root_cls)s_wire_object_id_get(obj, &object_id);
573 TEST_ASSERT(object_id == %(u_cls)s);
574 }
575""" % dict(root_cls=root.name, u_cls=cls.upper()))
576
Rich Lanea06d0c32013-03-25 08:52:03 -0700577 if not type_maps.class_is_virtual(cls):
578 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700579 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 int length;
581
Rich Lanedc46fe22014-04-03 15:10:38 -0700582 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700583 TEST_ASSERT(length == %(length)d);
584 }
585
586 /* Set up incrementing values for scalar members */
587 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
588
589 /* Check values just set */
590 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700591""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700592 v_name=v_name, length=length, version=version))
593
594 out.write("""
595 %(cls)s_delete(obj);
596
597 /* To do: Check memory */
598 return TEST_PASS;
599}
600""" % dict(cls=cls))
601
602# Get the members and list of scalar types for members of a given class
603def scalar_member_types_get(cls, version):
604 member_types = []
605
606 if not version in of_g.unified[cls]:
607 return ([], [])
608
609 if "use_version" in of_g.unified[cls][version]:
610 v = of_g.unified[cls][version]["use_version"]
611 members = of_g.unified[cls][v]["members"]
612 else:
613 members = of_g.unified[cls][version]["members"]
614 # Accumulate variables that are supported
615 for member in members:
616 m_type = member["m_type"]
617 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700618 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700619 ignore_member(cls, version, m_name, m_type)):
620 continue
621 if not m_type in member_types:
622 member_types.append(m_type)
623
624 return (members, member_types)
625
626def scalar_funs_instance(out, cls, version, members, member_types):
627 """
628 Generate one instance of scalar set/check functions
629 """
630 out.write("""
631/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700632 * Populate the scalar values in obj of type %(cls)s,
633 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700634 * @param obj Pointer to an object to populate
635 * @param value The seed value to use in populating the object
636 * @returns The value after increments for this object's values
637 */
638int %(cls)s_%(v_name)s_populate_scalars(
639 %(cls)s_t *obj, int value) {
640""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
641 # Declare string types
642 for t in member_types:
643 out.write(" %s %s;\n" % (t, var_name_map(t)))
644 for member in members:
645 m_type = member["m_type"]
646 m_name = member["name"]
647 if (not loxi_utils.type_is_scalar(m_type) or
648 ignore_member(cls, version, m_name, m_type)):
649 continue
650 v_name = var_name_map(m_type);
651 out.write("""
652 VAR_%(u_type)s_INIT(%(v_name)s, value);
653 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
654 value += 1;
655""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
656 out.write("""
657 return value;
658}
659""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700660
Rich Lanea06d0c32013-03-25 08:52:03 -0700661 out.write("""
662/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700663 * Check scalar values in obj of type %(cls)s,
664 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700665 * @param obj Pointer to an object to check
666 * @param value Starting value for checking
667 * @returns The value after increments for this object's values
668 */
669int %(cls)s_%(v_name)s_check_scalars(
670 %(cls)s_t *obj, int value) {
671""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
672
673 for t in member_types:
674 out.write(" %s %s;\n" % (t, var_name_map(t)))
675 for member in members:
676 m_type = member["m_type"]
677 m_name = member["name"]
678 if (not loxi_utils.type_is_scalar(m_type) or
679 ignore_member(cls, version, m_name, m_type)):
680 continue
681 v_name = var_name_map(m_type);
682 out.write("""
683 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
684 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
685 value += 1;
686""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
687
688 out.write("""
689 return value;
690}
691
692""")
693
694def gen_scalar_set_check_funs(out):
695 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700696 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700697 set and check their values
698 """
699 for version in of_g.of_version_range:
700 for cls in of_g.standard_class_order:
701 (members, member_types) = scalar_member_types_get(cls, version)
702 scalar_funs_instance(out, cls, version, members, member_types)
703
704
705# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700706def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700707 base_type = loxi_utils.list_to_entry_type(cls)
708 setup_template = """
709 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700710 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700711 (%(base_type)s_t *)%(inst)s);
712 value = %(subcls)s_%(v_name)s_populate(
713 %(inst)s, value);
714 cur_len += %(inst)s->length;
715 TEST_ASSERT(list->length == cur_len);
716"""
717 out.write("""
718 /* Append two instances of type %s */
719""" % subcls)
720 for i in range(2):
721 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700722 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700723 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700724 version=version))
725
Rich Lane9afc3b92014-04-09 22:55:53 -0700726def check_instance(out, cls, subcls, instance, v_name, version, last):
727 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700728 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
729 value = %(subcls)s_%(v_name)s_check(
730 %(inst)s, value);
731 TEST_ASSERT(value != 0);
732"""
733 out.write("\n /* Check two instances of type %s */" % instance)
734
Andreas Wundsam53256162013-05-02 14:05:53 -0700735 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700736 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700737 inst=instance, subcls=subcls,
738 v_name=loxi_utils.version_to_name(version)))
739 out.write("""\
740 TEST_OK(%(cls)s_next(list, &elt));
741""" % dict(cls=cls))
742
Andreas Wundsam53256162013-05-02 14:05:53 -0700743 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700744 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700745 inst=instance, subcls=subcls,
746 v_name=loxi_utils.version_to_name(version)))
747 if last:
748 out.write("""\
749 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
750""" % dict(cls=cls))
751 else:
752 out.write("""\
753 TEST_OK(%(cls)s_next(list, &elt));
754""" % dict(cls=cls))
755
756def setup_list_fn(out, version, cls):
757 """
758 Generate a helper function that populates a list with two
759 of each type of subclass it supports
760 """
761 out.write("""
762/**
763 * Set up a list of type %(cls)s with two of each type of subclass
764 */
765int
766list_setup_%(cls)s_%(v_name)s(
767 %(cls)s_t *list, int value)
768{
769""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
770 base_type = loxi_utils.list_to_entry_type(cls)
771 out.write("""
772 %(base_type)s_t elt;
773 int cur_len = 0;
774""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700775
Rich Lanea06d0c32013-03-25 08:52:03 -0700776 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700777 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 -0700778 v_name = loxi_utils.version_to_name(version)
779
780 if len(sub_classes) == 0:
781 out.write(" /* No subclasses for %s */\n"% base_type)
782 out.write(" %s_t *elt_p;\n" % base_type)
783 out.write("\n elt_p = &elt;\n")
784 else:
785 out.write(" /* Declare pointers for each subclass */\n")
786 for instance, subcls in sub_classes:
787 out.write(" %s_t *%s;\n" % (subcls, instance))
788 out.write("\n /* Instantiate pointers for each subclass */\n")
789 for instance, subcls in sub_classes:
790 out.write(" %s = &elt.%s;\n" % (instance, instance))
791
792 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700793 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700794 else:
795 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700796 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700797 out.write("""
798
799 return value;
800}
801""")
802
803def check_list_fn(out, version, cls):
804 """
805 Generate a helper function that checks a list populated by above fn
806 """
807 out.write("""
808/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700809 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700810 * list_setup_%(cls)s_%(v_name)s
811 */
812int
813list_check_%(cls)s_%(v_name)s(
814 %(cls)s_t *list, int value)
815{
816""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
817 base_type = loxi_utils.list_to_entry_type(cls)
818 out.write("""
819 %(base_type)s_t elt;
820""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700821
Rich Lanea06d0c32013-03-25 08:52:03 -0700822 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700823 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 -0700824 v_name = loxi_utils.version_to_name(version)
825
826 if len(sub_classes) == 0:
827 out.write(" /* No subclasses for %s */\n"% base_type)
828 out.write(" %s_t *elt_p;\n" % base_type)
829 out.write("\n elt_p = &elt;\n")
830 else:
831 out.write(" /* Declare pointers for each subclass */\n")
832 for instance, subcls in sub_classes:
833 out.write(" %s_t *%s;\n" % (subcls, instance))
834 out.write("\n /* Instantiate pointers for each subclass */\n")
835 for instance, subcls in sub_classes:
836 out.write(" %s = &elt.%s;\n" % (instance, instance))
837
838 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
839 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700840 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700841 else:
842 count = 0
843 for instance, subcls in sub_classes:
844 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700845 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700846 version, count==len(sub_classes))
847
848 out.write("""
849 return value;
850}
851""" % dict(base_type=base_type))
852
853def gen_list_set_check_funs(out):
854 for version in of_g.of_version_range:
855 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700856 if version in of_g.unified[cls]:
857 setup_list_fn(out, version, cls)
858 check_list_fn(out, version, cls)
859
860# Maybe: Get a map from list class to parent, mem_name of container
861
862def list_test(out, version, cls):
863 out.write("""
864static int
865test_%(cls)s_%(v_name)s(void)
866{
867""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
868 base_type = loxi_utils.list_to_entry_type(cls)
869
870 out.write(""" %(cls)s_t *list;
871 int value = 1;
872""" % dict(cls=cls, base_type=base_type))
873
874 out.write("""
875 list = %(cls)s_new(%(v_name)s);
876 TEST_ASSERT(list != NULL);
877 TEST_ASSERT(list->version == %(v_name)s);
878 TEST_ASSERT(list->length == 0);
879 TEST_ASSERT(list->parent == NULL);
880 TEST_ASSERT(list->object_id == %(enum_cls)s);
881
882 value = list_setup_%(cls)s_%(v_name)s(list, value);
883 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700884""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700885 enum_cls=loxi_utils.enum_name(cls)))
886
887 out.write("""
888 /* Now check values */
889 value = 1;
890 value = list_check_%(cls)s_%(v_name)s(list, value);
891 TEST_ASSERT(value != 0);
892""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
893
894 out.write("""
895 %(cls)s_delete(list);
896
897 return TEST_PASS;
898}
899""" % dict(cls=cls))
900
901def gen_list_test(out, name):
902 """
903 Generate base line test cases for lists
904 @param out The file handle to write to
905 """
906
907 loxi_utils.gen_c_copy_license(out)
908 out.write("""
909/**
910 *
911 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
912 *
913 * Message-scalar tests for all versions
914 */
915
916#include <locitest/test_common.h>
917""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700918
Rich Lanea06d0c32013-03-25 08:52:03 -0700919 for version in of_g.of_version_range:
920 v_name = loxi_utils.version_to_name(version)
921 out.write("""
922/**
923 * Baseline list tests for version %s
924 */
925""" % v_name)
926 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700927 if version in of_g.unified[cls]:
928 list_test(out, version, cls)
929
930 out.write("""
931int
932run_list_tests(void)
933{
934""")
935 for version in of_g.of_version_range:
936 v_name = loxi_utils.version_to_name(version)
937 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700938 if version in of_g.unified[cls]:
939 test_name = "%s_%s" % (cls, v_name)
940 out.write(" RUN_TEST(%s);\n" % test_name)
941
942 out.write("\n return TEST_PASS;\n}\n");
943
944def gen_match_test(out, name):
945 """
946 Generate baseline tests for match functions
947 """
948
949 loxi_utils.gen_c_copy_license(out)
950 out.write("""\
951/**
952 *
953 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
954 *
955 * Message-scalar tests for all versions
956 * @fixme These are mostly hard coded now.
957 */
958
959#include <locitest/test_common.h>
960
961static int
962test_match_1(void)
963{
964 of_match_v1_t *m_v1;
965 of_match_v2_t *m_v2;
966 of_match_v3_t *m_v3;
967 of_match_v4_t *m_v4;
968 of_match_t match;
969 int value = 1;
970 int idx;
971 uint32_t exp_value;
972
973 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700974 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700975 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
976 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
977 if (idx < 32) {
978 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
979 }
980 }
981""")
982
983 for version in of_g.of_version_range:
984 out.write("""
985 /* Create/populate/convert and delete for version %(v_name)s */
986 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
987 TEST_ASSERT(m_v%(version)d != NULL);
988 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
989 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
990 of_match_v%(version)d_delete(m_v%(version)d);
991""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
992
993 out.write("""
994 return TEST_PASS;
995}
996""")
997
998 out.write("""
999static int
1000test_match_2(void)
1001{
1002 of_match_v1_t *m_v1;
1003 of_match_v2_t *m_v2;
1004 of_match_v3_t *m_v3;
1005 of_match_v3_t *m_v4;
1006 of_match_t match1;
1007 of_match_t match2;
1008 int value = 1;
1009""")
1010
1011 for version in of_g.of_version_range:
1012 out.write("""
1013 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1014 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1015 TEST_ASSERT(m_v%(version)d != NULL);
1016 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1017 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1018 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1019 of_match_v%(version)d_delete(m_v%(version)d);
1020""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1021
1022 out.write("""
1023 return TEST_PASS;
1024}
1025""")
1026
1027 out.write("""
1028static int
1029test_match_3(void)
1030{
1031 of_match_t match1;
1032 of_match_t match2;
1033 int value = 1;
1034 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001035 of_object_storage_t storage;
1036 memset(&storage, 0, sizeof(storage));
1037 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001038""")
1039 for version in of_g.of_version_range:
1040 out.write("""
1041 /* Serialize to version %(v_name)s */
1042 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001043 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001044 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001045 storage.obj.wbuf->buf = octets.data;
1046 storage.obj.wbuf->alloc_bytes = octets.bytes;
1047 storage.obj.wbuf->current_bytes = octets.bytes;
1048 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001049 OF_ERROR_NONE);
1050 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1051 FREE(octets.data);
1052""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1053
1054 out.write("""
1055 return TEST_PASS;
1056}
1057""")
1058
1059 out.write("""
1060int run_match_tests(void)
1061{
1062 RUN_TEST(match_1);
1063 RUN_TEST(match_2);
1064 RUN_TEST(match_3);
1065 RUN_TEST(match_utils);
1066
1067 return TEST_PASS;
1068}
1069""")
1070
1071def gen_msg_test(out, name):
1072 loxi_utils.gen_c_copy_license(out)
1073 out.write("""
1074/**
1075 *
1076 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1077 *
1078 * Message-scalar tests for all versions
1079 */
1080
1081#include <locitest/test_common.h>
1082""")
1083 for version in of_g.of_version_range:
1084 for cls in of_g.ordered_messages:
1085 if not (cls, version) in of_g.base_length:
1086 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001087 if type_maps.class_is_virtual(cls):
1088 continue
Rich Lanef70be942013-07-18 13:33:14 -07001089 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001090 out.write("""
1091static int
1092test_%(cls)s_create_%(v_name)s(void)
1093{
1094 %(cls)s_t *obj;
1095 uint8_t *msg_buf;
1096 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001097 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001098 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001099
1100 obj = %(cls)s_new(%(v_name)s);
1101 TEST_ASSERT(obj != NULL);
1102 TEST_ASSERT(obj->version == %(v_name)s);
1103 TEST_ASSERT(obj->length == %(bytes)d);
1104 TEST_ASSERT(obj->parent == NULL);
1105 TEST_ASSERT(obj->object_id == %(enum)s);
1106
Rich Lanea4b68302014-03-12 15:17:58 -07001107 of_header_wire_object_id_get(obj, &object_id);
1108 TEST_ASSERT(object_id == %(enum)s);
1109
Rich Lanea06d0c32013-03-25 08:52:03 -07001110 /* Set up incrementing values for scalar members */
1111 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1112 TEST_ASSERT(value != 0);
1113
Rich Lanebb8f17c2014-06-12 13:14:09 -07001114 len = obj->length;
1115
Rich Lanea06d0c32013-03-25 08:52:03 -07001116 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001117 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1118 TEST_ASSERT(msg_buf != NULL);
1119 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001120 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001121
1122 TEST_ASSERT(obj != NULL);
1123
1124 /* @fixme Set up all message objects (recursively?) */
1125
1126 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1127 TEST_ASSERT(value != 0);
1128
1129 %(cls)s_delete(obj);
1130
1131 return TEST_PASS;
1132}
1133""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1134 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1135
1136 out.write("""
1137int
1138run_message_tests(void)
1139{
1140""")
1141 for version in of_g.of_version_range:
1142 for cls in of_g.ordered_messages:
1143 if not (cls, version) in of_g.base_length:
1144 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001145 if type_maps.class_is_virtual(cls):
1146 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001147 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1148 out.write(" RUN_TEST(%s);\n" % test_name)
1149
1150 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001151
Rich Lanea06d0c32013-03-25 08:52:03 -07001152
1153def gen_list_setup_check(out, cls, version):
1154 """
1155 Generate functions that populate and check a list with two
1156 of each type of subclass it supports
1157 """
1158 out.write("""
1159/**
1160 * Populate a list of type %(cls)s with two of each type of subclass
1161 * @param list Pointer to the list to be populated
1162 * @param value The seed value to use in populating the list
1163 * @returns The value after increments for this object's values
1164 */
1165int
1166%(cls)s_%(v_name)s_populate(
1167 %(cls)s_t *list, int value)
1168{
1169""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1170 base_type = loxi_utils.list_to_entry_type(cls)
1171 out.write("""
1172 %(base_type)s_t elt;
1173 int cur_len = 0;
1174""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001175
Rich Lanea06d0c32013-03-25 08:52:03 -07001176 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001177 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 -07001178 v_name = loxi_utils.version_to_name(version)
1179
1180 if len(sub_classes) == 0:
1181 out.write(" /* No subclasses for %s */\n"% base_type)
1182 out.write(" %s_t *elt_p;\n" % base_type)
1183 out.write("\n elt_p = &elt;\n")
1184 else:
1185 out.write(" /* Declare pointers for each subclass */\n")
1186 for instance, subcls in sub_classes:
1187 out.write(" %s_t *%s;\n" % (subcls, instance))
1188 out.write("\n /* Instantiate pointers for each subclass */\n")
1189 for instance, subcls in sub_classes:
1190 out.write(" %s = &elt.%s;\n" % (instance, instance))
1191
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001193 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001194 else:
1195 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001196 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001197 out.write("""
1198 return value;
1199}
1200""")
1201 out.write("""
1202/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001203 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001204 * %(cls)s_%(v_name)s_populate
1205 * @param list Pointer to the list that was populated
1206 * @param value Starting value for checking
1207 * @returns The value after increments for this object's values
1208 */
1209int
1210%(cls)s_%(v_name)s_check(
1211 %(cls)s_t *list, int value)
1212{
1213""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1214 base_type = loxi_utils.list_to_entry_type(cls)
1215 out.write("""
1216 %(base_type)s_t elt;
1217 int count = 0;
1218 int rv;
1219""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001220
Rich Lanea06d0c32013-03-25 08:52:03 -07001221
1222 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001223 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 -07001224 v_name = loxi_utils.version_to_name(version)
1225
1226 if len(sub_classes) == 0:
1227 entry_count = 2
1228 out.write(" /* No subclasses for %s */\n"% base_type)
1229 out.write(" %s_t *elt_p;\n" % base_type)
1230 out.write("\n elt_p = &elt;\n")
1231 else:
1232 entry_count = 2 * len(sub_classes) # Two of each type appended
1233 out.write(" /* Declare pointers for each subclass */\n")
1234 for instance, subcls in sub_classes:
1235 out.write(" %s_t *%s;\n" % (subcls, instance))
1236 out.write("\n /* Instantiate pointers for each subclass */\n")
1237 for instance, subcls in sub_classes:
1238 out.write(" %s = &elt.%s;\n" % (instance, instance))
1239
1240 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1241 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001242 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001243 version, True)
1244 else:
1245 count = 0
1246 for instance, subcls in sub_classes:
1247 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001248 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001249 version, count==len(sub_classes))
1250 out.write("""
1251""" % dict(base_type=base_type))
1252
1253 out.write("""
1254 /* Do an iterate to test the iterator */
1255 %(u_cls)s_ITER(list, &elt, rv) {
1256 count += 1;
1257 }
1258
1259 TEST_ASSERT(rv == OF_ERROR_RANGE);
1260 TEST_ASSERT(count == %(entry_count)d);
1261
1262 /* We shoehorn a test of the dup functions here */
1263 {
1264 %(cls)s_t *dup;
1265
1266 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1267 TEST_ASSERT(dup->length == list->length);
1268 TEST_ASSERT(dup->object_id == list->object_id);
1269 TEST_ASSERT(dup->version == list->version);
1270 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1271 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1272 of_object_delete((of_object_t *)dup);
1273
1274 /* And now for the generic dup function */
1275 TEST_ASSERT((dup = (%(cls)s_t *)
1276 of_object_dup(list)) != NULL);
1277 TEST_ASSERT(dup->length == list->length);
1278 TEST_ASSERT(dup->object_id == list->object_id);
1279 TEST_ASSERT(dup->version == list->version);
1280 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1281 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1282 of_object_delete((of_object_t *)dup);
1283 }
1284
1285 return value;
1286}
1287""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1288
1289
1290def gen_class_setup_check(out, cls, version):
1291 out.write("""
1292/**
1293 * Populate all members of an object of type %(cls)s
1294 * with incrementing values
1295 * @param obj Pointer to an object to populate
1296 * @param value The seed value to use in populating the object
1297 * @returns The value after increments for this object's values
1298 */
1299
1300int
1301%(cls)s_%(v_name)s_populate(
1302 %(cls)s_t *obj, int value)
1303{
1304""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1305 members, member_types = loxi_utils.all_member_types_get(cls, version)
1306 for m_type in member_types:
1307 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1308 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001309 elif m_type == "of_bsn_vport_header_t":
1310 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001311 else:
1312 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1313 out.write("""
1314 /* Run thru accessors after new to ensure okay */
1315""")
1316 for member in members:
1317 m_type = member["m_type"]
1318 m_name = member["name"]
1319 if loxi_utils.skip_member_name(m_name):
1320 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001321 if m_type == "of_bsn_vport_header_t":
1322 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001323 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1324 out.write("""\
1325 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1326""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1327 else:
1328 sub_cls = m_type[:-2] # Trim _t
1329 out.write("""\
1330 {
1331 %(sub_cls)s_t sub_cls;
1332
1333 /* Test bind */
1334 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1335 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001336""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001337 m_name=m_name, sub_cls=sub_cls,
1338 v_name=loxi_utils.version_to_name(version)))
1339
1340 out.write("""
1341 value = %(cls)s_%(v_name)s_populate_scalars(
1342 obj, value);
1343 TEST_ASSERT(value != 0);
1344""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1345
1346 for member in members:
1347 m_type = member["m_type"]
1348 m_name = member["name"]
1349 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1350 continue
1351 if loxi_utils.skip_member_name(m_name):
1352 continue
1353 if m_type == "of_match_t":
1354 out.write("""\
1355 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1356 TEST_ASSERT(value != 0);
1357 %(cls)s_%(m_name)s_set(
1358 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001359""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001360 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1361 elif m_type == "of_octets_t":
1362 out.write("""\
1363 value = of_octets_populate(&%(var_name)s, value);
1364 TEST_ASSERT(value != 0);
1365 %(cls)s_%(m_name)s_set(
1366 obj, &%(var_name)s);
1367 if (octets.bytes) {
1368 FREE(octets.data);
1369 }
1370""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001371 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1372 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001373 out.write("""\
1374 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1375 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001376 value = %(sub_cls)s_%(v_name)s_populate(
1377 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001378 TEST_ASSERT(value != 0);
1379 %(cls)s_%(m_name)s_set(
1380 obj, %(var_name)s);
1381 %(sub_cls)s_delete(%(var_name)s);
1382""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1383 var_name=var_name_map(m_type),
1384 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001385 else:
1386 sub_cls = m_type[:-2] # Trim _t
1387 out.write("""
1388 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1389 TEST_ASSERT(%(var_name)s != NULL);
1390 value = %(sub_cls)s_%(v_name)s_populate(
1391 %(var_name)s, value);
1392 TEST_ASSERT(value != 0);
1393 %(cls)s_%(m_name)s_set(
1394 obj, %(var_name)s);
1395 %(sub_cls)s_delete(%(var_name)s);
1396""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1397 var_name=var_name_map(m_type),
1398 v_name=loxi_utils.version_to_name(version)))
1399
1400 out.write("""
1401 return value;
1402}
1403""")
1404
1405 out.write("""
1406/**
1407 * Check all members of an object of type %(cls)s
1408 * populated by the above function
1409 * @param obj Pointer to an object to check
1410 * @param value Starting value for checking
1411 * @returns The value after increments for this object's values
1412 */
1413
1414int
1415%(cls)s_%(v_name)s_check(
1416 %(cls)s_t *obj, int value)
1417{
1418""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1419 members, member_types = loxi_utils.all_member_types_get(cls, version)
1420 for m_type in member_types:
1421 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1422 continue
1423 if loxi_utils.type_is_of_object(m_type):
1424 continue
1425 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1426 out.write("""
1427 value = %(cls)s_%(v_name)s_check_scalars(
1428 obj, value);
1429 TEST_ASSERT(value != 0);
1430""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1431
1432 for member in members:
1433 m_type = member["m_type"]
1434 m_name = member["name"]
1435 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1436 continue
1437 if loxi_utils.skip_member_name(m_name):
1438 continue
1439 if m_type == "of_match_t":
1440 out.write("""\
1441 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1442 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1443""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1444 v_name=loxi_utils.version_to_name(version)))
1445 elif m_type == "of_octets_t":
1446 out.write("""\
1447 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1448 value = of_octets_check(&%(var_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)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001451 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1452 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001453 out.write("""
1454 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001455 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001456
1457 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1458 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001459 value = %(sub_cls)s_%(v_name)s_check(
1460 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001461 TEST_ASSERT(value != 0);
1462 %(sub_cls)s_delete(%(m_name)s_ptr);
1463 }
1464""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1465 var_name=var_name_map(m_type),
1466 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001467 else:
1468 sub_cls = m_type[:-2] # Trim _t
1469 out.write("""
1470 { /* Use get/delete to access on check */
1471 %(m_type)s *%(m_name)s_ptr;
1472
1473 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1474 TEST_ASSERT(%(m_name)s_ptr != NULL);
1475 value = %(sub_cls)s_%(v_name)s_check(
1476 %(m_name)s_ptr, value);
1477 TEST_ASSERT(value != 0);
1478 %(sub_cls)s_delete(%(m_name)s_ptr);
1479 }
1480""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1481 var_name=var_name_map(m_type),
1482 v_name=loxi_utils.version_to_name(version)))
1483
1484 out.write("""
1485 /* We shoehorn a test of the dup functions here */
1486 {
1487 %(cls)s_t *dup;
1488
1489 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1490 TEST_ASSERT(dup->length == obj->length);
1491 TEST_ASSERT(dup->object_id == obj->object_id);
1492 TEST_ASSERT(dup->version == obj->version);
1493 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1494 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1495 of_object_delete((of_object_t *)dup);
1496
1497 /* And now for the generic dup function */
1498 TEST_ASSERT((dup = (%(cls)s_t *)
1499 of_object_dup(obj)) != NULL);
1500 TEST_ASSERT(dup->length == obj->length);
1501 TEST_ASSERT(dup->object_id == obj->object_id);
1502 TEST_ASSERT(dup->version == obj->version);
1503 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1504 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1505 of_object_delete((of_object_t *)dup);
1506 }
1507
1508 return value;
1509}
1510""" % dict(cls=cls))
1511
1512def unified_accessor_test_case(out, cls, version):
1513 """
1514 Generate one test case for the given version and class
1515 """
1516
1517 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001518 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001519 v_name = loxi_utils.version_to_name(version)
1520
1521 out.write("""
1522static int
1523test_%(cls)s_%(v_name)s(void)
1524{
1525 %(cls)s_t *obj;
1526 obj = %(cls)s_new(%(v_name)s);
1527 TEST_ASSERT(obj != NULL);
1528 TEST_ASSERT(obj->version == %(v_name)s);
1529 TEST_ASSERT(obj->length == %(length)d);
1530 TEST_ASSERT(obj->parent == NULL);
1531 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001532""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001533 v_name=v_name, length=length, version=version))
1534 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1535 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001536 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001537 int length;
1538
Rich Lanedc46fe22014-04-03 15:10:38 -07001539 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001540 TEST_ASSERT(length == %(length)d);
1541 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001542 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001543 of_object_id_t obj_id;
1544
Rich Lanedc46fe22014-04-03 15:10:38 -07001545 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001546 TEST_ASSERT(obj_id == %(u_cls)s);
1547 }
1548
1549 /* Set up incrementing values for members */
1550 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1551 obj, 1) != 0);
1552
1553 /* Check values just set */
1554 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1555 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001556""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001557 v_name=v_name, length=length, version=version))
1558
1559 out.write("""
1560 %(cls)s_delete(obj);
1561
1562 /* To do: Check memory */
1563 return TEST_PASS;
1564}
1565""" % dict(cls=cls))
1566
1567
1568def gen_unified_accessor_funs(out):
1569 for version in of_g.of_version_range:
1570 for cls in of_g.standard_class_order:
1571 if not loxi_utils.class_in_version(cls, version):
1572 continue
1573 if cls in type_maps.inheritance_map:
1574 continue
1575 elif loxi_utils.class_is_list(cls):
1576 gen_list_setup_check(out, cls, version)
1577 else:
1578 gen_class_setup_check(out, cls, version)
1579
1580def gen_unified_accessor_tests(out, name):
1581 loxi_utils.gen_c_copy_license(out)
1582 out.write("""
1583/**
1584 *
1585 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1586 *
1587 * Unified simple class instantiation tests for all versions
1588 */
1589
1590#include <locitest/test_common.h>
1591""")
1592 for version in of_g.of_version_range:
1593 for cls in of_g.standard_class_order:
1594 if not loxi_utils.class_in_version(cls, version):
1595 continue
1596 if cls in type_maps.inheritance_map:
1597 continue
1598 unified_accessor_test_case(out, cls, version)
1599
1600 out.write("""
1601int
1602run_unified_accessor_tests(void)
1603{
1604""")
1605 for version in of_g.of_version_range:
1606 v_name = loxi_utils.version_to_name(version)
1607 for cls in of_g.standard_class_order:
1608 if not loxi_utils.class_in_version(cls, version):
1609 continue
1610 if cls in type_maps.inheritance_map:
1611 continue
1612 test_name = "%s_%s" % (cls, v_name)
1613 out.write(" RUN_TEST(%s);\n" % test_name)
1614
1615 out.write(" return TEST_PASS;\n}\n");
1616
1617
1618
1619################################################################
1620#
1621# Object duplication functions
1622#
1623# These exercise the accessors to create duplicate objects.
1624# They are used in the LOCI test shim which sits in an OF
1625# protocol stream.
1626#
1627# TODO
1628# Resolve version stuff
1629# Complete list dup
1630
1631def gen_dup_list(out, cls, version):
1632 ver_name = loxi_utils.version_to_name(version)
1633 elt_type = loxi_utils.list_to_entry_type(cls)
1634 out.write("""
1635/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001636 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001637 * using accessor functions
1638 * @param src Pointer to object to be duplicated
1639 * @returns A new object of type %(cls)s.
1640 *
1641 * The caller is responsible for deleting the returned value
1642 */
1643%(cls)s_t *
1644%(cls)s_%(ver_name)s_dup(
1645 %(cls)s_t *src)
1646{
1647 %(elt_type)s_t src_elt;
1648 %(elt_type)s_t *dst_elt;
1649 int rv;
1650 %(cls)s_t *dst;
1651
1652 if ((dst = %(cls)s_new(src->version)) == NULL) {
1653 return NULL;
1654 }
1655""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1656
1657 out.write("""
1658 %(u_cls)s_ITER(src, &src_elt, rv) {
1659 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1660 of_object_delete((of_object_t *)dst);
1661 return NULL;
1662 }
1663 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1664 dst, NULL);
1665 of_object_delete((of_object_t *)dst_elt);
1666 }
1667
1668 return dst;
1669}
1670""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1671
1672
1673def gen_dup_inheritance(out, cls, version):
1674 ver_name = loxi_utils.version_to_name(version)
1675 out.write("""
1676/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001677 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001678 * @param src Pointer to object to be duplicated
1679 * @returns A new object of type %(cls)s.
1680 *
1681 * The caller is responsible for deleting the returned value
1682 */
1683%(cls)s_t *
1684%(cls)s_%(ver_name)s_dup(
1685 %(cls)s_t *src)
1686{
1687""" % dict(cls=cls, ver_name=ver_name))
1688
1689 # For each subclass, check if this is an instance of that subclass
1690 version_classes = type_maps.inheritance_data[cls][version]
1691 for sub_cls in version_classes:
1692 sub_enum = (cls + "_" + sub_cls).upper()
1693 out.write("""
1694 if (src->header.object_id == %(sub_enum)s) {
1695 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1696 &src->%(sub_cls)s);
1697 }
1698""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1699
1700 out.write("""
1701 return NULL;
1702}
1703""")
1704
1705
1706def gen_dup_cls(out, cls, version):
1707 """
1708 Generate duplication routine for class cls
1709 """
1710 ver_name = loxi_utils.version_to_name(version)
1711
1712 out.write("""
1713/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001714 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001715 * using accessor functions
1716 * @param src Pointer to object to be duplicated
1717 * @returns A new object of type %(cls)s.
1718 *
1719 * The caller is responsible for deleting the returned value
1720 */
1721%(cls)s_t *
1722%(cls)s_%(ver_name)s_dup(
1723 %(cls)s_t *src)
1724{
1725 %(cls)s_t *dst;
1726""" % dict(cls=cls, ver_name=ver_name))
1727
1728 # Get members and types for the class
1729 members, member_types = loxi_utils.all_member_types_get(cls, version)
1730
1731 # Add declarations for each member type
1732 for m_type in member_types:
1733 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1734 # Declare instance of these
1735 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001736 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1737 out.write("""
1738 of_bsn_vport_q_in_q_t src_%(v_name)s;
1739 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1740""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001741 else:
1742 out.write("""
1743 %(m_type)s src_%(v_name)s;
1744 %(m_type)s *dst_%(v_name)s;
1745""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1746
1747 out.write("""
1748 if ((dst = %(cls)s_new(src->version)) == NULL) {
1749 return NULL;
1750 }
1751""" % dict(cls=cls))
1752
1753 for member in members:
1754 m_type = member["m_type"]
1755 m_name = member["name"]
1756 if loxi_utils.skip_member_name(m_name):
1757 continue
1758 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1759 out.write("""
1760 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1761 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1762""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1763 elif m_type in ["of_match_t", "of_octets_t"]:
1764 out.write("""
1765 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1766 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1767""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001768 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1769 sub_cls = "of_bsn_vport_q_in_q"
1770 out.write("""
1771 %(cls)s_%(m_name)s_bind(
1772 src, &src_%(v_name)s);
1773 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1774 if (dst_%(v_name)s == NULL) {
1775 %(cls)s_delete(dst);
1776 return NULL;
1777 }
1778 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1779 %(sub_cls)s_delete(dst_%(v_name)s);
1780""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1781 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001782 else:
1783 sub_cls = m_type[:-2] # Trim _t
1784 out.write("""
1785 %(cls)s_%(m_name)s_bind(
1786 src, &src_%(v_name)s);
1787 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1788 if (dst_%(v_name)s == NULL) {
1789 %(cls)s_delete(dst);
1790 return NULL;
1791 }
1792 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1793 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001794""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001795 v_name=var_name_map(m_type), ver_name=ver_name))
1796
1797 out.write("""
1798 return dst;
1799}
1800""")
1801
1802def gen_version_dup(out=sys.stdout):
1803 """
1804 Generate duplication routines for each object type
1805 """
1806 out.write("""
1807/* Special try macro for duplicating */
1808#define _TRY_FREE(op, obj, rv) do { \\
1809 int _rv; \\
1810 if ((_rv = (op)) < 0) { \\
1811 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1812 of_object_delete((of_object_t *)(obj)); \\
1813 return (rv); \\
1814 } \\
1815 } while (0)
1816""")
1817
1818 for version in of_g.of_version_range:
1819 for cls in of_g.standard_class_order:
1820 if not loxi_utils.class_in_version(cls, version):
1821 continue
1822 if cls in type_maps.inheritance_map:
1823 gen_dup_inheritance(out, cls, version)
1824 elif loxi_utils.class_is_list(cls):
1825 gen_dup_list(out, cls, version)
1826 else:
1827 gen_dup_cls(out, cls, version)
1828
1829def gen_dup(out=sys.stdout):
1830 """
1831 Generate non-version specific duplication routines for each object type
1832 """
1833
1834 for cls in of_g.standard_class_order:
1835 out.write("""
1836%(cls)s_t *
1837%(cls)s_dup(
1838 %(cls)s_t *src)
1839{
1840""" % dict(cls=cls))
1841 for version in of_g.of_version_range:
1842 if not loxi_utils.class_in_version(cls, version):
1843 continue
1844 hdr = "header." if cls in type_maps.inheritance_map else ""
1845
1846 ver_name = loxi_utils.version_to_name(version)
1847 out.write("""
1848 if (src->%(hdr)sversion == %(ver_name)s) {
1849 return %(cls)s_%(ver_name)s_dup(src);
1850 }
1851""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1852
1853 out.write("""
1854 /* Class not supported in given version */
1855 return NULL;
1856}
1857""")
1858
1859def dup_c_gen(out, name):
1860 """
1861 Generate the C file for duplication functions
1862 """
1863 loxi_utils.gen_c_copy_license(out)
1864 out.write("""\
1865/*
1866 * Duplication functions for all OF objects
1867 *
1868 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1869 *
1870 * These are test functions for exercising accessors. You can call
1871 * of_object_dup for an efficient duplication.
1872 */
1873
1874#define DISABLE_WARN_UNUSED_RESULT
1875#include "loci_log.h"
1876#include <locitest/of_dup.h>
1877
1878""")
1879
1880 gen_version_dup(out)
1881 gen_dup(out)
1882
1883
1884def dup_h_gen(out, name):
1885 """
1886 Generate the header file for duplication functions
1887 """
1888
1889 loxi_utils.gen_c_copy_license(out)
1890 out.write("""
1891/*
1892 * Duplication function header file
1893 *
1894 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1895 */
1896
1897#if !defined(_OF_DUP_H_)
1898#define _OF_DUP_H_
1899
1900#include <loci/loci.h>
1901""")
1902
1903 for cls in of_g.standard_class_order:
1904 out.write("""
1905extern %(cls)s_t *
1906 %(cls)s_dup(
1907 %(cls)s_t *src);
1908""" % dict(cls=cls))
1909
1910 for version in of_g.of_version_range:
1911 for cls in of_g.standard_class_order:
1912 if not loxi_utils.class_in_version(cls, version):
1913 continue
1914 ver_name = loxi_utils.version_to_name(version)
1915 out.write("""
1916extern %(cls)s_t *
1917 %(cls)s_%(ver_name)s_dup(
1918 %(cls)s_t *src);
1919""" % dict(cls=cls, ver_name=ver_name))
1920
1921 out.write("\n#endif /* _OF_DUP_H_ */\n")
1922
1923def gen_log_test(out):
1924 """
1925 Generate test for obj log calls
1926
1927 Define a trivial handler for object logging; call all obj log fns
1928 """
1929 out.write("""
1930
1931/**
1932 * Test object dump functions
1933 */
1934
1935int
1936test_dump_objs(void)
1937{
1938 of_object_t *obj;
1939
1940 FILE *out = fopen("/dev/null", "w");
1941
1942 /* Call each obj dump function */
1943""")
1944 for version in of_g.of_version_range:
1945 for j, cls in enumerate(of_g.all_class_order):
1946 if not loxi_utils.class_in_version(cls, version):
1947 continue
1948 if cls in type_maps.inheritance_map:
1949 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001950 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1951 out.write("""
1952 obj = (of_object_t *)%(cls)s_new(%(version)s);
1953 {
1954 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1955 %(cls)s_vport_set(obj, vport);
1956 of_object_delete(vport);
1957 }
1958 of_object_dump((loci_writer_f)fprintf, out, obj);
1959 of_object_delete(obj);
1960""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1961 else:
1962 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001963 obj = (of_object_t *)%(cls)s_new(%(version)s);
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]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001967
Rich Lanea06d0c32013-03-25 08:52:03 -07001968 out.write("""
1969 fclose(out);
1970 return TEST_PASS;
1971}
1972""")
1973
1974def gen_ident_tests(out):
1975 """
1976 Generate tests for identifiers
1977
1978 For all idents, instantiate, test version supported macros
1979 For flags, set it, test it, clear it, test it.
1980 """
1981 out.write("""
1982/**
1983 * Test cases for all flag accessor macros
1984 * These only test self consistency (and that they compile)
1985 */
1986int
1987test_ident_macros(void)
1988{
1989 int value __attribute__((unused));
1990 uint32_t flags;
1991
1992""")
1993
1994 for ident, info in of_g.identifiers.items():
1995 if not identifiers.defined_versions_agree(of_g.identifiers,
1996 of_g.target_version_list,
1997 ident):
1998 # @fixme
1999 continue
2000 out.write(" value = %s;\n" % ident)
2001 for version in of_g.target_version_list:
2002 if version in info["values_by_version"].keys():
2003 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2004 (ident, of_g.of_version_wire2name[version]))
2005 else:
2006 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2007 (ident, of_g.of_version_wire2name[version]))
2008 if flags.ident_is_flag(ident):
2009 # Grab first supported version
2010 for version in info["values_by_version"]:
2011 break
2012 out.write("""
2013 flags = 0;
2014 %(ident)s_SET(flags, %(ver_name)s);
2015 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2016 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2017 %(ident)s_CLEAR(flags, %(ver_name)s);
2018 TEST_ASSERT(flags == 0);
2019 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2020""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2021
2022 out.write("""
2023 return TEST_PASS;
2024}
2025""")
2026
Rich Laneccae0312013-07-21 23:34:13 -07002027def gen_datafiles_tests(out, name):
2028 tests = []
2029 for filename in test_data.list_files():
2030 data = test_data.read(filename)
2031 if not 'c' in data:
2032 continue
2033 name = filename[:-5].replace("/", "_")
2034 tests.append(dict(name=name,
2035 filename=filename,
2036 c=data['c'],
2037 binary=data['binary']))
2038
2039 util.render_template(out, "test_data.c", tests=tests)