blob: 3eaaf8220f14082c8c884238425eb172fabd7444 [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",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700103 # BSN extensions
104 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700105 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800106 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700107 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700108
109 if m_type.find("of_list_") == 0:
110 return "list"
111 if m_type in of_g.of_mixed_types:
112 return of_g.of_mixed_types[m_type]["short_name"]
113 return _var_name_map[m_type]
114
115integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
116 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700117 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700118string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700119 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700120 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
121 "of_str64_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700122
123scalar_types = integer_types[:]
124scalar_types.extend(string_types)
125
126def ignore_member(cls, version, m_name, m_type):
127 """
128 Filter out names or types that either don't have accessors
129 or those that should not be messed with
130 or whose types we're not ready to deal with yet.
131 """
Rich Lane79c87192014-03-04 10:56:59 -0800132
133 uclass = loxi_globals.unified.class_by_name(cls)
134 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700135 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800136
Rich Lane79c87192014-03-04 10:56:59 -0800137 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800138 return True
Rich Lane79c87192014-03-04 10:56:59 -0800139
Rich Lanea06d0c32013-03-25 08:52:03 -0700140 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
141
142def gen_fill_string(out):
143 out.write("""
144
145/**
146 * The increment to use on values inside a string
147 */
148#define OF_TEST_STR_INCR 3
149
150/**
151 * Fill in a buffer with incrementing values starting
152 * at the given offset with the given value
153 * @param buf The buffer to fill
154 * @param value The value to use for data
155 * @param len The number of bytes to fill
156 */
157
158void
159of_test_str_fill(uint8_t *buf, int value, int len)
160{
161 int i;
162
163 for (i = 0; i < len; i++) {
164 *buf = value;
165 value += OF_TEST_STR_INCR;
166 buf++;
167 }
168}
169
170/**
171 * Given a buffer, verify that it's filled as above
172 * @param buf The buffer to check
173 * @param value The value to use for data
174 * @param len The number of bytes to fill
175 * @return Boolean True on equality (success)
176 */
177
178int
179of_test_str_check(uint8_t *buf, int value, int len)
180{
181 int i;
182 uint8_t val8;
183
184 val8 = value;
185
186 for (i = 0; i < len; i++) {
187 if (*buf != val8) {
188 return 0;
189 }
190 val8 += OF_TEST_STR_INCR;
191 buf++;
192 }
193
194 return 1;
195}
196
197/**
198 * Global that determines how octets should be populated
199 * -1 means use value % MAX (below) to determine length
200 * 0, 1, ... means used that fixed length
201 *
202 * Note: Was 16K, but that made objects too big. May add flexibility
203 * to call populate with a max parameter for length
204 */
205int octets_pop_style = -1;
206#define OCTETS_MAX_VALUE (128) /* 16K was too big */
207#define OCTETS_MULTIPLIER 6367 /* A prime */
208
209int
210of_octets_populate(of_octets_t *octets, int value)
211{
212 if (octets_pop_style < 0) {
213 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
214 } else {
215 octets->bytes = octets_pop_style;
216 }
217
218 if (octets->bytes != 0) {
219 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
220 return 0;
221 }
222 of_test_str_fill(octets->data, value, octets->bytes);
223 value += 1;
224 }
225
226 return value;
227}
228
229int
230of_octets_check(of_octets_t *octets, int value)
231{
232 int len;
233
234 if (octets_pop_style < 0) {
235 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
236 TEST_ASSERT(octets->bytes == len);
237 } else {
238 TEST_ASSERT(octets->bytes == octets_pop_style);
239 }
240
241 if (octets->bytes != 0) {
242 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
243 == 1);
244 value += 1;
245 }
246
247 return value;
248}
249
250int
251of_match_populate(of_match_t *match, of_version_t version, int value)
252{
253 MEMSET(match, 0, sizeof(*match));
254 match->version = version;
255""")
256
257 for key, entry in match.of_match_members.items():
258 out.write("""
Andreas Wundsam53256162013-05-02 14:05:53 -0700259 if (!(of_match_incompat[version] &
Rich Lanea06d0c32013-03-25 08:52:03 -0700260 OF_OXM_BIT(OF_OXM_INDEX_%(ku)s))) {
261 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
262 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
263 value += 1;
264 }
265
266""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
267
268 out.write("""
269 if (value % 2) {
270 /* Sometimes set ipv4 addr masks to non-exact */
271 match->masks.ipv4_src = 0xffff0000;
272 match->masks.ipv4_dst = 0xfffff800;
273 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700274
275 /* Restrict values according to masks */
276 of_match_values_mask(match);
Rich Lanea06d0c32013-03-25 08:52:03 -0700277 return value;
278}
279
280int
281of_match_check(of_match_t *match, of_version_t version, int value)
282{
283 of_match_t check;
284
285 value = of_match_populate(&check, match->version, value);
286 TEST_ASSERT(value != 0);
287 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
288
289 return value;
290}
291""")
292
293def gen_common_test_header(out, name):
294 loxi_utils.gen_c_copy_license(out)
295 out.write("""
296/*
297 * Test header file
298 *
299 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
300 */
301
302#if !defined(_TEST_COMMON_H_)
303#define _TEST_COMMON_H_
304
305#define DISABLE_WARN_UNUSED_RESULT
306#include <loci/loci.h>
307#include <locitest/of_dup.h>
308#include <locitest/unittest.h>
309
310extern int global_error;
311extern int exit_on_error;
312
313/* @todo Make option for -k to continue tests if errors */
314#define RUN_TEST(test) do { \\
315 int rv; \\
316 TESTCASE(test, rv); \\
317 if (rv != TEST_PASS) { \\
318 global_error=1; \\
319 if (exit_on_error) return(1); \\
320 } \\
321 } while(0)
322
323#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
324#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
325
326/*
327 * Declarations of functions to populate scalar values in a a class
328 */
329
330extern void of_test_str_fill(uint8_t *buf, int value, int len);
331extern int of_test_str_check(uint8_t *buf, int value, int len);
332
333
334extern int of_octets_populate(of_octets_t *octets, int value);
335extern int of_octets_check(of_octets_t *octets, int value);
336extern int of_match_populate(of_match_t *match, of_version_t version,
337 int value);
338extern int of_match_check(of_match_t *match, of_version_t version, int value);
339extern int test_ident_macros(void);
340extern int test_dump_objs(void);
341
342/* In test_match_utils.c */
343extern int test_match_utils(void);
344
345extern int run_unified_accessor_tests(void);
346extern int run_match_tests(void);
347extern int run_utility_tests(void);
348
349extern int run_scalar_acc_tests(void);
350extern int run_list_tests(void);
351extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700352
353extern int run_validator_tests(void);
354
355extern int run_list_limits_tests(void);
356
357extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700358extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700359
360""")
361
362 for version in of_g.of_version_range:
363 for cls in of_g.standard_class_order:
364 if not loxi_utils.class_in_version(cls, version):
365 continue
366 if cls in type_maps.inheritance_map:
367 continue
368 out.write("""
369extern int %(cls)s_%(v_name)s_populate(
370 %(cls)s_t *obj, int value);
371extern int %(cls)s_%(v_name)s_check(
372 %(cls)s_t *obj, int value);
373extern int %(cls)s_%(v_name)s_populate_scalars(
374 %(cls)s_t *obj, int value);
375extern int %(cls)s_%(v_name)s_check_scalars(
376 %(cls)s_t *obj, int value);
377""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
378
379 out.write("""
380/*
381 * Declarations for list population and check primitives
382 */
383""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700384
Rich Lanea06d0c32013-03-25 08:52:03 -0700385 for version in of_g.of_version_range:
386 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700387 if version in of_g.unified[cls]:
388 out.write("""
389extern int
390 list_setup_%(cls)s_%(v_name)s(
391 %(cls)s_t *list, int value);
392extern int
393 list_check_%(cls)s_%(v_name)s(
394 %(cls)s_t *list, int value);
395""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
396
397 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
398
399def gen_common_test(out, name):
400 """
401 Generate common test content including main
402 """
403 loxi_utils.gen_c_copy_license(out)
404 out.write("""
405/*
406 * Common test code for LOCI
407 *
408 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
409 */
410
411#define DISABLE_WARN_UNUSED_RESULT
412#include "loci_log.h"
413#include <loci/loci_obj_dump.h>
414#include <locitest/unittest.h>
415#include <locitest/test_common.h>
416
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900417/* mcheck is a glibc extension */
418#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700419#include <mcheck.h>
420#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900421#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700422#define MCHECK_INIT do { } while (0)
423#endif
424
425/**
426 * Exit on error if set to 1
427 */
428int exit_on_error = 1;
429
430/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700431 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700432 */
433int global_error = 0;
434
435extern int run_unified_accessor_tests(void);
436extern int run_match_tests(void);
437extern int run_utility_tests(void);
438
439extern int run_scalar_acc_tests(void);
440extern int run_list_tests(void);
441extern int run_message_tests(void);
442
443/**
444 * Macros for initializing and checking scalar types
445 *
446 * @param var The variable being initialized or checked
447 * @param val The integer value to set/check against, see below
448 *
449 * Note that equality means something special for strings. Each byte
450 * is initialized to an incrementing value. So check is done against that.
451 *
452 */
453
454""")
455 for t in scalar_types:
456 if t in integer_types:
457 out.write("""
458#define VAR_%s_INIT(var, val) var = (%s)(val)
459#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
460""" % (t.upper(), t, t.upper(), t))
461 else:
462 out.write("""
463#define VAR_%s_INIT(var, val) \\
464 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
465#define VAR_%s_CHECK(var, val) \\
466 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
467""" % (t.upper(), t.upper()))
468
469 gen_fill_string(out)
470 gen_scalar_set_check_funs(out)
471 gen_list_set_check_funs(out)
472 gen_unified_accessor_funs(out)
473
474 gen_ident_tests(out)
475 gen_log_test(out)
476
477def gen_message_scalar_test(out, name):
478 """
479 Generate test cases for message objects, scalar accessors
480 """
481
482 loxi_utils.gen_c_copy_license(out)
483 out.write("""
484/**
485 *
486 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
487 *
488 * Message-scalar tests for all versions
489 */
490
491#include <locitest/test_common.h>
492""")
493 for version in of_g.of_version_range:
494 v_name = loxi_utils.version_to_name(version)
495 out.write("""
496/**
497 * Message-scalar tests for version %s
498 */
499""" % v_name)
500 for cls in of_g.standard_class_order:
501 if cls in type_maps.inheritance_map:
502 continue
503 if version in of_g.unified[cls]:
504 message_scalar_test(out, version, cls)
505
506 out.write("""
507int
508run_scalar_acc_tests(void)
509{
510""")
511 for version in of_g.of_version_range:
512 v_name = loxi_utils.version_to_name(version)
513 for cls in of_g.standard_class_order:
514 if cls in type_maps.inheritance_map:
515 continue
516 if version in of_g.unified[cls]:
517 test_name = "%s_%s" % (cls, v_name)
518 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
519
520 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700521
Rich Lanea06d0c32013-03-25 08:52:03 -0700522def message_scalar_test(out, version, cls):
523 """
524 Generate one test case for the given version and class
525 """
526
527 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700528 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700529 v_name = loxi_utils.version_to_name(version)
530
531 out.write("""
532static int
533test_%(cls)s_%(v_name)s_scalar(void)
534{
535 %(cls)s_t *obj;
536
537 obj = %(cls)s_new(%(v_name)s);
538 TEST_ASSERT(obj != NULL);
539 TEST_ASSERT(obj->version == %(v_name)s);
540 TEST_ASSERT(obj->length == %(length)d);
541 TEST_ASSERT(obj->parent == NULL);
542 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700543""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700544 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700545
546 # If this class is a concrete member of an inheritance hierarchy,
547 # run the hierarchy's root wire type parser and assert it returns
548 # the expected object id.
549 ofclass = loxi_globals.unified.class_by_name(cls)
550 if ofclass and not ofclass.virtual:
551 root = ofclass
552 while root.superclass:
553 root = root.superclass
554 if root.virtual:
555 out.write("""
556 {
557 of_object_id_t object_id;
558 %(root_cls)s_wire_object_id_get(obj, &object_id);
559 TEST_ASSERT(object_id == %(u_cls)s);
560 }
561""" % dict(root_cls=root.name, u_cls=cls.upper()))
562
Rich Lanea06d0c32013-03-25 08:52:03 -0700563 if not type_maps.class_is_virtual(cls):
564 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700565 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700566 int length;
567
Rich Lanedc46fe22014-04-03 15:10:38 -0700568 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700569 TEST_ASSERT(length == %(length)d);
570 }
571
572 /* Set up incrementing values for scalar members */
573 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
574
575 /* Check values just set */
576 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700577""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700578 v_name=v_name, length=length, version=version))
579
580 out.write("""
581 %(cls)s_delete(obj);
582
583 /* To do: Check memory */
584 return TEST_PASS;
585}
586""" % dict(cls=cls))
587
588# Get the members and list of scalar types for members of a given class
589def scalar_member_types_get(cls, version):
590 member_types = []
591
592 if not version in of_g.unified[cls]:
593 return ([], [])
594
595 if "use_version" in of_g.unified[cls][version]:
596 v = of_g.unified[cls][version]["use_version"]
597 members = of_g.unified[cls][v]["members"]
598 else:
599 members = of_g.unified[cls][version]["members"]
600 # Accumulate variables that are supported
601 for member in members:
602 m_type = member["m_type"]
603 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700604 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700605 ignore_member(cls, version, m_name, m_type)):
606 continue
607 if not m_type in member_types:
608 member_types.append(m_type)
609
610 return (members, member_types)
611
612def scalar_funs_instance(out, cls, version, members, member_types):
613 """
614 Generate one instance of scalar set/check functions
615 """
616 out.write("""
617/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700618 * Populate the scalar values in obj of type %(cls)s,
619 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700620 * @param obj Pointer to an object to populate
621 * @param value The seed value to use in populating the object
622 * @returns The value after increments for this object's values
623 */
624int %(cls)s_%(v_name)s_populate_scalars(
625 %(cls)s_t *obj, int value) {
626""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
627 # Declare string types
628 for t in member_types:
629 out.write(" %s %s;\n" % (t, var_name_map(t)))
630 for member in members:
631 m_type = member["m_type"]
632 m_name = member["name"]
633 if (not loxi_utils.type_is_scalar(m_type) or
634 ignore_member(cls, version, m_name, m_type)):
635 continue
636 v_name = var_name_map(m_type);
637 out.write("""
638 VAR_%(u_type)s_INIT(%(v_name)s, value);
639 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
640 value += 1;
641""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
642 out.write("""
643 return value;
644}
645""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700646
Rich Lanea06d0c32013-03-25 08:52:03 -0700647 out.write("""
648/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700649 * Check scalar values in obj of type %(cls)s,
650 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700651 * @param obj Pointer to an object to check
652 * @param value Starting value for checking
653 * @returns The value after increments for this object's values
654 */
655int %(cls)s_%(v_name)s_check_scalars(
656 %(cls)s_t *obj, int value) {
657""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
658
659 for t in member_types:
660 out.write(" %s %s;\n" % (t, var_name_map(t)))
661 for member in members:
662 m_type = member["m_type"]
663 m_name = member["name"]
664 if (not loxi_utils.type_is_scalar(m_type) or
665 ignore_member(cls, version, m_name, m_type)):
666 continue
667 v_name = var_name_map(m_type);
668 out.write("""
669 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
670 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
671 value += 1;
672""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
673
674 out.write("""
675 return value;
676}
677
678""")
679
680def gen_scalar_set_check_funs(out):
681 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700682 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700683 set and check their values
684 """
685 for version in of_g.of_version_range:
686 for cls in of_g.standard_class_order:
687 (members, member_types) = scalar_member_types_get(cls, version)
688 scalar_funs_instance(out, cls, version, members, member_types)
689
690
691# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700692def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700693 base_type = loxi_utils.list_to_entry_type(cls)
694 setup_template = """
695 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700696 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700697 (%(base_type)s_t *)%(inst)s);
698 value = %(subcls)s_%(v_name)s_populate(
699 %(inst)s, value);
700 cur_len += %(inst)s->length;
701 TEST_ASSERT(list->length == cur_len);
702"""
703 out.write("""
704 /* Append two instances of type %s */
705""" % subcls)
706 for i in range(2):
707 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700708 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700709 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700710 version=version))
711
Rich Lane9afc3b92014-04-09 22:55:53 -0700712def check_instance(out, cls, subcls, instance, v_name, version, last):
713 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700714 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
715 value = %(subcls)s_%(v_name)s_check(
716 %(inst)s, value);
717 TEST_ASSERT(value != 0);
718"""
719 out.write("\n /* Check two instances of type %s */" % instance)
720
Andreas Wundsam53256162013-05-02 14:05:53 -0700721 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700722 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700723 inst=instance, subcls=subcls,
724 v_name=loxi_utils.version_to_name(version)))
725 out.write("""\
726 TEST_OK(%(cls)s_next(list, &elt));
727""" % dict(cls=cls))
728
Andreas Wundsam53256162013-05-02 14:05:53 -0700729 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700730 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700731 inst=instance, subcls=subcls,
732 v_name=loxi_utils.version_to_name(version)))
733 if last:
734 out.write("""\
735 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
736""" % dict(cls=cls))
737 else:
738 out.write("""\
739 TEST_OK(%(cls)s_next(list, &elt));
740""" % dict(cls=cls))
741
742def setup_list_fn(out, version, cls):
743 """
744 Generate a helper function that populates a list with two
745 of each type of subclass it supports
746 """
747 out.write("""
748/**
749 * Set up a list of type %(cls)s with two of each type of subclass
750 */
751int
752list_setup_%(cls)s_%(v_name)s(
753 %(cls)s_t *list, int value)
754{
755""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
756 base_type = loxi_utils.list_to_entry_type(cls)
757 out.write("""
758 %(base_type)s_t elt;
759 int cur_len = 0;
760""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700761
Rich Lanea06d0c32013-03-25 08:52:03 -0700762 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700763 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 -0700764 v_name = loxi_utils.version_to_name(version)
765
766 if len(sub_classes) == 0:
767 out.write(" /* No subclasses for %s */\n"% base_type)
768 out.write(" %s_t *elt_p;\n" % base_type)
769 out.write("\n elt_p = &elt;\n")
770 else:
771 out.write(" /* Declare pointers for each subclass */\n")
772 for instance, subcls in sub_classes:
773 out.write(" %s_t *%s;\n" % (subcls, instance))
774 out.write("\n /* Instantiate pointers for each subclass */\n")
775 for instance, subcls in sub_classes:
776 out.write(" %s = &elt.%s;\n" % (instance, instance))
777
778 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700779 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700780 else:
781 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700782 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700783 out.write("""
784
785 return value;
786}
787""")
788
789def check_list_fn(out, version, cls):
790 """
791 Generate a helper function that checks a list populated by above fn
792 """
793 out.write("""
794/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700795 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700796 * list_setup_%(cls)s_%(v_name)s
797 */
798int
799list_check_%(cls)s_%(v_name)s(
800 %(cls)s_t *list, int value)
801{
802""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
803 base_type = loxi_utils.list_to_entry_type(cls)
804 out.write("""
805 %(base_type)s_t elt;
806""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700807
Rich Lanea06d0c32013-03-25 08:52:03 -0700808 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700809 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 -0700810 v_name = loxi_utils.version_to_name(version)
811
812 if len(sub_classes) == 0:
813 out.write(" /* No subclasses for %s */\n"% base_type)
814 out.write(" %s_t *elt_p;\n" % base_type)
815 out.write("\n elt_p = &elt;\n")
816 else:
817 out.write(" /* Declare pointers for each subclass */\n")
818 for instance, subcls in sub_classes:
819 out.write(" %s_t *%s;\n" % (subcls, instance))
820 out.write("\n /* Instantiate pointers for each subclass */\n")
821 for instance, subcls in sub_classes:
822 out.write(" %s = &elt.%s;\n" % (instance, instance))
823
824 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
825 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700826 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700827 else:
828 count = 0
829 for instance, subcls in sub_classes:
830 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700831 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700832 version, count==len(sub_classes))
833
834 out.write("""
835 return value;
836}
837""" % dict(base_type=base_type))
838
839def gen_list_set_check_funs(out):
840 for version in of_g.of_version_range:
841 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700842 if version in of_g.unified[cls]:
843 setup_list_fn(out, version, cls)
844 check_list_fn(out, version, cls)
845
846# Maybe: Get a map from list class to parent, mem_name of container
847
848def list_test(out, version, cls):
849 out.write("""
850static int
851test_%(cls)s_%(v_name)s(void)
852{
853""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
854 base_type = loxi_utils.list_to_entry_type(cls)
855
856 out.write(""" %(cls)s_t *list;
857 int value = 1;
858""" % dict(cls=cls, base_type=base_type))
859
860 out.write("""
861 list = %(cls)s_new(%(v_name)s);
862 TEST_ASSERT(list != NULL);
863 TEST_ASSERT(list->version == %(v_name)s);
864 TEST_ASSERT(list->length == 0);
865 TEST_ASSERT(list->parent == NULL);
866 TEST_ASSERT(list->object_id == %(enum_cls)s);
867
868 value = list_setup_%(cls)s_%(v_name)s(list, value);
869 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700870""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700871 enum_cls=loxi_utils.enum_name(cls)))
872
873 out.write("""
874 /* Now check values */
875 value = 1;
876 value = list_check_%(cls)s_%(v_name)s(list, value);
877 TEST_ASSERT(value != 0);
878""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
879
880 out.write("""
881 %(cls)s_delete(list);
882
883 return TEST_PASS;
884}
885""" % dict(cls=cls))
886
887def gen_list_test(out, name):
888 """
889 Generate base line test cases for lists
890 @param out The file handle to write to
891 """
892
893 loxi_utils.gen_c_copy_license(out)
894 out.write("""
895/**
896 *
897 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
898 *
899 * Message-scalar tests for all versions
900 */
901
902#include <locitest/test_common.h>
903""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700904
Rich Lanea06d0c32013-03-25 08:52:03 -0700905 for version in of_g.of_version_range:
906 v_name = loxi_utils.version_to_name(version)
907 out.write("""
908/**
909 * Baseline list tests for version %s
910 */
911""" % v_name)
912 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700913 if version in of_g.unified[cls]:
914 list_test(out, version, cls)
915
916 out.write("""
917int
918run_list_tests(void)
919{
920""")
921 for version in of_g.of_version_range:
922 v_name = loxi_utils.version_to_name(version)
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 test_name = "%s_%s" % (cls, v_name)
926 out.write(" RUN_TEST(%s);\n" % test_name)
927
928 out.write("\n return TEST_PASS;\n}\n");
929
930def gen_match_test(out, name):
931 """
932 Generate baseline tests for match functions
933 """
934
935 loxi_utils.gen_c_copy_license(out)
936 out.write("""\
937/**
938 *
939 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
940 *
941 * Message-scalar tests for all versions
942 * @fixme These are mostly hard coded now.
943 */
944
945#include <locitest/test_common.h>
946
947static int
948test_match_1(void)
949{
950 of_match_v1_t *m_v1;
951 of_match_v2_t *m_v2;
952 of_match_v3_t *m_v3;
953 of_match_v4_t *m_v4;
954 of_match_t match;
955 int value = 1;
956 int idx;
957 uint32_t exp_value;
958
959 /* Verify default values for ip mask map */
960 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
961 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
962 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
963 if (idx < 32) {
964 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
965 }
966 }
967
968 TEST_ASSERT(of_ip_mask_map_set(17, 0xabcdef00) == OF_ERROR_NONE);
969 TEST_ASSERT(of_ip_mask_to_index(0xabcdef00) == 17);
970 TEST_ASSERT(of_ip_index_to_mask(17) == 0xabcdef00);
971
972 TEST_ASSERT(of_ip_mask_map_set(62, 0xabcdefff) == OF_ERROR_NONE);
973 TEST_ASSERT(of_ip_mask_to_index(0xabcdefff) == 62);
974 TEST_ASSERT(of_ip_index_to_mask(62) == 0xabcdefff);
975
976 /* Test re-init */
977 of_ip_mask_map_init();
978 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
979 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
980 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
981 if (idx < 32) {
982 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
983 }
984 }
985""")
986
987 for version in of_g.of_version_range:
988 out.write("""
989 /* Create/populate/convert and delete for version %(v_name)s */
990 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
991 TEST_ASSERT(m_v%(version)d != NULL);
992 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
993 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
994 of_match_v%(version)d_delete(m_v%(version)d);
995""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
996
997 out.write("""
998 return TEST_PASS;
999}
1000""")
1001
1002 out.write("""
1003static int
1004test_match_2(void)
1005{
1006 of_match_v1_t *m_v1;
1007 of_match_v2_t *m_v2;
1008 of_match_v3_t *m_v3;
1009 of_match_v3_t *m_v4;
1010 of_match_t match1;
1011 of_match_t match2;
1012 int value = 1;
1013""")
1014
1015 for version in of_g.of_version_range:
1016 out.write("""
1017 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1018 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1019 TEST_ASSERT(m_v%(version)d != NULL);
1020 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1021 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1022 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1023 of_match_v%(version)d_delete(m_v%(version)d);
1024""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1025
1026 out.write("""
1027 return TEST_PASS;
1028}
1029""")
1030
1031 out.write("""
1032static int
1033test_match_3(void)
1034{
1035 of_match_t match1;
1036 of_match_t match2;
1037 int value = 1;
1038 of_octets_t octets;
1039""")
1040 for version in of_g.of_version_range:
1041 out.write("""
1042 /* Serialize to version %(v_name)s */
1043 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001044 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001045 OF_ERROR_NONE);
Andreas Wundsam53256162013-05-02 14:05:53 -07001046 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001047 OF_ERROR_NONE);
1048 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1049 FREE(octets.data);
1050""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1051
1052 out.write("""
1053 return TEST_PASS;
1054}
1055""")
1056
1057 out.write("""
1058int run_match_tests(void)
1059{
1060 RUN_TEST(match_1);
1061 RUN_TEST(match_2);
1062 RUN_TEST(match_3);
1063 RUN_TEST(match_utils);
1064
1065 return TEST_PASS;
1066}
1067""")
1068
1069def gen_msg_test(out, name):
1070 loxi_utils.gen_c_copy_license(out)
1071 out.write("""
1072/**
1073 *
1074 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1075 *
1076 * Message-scalar tests for all versions
1077 */
1078
1079#include <locitest/test_common.h>
1080""")
1081 for version in of_g.of_version_range:
1082 for cls in of_g.ordered_messages:
1083 if not (cls, version) in of_g.base_length:
1084 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001085 if type_maps.class_is_virtual(cls):
1086 continue
Rich Lanef70be942013-07-18 13:33:14 -07001087 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001088 out.write("""
1089static int
1090test_%(cls)s_create_%(v_name)s(void)
1091{
1092 %(cls)s_t *obj;
1093 uint8_t *msg_buf;
1094 int value;
1095 int len;
Rich Lanea4b68302014-03-12 15:17:58 -07001096 of_object_id_t object_id;
Rich Lanea06d0c32013-03-25 08:52:03 -07001097
1098 obj = %(cls)s_new(%(v_name)s);
1099 TEST_ASSERT(obj != NULL);
1100 TEST_ASSERT(obj->version == %(v_name)s);
1101 TEST_ASSERT(obj->length == %(bytes)d);
1102 TEST_ASSERT(obj->parent == NULL);
1103 TEST_ASSERT(obj->object_id == %(enum)s);
1104
Rich Lanea4b68302014-03-12 15:17:58 -07001105 of_header_wire_object_id_get(obj, &object_id);
1106 TEST_ASSERT(object_id == %(enum)s);
1107
Rich Lanea06d0c32013-03-25 08:52:03 -07001108 /* Set up incrementing values for scalar members */
1109 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1110 TEST_ASSERT(value != 0);
1111
1112 /* Grab the underlying buffer from the message */
1113 len = obj->length;
1114 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1115 TEST_ASSERT(msg_buf != NULL);
1116 %(cls)s_delete(obj);
1117 /* TODO: */
1118 TEST_ASSERT(of_message_to_object_id(msg_buf, len) == %(enum)s);
1119 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1120
1121 TEST_ASSERT(obj != NULL);
1122
1123 /* @fixme Set up all message objects (recursively?) */
1124
1125 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1126 TEST_ASSERT(value != 0);
1127
1128 %(cls)s_delete(obj);
1129
1130 return TEST_PASS;
1131}
1132""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1133 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1134
1135 out.write("""
1136int
1137run_message_tests(void)
1138{
1139""")
1140 for version in of_g.of_version_range:
1141 for cls in of_g.ordered_messages:
1142 if not (cls, version) in of_g.base_length:
1143 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001144 if type_maps.class_is_virtual(cls):
1145 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001146 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1147 out.write(" RUN_TEST(%s);\n" % test_name)
1148
1149 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001150
Rich Lanea06d0c32013-03-25 08:52:03 -07001151
1152def gen_list_setup_check(out, cls, version):
1153 """
1154 Generate functions that populate and check a list with two
1155 of each type of subclass it supports
1156 """
1157 out.write("""
1158/**
1159 * Populate a list of type %(cls)s with two of each type of subclass
1160 * @param list Pointer to the list to be populated
1161 * @param value The seed value to use in populating the list
1162 * @returns The value after increments for this object's values
1163 */
1164int
1165%(cls)s_%(v_name)s_populate(
1166 %(cls)s_t *list, int value)
1167{
1168""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1169 base_type = loxi_utils.list_to_entry_type(cls)
1170 out.write("""
1171 %(base_type)s_t elt;
1172 int cur_len = 0;
1173""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001174
Rich Lanea06d0c32013-03-25 08:52:03 -07001175 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001176 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 -07001177 v_name = loxi_utils.version_to_name(version)
1178
1179 if len(sub_classes) == 0:
1180 out.write(" /* No subclasses for %s */\n"% base_type)
1181 out.write(" %s_t *elt_p;\n" % base_type)
1182 out.write("\n elt_p = &elt;\n")
1183 else:
1184 out.write(" /* Declare pointers for each subclass */\n")
1185 for instance, subcls in sub_classes:
1186 out.write(" %s_t *%s;\n" % (subcls, instance))
1187 out.write("\n /* Instantiate pointers for each subclass */\n")
1188 for instance, subcls in sub_classes:
1189 out.write(" %s = &elt.%s;\n" % (instance, instance))
1190
Rich Lanea06d0c32013-03-25 08:52:03 -07001191 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001192 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001193 else:
1194 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001195 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001196 out.write("""
1197 return value;
1198}
1199""")
1200 out.write("""
1201/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001202 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001203 * %(cls)s_%(v_name)s_populate
1204 * @param list Pointer to the list that was populated
1205 * @param value Starting value for checking
1206 * @returns The value after increments for this object's values
1207 */
1208int
1209%(cls)s_%(v_name)s_check(
1210 %(cls)s_t *list, int value)
1211{
1212""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1213 base_type = loxi_utils.list_to_entry_type(cls)
1214 out.write("""
1215 %(base_type)s_t elt;
1216 int count = 0;
1217 int rv;
1218""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001219
Rich Lanea06d0c32013-03-25 08:52:03 -07001220
1221 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001222 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 -07001223 v_name = loxi_utils.version_to_name(version)
1224
1225 if len(sub_classes) == 0:
1226 entry_count = 2
1227 out.write(" /* No subclasses for %s */\n"% base_type)
1228 out.write(" %s_t *elt_p;\n" % base_type)
1229 out.write("\n elt_p = &elt;\n")
1230 else:
1231 entry_count = 2 * len(sub_classes) # Two of each type appended
1232 out.write(" /* Declare pointers for each subclass */\n")
1233 for instance, subcls in sub_classes:
1234 out.write(" %s_t *%s;\n" % (subcls, instance))
1235 out.write("\n /* Instantiate pointers for each subclass */\n")
1236 for instance, subcls in sub_classes:
1237 out.write(" %s = &elt.%s;\n" % (instance, instance))
1238
1239 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1240 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001241 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001242 version, True)
1243 else:
1244 count = 0
1245 for instance, subcls in sub_classes:
1246 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001247 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001248 version, count==len(sub_classes))
1249 out.write("""
1250""" % dict(base_type=base_type))
1251
1252 out.write("""
1253 /* Do an iterate to test the iterator */
1254 %(u_cls)s_ITER(list, &elt, rv) {
1255 count += 1;
1256 }
1257
1258 TEST_ASSERT(rv == OF_ERROR_RANGE);
1259 TEST_ASSERT(count == %(entry_count)d);
1260
1261 /* We shoehorn a test of the dup functions here */
1262 {
1263 %(cls)s_t *dup;
1264
1265 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1266 TEST_ASSERT(dup->length == list->length);
1267 TEST_ASSERT(dup->object_id == list->object_id);
1268 TEST_ASSERT(dup->version == list->version);
1269 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1270 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1271 of_object_delete((of_object_t *)dup);
1272
1273 /* And now for the generic dup function */
1274 TEST_ASSERT((dup = (%(cls)s_t *)
1275 of_object_dup(list)) != NULL);
1276 TEST_ASSERT(dup->length == list->length);
1277 TEST_ASSERT(dup->object_id == list->object_id);
1278 TEST_ASSERT(dup->version == list->version);
1279 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1280 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1281 of_object_delete((of_object_t *)dup);
1282 }
1283
1284 return value;
1285}
1286""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1287
1288
1289def gen_class_setup_check(out, cls, version):
1290 out.write("""
1291/**
1292 * Populate all members of an object of type %(cls)s
1293 * with incrementing values
1294 * @param obj Pointer to an object to populate
1295 * @param value The seed value to use in populating the object
1296 * @returns The value after increments for this object's values
1297 */
1298
1299int
1300%(cls)s_%(v_name)s_populate(
1301 %(cls)s_t *obj, int value)
1302{
1303""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1304 members, member_types = loxi_utils.all_member_types_get(cls, version)
1305 for m_type in member_types:
1306 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1307 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1308 else:
1309 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1310 out.write("""
1311 /* Run thru accessors after new to ensure okay */
1312""")
1313 for member in members:
1314 m_type = member["m_type"]
1315 m_name = member["name"]
1316 if loxi_utils.skip_member_name(m_name):
1317 continue
1318 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1319 out.write("""\
1320 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1321""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1322 else:
1323 sub_cls = m_type[:-2] # Trim _t
1324 out.write("""\
1325 {
1326 %(sub_cls)s_t sub_cls;
1327
1328 /* Test bind */
1329 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1330 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001331""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001332 m_name=m_name, sub_cls=sub_cls,
1333 v_name=loxi_utils.version_to_name(version)))
1334
1335 out.write("""
1336 value = %(cls)s_%(v_name)s_populate_scalars(
1337 obj, value);
1338 TEST_ASSERT(value != 0);
1339""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1340
1341 for member in members:
1342 m_type = member["m_type"]
1343 m_name = member["name"]
1344 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1345 continue
1346 if loxi_utils.skip_member_name(m_name):
1347 continue
1348 if m_type == "of_match_t":
1349 out.write("""\
1350 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1351 TEST_ASSERT(value != 0);
1352 %(cls)s_%(m_name)s_set(
1353 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001354""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001355 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1356 elif m_type == "of_octets_t":
1357 out.write("""\
1358 value = of_octets_populate(&%(var_name)s, value);
1359 TEST_ASSERT(value != 0);
1360 %(cls)s_%(m_name)s_set(
1361 obj, &%(var_name)s);
1362 if (octets.bytes) {
1363 FREE(octets.data);
1364 }
1365""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1366 else:
1367 sub_cls = m_type[:-2] # Trim _t
1368 out.write("""
1369 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1370 TEST_ASSERT(%(var_name)s != NULL);
1371 value = %(sub_cls)s_%(v_name)s_populate(
1372 %(var_name)s, value);
1373 TEST_ASSERT(value != 0);
1374 %(cls)s_%(m_name)s_set(
1375 obj, %(var_name)s);
1376 %(sub_cls)s_delete(%(var_name)s);
1377""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1378 var_name=var_name_map(m_type),
1379 v_name=loxi_utils.version_to_name(version)))
1380
1381 out.write("""
1382 return value;
1383}
1384""")
1385
1386 out.write("""
1387/**
1388 * Check all members of an object of type %(cls)s
1389 * populated by the above function
1390 * @param obj Pointer to an object to check
1391 * @param value Starting value for checking
1392 * @returns The value after increments for this object's values
1393 */
1394
1395int
1396%(cls)s_%(v_name)s_check(
1397 %(cls)s_t *obj, int value)
1398{
1399""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1400 members, member_types = loxi_utils.all_member_types_get(cls, version)
1401 for m_type in member_types:
1402 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1403 continue
1404 if loxi_utils.type_is_of_object(m_type):
1405 continue
1406 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1407 out.write("""
1408 value = %(cls)s_%(v_name)s_check_scalars(
1409 obj, value);
1410 TEST_ASSERT(value != 0);
1411""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1412
1413 for member in members:
1414 m_type = member["m_type"]
1415 m_name = member["name"]
1416 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1417 continue
1418 if loxi_utils.skip_member_name(m_name):
1419 continue
1420 if m_type == "of_match_t":
1421 out.write("""\
1422 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1423 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1424""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1425 v_name=loxi_utils.version_to_name(version)))
1426 elif m_type == "of_octets_t":
1427 out.write("""\
1428 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1429 value = of_octets_check(&%(var_name)s, value);
1430""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1431 v_name=loxi_utils.version_to_name(version)))
1432 else:
1433 sub_cls = m_type[:-2] # Trim _t
1434 out.write("""
1435 { /* Use get/delete to access on check */
1436 %(m_type)s *%(m_name)s_ptr;
1437
1438 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1439 TEST_ASSERT(%(m_name)s_ptr != NULL);
1440 value = %(sub_cls)s_%(v_name)s_check(
1441 %(m_name)s_ptr, value);
1442 TEST_ASSERT(value != 0);
1443 %(sub_cls)s_delete(%(m_name)s_ptr);
1444 }
1445""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1446 var_name=var_name_map(m_type),
1447 v_name=loxi_utils.version_to_name(version)))
1448
1449 out.write("""
1450 /* We shoehorn a test of the dup functions here */
1451 {
1452 %(cls)s_t *dup;
1453
1454 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1455 TEST_ASSERT(dup->length == obj->length);
1456 TEST_ASSERT(dup->object_id == obj->object_id);
1457 TEST_ASSERT(dup->version == obj->version);
1458 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1459 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1460 of_object_delete((of_object_t *)dup);
1461
1462 /* And now for the generic dup function */
1463 TEST_ASSERT((dup = (%(cls)s_t *)
1464 of_object_dup(obj)) != NULL);
1465 TEST_ASSERT(dup->length == obj->length);
1466 TEST_ASSERT(dup->object_id == obj->object_id);
1467 TEST_ASSERT(dup->version == obj->version);
1468 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1469 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1470 of_object_delete((of_object_t *)dup);
1471 }
1472
1473 return value;
1474}
1475""" % dict(cls=cls))
1476
1477def unified_accessor_test_case(out, cls, version):
1478 """
1479 Generate one test case for the given version and class
1480 """
1481
1482 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001483 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001484 v_name = loxi_utils.version_to_name(version)
1485
1486 out.write("""
1487static int
1488test_%(cls)s_%(v_name)s(void)
1489{
1490 %(cls)s_t *obj;
1491 obj = %(cls)s_new(%(v_name)s);
1492 TEST_ASSERT(obj != NULL);
1493 TEST_ASSERT(obj->version == %(v_name)s);
1494 TEST_ASSERT(obj->length == %(length)d);
1495 TEST_ASSERT(obj->parent == NULL);
1496 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001497""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001498 v_name=v_name, length=length, version=version))
1499 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1500 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001501 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001502 int length;
1503
Rich Lanedc46fe22014-04-03 15:10:38 -07001504 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001505 TEST_ASSERT(length == %(length)d);
1506 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001507 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001508 of_object_id_t obj_id;
1509
Rich Lanedc46fe22014-04-03 15:10:38 -07001510 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001511 TEST_ASSERT(obj_id == %(u_cls)s);
1512 }
1513
1514 /* Set up incrementing values for members */
1515 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1516 obj, 1) != 0);
1517
1518 /* Check values just set */
1519 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1520 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001521""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001522 v_name=v_name, length=length, version=version))
1523
1524 out.write("""
1525 %(cls)s_delete(obj);
1526
1527 /* To do: Check memory */
1528 return TEST_PASS;
1529}
1530""" % dict(cls=cls))
1531
1532
1533def gen_unified_accessor_funs(out):
1534 for version in of_g.of_version_range:
1535 for cls in of_g.standard_class_order:
1536 if not loxi_utils.class_in_version(cls, version):
1537 continue
1538 if cls in type_maps.inheritance_map:
1539 continue
1540 elif loxi_utils.class_is_list(cls):
1541 gen_list_setup_check(out, cls, version)
1542 else:
1543 gen_class_setup_check(out, cls, version)
1544
1545def gen_unified_accessor_tests(out, name):
1546 loxi_utils.gen_c_copy_license(out)
1547 out.write("""
1548/**
1549 *
1550 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1551 *
1552 * Unified simple class instantiation tests for all versions
1553 */
1554
1555#include <locitest/test_common.h>
1556""")
1557 for version in of_g.of_version_range:
1558 for cls in of_g.standard_class_order:
1559 if not loxi_utils.class_in_version(cls, version):
1560 continue
1561 if cls in type_maps.inheritance_map:
1562 continue
1563 unified_accessor_test_case(out, cls, version)
1564
1565 out.write("""
1566int
1567run_unified_accessor_tests(void)
1568{
1569""")
1570 for version in of_g.of_version_range:
1571 v_name = loxi_utils.version_to_name(version)
1572 for cls in of_g.standard_class_order:
1573 if not loxi_utils.class_in_version(cls, version):
1574 continue
1575 if cls in type_maps.inheritance_map:
1576 continue
1577 test_name = "%s_%s" % (cls, v_name)
1578 out.write(" RUN_TEST(%s);\n" % test_name)
1579
1580 out.write(" return TEST_PASS;\n}\n");
1581
1582
1583
1584################################################################
1585#
1586# Object duplication functions
1587#
1588# These exercise the accessors to create duplicate objects.
1589# They are used in the LOCI test shim which sits in an OF
1590# protocol stream.
1591#
1592# TODO
1593# Resolve version stuff
1594# Complete list dup
1595
1596def gen_dup_list(out, cls, version):
1597 ver_name = loxi_utils.version_to_name(version)
1598 elt_type = loxi_utils.list_to_entry_type(cls)
1599 out.write("""
1600/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001601 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001602 * using accessor functions
1603 * @param src Pointer to object to be duplicated
1604 * @returns A new object of type %(cls)s.
1605 *
1606 * The caller is responsible for deleting the returned value
1607 */
1608%(cls)s_t *
1609%(cls)s_%(ver_name)s_dup(
1610 %(cls)s_t *src)
1611{
1612 %(elt_type)s_t src_elt;
1613 %(elt_type)s_t *dst_elt;
1614 int rv;
1615 %(cls)s_t *dst;
1616
1617 if ((dst = %(cls)s_new(src->version)) == NULL) {
1618 return NULL;
1619 }
1620""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1621
1622 out.write("""
1623 %(u_cls)s_ITER(src, &src_elt, rv) {
1624 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1625 of_object_delete((of_object_t *)dst);
1626 return NULL;
1627 }
1628 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1629 dst, NULL);
1630 of_object_delete((of_object_t *)dst_elt);
1631 }
1632
1633 return dst;
1634}
1635""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1636
1637
1638def gen_dup_inheritance(out, cls, version):
1639 ver_name = loxi_utils.version_to_name(version)
1640 out.write("""
1641/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001642 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001643 * @param src Pointer to object to be duplicated
1644 * @returns A new object of type %(cls)s.
1645 *
1646 * The caller is responsible for deleting the returned value
1647 */
1648%(cls)s_t *
1649%(cls)s_%(ver_name)s_dup(
1650 %(cls)s_t *src)
1651{
1652""" % dict(cls=cls, ver_name=ver_name))
1653
1654 # For each subclass, check if this is an instance of that subclass
1655 version_classes = type_maps.inheritance_data[cls][version]
1656 for sub_cls in version_classes:
1657 sub_enum = (cls + "_" + sub_cls).upper()
1658 out.write("""
1659 if (src->header.object_id == %(sub_enum)s) {
1660 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1661 &src->%(sub_cls)s);
1662 }
1663""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1664
1665 out.write("""
1666 return NULL;
1667}
1668""")
1669
1670
1671def gen_dup_cls(out, cls, version):
1672 """
1673 Generate duplication routine for class cls
1674 """
1675 ver_name = loxi_utils.version_to_name(version)
1676
1677 out.write("""
1678/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001679 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001680 * using accessor functions
1681 * @param src Pointer to object to be duplicated
1682 * @returns A new object of type %(cls)s.
1683 *
1684 * The caller is responsible for deleting the returned value
1685 */
1686%(cls)s_t *
1687%(cls)s_%(ver_name)s_dup(
1688 %(cls)s_t *src)
1689{
1690 %(cls)s_t *dst;
1691""" % dict(cls=cls, ver_name=ver_name))
1692
1693 # Get members and types for the class
1694 members, member_types = loxi_utils.all_member_types_get(cls, version)
1695
1696 # Add declarations for each member type
1697 for m_type in member_types:
1698 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1699 # Declare instance of these
1700 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1701 else:
1702 out.write("""
1703 %(m_type)s src_%(v_name)s;
1704 %(m_type)s *dst_%(v_name)s;
1705""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1706
1707 out.write("""
1708 if ((dst = %(cls)s_new(src->version)) == NULL) {
1709 return NULL;
1710 }
1711""" % dict(cls=cls))
1712
1713 for member in members:
1714 m_type = member["m_type"]
1715 m_name = member["name"]
1716 if loxi_utils.skip_member_name(m_name):
1717 continue
1718 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1719 out.write("""
1720 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1721 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1722""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1723 elif m_type in ["of_match_t", "of_octets_t"]:
1724 out.write("""
1725 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1726 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1727""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1728 else:
1729 sub_cls = m_type[:-2] # Trim _t
1730 out.write("""
1731 %(cls)s_%(m_name)s_bind(
1732 src, &src_%(v_name)s);
1733 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1734 if (dst_%(v_name)s == NULL) {
1735 %(cls)s_delete(dst);
1736 return NULL;
1737 }
1738 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1739 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001740""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001741 v_name=var_name_map(m_type), ver_name=ver_name))
1742
1743 out.write("""
1744 return dst;
1745}
1746""")
1747
1748def gen_version_dup(out=sys.stdout):
1749 """
1750 Generate duplication routines for each object type
1751 """
1752 out.write("""
1753/* Special try macro for duplicating */
1754#define _TRY_FREE(op, obj, rv) do { \\
1755 int _rv; \\
1756 if ((_rv = (op)) < 0) { \\
1757 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1758 of_object_delete((of_object_t *)(obj)); \\
1759 return (rv); \\
1760 } \\
1761 } while (0)
1762""")
1763
1764 for version in of_g.of_version_range:
1765 for cls in of_g.standard_class_order:
1766 if not loxi_utils.class_in_version(cls, version):
1767 continue
1768 if cls in type_maps.inheritance_map:
1769 gen_dup_inheritance(out, cls, version)
1770 elif loxi_utils.class_is_list(cls):
1771 gen_dup_list(out, cls, version)
1772 else:
1773 gen_dup_cls(out, cls, version)
1774
1775def gen_dup(out=sys.stdout):
1776 """
1777 Generate non-version specific duplication routines for each object type
1778 """
1779
1780 for cls in of_g.standard_class_order:
1781 out.write("""
1782%(cls)s_t *
1783%(cls)s_dup(
1784 %(cls)s_t *src)
1785{
1786""" % dict(cls=cls))
1787 for version in of_g.of_version_range:
1788 if not loxi_utils.class_in_version(cls, version):
1789 continue
1790 hdr = "header." if cls in type_maps.inheritance_map else ""
1791
1792 ver_name = loxi_utils.version_to_name(version)
1793 out.write("""
1794 if (src->%(hdr)sversion == %(ver_name)s) {
1795 return %(cls)s_%(ver_name)s_dup(src);
1796 }
1797""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1798
1799 out.write("""
1800 /* Class not supported in given version */
1801 return NULL;
1802}
1803""")
1804
1805def dup_c_gen(out, name):
1806 """
1807 Generate the C file for duplication functions
1808 """
1809 loxi_utils.gen_c_copy_license(out)
1810 out.write("""\
1811/*
1812 * Duplication functions for all OF objects
1813 *
1814 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1815 *
1816 * These are test functions for exercising accessors. You can call
1817 * of_object_dup for an efficient duplication.
1818 */
1819
1820#define DISABLE_WARN_UNUSED_RESULT
1821#include "loci_log.h"
1822#include <locitest/of_dup.h>
1823
1824""")
1825
1826 gen_version_dup(out)
1827 gen_dup(out)
1828
1829
1830def dup_h_gen(out, name):
1831 """
1832 Generate the header file for duplication functions
1833 """
1834
1835 loxi_utils.gen_c_copy_license(out)
1836 out.write("""
1837/*
1838 * Duplication function header file
1839 *
1840 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1841 */
1842
1843#if !defined(_OF_DUP_H_)
1844#define _OF_DUP_H_
1845
1846#include <loci/loci.h>
1847""")
1848
1849 for cls in of_g.standard_class_order:
1850 out.write("""
1851extern %(cls)s_t *
1852 %(cls)s_dup(
1853 %(cls)s_t *src);
1854""" % dict(cls=cls))
1855
1856 for version in of_g.of_version_range:
1857 for cls in of_g.standard_class_order:
1858 if not loxi_utils.class_in_version(cls, version):
1859 continue
1860 ver_name = loxi_utils.version_to_name(version)
1861 out.write("""
1862extern %(cls)s_t *
1863 %(cls)s_%(ver_name)s_dup(
1864 %(cls)s_t *src);
1865""" % dict(cls=cls, ver_name=ver_name))
1866
1867 out.write("\n#endif /* _OF_DUP_H_ */\n")
1868
1869def gen_log_test(out):
1870 """
1871 Generate test for obj log calls
1872
1873 Define a trivial handler for object logging; call all obj log fns
1874 """
1875 out.write("""
1876
1877/**
1878 * Test object dump functions
1879 */
1880
1881int
1882test_dump_objs(void)
1883{
1884 of_object_t *obj;
1885
1886 FILE *out = fopen("/dev/null", "w");
1887
1888 /* Call each obj dump function */
1889""")
1890 for version in of_g.of_version_range:
1891 for j, cls in enumerate(of_g.all_class_order):
1892 if not loxi_utils.class_in_version(cls, version):
1893 continue
1894 if cls in type_maps.inheritance_map:
1895 continue
1896 out.write("""
1897 obj = (of_object_t *)%(cls)s_new(%(version)s);
1898 of_object_dump((loci_writer_f)fprintf, out, obj);
1899 of_object_delete(obj);
1900""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001901
Rich Lanea06d0c32013-03-25 08:52:03 -07001902 out.write("""
1903 fclose(out);
1904 return TEST_PASS;
1905}
1906""")
1907
1908def gen_ident_tests(out):
1909 """
1910 Generate tests for identifiers
1911
1912 For all idents, instantiate, test version supported macros
1913 For flags, set it, test it, clear it, test it.
1914 """
1915 out.write("""
1916/**
1917 * Test cases for all flag accessor macros
1918 * These only test self consistency (and that they compile)
1919 */
1920int
1921test_ident_macros(void)
1922{
1923 int value __attribute__((unused));
1924 uint32_t flags;
1925
1926""")
1927
1928 for ident, info in of_g.identifiers.items():
1929 if not identifiers.defined_versions_agree(of_g.identifiers,
1930 of_g.target_version_list,
1931 ident):
1932 # @fixme
1933 continue
1934 out.write(" value = %s;\n" % ident)
1935 for version in of_g.target_version_list:
1936 if version in info["values_by_version"].keys():
1937 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1938 (ident, of_g.of_version_wire2name[version]))
1939 else:
1940 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1941 (ident, of_g.of_version_wire2name[version]))
1942 if flags.ident_is_flag(ident):
1943 # Grab first supported version
1944 for version in info["values_by_version"]:
1945 break
1946 out.write("""
1947 flags = 0;
1948 %(ident)s_SET(flags, %(ver_name)s);
1949 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1950 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1951 %(ident)s_CLEAR(flags, %(ver_name)s);
1952 TEST_ASSERT(flags == 0);
1953 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1954""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1955
1956 out.write("""
1957 return TEST_PASS;
1958}
1959""")
1960
Rich Laneccae0312013-07-21 23:34:13 -07001961def gen_datafiles_tests(out, name):
1962 tests = []
1963 for filename in test_data.list_files():
1964 data = test_data.read(filename)
1965 if not 'c' in data:
1966 continue
1967 name = filename[:-5].replace("/", "_")
1968 tests.append(dict(name=name,
1969 filename=filename,
1970 c=data['c'],
1971 binary=data['binary']))
1972
1973 util.render_template(out, "test_data.c", tests=tests)