blob: a0cdca134b80d0d991bfe41e81be9b55fe621224 [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);
352extern int run_setup_from_add_tests(void);
353
354extern int run_validator_tests(void);
355
356extern int run_list_limits_tests(void);
357
358extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700359extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700360
361""")
362
363 for version in of_g.of_version_range:
364 for cls in of_g.standard_class_order:
365 if not loxi_utils.class_in_version(cls, version):
366 continue
367 if cls in type_maps.inheritance_map:
368 continue
369 out.write("""
370extern int %(cls)s_%(v_name)s_populate(
371 %(cls)s_t *obj, int value);
372extern int %(cls)s_%(v_name)s_check(
373 %(cls)s_t *obj, int value);
374extern int %(cls)s_%(v_name)s_populate_scalars(
375 %(cls)s_t *obj, int value);
376extern int %(cls)s_%(v_name)s_check_scalars(
377 %(cls)s_t *obj, int value);
378""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
379
380 out.write("""
381/*
382 * Declarations for list population and check primitives
383 */
384""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700385
Rich Lanea06d0c32013-03-25 08:52:03 -0700386 for version in of_g.of_version_range:
387 for cls in of_g.ordered_list_objects:
388 if cls in type_maps.inheritance_map:
389 continue
390
391 if version in of_g.unified[cls]:
392 out.write("""
393extern int
394 list_setup_%(cls)s_%(v_name)s(
395 %(cls)s_t *list, int value);
396extern int
397 list_check_%(cls)s_%(v_name)s(
398 %(cls)s_t *list, int value);
399""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
400
401 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
402
403def gen_common_test(out, name):
404 """
405 Generate common test content including main
406 """
407 loxi_utils.gen_c_copy_license(out)
408 out.write("""
409/*
410 * Common test code for LOCI
411 *
412 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
413 */
414
415#define DISABLE_WARN_UNUSED_RESULT
416#include "loci_log.h"
417#include <loci/loci_obj_dump.h>
418#include <locitest/unittest.h>
419#include <locitest/test_common.h>
420
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900421/* mcheck is a glibc extension */
422#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700423#include <mcheck.h>
424#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900425#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700426#define MCHECK_INIT do { } while (0)
427#endif
428
429/**
430 * Exit on error if set to 1
431 */
432int exit_on_error = 1;
433
434/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700435 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700436 */
437int global_error = 0;
438
439extern int run_unified_accessor_tests(void);
440extern int run_match_tests(void);
441extern int run_utility_tests(void);
442
443extern int run_scalar_acc_tests(void);
444extern int run_list_tests(void);
445extern int run_message_tests(void);
446
447/**
448 * Macros for initializing and checking scalar types
449 *
450 * @param var The variable being initialized or checked
451 * @param val The integer value to set/check against, see below
452 *
453 * Note that equality means something special for strings. Each byte
454 * is initialized to an incrementing value. So check is done against that.
455 *
456 */
457
458""")
459 for t in scalar_types:
460 if t in integer_types:
461 out.write("""
462#define VAR_%s_INIT(var, val) var = (%s)(val)
463#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
464""" % (t.upper(), t, t.upper(), t))
465 else:
466 out.write("""
467#define VAR_%s_INIT(var, val) \\
468 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
469#define VAR_%s_CHECK(var, val) \\
470 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
471""" % (t.upper(), t.upper()))
472
473 gen_fill_string(out)
474 gen_scalar_set_check_funs(out)
475 gen_list_set_check_funs(out)
476 gen_unified_accessor_funs(out)
477
478 gen_ident_tests(out)
479 gen_log_test(out)
480
481def gen_message_scalar_test(out, name):
482 """
483 Generate test cases for message objects, scalar accessors
484 """
485
486 loxi_utils.gen_c_copy_license(out)
487 out.write("""
488/**
489 *
490 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
491 *
492 * Message-scalar tests for all versions
493 */
494
495#include <locitest/test_common.h>
496""")
497 for version in of_g.of_version_range:
498 v_name = loxi_utils.version_to_name(version)
499 out.write("""
500/**
501 * Message-scalar tests for version %s
502 */
503""" % v_name)
504 for cls in of_g.standard_class_order:
505 if cls in type_maps.inheritance_map:
506 continue
507 if version in of_g.unified[cls]:
508 message_scalar_test(out, version, cls)
509
510 out.write("""
511int
512run_scalar_acc_tests(void)
513{
514""")
515 for version in of_g.of_version_range:
516 v_name = loxi_utils.version_to_name(version)
517 for cls in of_g.standard_class_order:
518 if cls in type_maps.inheritance_map:
519 continue
520 if version in of_g.unified[cls]:
521 test_name = "%s_%s" % (cls, v_name)
522 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
523
524 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700525
Rich Lanea06d0c32013-03-25 08:52:03 -0700526def message_scalar_test(out, version, cls):
527 """
528 Generate one test case for the given version and class
529 """
530
531 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700532 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700533 v_name = loxi_utils.version_to_name(version)
534
535 out.write("""
536static int
537test_%(cls)s_%(v_name)s_scalar(void)
538{
539 %(cls)s_t *obj;
540
541 obj = %(cls)s_new(%(v_name)s);
542 TEST_ASSERT(obj != NULL);
543 TEST_ASSERT(obj->version == %(v_name)s);
544 TEST_ASSERT(obj->length == %(length)d);
545 TEST_ASSERT(obj->parent == NULL);
546 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700547""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700548 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700549
550 # If this class is a concrete member of an inheritance hierarchy,
551 # run the hierarchy's root wire type parser and assert it returns
552 # the expected object id.
553 ofclass = loxi_globals.unified.class_by_name(cls)
554 if ofclass and not ofclass.virtual:
555 root = ofclass
556 while root.superclass:
557 root = root.superclass
558 if root.virtual:
559 out.write("""
560 {
561 of_object_id_t object_id;
562 %(root_cls)s_wire_object_id_get(obj, &object_id);
563 TEST_ASSERT(object_id == %(u_cls)s);
564 }
565""" % dict(root_cls=root.name, u_cls=cls.upper()))
566
Rich Lanea06d0c32013-03-25 08:52:03 -0700567 if not type_maps.class_is_virtual(cls):
568 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700569 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700570 int length;
571
Rich Lanedc46fe22014-04-03 15:10:38 -0700572 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700573 TEST_ASSERT(length == %(length)d);
574 }
575
576 /* Set up incrementing values for scalar members */
577 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
578
579 /* Check values just set */
580 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700581""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700582 v_name=v_name, length=length, version=version))
583
584 out.write("""
585 %(cls)s_delete(obj);
586
587 /* To do: Check memory */
588 return TEST_PASS;
589}
590""" % dict(cls=cls))
591
592# Get the members and list of scalar types for members of a given class
593def scalar_member_types_get(cls, version):
594 member_types = []
595
596 if not version in of_g.unified[cls]:
597 return ([], [])
598
599 if "use_version" in of_g.unified[cls][version]:
600 v = of_g.unified[cls][version]["use_version"]
601 members = of_g.unified[cls][v]["members"]
602 else:
603 members = of_g.unified[cls][version]["members"]
604 # Accumulate variables that are supported
605 for member in members:
606 m_type = member["m_type"]
607 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700608 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700609 ignore_member(cls, version, m_name, m_type)):
610 continue
611 if not m_type in member_types:
612 member_types.append(m_type)
613
614 return (members, member_types)
615
616def scalar_funs_instance(out, cls, version, members, member_types):
617 """
618 Generate one instance of scalar set/check functions
619 """
620 out.write("""
621/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700622 * Populate the scalar values in obj of type %(cls)s,
623 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700624 * @param obj Pointer to an object to populate
625 * @param value The seed value to use in populating the object
626 * @returns The value after increments for this object's values
627 */
628int %(cls)s_%(v_name)s_populate_scalars(
629 %(cls)s_t *obj, int value) {
630""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
631 # Declare string types
632 for t in member_types:
633 out.write(" %s %s;\n" % (t, var_name_map(t)))
634 for member in members:
635 m_type = member["m_type"]
636 m_name = member["name"]
637 if (not loxi_utils.type_is_scalar(m_type) or
638 ignore_member(cls, version, m_name, m_type)):
639 continue
640 v_name = var_name_map(m_type);
641 out.write("""
642 VAR_%(u_type)s_INIT(%(v_name)s, value);
643 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
644 value += 1;
645""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
646 out.write("""
647 return value;
648}
649""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700650
Rich Lanea06d0c32013-03-25 08:52:03 -0700651 out.write("""
652/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700653 * Check scalar values in obj of type %(cls)s,
654 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700655 * @param obj Pointer to an object to check
656 * @param value Starting value for checking
657 * @returns The value after increments for this object's values
658 */
659int %(cls)s_%(v_name)s_check_scalars(
660 %(cls)s_t *obj, int value) {
661""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
662
663 for t in member_types:
664 out.write(" %s %s;\n" % (t, var_name_map(t)))
665 for member in members:
666 m_type = member["m_type"]
667 m_name = member["name"]
668 if (not loxi_utils.type_is_scalar(m_type) or
669 ignore_member(cls, version, m_name, m_type)):
670 continue
671 v_name = var_name_map(m_type);
672 out.write("""
673 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
674 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
675 value += 1;
676""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
677
678 out.write("""
679 return value;
680}
681
682""")
683
684def gen_scalar_set_check_funs(out):
685 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700686 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700687 set and check their values
688 """
689 for version in of_g.of_version_range:
690 for cls in of_g.standard_class_order:
691 (members, member_types) = scalar_member_types_get(cls, version)
692 scalar_funs_instance(out, cls, version, members, member_types)
693
694
695# Helper function to set up a subclass instance for a test
696def setup_instance(out, cls, subcls, instance, v_name, inst_len, version):
697 base_type = loxi_utils.list_to_entry_type(cls)
698 setup_template = """
699 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700700 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700701 (%(base_type)s_t *)%(inst)s);
702 value = %(subcls)s_%(v_name)s_populate(
703 %(inst)s, value);
704 cur_len += %(inst)s->length;
705 TEST_ASSERT(list->length == cur_len);
706"""
707 out.write("""
708 /* Append two instances of type %s */
709""" % subcls)
710 for i in range(2):
711 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700712 dict(inst=instance, subcls=subcls, v_name=v_name,
713 base_type=base_type, cls=cls, inst_len=inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -0700714 version=version))
715
716def check_instance(out, cls, subcls, instance, v_name, inst_len, version, last):
717 check_template = ""
718 if inst_len >= 0:
719 check_template = """
720 TEST_ASSERT(%(inst)s->length == %(inst_len)d);
Rich Lanedc46fe22014-04-03 15:10:38 -0700721 if (loci_class_metadata[%(inst)s->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700722 int length;
723
Rich Lanedc46fe22014-04-03 15:10:38 -0700724 loci_class_metadata[%(inst)s->object_id].wire_length_get(
Rich Lanea06d0c32013-03-25 08:52:03 -0700725 (of_object_t *)&elt, &length);
726 TEST_ASSERT(length == %(inst_len)d);
727 }
728"""
729 check_template += """
730 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
731 value = %(subcls)s_%(v_name)s_check(
732 %(inst)s, value);
733 TEST_ASSERT(value != 0);
734"""
735 out.write("\n /* Check two instances of type %s */" % instance)
736
Andreas Wundsam53256162013-05-02 14:05:53 -0700737 out.write(check_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700738 dict(elt_name=loxi_utils.enum_name(subcls), inst_len=inst_len,
739 inst=instance, subcls=subcls,
740 v_name=loxi_utils.version_to_name(version)))
741 out.write("""\
742 TEST_OK(%(cls)s_next(list, &elt));
743""" % dict(cls=cls))
744
Andreas Wundsam53256162013-05-02 14:05:53 -0700745 out.write(check_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700746 dict(elt_name=loxi_utils.enum_name(subcls), inst_len=inst_len,
747 inst=instance, subcls=subcls,
748 v_name=loxi_utils.version_to_name(version)))
749 if last:
750 out.write("""\
751 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
752""" % dict(cls=cls))
753 else:
754 out.write("""\
755 TEST_OK(%(cls)s_next(list, &elt));
756""" % dict(cls=cls))
757
758def setup_list_fn(out, version, cls):
759 """
760 Generate a helper function that populates a list with two
761 of each type of subclass it supports
762 """
763 out.write("""
764/**
765 * Set up a list of type %(cls)s with two of each type of subclass
766 */
767int
768list_setup_%(cls)s_%(v_name)s(
769 %(cls)s_t *list, int value)
770{
771""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
772 base_type = loxi_utils.list_to_entry_type(cls)
773 out.write("""
774 %(base_type)s_t elt;
775 int cur_len = 0;
776""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700777
Rich Lanea06d0c32013-03-25 08:52:03 -0700778 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700779 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 -0700780 v_name = loxi_utils.version_to_name(version)
781
782 if len(sub_classes) == 0:
783 out.write(" /* No subclasses for %s */\n"% base_type)
784 out.write(" %s_t *elt_p;\n" % base_type)
785 out.write("\n elt_p = &elt;\n")
786 else:
787 out.write(" /* Declare pointers for each subclass */\n")
788 for instance, subcls in sub_classes:
789 out.write(" %s_t *%s;\n" % (subcls, instance))
790 out.write("\n /* Instantiate pointers for each subclass */\n")
791 for instance, subcls in sub_classes:
792 out.write(" %s = &elt.%s;\n" % (instance, instance))
793
794 if len(sub_classes) == 0: # No inheritance case
795 inst_len = loxi_utils.base_type_to_length(base_type, version)
796 setup_instance(out, cls, base_type, "elt_p", v_name, inst_len, version)
797 else:
798 for instance, subcls in sub_classes:
799 inst_len = of_g.base_length[(subcls, version)]
800 setup_instance(out, cls, subcls, instance, v_name, inst_len, version)
801 out.write("""
802
803 return value;
804}
805""")
806
807def check_list_fn(out, version, cls):
808 """
809 Generate a helper function that checks a list populated by above fn
810 """
811 out.write("""
812/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700813 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700814 * list_setup_%(cls)s_%(v_name)s
815 */
816int
817list_check_%(cls)s_%(v_name)s(
818 %(cls)s_t *list, int value)
819{
820""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
821 base_type = loxi_utils.list_to_entry_type(cls)
822 out.write("""
823 %(base_type)s_t elt;
824""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700825
Rich Lanea06d0c32013-03-25 08:52:03 -0700826 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700827 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 -0700828 v_name = loxi_utils.version_to_name(version)
829
830 if len(sub_classes) == 0:
831 out.write(" /* No subclasses for %s */\n"% base_type)
832 out.write(" %s_t *elt_p;\n" % base_type)
833 out.write("\n elt_p = &elt;\n")
834 else:
835 out.write(" /* Declare pointers for each subclass */\n")
836 for instance, subcls in sub_classes:
837 out.write(" %s_t *%s;\n" % (subcls, instance))
838 out.write("\n /* Instantiate pointers for each subclass */\n")
839 for instance, subcls in sub_classes:
840 out.write(" %s = &elt.%s;\n" % (instance, instance))
841
842 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
843 if len(sub_classes) == 0: # No inheritance case
844 if loxi_utils.class_is_var_len(base_type, version):
845 inst_len = -1
846 else:
847 inst_len = loxi_utils.base_type_to_length(base_type, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700848 check_instance(out, cls, base_type, "elt_p", v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -0700849 version, True)
850 else:
851 count = 0
852 for instance, subcls in sub_classes:
853 count += 1
854 if loxi_utils.class_is_var_len(subcls, version):
855 inst_len = -1
856 else:
857 inst_len = of_g.base_length[(subcls, version)]
Andreas Wundsam53256162013-05-02 14:05:53 -0700858 check_instance(out, cls, subcls, instance, v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -0700859 version, count==len(sub_classes))
860
861 out.write("""
862 return value;
863}
864""" % dict(base_type=base_type))
865
866def gen_list_set_check_funs(out):
867 for version in of_g.of_version_range:
868 for cls in of_g.ordered_list_objects:
869 if cls in type_maps.inheritance_map:
870 continue
871
872 if version in of_g.unified[cls]:
873 setup_list_fn(out, version, cls)
874 check_list_fn(out, version, cls)
875
876# Maybe: Get a map from list class to parent, mem_name of container
877
878def list_test(out, version, cls):
879 out.write("""
880static int
881test_%(cls)s_%(v_name)s(void)
882{
883""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
884 base_type = loxi_utils.list_to_entry_type(cls)
885
886 out.write(""" %(cls)s_t *list;
887 int value = 1;
888""" % dict(cls=cls, base_type=base_type))
889
890 out.write("""
891 list = %(cls)s_new(%(v_name)s);
892 TEST_ASSERT(list != NULL);
893 TEST_ASSERT(list->version == %(v_name)s);
894 TEST_ASSERT(list->length == 0);
895 TEST_ASSERT(list->parent == NULL);
896 TEST_ASSERT(list->object_id == %(enum_cls)s);
897
898 value = list_setup_%(cls)s_%(v_name)s(list, value);
899 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700900""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700901 enum_cls=loxi_utils.enum_name(cls)))
902
903 out.write("""
904 /* Now check values */
905 value = 1;
906 value = list_check_%(cls)s_%(v_name)s(list, value);
907 TEST_ASSERT(value != 0);
908""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
909
910 out.write("""
911 %(cls)s_delete(list);
912
913 return TEST_PASS;
914}
915""" % dict(cls=cls))
916
917def gen_list_test(out, name):
918 """
919 Generate base line test cases for lists
920 @param out The file handle to write to
921 """
922
923 loxi_utils.gen_c_copy_license(out)
924 out.write("""
925/**
926 *
927 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
928 *
929 * Message-scalar tests for all versions
930 */
931
932#include <locitest/test_common.h>
933""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700934
Rich Lanea06d0c32013-03-25 08:52:03 -0700935 for version in of_g.of_version_range:
936 v_name = loxi_utils.version_to_name(version)
937 out.write("""
938/**
939 * Baseline list tests for version %s
940 */
941""" % v_name)
942 for cls in of_g.ordered_list_objects:
943 if cls in type_maps.inheritance_map:
944 continue
945 if version in of_g.unified[cls]:
946 list_test(out, version, cls)
947
948 out.write("""
949int
950run_list_tests(void)
951{
952""")
953 for version in of_g.of_version_range:
954 v_name = loxi_utils.version_to_name(version)
955 for cls in of_g.ordered_list_objects:
956 if cls in type_maps.inheritance_map:
957 continue
958 if version in of_g.unified[cls]:
959 test_name = "%s_%s" % (cls, v_name)
960 out.write(" RUN_TEST(%s);\n" % test_name)
961
962 out.write("\n return TEST_PASS;\n}\n");
963
964def gen_match_test(out, name):
965 """
966 Generate baseline tests for match functions
967 """
968
969 loxi_utils.gen_c_copy_license(out)
970 out.write("""\
971/**
972 *
973 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
974 *
975 * Message-scalar tests for all versions
976 * @fixme These are mostly hard coded now.
977 */
978
979#include <locitest/test_common.h>
980
981static int
982test_match_1(void)
983{
984 of_match_v1_t *m_v1;
985 of_match_v2_t *m_v2;
986 of_match_v3_t *m_v3;
987 of_match_v4_t *m_v4;
988 of_match_t match;
989 int value = 1;
990 int idx;
991 uint32_t exp_value;
992
993 /* Verify default values for ip mask map */
994 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
995 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
996 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
997 if (idx < 32) {
998 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
999 }
1000 }
1001
1002 TEST_ASSERT(of_ip_mask_map_set(17, 0xabcdef00) == OF_ERROR_NONE);
1003 TEST_ASSERT(of_ip_mask_to_index(0xabcdef00) == 17);
1004 TEST_ASSERT(of_ip_index_to_mask(17) == 0xabcdef00);
1005
1006 TEST_ASSERT(of_ip_mask_map_set(62, 0xabcdefff) == OF_ERROR_NONE);
1007 TEST_ASSERT(of_ip_mask_to_index(0xabcdefff) == 62);
1008 TEST_ASSERT(of_ip_index_to_mask(62) == 0xabcdefff);
1009
1010 /* Test re-init */
1011 of_ip_mask_map_init();
1012 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
1013 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
1014 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
1015 if (idx < 32) {
1016 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
1017 }
1018 }
1019""")
1020
1021 for version in of_g.of_version_range:
1022 out.write("""
1023 /* Create/populate/convert and delete for version %(v_name)s */
1024 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1025 TEST_ASSERT(m_v%(version)d != NULL);
1026 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
1027 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
1028 of_match_v%(version)d_delete(m_v%(version)d);
1029""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1030
1031 out.write("""
1032 return TEST_PASS;
1033}
1034""")
1035
1036 out.write("""
1037static int
1038test_match_2(void)
1039{
1040 of_match_v1_t *m_v1;
1041 of_match_v2_t *m_v2;
1042 of_match_v3_t *m_v3;
1043 of_match_v3_t *m_v4;
1044 of_match_t match1;
1045 of_match_t match2;
1046 int value = 1;
1047""")
1048
1049 for version in of_g.of_version_range:
1050 out.write("""
1051 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1052 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1053 TEST_ASSERT(m_v%(version)d != NULL);
1054 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1055 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1056 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1057 of_match_v%(version)d_delete(m_v%(version)d);
1058""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1059
1060 out.write("""
1061 return TEST_PASS;
1062}
1063""")
1064
1065 out.write("""
1066static int
1067test_match_3(void)
1068{
1069 of_match_t match1;
1070 of_match_t match2;
1071 int value = 1;
1072 of_octets_t octets;
1073""")
1074 for version in of_g.of_version_range:
1075 out.write("""
1076 /* Serialize to version %(v_name)s */
1077 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001078 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001079 OF_ERROR_NONE);
Andreas Wundsam53256162013-05-02 14:05:53 -07001080 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001081 OF_ERROR_NONE);
1082 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1083 FREE(octets.data);
1084""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1085
1086 out.write("""
1087 return TEST_PASS;
1088}
1089""")
1090
1091 out.write("""
1092int run_match_tests(void)
1093{
1094 RUN_TEST(match_1);
1095 RUN_TEST(match_2);
1096 RUN_TEST(match_3);
1097 RUN_TEST(match_utils);
1098
1099 return TEST_PASS;
1100}
1101""")
1102
1103def gen_msg_test(out, name):
1104 loxi_utils.gen_c_copy_license(out)
1105 out.write("""
1106/**
1107 *
1108 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1109 *
1110 * Message-scalar tests for all versions
1111 */
1112
1113#include <locitest/test_common.h>
1114""")
1115 for version in of_g.of_version_range:
1116 for cls in of_g.ordered_messages:
1117 if not (cls, version) in of_g.base_length:
1118 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001119 if type_maps.class_is_virtual(cls):
1120 continue
Rich Lanef70be942013-07-18 13:33:14 -07001121 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001122 out.write("""
1123static int
1124test_%(cls)s_create_%(v_name)s(void)
1125{
1126 %(cls)s_t *obj;
1127 uint8_t *msg_buf;
1128 int value;
1129 int len;
Rich Lanea4b68302014-03-12 15:17:58 -07001130 of_object_id_t object_id;
Rich Lanea06d0c32013-03-25 08:52:03 -07001131
1132 obj = %(cls)s_new(%(v_name)s);
1133 TEST_ASSERT(obj != NULL);
1134 TEST_ASSERT(obj->version == %(v_name)s);
1135 TEST_ASSERT(obj->length == %(bytes)d);
1136 TEST_ASSERT(obj->parent == NULL);
1137 TEST_ASSERT(obj->object_id == %(enum)s);
1138
Rich Lanea4b68302014-03-12 15:17:58 -07001139 of_header_wire_object_id_get(obj, &object_id);
1140 TEST_ASSERT(object_id == %(enum)s);
1141
Rich Lanea06d0c32013-03-25 08:52:03 -07001142 /* Set up incrementing values for scalar members */
1143 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1144 TEST_ASSERT(value != 0);
1145
1146 /* Grab the underlying buffer from the message */
1147 len = obj->length;
1148 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1149 TEST_ASSERT(msg_buf != NULL);
1150 %(cls)s_delete(obj);
1151 /* TODO: */
1152 TEST_ASSERT(of_message_to_object_id(msg_buf, len) == %(enum)s);
1153 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1154
1155 TEST_ASSERT(obj != NULL);
1156
1157 /* @fixme Set up all message objects (recursively?) */
1158
1159 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1160 TEST_ASSERT(value != 0);
1161
1162 %(cls)s_delete(obj);
1163
1164 return TEST_PASS;
1165}
1166""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1167 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1168
1169 out.write("""
1170int
1171run_message_tests(void)
1172{
1173""")
1174 for version in of_g.of_version_range:
1175 for cls in of_g.ordered_messages:
1176 if not (cls, version) in of_g.base_length:
1177 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001178 if type_maps.class_is_virtual(cls):
1179 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001180 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1181 out.write(" RUN_TEST(%s);\n" % test_name)
1182
1183 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001184
Rich Lanea06d0c32013-03-25 08:52:03 -07001185
1186def gen_list_setup_check(out, cls, version):
1187 """
1188 Generate functions that populate and check a list with two
1189 of each type of subclass it supports
1190 """
1191 out.write("""
1192/**
1193 * Populate a list of type %(cls)s with two of each type of subclass
1194 * @param list Pointer to the list to be populated
1195 * @param value The seed value to use in populating the list
1196 * @returns The value after increments for this object's values
1197 */
1198int
1199%(cls)s_%(v_name)s_populate(
1200 %(cls)s_t *list, int value)
1201{
1202""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1203 base_type = loxi_utils.list_to_entry_type(cls)
1204 out.write("""
1205 %(base_type)s_t elt;
1206 int cur_len = 0;
1207""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001208
Rich Lanea06d0c32013-03-25 08:52:03 -07001209 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001210 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 -07001211 v_name = loxi_utils.version_to_name(version)
1212
1213 if len(sub_classes) == 0:
1214 out.write(" /* No subclasses for %s */\n"% base_type)
1215 out.write(" %s_t *elt_p;\n" % base_type)
1216 out.write("\n elt_p = &elt;\n")
1217 else:
1218 out.write(" /* Declare pointers for each subclass */\n")
1219 for instance, subcls in sub_classes:
1220 out.write(" %s_t *%s;\n" % (subcls, instance))
1221 out.write("\n /* Instantiate pointers for each subclass */\n")
1222 for instance, subcls in sub_classes:
1223 out.write(" %s = &elt.%s;\n" % (instance, instance))
1224
1225# if type_maps.class_is_virtual(base_type):
1226# out.write("""\
1227# TEST_OK(%(base_type)s_header_init(
1228# (%(base_type)s_header_t *)&elt, %(v_name)s, -1, 1));
1229# """ % dict(base_type=base_type, v_name=loxi_utils.version_to_name(version)))
1230# else:
1231# out.write("""\
1232# TEST_OK(%(base_type)s_init(&elt, %(v_name)s, -1, 1));
1233# """ % dict(base_type=base_type, v_name=loxi_utils.version_to_name(version)))
1234
1235 if len(sub_classes) == 0: # No inheritance case
1236 inst_len = loxi_utils.base_type_to_length(base_type, version)
1237 setup_instance(out, cls, base_type, "elt_p", v_name, inst_len, version)
1238 else:
1239 for instance, subcls in sub_classes:
1240 inst_len = of_g.base_length[(subcls, version)]
Andreas Wundsam53256162013-05-02 14:05:53 -07001241 setup_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001242 inst_len, version)
1243 out.write("""
1244 return value;
1245}
1246""")
1247 out.write("""
1248/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001249 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001250 * %(cls)s_%(v_name)s_populate
1251 * @param list Pointer to the list that was populated
1252 * @param value Starting value for checking
1253 * @returns The value after increments for this object's values
1254 */
1255int
1256%(cls)s_%(v_name)s_check(
1257 %(cls)s_t *list, int value)
1258{
1259""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1260 base_type = loxi_utils.list_to_entry_type(cls)
1261 out.write("""
1262 %(base_type)s_t elt;
1263 int count = 0;
1264 int rv;
1265""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001266
Rich Lanea06d0c32013-03-25 08:52:03 -07001267
1268 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001269 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 -07001270 v_name = loxi_utils.version_to_name(version)
1271
1272 if len(sub_classes) == 0:
1273 entry_count = 2
1274 out.write(" /* No subclasses for %s */\n"% base_type)
1275 out.write(" %s_t *elt_p;\n" % base_type)
1276 out.write("\n elt_p = &elt;\n")
1277 else:
1278 entry_count = 2 * len(sub_classes) # Two of each type appended
1279 out.write(" /* Declare pointers for each subclass */\n")
1280 for instance, subcls in sub_classes:
1281 out.write(" %s_t *%s;\n" % (subcls, instance))
1282 out.write("\n /* Instantiate pointers for each subclass */\n")
1283 for instance, subcls in sub_classes:
1284 out.write(" %s = &elt.%s;\n" % (instance, instance))
1285
1286 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1287 if len(sub_classes) == 0: # No inheritance case
1288 if loxi_utils.class_is_var_len(base_type, version):
1289 inst_len = -1
1290 else:
1291 inst_len = loxi_utils.base_type_to_length(base_type, version)
Andreas Wundsam53256162013-05-02 14:05:53 -07001292 check_instance(out, cls, base_type, "elt_p", v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -07001293 version, True)
1294 else:
1295 count = 0
1296 for instance, subcls in sub_classes:
1297 count += 1
1298 if loxi_utils.class_is_var_len(subcls, version):
1299 inst_len = -1
1300 else:
1301 inst_len = of_g.base_length[(subcls, version)]
Andreas Wundsam53256162013-05-02 14:05:53 -07001302 check_instance(out, cls, subcls, instance, v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -07001303 version, count==len(sub_classes))
1304 out.write("""
1305""" % dict(base_type=base_type))
1306
1307 out.write("""
1308 /* Do an iterate to test the iterator */
1309 %(u_cls)s_ITER(list, &elt, rv) {
1310 count += 1;
1311 }
1312
1313 TEST_ASSERT(rv == OF_ERROR_RANGE);
1314 TEST_ASSERT(count == %(entry_count)d);
1315
1316 /* We shoehorn a test of the dup functions here */
1317 {
1318 %(cls)s_t *dup;
1319
1320 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1321 TEST_ASSERT(dup->length == list->length);
1322 TEST_ASSERT(dup->object_id == list->object_id);
1323 TEST_ASSERT(dup->version == list->version);
1324 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1325 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1326 of_object_delete((of_object_t *)dup);
1327
1328 /* And now for the generic dup function */
1329 TEST_ASSERT((dup = (%(cls)s_t *)
1330 of_object_dup(list)) != NULL);
1331 TEST_ASSERT(dup->length == list->length);
1332 TEST_ASSERT(dup->object_id == list->object_id);
1333 TEST_ASSERT(dup->version == list->version);
1334 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1335 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1336 of_object_delete((of_object_t *)dup);
1337 }
1338
1339 return value;
1340}
1341""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1342
1343
1344def gen_class_setup_check(out, cls, version):
1345 out.write("""
1346/**
1347 * Populate all members of an object of type %(cls)s
1348 * with incrementing values
1349 * @param obj Pointer to an object to populate
1350 * @param value The seed value to use in populating the object
1351 * @returns The value after increments for this object's values
1352 */
1353
1354int
1355%(cls)s_%(v_name)s_populate(
1356 %(cls)s_t *obj, int value)
1357{
1358""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1359 members, member_types = loxi_utils.all_member_types_get(cls, version)
1360 for m_type in member_types:
1361 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1362 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1363 else:
1364 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1365 out.write("""
1366 /* Run thru accessors after new to ensure okay */
1367""")
1368 for member in members:
1369 m_type = member["m_type"]
1370 m_name = member["name"]
1371 if loxi_utils.skip_member_name(m_name):
1372 continue
1373 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1374 out.write("""\
1375 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1376""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1377 else:
1378 sub_cls = m_type[:-2] # Trim _t
1379 out.write("""\
1380 {
1381 %(sub_cls)s_t sub_cls;
1382
1383 /* Test bind */
1384 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1385 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001386""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001387 m_name=m_name, sub_cls=sub_cls,
1388 v_name=loxi_utils.version_to_name(version)))
1389
1390 out.write("""
1391 value = %(cls)s_%(v_name)s_populate_scalars(
1392 obj, value);
1393 TEST_ASSERT(value != 0);
1394""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1395
1396 for member in members:
1397 m_type = member["m_type"]
1398 m_name = member["name"]
1399 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1400 continue
1401 if loxi_utils.skip_member_name(m_name):
1402 continue
1403 if m_type == "of_match_t":
1404 out.write("""\
1405 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1406 TEST_ASSERT(value != 0);
1407 %(cls)s_%(m_name)s_set(
1408 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001409""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001410 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1411 elif m_type == "of_octets_t":
1412 out.write("""\
1413 value = of_octets_populate(&%(var_name)s, value);
1414 TEST_ASSERT(value != 0);
1415 %(cls)s_%(m_name)s_set(
1416 obj, &%(var_name)s);
1417 if (octets.bytes) {
1418 FREE(octets.data);
1419 }
1420""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1421 else:
1422 sub_cls = m_type[:-2] # Trim _t
1423 out.write("""
1424 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1425 TEST_ASSERT(%(var_name)s != NULL);
1426 value = %(sub_cls)s_%(v_name)s_populate(
1427 %(var_name)s, value);
1428 TEST_ASSERT(value != 0);
1429 %(cls)s_%(m_name)s_set(
1430 obj, %(var_name)s);
1431 %(sub_cls)s_delete(%(var_name)s);
1432""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1433 var_name=var_name_map(m_type),
1434 v_name=loxi_utils.version_to_name(version)))
1435
1436 out.write("""
1437 return value;
1438}
1439""")
1440
1441 out.write("""
1442/**
1443 * Check all members of an object of type %(cls)s
1444 * populated by the above function
1445 * @param obj Pointer to an object to check
1446 * @param value Starting value for checking
1447 * @returns The value after increments for this object's values
1448 */
1449
1450int
1451%(cls)s_%(v_name)s_check(
1452 %(cls)s_t *obj, int value)
1453{
1454""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1455 members, member_types = loxi_utils.all_member_types_get(cls, version)
1456 for m_type in member_types:
1457 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1458 continue
1459 if loxi_utils.type_is_of_object(m_type):
1460 continue
1461 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1462 out.write("""
1463 value = %(cls)s_%(v_name)s_check_scalars(
1464 obj, value);
1465 TEST_ASSERT(value != 0);
1466""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1467
1468 for member in members:
1469 m_type = member["m_type"]
1470 m_name = member["name"]
1471 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1472 continue
1473 if loxi_utils.skip_member_name(m_name):
1474 continue
1475 if m_type == "of_match_t":
1476 out.write("""\
1477 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1478 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1479""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1480 v_name=loxi_utils.version_to_name(version)))
1481 elif m_type == "of_octets_t":
1482 out.write("""\
1483 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1484 value = of_octets_check(&%(var_name)s, value);
1485""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1486 v_name=loxi_utils.version_to_name(version)))
1487 else:
1488 sub_cls = m_type[:-2] # Trim _t
1489 out.write("""
1490 { /* Use get/delete to access on check */
1491 %(m_type)s *%(m_name)s_ptr;
1492
1493 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1494 TEST_ASSERT(%(m_name)s_ptr != NULL);
1495 value = %(sub_cls)s_%(v_name)s_check(
1496 %(m_name)s_ptr, value);
1497 TEST_ASSERT(value != 0);
1498 %(sub_cls)s_delete(%(m_name)s_ptr);
1499 }
1500""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1501 var_name=var_name_map(m_type),
1502 v_name=loxi_utils.version_to_name(version)))
1503
1504 out.write("""
1505 /* We shoehorn a test of the dup functions here */
1506 {
1507 %(cls)s_t *dup;
1508
1509 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1510 TEST_ASSERT(dup->length == obj->length);
1511 TEST_ASSERT(dup->object_id == obj->object_id);
1512 TEST_ASSERT(dup->version == obj->version);
1513 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1514 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1515 of_object_delete((of_object_t *)dup);
1516
1517 /* And now for the generic dup function */
1518 TEST_ASSERT((dup = (%(cls)s_t *)
1519 of_object_dup(obj)) != NULL);
1520 TEST_ASSERT(dup->length == obj->length);
1521 TEST_ASSERT(dup->object_id == obj->object_id);
1522 TEST_ASSERT(dup->version == obj->version);
1523 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1524 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1525 of_object_delete((of_object_t *)dup);
1526 }
1527
1528 return value;
1529}
1530""" % dict(cls=cls))
1531
1532def unified_accessor_test_case(out, cls, version):
1533 """
1534 Generate one test case for the given version and class
1535 """
1536
1537 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001538 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001539 v_name = loxi_utils.version_to_name(version)
1540
1541 out.write("""
1542static int
1543test_%(cls)s_%(v_name)s(void)
1544{
1545 %(cls)s_t *obj;
1546 obj = %(cls)s_new(%(v_name)s);
1547 TEST_ASSERT(obj != NULL);
1548 TEST_ASSERT(obj->version == %(v_name)s);
1549 TEST_ASSERT(obj->length == %(length)d);
1550 TEST_ASSERT(obj->parent == NULL);
1551 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001552""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001553 v_name=v_name, length=length, version=version))
1554 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1555 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001556 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001557 int length;
1558
Rich Lanedc46fe22014-04-03 15:10:38 -07001559 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001560 TEST_ASSERT(length == %(length)d);
1561 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001562 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001563 of_object_id_t obj_id;
1564
Rich Lanedc46fe22014-04-03 15:10:38 -07001565 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001566 TEST_ASSERT(obj_id == %(u_cls)s);
1567 }
1568
1569 /* Set up incrementing values for members */
1570 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1571 obj, 1) != 0);
1572
1573 /* Check values just set */
1574 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1575 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001576""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001577 v_name=v_name, length=length, version=version))
1578
1579 out.write("""
1580 %(cls)s_delete(obj);
1581
1582 /* To do: Check memory */
1583 return TEST_PASS;
1584}
1585""" % dict(cls=cls))
1586
1587
1588def gen_unified_accessor_funs(out):
1589 for version in of_g.of_version_range:
1590 for cls in of_g.standard_class_order:
1591 if not loxi_utils.class_in_version(cls, version):
1592 continue
1593 if cls in type_maps.inheritance_map:
1594 continue
1595 elif loxi_utils.class_is_list(cls):
1596 gen_list_setup_check(out, cls, version)
1597 else:
1598 gen_class_setup_check(out, cls, version)
1599
1600def gen_unified_accessor_tests(out, name):
1601 loxi_utils.gen_c_copy_license(out)
1602 out.write("""
1603/**
1604 *
1605 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1606 *
1607 * Unified simple class instantiation tests for all versions
1608 */
1609
1610#include <locitest/test_common.h>
1611""")
1612 for version in of_g.of_version_range:
1613 for cls in of_g.standard_class_order:
1614 if not loxi_utils.class_in_version(cls, version):
1615 continue
1616 if cls in type_maps.inheritance_map:
1617 continue
1618 unified_accessor_test_case(out, cls, version)
1619
1620 out.write("""
1621int
1622run_unified_accessor_tests(void)
1623{
1624""")
1625 for version in of_g.of_version_range:
1626 v_name = loxi_utils.version_to_name(version)
1627 for cls in of_g.standard_class_order:
1628 if not loxi_utils.class_in_version(cls, version):
1629 continue
1630 if cls in type_maps.inheritance_map:
1631 continue
1632 test_name = "%s_%s" % (cls, v_name)
1633 out.write(" RUN_TEST(%s);\n" % test_name)
1634
1635 out.write(" return TEST_PASS;\n}\n");
1636
1637
1638
1639################################################################
1640#
1641# Object duplication functions
1642#
1643# These exercise the accessors to create duplicate objects.
1644# They are used in the LOCI test shim which sits in an OF
1645# protocol stream.
1646#
1647# TODO
1648# Resolve version stuff
1649# Complete list dup
1650
1651def gen_dup_list(out, cls, version):
1652 ver_name = loxi_utils.version_to_name(version)
1653 elt_type = loxi_utils.list_to_entry_type(cls)
1654 out.write("""
1655/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001656 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001657 * using accessor functions
1658 * @param src Pointer to object to be duplicated
1659 * @returns A new object of type %(cls)s.
1660 *
1661 * The caller is responsible for deleting the returned value
1662 */
1663%(cls)s_t *
1664%(cls)s_%(ver_name)s_dup(
1665 %(cls)s_t *src)
1666{
1667 %(elt_type)s_t src_elt;
1668 %(elt_type)s_t *dst_elt;
1669 int rv;
1670 %(cls)s_t *dst;
1671
1672 if ((dst = %(cls)s_new(src->version)) == NULL) {
1673 return NULL;
1674 }
1675""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1676
1677 out.write("""
1678 %(u_cls)s_ITER(src, &src_elt, rv) {
1679 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1680 of_object_delete((of_object_t *)dst);
1681 return NULL;
1682 }
1683 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1684 dst, NULL);
1685 of_object_delete((of_object_t *)dst_elt);
1686 }
1687
1688 return dst;
1689}
1690""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1691
1692
1693def gen_dup_inheritance(out, cls, version):
1694 ver_name = loxi_utils.version_to_name(version)
1695 out.write("""
1696/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001697 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001698 * @param src Pointer to object to be duplicated
1699 * @returns A new object of type %(cls)s.
1700 *
1701 * The caller is responsible for deleting the returned value
1702 */
1703%(cls)s_t *
1704%(cls)s_%(ver_name)s_dup(
1705 %(cls)s_t *src)
1706{
1707""" % dict(cls=cls, ver_name=ver_name))
1708
1709 # For each subclass, check if this is an instance of that subclass
1710 version_classes = type_maps.inheritance_data[cls][version]
1711 for sub_cls in version_classes:
1712 sub_enum = (cls + "_" + sub_cls).upper()
1713 out.write("""
1714 if (src->header.object_id == %(sub_enum)s) {
1715 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1716 &src->%(sub_cls)s);
1717 }
1718""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1719
1720 out.write("""
1721 return NULL;
1722}
1723""")
1724
1725
1726def gen_dup_cls(out, cls, version):
1727 """
1728 Generate duplication routine for class cls
1729 """
1730 ver_name = loxi_utils.version_to_name(version)
1731
1732 out.write("""
1733/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001734 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001735 * using accessor functions
1736 * @param src Pointer to object to be duplicated
1737 * @returns A new object of type %(cls)s.
1738 *
1739 * The caller is responsible for deleting the returned value
1740 */
1741%(cls)s_t *
1742%(cls)s_%(ver_name)s_dup(
1743 %(cls)s_t *src)
1744{
1745 %(cls)s_t *dst;
1746""" % dict(cls=cls, ver_name=ver_name))
1747
1748 # Get members and types for the class
1749 members, member_types = loxi_utils.all_member_types_get(cls, version)
1750
1751 # Add declarations for each member type
1752 for m_type in member_types:
1753 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1754 # Declare instance of these
1755 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1756 else:
1757 out.write("""
1758 %(m_type)s src_%(v_name)s;
1759 %(m_type)s *dst_%(v_name)s;
1760""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1761
1762 out.write("""
1763 if ((dst = %(cls)s_new(src->version)) == NULL) {
1764 return NULL;
1765 }
1766""" % dict(cls=cls))
1767
1768 for member in members:
1769 m_type = member["m_type"]
1770 m_name = member["name"]
1771 if loxi_utils.skip_member_name(m_name):
1772 continue
1773 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1774 out.write("""
1775 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1776 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1777""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1778 elif m_type in ["of_match_t", "of_octets_t"]:
1779 out.write("""
1780 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1781 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1782""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1783 else:
1784 sub_cls = m_type[:-2] # Trim _t
1785 out.write("""
1786 %(cls)s_%(m_name)s_bind(
1787 src, &src_%(v_name)s);
1788 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1789 if (dst_%(v_name)s == NULL) {
1790 %(cls)s_delete(dst);
1791 return NULL;
1792 }
1793 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1794 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001795""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001796 v_name=var_name_map(m_type), ver_name=ver_name))
1797
1798 out.write("""
1799 return dst;
1800}
1801""")
1802
1803def gen_version_dup(out=sys.stdout):
1804 """
1805 Generate duplication routines for each object type
1806 """
1807 out.write("""
1808/* Special try macro for duplicating */
1809#define _TRY_FREE(op, obj, rv) do { \\
1810 int _rv; \\
1811 if ((_rv = (op)) < 0) { \\
1812 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1813 of_object_delete((of_object_t *)(obj)); \\
1814 return (rv); \\
1815 } \\
1816 } while (0)
1817""")
1818
1819 for version in of_g.of_version_range:
1820 for cls in of_g.standard_class_order:
1821 if not loxi_utils.class_in_version(cls, version):
1822 continue
1823 if cls in type_maps.inheritance_map:
1824 gen_dup_inheritance(out, cls, version)
1825 elif loxi_utils.class_is_list(cls):
1826 gen_dup_list(out, cls, version)
1827 else:
1828 gen_dup_cls(out, cls, version)
1829
1830def gen_dup(out=sys.stdout):
1831 """
1832 Generate non-version specific duplication routines for each object type
1833 """
1834
1835 for cls in of_g.standard_class_order:
1836 out.write("""
1837%(cls)s_t *
1838%(cls)s_dup(
1839 %(cls)s_t *src)
1840{
1841""" % dict(cls=cls))
1842 for version in of_g.of_version_range:
1843 if not loxi_utils.class_in_version(cls, version):
1844 continue
1845 hdr = "header." if cls in type_maps.inheritance_map else ""
1846
1847 ver_name = loxi_utils.version_to_name(version)
1848 out.write("""
1849 if (src->%(hdr)sversion == %(ver_name)s) {
1850 return %(cls)s_%(ver_name)s_dup(src);
1851 }
1852""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1853
1854 out.write("""
1855 /* Class not supported in given version */
1856 return NULL;
1857}
1858""")
1859
1860def dup_c_gen(out, name):
1861 """
1862 Generate the C file for duplication functions
1863 """
1864 loxi_utils.gen_c_copy_license(out)
1865 out.write("""\
1866/*
1867 * Duplication functions for all OF objects
1868 *
1869 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1870 *
1871 * These are test functions for exercising accessors. You can call
1872 * of_object_dup for an efficient duplication.
1873 */
1874
1875#define DISABLE_WARN_UNUSED_RESULT
1876#include "loci_log.h"
1877#include <locitest/of_dup.h>
1878
1879""")
1880
1881 gen_version_dup(out)
1882 gen_dup(out)
1883
1884
1885def dup_h_gen(out, name):
1886 """
1887 Generate the header file for duplication functions
1888 """
1889
1890 loxi_utils.gen_c_copy_license(out)
1891 out.write("""
1892/*
1893 * Duplication function header file
1894 *
1895 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1896 */
1897
1898#if !defined(_OF_DUP_H_)
1899#define _OF_DUP_H_
1900
1901#include <loci/loci.h>
1902""")
1903
1904 for cls in of_g.standard_class_order:
1905 out.write("""
1906extern %(cls)s_t *
1907 %(cls)s_dup(
1908 %(cls)s_t *src);
1909""" % dict(cls=cls))
1910
1911 for version in of_g.of_version_range:
1912 for cls in of_g.standard_class_order:
1913 if not loxi_utils.class_in_version(cls, version):
1914 continue
1915 ver_name = loxi_utils.version_to_name(version)
1916 out.write("""
1917extern %(cls)s_t *
1918 %(cls)s_%(ver_name)s_dup(
1919 %(cls)s_t *src);
1920""" % dict(cls=cls, ver_name=ver_name))
1921
1922 out.write("\n#endif /* _OF_DUP_H_ */\n")
1923
1924def gen_log_test(out):
1925 """
1926 Generate test for obj log calls
1927
1928 Define a trivial handler for object logging; call all obj log fns
1929 """
1930 out.write("""
1931
1932/**
1933 * Test object dump functions
1934 */
1935
1936int
1937test_dump_objs(void)
1938{
1939 of_object_t *obj;
1940
1941 FILE *out = fopen("/dev/null", "w");
1942
1943 /* Call each obj dump function */
1944""")
1945 for version in of_g.of_version_range:
1946 for j, cls in enumerate(of_g.all_class_order):
1947 if not loxi_utils.class_in_version(cls, version):
1948 continue
1949 if cls in type_maps.inheritance_map:
1950 continue
1951 out.write("""
1952 obj = (of_object_t *)%(cls)s_new(%(version)s);
1953 of_object_dump((loci_writer_f)fprintf, out, obj);
1954 of_object_delete(obj);
1955""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001956
Rich Lanea06d0c32013-03-25 08:52:03 -07001957 out.write("""
1958 fclose(out);
1959 return TEST_PASS;
1960}
1961""")
1962
1963def gen_ident_tests(out):
1964 """
1965 Generate tests for identifiers
1966
1967 For all idents, instantiate, test version supported macros
1968 For flags, set it, test it, clear it, test it.
1969 """
1970 out.write("""
1971/**
1972 * Test cases for all flag accessor macros
1973 * These only test self consistency (and that they compile)
1974 */
1975int
1976test_ident_macros(void)
1977{
1978 int value __attribute__((unused));
1979 uint32_t flags;
1980
1981""")
1982
1983 for ident, info in of_g.identifiers.items():
1984 if not identifiers.defined_versions_agree(of_g.identifiers,
1985 of_g.target_version_list,
1986 ident):
1987 # @fixme
1988 continue
1989 out.write(" value = %s;\n" % ident)
1990 for version in of_g.target_version_list:
1991 if version in info["values_by_version"].keys():
1992 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1993 (ident, of_g.of_version_wire2name[version]))
1994 else:
1995 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1996 (ident, of_g.of_version_wire2name[version]))
1997 if flags.ident_is_flag(ident):
1998 # Grab first supported version
1999 for version in info["values_by_version"]:
2000 break
2001 out.write("""
2002 flags = 0;
2003 %(ident)s_SET(flags, %(ver_name)s);
2004 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2005 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2006 %(ident)s_CLEAR(flags, %(ver_name)s);
2007 TEST_ASSERT(flags == 0);
2008 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2009""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2010
2011 out.write("""
2012 return TEST_PASS;
2013}
2014""")
2015
Rich Laneccae0312013-07-21 23:34:13 -07002016def gen_datafiles_tests(out, name):
2017 tests = []
2018 for filename in test_data.list_files():
2019 data = test_data.read(filename)
2020 if not 'c' in data:
2021 continue
2022 name = filename[:-5].replace("/", "_")
2023 tests.append(dict(name=name,
2024 filename=filename,
2025 c=data['c'],
2026 binary=data['binary']))
2027
2028 util.render_template(out, "test_data.c", tests=tests)