blob: 0784fd4fdbf7e32399337e0584133e2e8ece4826 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Test case generation functions
30
31@fixme Update the following
32The following components are generated.
33
34test_common.[ch]: A collection of common code for tests. Currently
35this includes the ability to set the scalar members of an object with
36incrementing values and then similarly verify those values
37
38test_scalar_acc.c: Instantiate each type of object, then set and get
39scalar values in the objects.
40
41test_list.c: Instantiate each type of list, add an element of each
42type the list supports, setting scalar values of the elements.
43
44test_match.c: Various tests for match objects
45
46test_msg.c: Instantiate top level messages
47
48These will move towards unified tests that do the following:
49
50Create or init an object.
51Populate the object with incrementing values.
52Possibly transform the object in some way (e.g., run the underlying
53wire buffer through a parse routine).
54Verify that the members all have the appropriate value
55
56Through out, checking the consistency of memory and memory operations
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +090057is done with mcheck (if available).
Rich Lanea06d0c32013-03-25 08:52:03 -070058
59"""
60
61import sys
Andreas Wundsam76db0062013-11-15 13:34:41 -080062import c_gen.of_g_legacy as of_g
Andreas Wundsam542a13c2013-11-15 13:28:55 -080063import c_gen.match as match
64import c_gen.flags as flags
Rich Lanea06d0c32013-03-25 08:52:03 -070065from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080066import c_gen.type_maps as type_maps
67import c_gen.loxi_utils_legacy as loxi_utils
68import c_gen.identifiers as identifiers
Rich Laneccae0312013-07-21 23:34:13 -070069import util
70import test_data
Rich Lane79c87192014-03-04 10:56:59 -080071import loxi_globals
72from loxi_ir import *
Rich Lanea06d0c32013-03-25 08:52:03 -070073
74def var_name_map(m_type):
75 """
76 Map a type to a generic variable name for the type.
77 @param m_type The data type
78
79 Used mostly in test code generation, but also for the dup functions.
80 """
81 _var_name_map= dict(
82 uint8_t="val8",
83 uint16_t="val16",
84 uint32_t="val32",
85 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070086 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_port_no_t="port_no",
88 of_fm_cmd_t="fm_cmd",
89 of_wc_bmap_t="wc_bmap",
90 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070091 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070092 of_table_name_t="table_name",
93 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070094 of_serial_num_t="ser_num",
Rich Lanef8a3d002014-03-19 13:33:52 -070095 of_str64_t="str64",
Andreas Wundsam53256162013-05-02 14:05:53 -070096 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070097 of_ipv6_t="ipv6",
98 # Non-scalars; more TBD
99 of_octets_t="octets",
100 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700101 of_match_t="match",
Rich Lanec247ade2014-11-07 09:33:24 -0800102 of_oxm_t="oxm",
103 of_bsn_vport_t="bsn_vport",
Rich Lane41b278f2014-10-17 18:29:56 -0700104 of_table_desc_t="table_desc",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700105 # BSN extensions
106 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700107 of_bitmap_128_t="bitmap_128",
Rich Lane119289c2014-12-01 13:44:08 -0800108 of_bitmap_512_t="bitmap_512",
Rich Lanefab0c822013-12-30 11:46:48 -0800109 of_checksum_128_t="checksum_128",
Praseed Balakrishnanf78068b2014-09-04 10:30:40 -0700110 #Circuit extensions
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700111 of_app_code_t="app_code",
Praseed Balakrishnan2ed6da02014-09-18 17:02:48 -0700112 of_sig_id_t="sig_id",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700113 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700114
115 if m_type.find("of_list_") == 0:
116 return "list"
117 if m_type in of_g.of_mixed_types:
118 return of_g.of_mixed_types[m_type]["short_name"]
119 return _var_name_map[m_type]
120
121integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
122 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700123 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700124string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700125 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700126 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
Brian O'Connor8bd36612015-05-27 18:37:08 -0700127 "of_str64_t", "of_app_code_t", "of_bitmap_512_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700128
129scalar_types = integer_types[:]
130scalar_types.extend(string_types)
131
Rich Lane1f315aa2014-10-13 17:11:35 -0700132# When embedding an object inside of another object we have to pick a single
133# subclass to use, unlike lists where we use all subclasses.
134embedded_subclasses = {
Rich Lanec247ade2014-11-07 09:33:24 -0800135 'of_oxm_t': 'of_oxm_eth_type',
136 'of_bsn_vport_t': 'of_bsn_vport_q_in_q',
Rich Lane1f315aa2014-10-13 17:11:35 -0700137}
138
Rich Lanea06d0c32013-03-25 08:52:03 -0700139def ignore_member(cls, version, m_name, m_type):
140 """
141 Filter out names or types that either don't have accessors
142 or those that should not be messed with
143 or whose types we're not ready to deal with yet.
144 """
Rich Lane79c87192014-03-04 10:56:59 -0800145
146 uclass = loxi_globals.unified.class_by_name(cls)
147 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700148 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800149
Rich Lane79c87192014-03-04 10:56:59 -0800150 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800151 return True
Rich Lane79c87192014-03-04 10:56:59 -0800152
Rich Lanea06d0c32013-03-25 08:52:03 -0700153 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
154
155def gen_fill_string(out):
156 out.write("""
157
158/**
159 * The increment to use on values inside a string
160 */
161#define OF_TEST_STR_INCR 3
162
163/**
164 * Fill in a buffer with incrementing values starting
165 * at the given offset with the given value
166 * @param buf The buffer to fill
167 * @param value The value to use for data
168 * @param len The number of bytes to fill
169 */
170
171void
172of_test_str_fill(uint8_t *buf, int value, int len)
173{
174 int i;
175
176 for (i = 0; i < len; i++) {
177 *buf = value;
178 value += OF_TEST_STR_INCR;
179 buf++;
180 }
181}
182
183/**
184 * Given a buffer, verify that it's filled as above
185 * @param buf The buffer to check
186 * @param value The value to use for data
187 * @param len The number of bytes to fill
188 * @return Boolean True on equality (success)
189 */
190
191int
192of_test_str_check(uint8_t *buf, int value, int len)
193{
194 int i;
195 uint8_t val8;
196
197 val8 = value;
198
199 for (i = 0; i < len; i++) {
200 if (*buf != val8) {
201 return 0;
202 }
203 val8 += OF_TEST_STR_INCR;
204 buf++;
205 }
206
207 return 1;
208}
209
210/**
211 * Global that determines how octets should be populated
212 * -1 means use value % MAX (below) to determine length
213 * 0, 1, ... means used that fixed length
214 *
215 * Note: Was 16K, but that made objects too big. May add flexibility
216 * to call populate with a max parameter for length
217 */
218int octets_pop_style = -1;
219#define OCTETS_MAX_VALUE (128) /* 16K was too big */
220#define OCTETS_MULTIPLIER 6367 /* A prime */
221
222int
223of_octets_populate(of_octets_t *octets, int value)
224{
225 if (octets_pop_style < 0) {
226 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
227 } else {
228 octets->bytes = octets_pop_style;
229 }
230
231 if (octets->bytes != 0) {
232 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
233 return 0;
234 }
235 of_test_str_fill(octets->data, value, octets->bytes);
236 value += 1;
237 }
238
239 return value;
240}
241
242int
243of_octets_check(of_octets_t *octets, int value)
244{
245 int len;
246
247 if (octets_pop_style < 0) {
248 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
249 TEST_ASSERT(octets->bytes == len);
250 } else {
251 TEST_ASSERT(octets->bytes == octets_pop_style);
252 }
253
254 if (octets->bytes != 0) {
255 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
256 == 1);
257 value += 1;
258 }
259
260 return value;
261}
262
263int
264of_match_populate(of_match_t *match, of_version_t version, int value)
265{
266 MEMSET(match, 0, sizeof(*match));
267 match->version = version;
268""")
269
Rich Laned56f8d22014-05-06 14:52:55 -0700270 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700271 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700272 if (version == %d) {\
273""" % wire_version)
274 for key in keys:
275 entry = match.of_match_members[key]
276 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700277 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
278 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
279 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700280""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
281 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700282 }
283
Rich Laned56f8d22014-05-06 14:52:55 -0700284""")
285
Rich Laneb4a63a52014-05-22 14:41:57 -0700286 for wire_version, match_keys in match.match_keys.items():
287 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700288
289 out.write("""
290 if (value % 2) {
291 /* Sometimes set ipv4 addr masks to non-exact */
292 match->masks.ipv4_src = 0xffff0000;
293 match->masks.ipv4_dst = 0xfffff800;
294 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700295
296 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700297 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700298 return value;
299}
300
301int
302of_match_check(of_match_t *match, of_version_t version, int value)
303{
304 of_match_t check;
305
306 value = of_match_populate(&check, match->version, value);
307 TEST_ASSERT(value != 0);
308 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
309
310 return value;
311}
312""")
313
314def gen_common_test_header(out, name):
315 loxi_utils.gen_c_copy_license(out)
316 out.write("""
317/*
318 * Test header file
319 *
320 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
321 */
322
323#if !defined(_TEST_COMMON_H_)
324#define _TEST_COMMON_H_
325
326#define DISABLE_WARN_UNUSED_RESULT
327#include <loci/loci.h>
328#include <locitest/of_dup.h>
329#include <locitest/unittest.h>
330
331extern int global_error;
332extern int exit_on_error;
333
334/* @todo Make option for -k to continue tests if errors */
335#define RUN_TEST(test) do { \\
336 int rv; \\
337 TESTCASE(test, rv); \\
338 if (rv != TEST_PASS) { \\
339 global_error=1; \\
340 if (exit_on_error) return(1); \\
341 } \\
342 } while(0)
343
344#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
345#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
346
347/*
348 * Declarations of functions to populate scalar values in a a class
349 */
350
351extern void of_test_str_fill(uint8_t *buf, int value, int len);
352extern int of_test_str_check(uint8_t *buf, int value, int len);
353
354
355extern int of_octets_populate(of_octets_t *octets, int value);
356extern int of_octets_check(of_octets_t *octets, int value);
357extern int of_match_populate(of_match_t *match, of_version_t version,
358 int value);
359extern int of_match_check(of_match_t *match, of_version_t version, int value);
360extern int test_ident_macros(void);
361extern int test_dump_objs(void);
362
363/* In test_match_utils.c */
364extern int test_match_utils(void);
365
366extern int run_unified_accessor_tests(void);
367extern int run_match_tests(void);
368extern int run_utility_tests(void);
369
370extern int run_scalar_acc_tests(void);
371extern int run_list_tests(void);
372extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700373
374extern int run_validator_tests(void);
375
376extern int run_list_limits_tests(void);
377
378extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700379extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700380
381""")
382
383 for version in of_g.of_version_range:
384 for cls in of_g.standard_class_order:
385 if not loxi_utils.class_in_version(cls, version):
386 continue
Rich Lane6171e632014-11-07 10:23:38 -0800387 if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700388 continue
389 out.write("""
390extern int %(cls)s_%(v_name)s_populate(
391 %(cls)s_t *obj, int value);
392extern int %(cls)s_%(v_name)s_check(
393 %(cls)s_t *obj, int value);
394extern int %(cls)s_%(v_name)s_populate_scalars(
395 %(cls)s_t *obj, int value);
396extern int %(cls)s_%(v_name)s_check_scalars(
397 %(cls)s_t *obj, int value);
398""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
399
Rich Lanea06d0c32013-03-25 08:52:03 -0700400 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
401
402def gen_common_test(out, name):
403 """
404 Generate common test content including main
405 """
406 loxi_utils.gen_c_copy_license(out)
407 out.write("""
408/*
409 * Common test code for LOCI
410 *
411 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
412 */
413
414#define DISABLE_WARN_UNUSED_RESULT
415#include "loci_log.h"
416#include <loci/loci_obj_dump.h>
417#include <locitest/unittest.h>
418#include <locitest/test_common.h>
419
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900420/* mcheck is a glibc extension */
421#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700422#include <mcheck.h>
423#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900424#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700425#define MCHECK_INIT do { } while (0)
426#endif
427
428/**
429 * Exit on error if set to 1
430 */
431int exit_on_error = 1;
432
433/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700434 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700435 */
436int global_error = 0;
437
438extern int run_unified_accessor_tests(void);
439extern int run_match_tests(void);
440extern int run_utility_tests(void);
441
442extern int run_scalar_acc_tests(void);
443extern int run_list_tests(void);
444extern int run_message_tests(void);
445
446/**
447 * Macros for initializing and checking scalar types
448 *
449 * @param var The variable being initialized or checked
450 * @param val The integer value to set/check against, see below
451 *
452 * Note that equality means something special for strings. Each byte
453 * is initialized to an incrementing value. So check is done against that.
454 *
455 */
456
457""")
458 for t in scalar_types:
459 if t in integer_types:
460 out.write("""
461#define VAR_%s_INIT(var, val) var = (%s)(val)
462#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
463""" % (t.upper(), t, t.upper(), t))
464 else:
465 out.write("""
466#define VAR_%s_INIT(var, val) \\
467 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
468#define VAR_%s_CHECK(var, val) \\
469 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
470""" % (t.upper(), t.upper()))
471
472 gen_fill_string(out)
473 gen_scalar_set_check_funs(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700474 gen_unified_accessor_funs(out)
475
476 gen_ident_tests(out)
477 gen_log_test(out)
478
479def gen_message_scalar_test(out, name):
480 """
481 Generate test cases for message objects, scalar accessors
482 """
483
484 loxi_utils.gen_c_copy_license(out)
485 out.write("""
486/**
487 *
488 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
489 *
490 * Message-scalar tests for all versions
491 */
492
493#include <locitest/test_common.h>
494""")
495 for version in of_g.of_version_range:
496 v_name = loxi_utils.version_to_name(version)
497 out.write("""
498/**
499 * Message-scalar tests for version %s
500 */
501""" % v_name)
502 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800503 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700504 continue
505 if version in of_g.unified[cls]:
506 message_scalar_test(out, version, cls)
507
508 out.write("""
509int
510run_scalar_acc_tests(void)
511{
512""")
513 for version in of_g.of_version_range:
514 v_name = loxi_utils.version_to_name(version)
515 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800516 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700517 continue
518 if version in of_g.unified[cls]:
519 test_name = "%s_%s" % (cls, v_name)
520 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
521
522 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700523
Rich Lanea06d0c32013-03-25 08:52:03 -0700524def message_scalar_test(out, version, cls):
525 """
526 Generate one test case for the given version and class
527 """
528
529 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700530 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700531 v_name = loxi_utils.version_to_name(version)
532
533 out.write("""
534static int
535test_%(cls)s_%(v_name)s_scalar(void)
536{
537 %(cls)s_t *obj;
538
539 obj = %(cls)s_new(%(v_name)s);
540 TEST_ASSERT(obj != NULL);
541 TEST_ASSERT(obj->version == %(v_name)s);
542 TEST_ASSERT(obj->length == %(length)d);
543 TEST_ASSERT(obj->parent == NULL);
544 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700545""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700546 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700547
548 # If this class is a concrete member of an inheritance hierarchy,
549 # run the hierarchy's root wire type parser and assert it returns
550 # the expected object id.
551 ofclass = loxi_globals.unified.class_by_name(cls)
552 if ofclass and not ofclass.virtual:
553 root = ofclass
554 while root.superclass:
555 root = root.superclass
556 if root.virtual:
557 out.write("""
558 {
559 of_object_id_t object_id;
560 %(root_cls)s_wire_object_id_get(obj, &object_id);
561 TEST_ASSERT(object_id == %(u_cls)s);
562 }
563""" % dict(root_cls=root.name, u_cls=cls.upper()))
564
Rich Lanea06d0c32013-03-25 08:52:03 -0700565 if not type_maps.class_is_virtual(cls):
566 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700567 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700568 int length;
569
Rich Lanedc46fe22014-04-03 15:10:38 -0700570 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700571 TEST_ASSERT(length == %(length)d);
572 }
573
574 /* Set up incrementing values for scalar members */
575 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
576
577 /* Check values just set */
578 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700579""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700580 v_name=v_name, length=length, version=version))
581
582 out.write("""
583 %(cls)s_delete(obj);
584
585 /* To do: Check memory */
586 return TEST_PASS;
587}
588""" % dict(cls=cls))
589
590# Get the members and list of scalar types for members of a given class
591def scalar_member_types_get(cls, version):
592 member_types = []
593
594 if not version in of_g.unified[cls]:
595 return ([], [])
596
597 if "use_version" in of_g.unified[cls][version]:
598 v = of_g.unified[cls][version]["use_version"]
599 members = of_g.unified[cls][v]["members"]
600 else:
601 members = of_g.unified[cls][version]["members"]
602 # Accumulate variables that are supported
603 for member in members:
604 m_type = member["m_type"]
605 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700606 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700607 ignore_member(cls, version, m_name, m_type)):
608 continue
609 if not m_type in member_types:
610 member_types.append(m_type)
611
612 return (members, member_types)
613
614def scalar_funs_instance(out, cls, version, members, member_types):
615 """
616 Generate one instance of scalar set/check functions
617 """
618 out.write("""
619/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700620 * Populate the scalar values in obj of type %(cls)s,
621 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700622 * @param obj Pointer to an object to populate
623 * @param value The seed value to use in populating the object
624 * @returns The value after increments for this object's values
625 */
626int %(cls)s_%(v_name)s_populate_scalars(
627 %(cls)s_t *obj, int value) {
628""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
629 # Declare string types
630 for t in member_types:
631 out.write(" %s %s;\n" % (t, var_name_map(t)))
632 for member in members:
633 m_type = member["m_type"]
634 m_name = member["name"]
635 if (not loxi_utils.type_is_scalar(m_type) or
636 ignore_member(cls, version, m_name, m_type)):
637 continue
638 v_name = var_name_map(m_type);
639 out.write("""
640 VAR_%(u_type)s_INIT(%(v_name)s, value);
641 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
642 value += 1;
643""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
644 out.write("""
645 return value;
646}
647""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700648
Rich Lanea06d0c32013-03-25 08:52:03 -0700649 out.write("""
650/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700651 * Check scalar values in obj of type %(cls)s,
652 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700653 * @param obj Pointer to an object to check
654 * @param value Starting value for checking
655 * @returns The value after increments for this object's values
656 */
657int %(cls)s_%(v_name)s_check_scalars(
658 %(cls)s_t *obj, int value) {
659""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
660
661 for t in member_types:
662 out.write(" %s %s;\n" % (t, var_name_map(t)))
663 for member in members:
664 m_type = member["m_type"]
665 m_name = member["name"]
666 if (not loxi_utils.type_is_scalar(m_type) or
667 ignore_member(cls, version, m_name, m_type)):
668 continue
669 v_name = var_name_map(m_type);
670 out.write("""
671 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
672 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
673 value += 1;
674""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
675
676 out.write("""
677 return value;
678}
679
680""")
681
682def gen_scalar_set_check_funs(out):
683 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700684 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700685 set and check their values
686 """
687 for version in of_g.of_version_range:
688 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800689 if type_maps.class_is_virtual(cls):
Rich Lanee499bd12014-10-28 15:25:09 -0700690 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700691 (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
Rich Lane9afc3b92014-04-09 22:55:53 -0700696def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700697 base_type = loxi_utils.list_to_entry_type(cls)
698 setup_template = """
699 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700700 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700701 value = %(subcls)s_%(v_name)s_populate(
702 %(inst)s, value);
703 cur_len += %(inst)s->length;
704 TEST_ASSERT(list->length == cur_len);
705"""
706 out.write("""
707 /* Append two instances of type %s */
708""" % subcls)
709 for i in range(2):
710 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700711 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700712 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700713 version=version))
714
Rich Lane9afc3b92014-04-09 22:55:53 -0700715def check_instance(out, cls, subcls, instance, v_name, version, last):
716 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700717 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
718 value = %(subcls)s_%(v_name)s_check(
719 %(inst)s, value);
720 TEST_ASSERT(value != 0);
721"""
722 out.write("\n /* Check two instances of type %s */" % instance)
723
Andreas Wundsam53256162013-05-02 14:05:53 -0700724 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700725 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700726 inst=instance, subcls=subcls,
727 v_name=loxi_utils.version_to_name(version)))
728 out.write("""\
729 TEST_OK(%(cls)s_next(list, &elt));
730""" % dict(cls=cls))
731
Andreas Wundsam53256162013-05-02 14:05:53 -0700732 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700733 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700734 inst=instance, subcls=subcls,
735 v_name=loxi_utils.version_to_name(version)))
736 if last:
737 out.write("""\
738 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
739""" % dict(cls=cls))
740 else:
741 out.write("""\
742 TEST_OK(%(cls)s_next(list, &elt));
743""" % dict(cls=cls))
744
Rich Lanea06d0c32013-03-25 08:52:03 -0700745# Maybe: Get a map from list class to parent, mem_name of container
746
747def list_test(out, version, cls):
748 out.write("""
749static int
750test_%(cls)s_%(v_name)s(void)
751{
752""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
753 base_type = loxi_utils.list_to_entry_type(cls)
754
755 out.write(""" %(cls)s_t *list;
756 int value = 1;
757""" % dict(cls=cls, base_type=base_type))
758
759 out.write("""
760 list = %(cls)s_new(%(v_name)s);
761 TEST_ASSERT(list != NULL);
762 TEST_ASSERT(list->version == %(v_name)s);
763 TEST_ASSERT(list->length == 0);
764 TEST_ASSERT(list->parent == NULL);
765 TEST_ASSERT(list->object_id == %(enum_cls)s);
766
Rich Lanec6e97f72014-12-03 12:08:25 -0800767 value = %(cls)s_%(v_name)s_populate(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700768 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700769""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700770 enum_cls=loxi_utils.enum_name(cls)))
771
772 out.write("""
773 /* Now check values */
774 value = 1;
Rich Lanec6e97f72014-12-03 12:08:25 -0800775 value = %(cls)s_%(v_name)s_check(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700776 TEST_ASSERT(value != 0);
777""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
778
779 out.write("""
780 %(cls)s_delete(list);
781
782 return TEST_PASS;
783}
784""" % dict(cls=cls))
785
786def gen_list_test(out, name):
787 """
788 Generate base line test cases for lists
789 @param out The file handle to write to
790 """
791
792 loxi_utils.gen_c_copy_license(out)
793 out.write("""
794/**
795 *
796 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
797 *
798 * Message-scalar tests for all versions
799 */
800
801#include <locitest/test_common.h>
802""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700803
Rich Lanea06d0c32013-03-25 08:52:03 -0700804 for version in of_g.of_version_range:
805 v_name = loxi_utils.version_to_name(version)
806 out.write("""
807/**
808 * Baseline list tests for version %s
809 */
810""" % v_name)
811 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700812 if version in of_g.unified[cls]:
813 list_test(out, version, cls)
814
815 out.write("""
816int
817run_list_tests(void)
818{
819""")
820 for version in of_g.of_version_range:
821 v_name = loxi_utils.version_to_name(version)
822 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700823 if version in of_g.unified[cls]:
824 test_name = "%s_%s" % (cls, v_name)
825 out.write(" RUN_TEST(%s);\n" % test_name)
826
827 out.write("\n return TEST_PASS;\n}\n");
828
829def gen_match_test(out, name):
830 """
831 Generate baseline tests for match functions
832 """
833
834 loxi_utils.gen_c_copy_license(out)
835 out.write("""\
836/**
837 *
838 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
839 *
840 * Message-scalar tests for all versions
841 * @fixme These are mostly hard coded now.
842 */
843
844#include <locitest/test_common.h>
845
846static int
847test_match_1(void)
848{
Rich Lanef87f4c32014-10-14 11:56:02 -0700849""")
850
851 for version in of_g.of_version_range:
852 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
853
854 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700855 of_match_t match;
856 int value = 1;
857 int idx;
858 uint32_t exp_value;
859
860 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700861 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700862 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
863 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
864 if (idx < 32) {
865 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
866 }
867 }
868""")
869
870 for version in of_g.of_version_range:
871 out.write("""
872 /* Create/populate/convert and delete for version %(v_name)s */
873 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
874 TEST_ASSERT(m_v%(version)d != NULL);
875 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
876 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
877 of_match_v%(version)d_delete(m_v%(version)d);
878""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
879
880 out.write("""
881 return TEST_PASS;
882}
883""")
884
885 out.write("""
886static int
887test_match_2(void)
888{
Rich Lanef87f4c32014-10-14 11:56:02 -0700889""")
890
891 for version in of_g.of_version_range:
892 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
893
894 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700895 of_match_t match1;
896 of_match_t match2;
897 int value = 1;
898""")
899
900 for version in of_g.of_version_range:
901 out.write("""
902 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
903 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
904 TEST_ASSERT(m_v%(version)d != NULL);
905 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
906 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
907 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
908 of_match_v%(version)d_delete(m_v%(version)d);
909""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
910
911 out.write("""
912 return TEST_PASS;
913}
914""")
915
916 out.write("""
917static int
918test_match_3(void)
919{
920 of_match_t match1;
921 of_match_t match2;
922 int value = 1;
923 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -0700924 of_object_storage_t storage;
925 memset(&storage, 0, sizeof(storage));
926 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700927""")
928 for version in of_g.of_version_range:
929 out.write("""
930 /* Serialize to version %(v_name)s */
931 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700932 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700933 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -0700934 storage.obj.wbuf->buf = octets.data;
935 storage.obj.wbuf->alloc_bytes = octets.bytes;
936 storage.obj.wbuf->current_bytes = octets.bytes;
937 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700938 OF_ERROR_NONE);
939 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
940 FREE(octets.data);
941""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
942
943 out.write("""
944 return TEST_PASS;
945}
946""")
947
948 out.write("""
949int run_match_tests(void)
950{
951 RUN_TEST(match_1);
952 RUN_TEST(match_2);
953 RUN_TEST(match_3);
954 RUN_TEST(match_utils);
955
956 return TEST_PASS;
957}
958""")
959
960def gen_msg_test(out, name):
961 loxi_utils.gen_c_copy_license(out)
962 out.write("""
963/**
964 *
965 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
966 *
967 * Message-scalar tests for all versions
968 */
969
970#include <locitest/test_common.h>
971""")
972 for version in of_g.of_version_range:
973 for cls in of_g.ordered_messages:
974 if not (cls, version) in of_g.base_length:
975 continue
Rich Lane488b3c52013-06-21 18:11:02 -0700976 if type_maps.class_is_virtual(cls):
977 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -0700978 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700979 out.write("""
980static int
981test_%(cls)s_create_%(v_name)s(void)
982{
983 %(cls)s_t *obj;
984 uint8_t *msg_buf;
985 int value;
Rich Lanea4b68302014-03-12 15:17:58 -0700986 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -0700987 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700988
989 obj = %(cls)s_new(%(v_name)s);
990 TEST_ASSERT(obj != NULL);
991 TEST_ASSERT(obj->version == %(v_name)s);
992 TEST_ASSERT(obj->length == %(bytes)d);
993 TEST_ASSERT(obj->parent == NULL);
994 TEST_ASSERT(obj->object_id == %(enum)s);
995
Rich Lanea4b68302014-03-12 15:17:58 -0700996 of_header_wire_object_id_get(obj, &object_id);
997 TEST_ASSERT(object_id == %(enum)s);
998
Rich Lanea06d0c32013-03-25 08:52:03 -0700999 /* Set up incrementing values for scalar members */
1000 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1001 TEST_ASSERT(value != 0);
1002
Rich Lanebb8f17c2014-06-12 13:14:09 -07001003 len = obj->length;
1004
Rich Lanea06d0c32013-03-25 08:52:03 -07001005 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001006 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1007 TEST_ASSERT(msg_buf != NULL);
1008 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001009 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001010
1011 TEST_ASSERT(obj != NULL);
1012
1013 /* @fixme Set up all message objects (recursively?) */
1014
1015 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1016 TEST_ASSERT(value != 0);
1017
1018 %(cls)s_delete(obj);
1019
1020 return TEST_PASS;
1021}
1022""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1023 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1024
1025 out.write("""
1026int
1027run_message_tests(void)
1028{
1029""")
1030 for version in of_g.of_version_range:
1031 for cls in of_g.ordered_messages:
1032 if not (cls, version) in of_g.base_length:
1033 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001034 if type_maps.class_is_virtual(cls):
1035 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001036 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1037 out.write(" RUN_TEST(%s);\n" % test_name)
1038
1039 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001040
Rich Lanea06d0c32013-03-25 08:52:03 -07001041
1042def gen_list_setup_check(out, cls, version):
1043 """
1044 Generate functions that populate and check a list with two
1045 of each type of subclass it supports
1046 """
1047 out.write("""
1048/**
1049 * Populate a list of type %(cls)s with two of each type of subclass
1050 * @param list Pointer to the list to be populated
1051 * @param value The seed value to use in populating the list
1052 * @returns The value after increments for this object's values
1053 */
1054int
1055%(cls)s_%(v_name)s_populate(
1056 %(cls)s_t *list, int value)
1057{
1058""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1059 base_type = loxi_utils.list_to_entry_type(cls)
1060 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001061 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001062 int cur_len = 0;
Rich Lanead708032014-12-03 12:40:58 -08001063 static int recursion;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001064 (void) elt;
1065 (void) cur_len;
Rich Lanead708032014-12-03 12:40:58 -08001066
1067 if (recursion > 0) {
1068 return value;
1069 }
1070
1071 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001072""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001073
Rich Lanea06d0c32013-03-25 08:52:03 -07001074 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001075 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 -07001076 v_name = loxi_utils.version_to_name(version)
1077
Rich Lanee98ee5d2014-10-14 10:43:44 -07001078 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001079 out.write(" /* No subclasses for %s */\n"% base_type)
1080 out.write(" %s_t *elt_p;\n" % base_type)
1081 out.write("\n elt_p = &elt;\n")
1082 else:
1083 out.write(" /* Declare pointers for each subclass */\n")
1084 for instance, subcls in sub_classes:
1085 out.write(" %s_t *%s;\n" % (subcls, instance))
1086 out.write("\n /* Instantiate pointers for each subclass */\n")
1087 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001088 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001089
Rich Lanee98ee5d2014-10-14 10:43:44 -07001090 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001091 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001092 else:
1093 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001094 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001095 out.write("""
Rich Lanead708032014-12-03 12:40:58 -08001096 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001097 return value;
1098}
1099""")
1100 out.write("""
1101/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001102 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001103 * %(cls)s_%(v_name)s_populate
1104 * @param list Pointer to the list that was populated
1105 * @param value Starting value for checking
1106 * @returns The value after increments for this object's values
1107 */
1108int
1109%(cls)s_%(v_name)s_check(
1110 %(cls)s_t *list, int value)
1111{
1112""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1113 base_type = loxi_utils.list_to_entry_type(cls)
1114 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001115 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001116 int count = 0;
1117 int rv;
Rich Lanead708032014-12-03 12:40:58 -08001118 static int recursion;
1119
1120 if (recursion > 0) {
1121 return value;
1122 }
1123
1124 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001125""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001126
Rich Lanea06d0c32013-03-25 08:52:03 -07001127
1128 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001129 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 -07001130 v_name = loxi_utils.version_to_name(version)
1131
Rich Lanee98ee5d2014-10-14 10:43:44 -07001132 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001133 entry_count = 2
1134 out.write(" /* No subclasses for %s */\n"% base_type)
1135 out.write(" %s_t *elt_p;\n" % base_type)
1136 out.write("\n elt_p = &elt;\n")
1137 else:
1138 entry_count = 2 * len(sub_classes) # Two of each type appended
1139 out.write(" /* Declare pointers for each subclass */\n")
1140 for instance, subcls in sub_classes:
1141 out.write(" %s_t *%s;\n" % (subcls, instance))
1142 out.write("\n /* Instantiate pointers for each subclass */\n")
1143 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001144 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001145
Rich Lanee98ee5d2014-10-14 10:43:44 -07001146 if not type_maps.class_is_virtual(base_type) or sub_classes:
1147 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1148
1149 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001150 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001151 version, True)
1152 else:
1153 count = 0
1154 for instance, subcls in sub_classes:
1155 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001156 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001157 version, count==len(sub_classes))
1158 out.write("""
1159""" % dict(base_type=base_type))
1160
1161 out.write("""
1162 /* Do an iterate to test the iterator */
1163 %(u_cls)s_ITER(list, &elt, rv) {
1164 count += 1;
1165 }
1166
1167 TEST_ASSERT(rv == OF_ERROR_RANGE);
1168 TEST_ASSERT(count == %(entry_count)d);
1169
1170 /* We shoehorn a test of the dup functions here */
1171 {
1172 %(cls)s_t *dup;
1173
1174 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1175 TEST_ASSERT(dup->length == list->length);
1176 TEST_ASSERT(dup->object_id == list->object_id);
1177 TEST_ASSERT(dup->version == list->version);
1178 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1179 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1180 of_object_delete((of_object_t *)dup);
1181
1182 /* And now for the generic dup function */
1183 TEST_ASSERT((dup = (%(cls)s_t *)
1184 of_object_dup(list)) != NULL);
1185 TEST_ASSERT(dup->length == list->length);
1186 TEST_ASSERT(dup->object_id == list->object_id);
1187 TEST_ASSERT(dup->version == list->version);
1188 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1189 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1190 of_object_delete((of_object_t *)dup);
1191 }
1192
Rich Lanead708032014-12-03 12:40:58 -08001193 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001194 return value;
1195}
1196""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1197
1198
1199def gen_class_setup_check(out, cls, version):
1200 out.write("""
1201/**
1202 * Populate all members of an object of type %(cls)s
1203 * with incrementing values
1204 * @param obj Pointer to an object to populate
1205 * @param value The seed value to use in populating the object
1206 * @returns The value after increments for this object's values
1207 */
1208
1209int
1210%(cls)s_%(v_name)s_populate(
1211 %(cls)s_t *obj, int value)
1212{
1213""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1214 members, member_types = loxi_utils.all_member_types_get(cls, version)
1215 for m_type in member_types:
1216 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1217 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001218 elif m_type in embedded_subclasses:
1219 subcls = embedded_subclasses[m_type]
1220 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001221 else:
1222 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1223 out.write("""
1224 /* Run thru accessors after new to ensure okay */
1225""")
1226 for member in members:
1227 m_type = member["m_type"]
1228 m_name = member["name"]
1229 if loxi_utils.skip_member_name(m_name):
1230 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001231 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001232 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001233 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1234 out.write("""\
1235 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1236""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1237 else:
1238 sub_cls = m_type[:-2] # Trim _t
1239 out.write("""\
1240 {
1241 %(sub_cls)s_t sub_cls;
1242
1243 /* Test bind */
1244 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1245 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001246""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001247 m_name=m_name, sub_cls=sub_cls,
1248 v_name=loxi_utils.version_to_name(version)))
1249
1250 out.write("""
1251 value = %(cls)s_%(v_name)s_populate_scalars(
1252 obj, value);
1253 TEST_ASSERT(value != 0);
1254""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1255
1256 for member in members:
1257 m_type = member["m_type"]
1258 m_name = member["name"]
1259 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1260 continue
1261 if loxi_utils.skip_member_name(m_name):
1262 continue
1263 if m_type == "of_match_t":
1264 out.write("""\
1265 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1266 TEST_ASSERT(value != 0);
1267 %(cls)s_%(m_name)s_set(
1268 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001269""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001270 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1271 elif m_type == "of_octets_t":
1272 out.write("""\
1273 value = of_octets_populate(&%(var_name)s, value);
1274 TEST_ASSERT(value != 0);
1275 %(cls)s_%(m_name)s_set(
1276 obj, &%(var_name)s);
1277 if (octets.bytes) {
1278 FREE(octets.data);
1279 }
1280""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001281 elif m_type in embedded_subclasses:
1282 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001283 out.write("""\
1284 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1285 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001286 value = %(sub_cls)s_%(v_name)s_populate(
1287 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001288 TEST_ASSERT(value != 0);
1289 %(cls)s_%(m_name)s_set(
1290 obj, %(var_name)s);
1291 %(sub_cls)s_delete(%(var_name)s);
1292""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1293 var_name=var_name_map(m_type),
1294 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001295 else:
1296 sub_cls = m_type[:-2] # Trim _t
1297 out.write("""
1298 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1299 TEST_ASSERT(%(var_name)s != NULL);
1300 value = %(sub_cls)s_%(v_name)s_populate(
1301 %(var_name)s, value);
1302 TEST_ASSERT(value != 0);
1303 %(cls)s_%(m_name)s_set(
1304 obj, %(var_name)s);
1305 %(sub_cls)s_delete(%(var_name)s);
1306""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1307 var_name=var_name_map(m_type),
1308 v_name=loxi_utils.version_to_name(version)))
1309
1310 out.write("""
1311 return value;
1312}
1313""")
1314
1315 out.write("""
1316/**
1317 * Check all members of an object of type %(cls)s
1318 * populated by the above function
1319 * @param obj Pointer to an object to check
1320 * @param value Starting value for checking
1321 * @returns The value after increments for this object's values
1322 */
1323
1324int
1325%(cls)s_%(v_name)s_check(
1326 %(cls)s_t *obj, int value)
1327{
1328""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1329 members, member_types = loxi_utils.all_member_types_get(cls, version)
1330 for m_type in member_types:
1331 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1332 continue
1333 if loxi_utils.type_is_of_object(m_type):
1334 continue
1335 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1336 out.write("""
1337 value = %(cls)s_%(v_name)s_check_scalars(
1338 obj, value);
1339 TEST_ASSERT(value != 0);
1340""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1341
1342 for member in members:
1343 m_type = member["m_type"]
1344 m_name = member["name"]
1345 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1346 continue
1347 if loxi_utils.skip_member_name(m_name):
1348 continue
1349 if m_type == "of_match_t":
1350 out.write("""\
1351 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1352 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1353""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1354 v_name=loxi_utils.version_to_name(version)))
1355 elif m_type == "of_octets_t":
1356 out.write("""\
1357 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1358 value = of_octets_check(&%(var_name)s, value);
1359""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1360 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001361 elif m_type in embedded_subclasses:
1362 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001363 out.write("""
1364 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001365 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001366
1367 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1368 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001369 value = %(sub_cls)s_%(v_name)s_check(
1370 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001371 TEST_ASSERT(value != 0);
1372 %(sub_cls)s_delete(%(m_name)s_ptr);
1373 }
1374""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1375 var_name=var_name_map(m_type),
1376 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001377 else:
1378 sub_cls = m_type[:-2] # Trim _t
1379 out.write("""
1380 { /* Use get/delete to access on check */
1381 %(m_type)s *%(m_name)s_ptr;
1382
1383 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1384 TEST_ASSERT(%(m_name)s_ptr != NULL);
1385 value = %(sub_cls)s_%(v_name)s_check(
1386 %(m_name)s_ptr, value);
1387 TEST_ASSERT(value != 0);
1388 %(sub_cls)s_delete(%(m_name)s_ptr);
1389 }
1390""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1391 var_name=var_name_map(m_type),
1392 v_name=loxi_utils.version_to_name(version)))
1393
1394 out.write("""
1395 /* We shoehorn a test of the dup functions here */
1396 {
1397 %(cls)s_t *dup;
1398
1399 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1400 TEST_ASSERT(dup->length == obj->length);
1401 TEST_ASSERT(dup->object_id == obj->object_id);
1402 TEST_ASSERT(dup->version == obj->version);
1403 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1404 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1405 of_object_delete((of_object_t *)dup);
1406
1407 /* And now for the generic dup function */
1408 TEST_ASSERT((dup = (%(cls)s_t *)
1409 of_object_dup(obj)) != NULL);
1410 TEST_ASSERT(dup->length == obj->length);
1411 TEST_ASSERT(dup->object_id == obj->object_id);
1412 TEST_ASSERT(dup->version == obj->version);
1413 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1414 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1415 of_object_delete((of_object_t *)dup);
1416 }
1417
1418 return value;
1419}
1420""" % dict(cls=cls))
1421
1422def unified_accessor_test_case(out, cls, version):
1423 """
1424 Generate one test case for the given version and class
1425 """
1426
1427 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001428 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001429 v_name = loxi_utils.version_to_name(version)
1430
1431 out.write("""
1432static int
1433test_%(cls)s_%(v_name)s(void)
1434{
1435 %(cls)s_t *obj;
1436 obj = %(cls)s_new(%(v_name)s);
1437 TEST_ASSERT(obj != NULL);
1438 TEST_ASSERT(obj->version == %(v_name)s);
1439 TEST_ASSERT(obj->length == %(length)d);
1440 TEST_ASSERT(obj->parent == NULL);
1441 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001442""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001443 v_name=v_name, length=length, version=version))
1444 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1445 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001446 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001447 int length;
1448
Rich Lanedc46fe22014-04-03 15:10:38 -07001449 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001450 TEST_ASSERT(length == %(length)d);
1451 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001452 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001453 of_object_id_t obj_id;
1454
Rich Lanedc46fe22014-04-03 15:10:38 -07001455 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001456 TEST_ASSERT(obj_id == %(u_cls)s);
1457 }
1458
1459 /* Set up incrementing values for members */
1460 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1461 obj, 1) != 0);
1462
1463 /* Check values just set */
1464 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1465 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001466""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001467 v_name=v_name, length=length, version=version))
1468
1469 out.write("""
1470 %(cls)s_delete(obj);
1471
1472 /* To do: Check memory */
1473 return TEST_PASS;
1474}
1475""" % dict(cls=cls))
1476
1477
1478def gen_unified_accessor_funs(out):
1479 for version in of_g.of_version_range:
1480 for cls in of_g.standard_class_order:
1481 if not loxi_utils.class_in_version(cls, version):
1482 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001483 elif loxi_utils.class_is_list(cls):
1484 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001485 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001486 gen_class_setup_check(out, cls, version)
1487
1488def gen_unified_accessor_tests(out, name):
1489 loxi_utils.gen_c_copy_license(out)
1490 out.write("""
1491/**
1492 *
1493 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1494 *
1495 * Unified simple class instantiation tests for all versions
1496 */
1497
1498#include <locitest/test_common.h>
1499""")
1500 for version in of_g.of_version_range:
1501 for cls in of_g.standard_class_order:
1502 if not loxi_utils.class_in_version(cls, version):
1503 continue
Rich Lane6171e632014-11-07 10:23:38 -08001504 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001505 continue
1506 unified_accessor_test_case(out, cls, version)
1507
1508 out.write("""
1509int
1510run_unified_accessor_tests(void)
1511{
1512""")
1513 for version in of_g.of_version_range:
1514 v_name = loxi_utils.version_to_name(version)
1515 for cls in of_g.standard_class_order:
1516 if not loxi_utils.class_in_version(cls, version):
1517 continue
Rich Lane6171e632014-11-07 10:23:38 -08001518 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001519 continue
1520 test_name = "%s_%s" % (cls, v_name)
1521 out.write(" RUN_TEST(%s);\n" % test_name)
1522
1523 out.write(" return TEST_PASS;\n}\n");
1524
1525
1526
1527################################################################
1528#
1529# Object duplication functions
1530#
1531# These exercise the accessors to create duplicate objects.
1532# They are used in the LOCI test shim which sits in an OF
1533# protocol stream.
1534#
1535# TODO
1536# Resolve version stuff
1537# Complete list dup
1538
1539def gen_dup_list(out, cls, version):
1540 ver_name = loxi_utils.version_to_name(version)
1541 elt_type = loxi_utils.list_to_entry_type(cls)
1542 out.write("""
1543/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001544 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001545 * using accessor functions
1546 * @param src Pointer to object to be duplicated
1547 * @returns A new object of type %(cls)s.
1548 *
1549 * The caller is responsible for deleting the returned value
1550 */
1551%(cls)s_t *
1552%(cls)s_%(ver_name)s_dup(
1553 %(cls)s_t *src)
1554{
Rich Lanee499bd12014-10-28 15:25:09 -07001555 of_object_t src_elt;
1556 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001557 int rv;
1558 %(cls)s_t *dst;
1559
1560 if ((dst = %(cls)s_new(src->version)) == NULL) {
1561 return NULL;
1562 }
1563""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1564
1565 out.write("""
1566 %(u_cls)s_ITER(src, &src_elt, rv) {
1567 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1568 of_object_delete((of_object_t *)dst);
1569 return NULL;
1570 }
1571 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1572 dst, NULL);
1573 of_object_delete((of_object_t *)dst_elt);
1574 }
1575
1576 return dst;
1577}
1578""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1579
1580
1581def gen_dup_inheritance(out, cls, version):
1582 ver_name = loxi_utils.version_to_name(version)
1583 out.write("""
1584/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001585 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001586 * @param src Pointer to object to be duplicated
1587 * @returns A new object of type %(cls)s.
1588 *
1589 * The caller is responsible for deleting the returned value
1590 */
Rich Lanee499bd12014-10-28 15:25:09 -07001591of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001592%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001593 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001594{
1595""" % dict(cls=cls, ver_name=ver_name))
1596
1597 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001598 sub_classes = type_maps.sub_class_map(cls, version)
1599 for (_, sub_cls) in sub_classes:
1600 sub_enum = sub_cls.upper()
Rich Lane6171e632014-11-07 10:23:38 -08001601 if type_maps.class_is_virtual(sub_cls):
1602 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001603 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001604 if (src->object_id == %(sub_enum)s) {
1605 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001606 }
1607""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1608
1609 out.write("""
1610 return NULL;
1611}
1612""")
1613
1614
1615def gen_dup_cls(out, cls, version):
1616 """
1617 Generate duplication routine for class cls
1618 """
1619 ver_name = loxi_utils.version_to_name(version)
1620
1621 out.write("""
1622/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001623 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001624 * using accessor functions
1625 * @param src Pointer to object to be duplicated
1626 * @returns A new object of type %(cls)s.
1627 *
1628 * The caller is responsible for deleting the returned value
1629 */
1630%(cls)s_t *
1631%(cls)s_%(ver_name)s_dup(
1632 %(cls)s_t *src)
1633{
1634 %(cls)s_t *dst;
1635""" % dict(cls=cls, ver_name=ver_name))
1636
1637 # Get members and types for the class
1638 members, member_types = loxi_utils.all_member_types_get(cls, version)
1639
1640 # Add declarations for each member type
1641 for m_type in member_types:
1642 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1643 # Declare instance of these
1644 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001645 elif m_type in embedded_subclasses:
1646 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001647 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001648 %(sub_cls)s_t src_%(v_name)s;
1649 %(sub_cls)s_t *dst_%(v_name)s;
1650""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001651 else:
1652 out.write("""
1653 %(m_type)s src_%(v_name)s;
1654 %(m_type)s *dst_%(v_name)s;
1655""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1656
1657 out.write("""
1658 if ((dst = %(cls)s_new(src->version)) == NULL) {
1659 return NULL;
1660 }
1661""" % dict(cls=cls))
1662
1663 for member in members:
1664 m_type = member["m_type"]
1665 m_name = member["name"]
1666 if loxi_utils.skip_member_name(m_name):
1667 continue
1668 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1669 out.write("""
1670 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1671 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1672""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1673 elif m_type in ["of_match_t", "of_octets_t"]:
1674 out.write("""
1675 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1676 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1677""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001678 elif m_type in embedded_subclasses:
1679 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001680 out.write("""
1681 %(cls)s_%(m_name)s_bind(
1682 src, &src_%(v_name)s);
1683 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1684 if (dst_%(v_name)s == NULL) {
1685 %(cls)s_delete(dst);
1686 return NULL;
1687 }
1688 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1689 %(sub_cls)s_delete(dst_%(v_name)s);
1690""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1691 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001692 else:
1693 sub_cls = m_type[:-2] # Trim _t
1694 out.write("""
1695 %(cls)s_%(m_name)s_bind(
1696 src, &src_%(v_name)s);
1697 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1698 if (dst_%(v_name)s == NULL) {
1699 %(cls)s_delete(dst);
1700 return NULL;
1701 }
1702 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1703 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001704""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001705 v_name=var_name_map(m_type), ver_name=ver_name))
1706
1707 out.write("""
1708 return dst;
1709}
1710""")
1711
1712def gen_version_dup(out=sys.stdout):
1713 """
1714 Generate duplication routines for each object type
1715 """
1716 out.write("""
1717/* Special try macro for duplicating */
1718#define _TRY_FREE(op, obj, rv) do { \\
1719 int _rv; \\
1720 if ((_rv = (op)) < 0) { \\
1721 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1722 of_object_delete((of_object_t *)(obj)); \\
1723 return (rv); \\
1724 } \\
1725 } while (0)
1726""")
1727
1728 for version in of_g.of_version_range:
1729 for cls in of_g.standard_class_order:
1730 if not loxi_utils.class_in_version(cls, version):
1731 continue
Rich Lane8841f352014-10-12 19:18:36 -07001732 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001733 gen_dup_inheritance(out, cls, version)
1734 elif loxi_utils.class_is_list(cls):
1735 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001736 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001737 gen_dup_cls(out, cls, version)
1738
1739def gen_dup(out=sys.stdout):
1740 """
1741 Generate non-version specific duplication routines for each object type
1742 """
1743
1744 for cls in of_g.standard_class_order:
1745 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001746of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001747%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001748 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001749{
1750""" % dict(cls=cls))
1751 for version in of_g.of_version_range:
1752 if not loxi_utils.class_in_version(cls, version):
1753 continue
Rich Lane6171e632014-11-07 10:23:38 -08001754 elif type_maps.class_is_inheritance_root(cls):
1755 pass
1756 elif loxi_utils.class_is_list(cls):
1757 pass
1758 elif type_maps.class_is_virtual(cls):
1759 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001760 ver_name = loxi_utils.version_to_name(version)
1761 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001762 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001763 return %(cls)s_%(ver_name)s_dup(src);
1764 }
Rich Lanee499bd12014-10-28 15:25:09 -07001765""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001766
1767 out.write("""
1768 /* Class not supported in given version */
1769 return NULL;
1770}
1771""")
1772
1773def dup_c_gen(out, name):
1774 """
1775 Generate the C file for duplication functions
1776 """
1777 loxi_utils.gen_c_copy_license(out)
1778 out.write("""\
1779/*
1780 * Duplication functions for all OF objects
1781 *
1782 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1783 *
1784 * These are test functions for exercising accessors. You can call
1785 * of_object_dup for an efficient duplication.
1786 */
1787
1788#define DISABLE_WARN_UNUSED_RESULT
1789#include "loci_log.h"
1790#include <locitest/of_dup.h>
1791
1792""")
1793
1794 gen_version_dup(out)
1795 gen_dup(out)
1796
1797
1798def dup_h_gen(out, name):
1799 """
1800 Generate the header file for duplication functions
1801 """
1802
1803 loxi_utils.gen_c_copy_license(out)
1804 out.write("""
1805/*
1806 * Duplication function header file
1807 *
1808 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1809 */
1810
1811#if !defined(_OF_DUP_H_)
1812#define _OF_DUP_H_
1813
1814#include <loci/loci.h>
1815""")
1816
1817 for cls in of_g.standard_class_order:
1818 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001819extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001820 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001821 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001822""" % dict(cls=cls))
1823
1824 for version in of_g.of_version_range:
1825 for cls in of_g.standard_class_order:
1826 if not loxi_utils.class_in_version(cls, version):
1827 continue
Rich Lane6171e632014-11-07 10:23:38 -08001828 elif type_maps.class_is_inheritance_root(cls):
1829 pass
1830 elif loxi_utils.class_is_list(cls):
1831 pass
1832 elif type_maps.class_is_virtual(cls):
1833 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001834 ver_name = loxi_utils.version_to_name(version)
1835 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001836extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001837 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001838 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001839""" % dict(cls=cls, ver_name=ver_name))
1840
1841 out.write("\n#endif /* _OF_DUP_H_ */\n")
1842
1843def gen_log_test(out):
1844 """
1845 Generate test for obj log calls
1846
1847 Define a trivial handler for object logging; call all obj log fns
1848 """
1849 out.write("""
1850
1851/**
1852 * Test object dump functions
1853 */
1854
1855int
1856test_dump_objs(void)
1857{
1858 of_object_t *obj;
1859
1860 FILE *out = fopen("/dev/null", "w");
1861
1862 /* Call each obj dump function */
1863""")
1864 for version in of_g.of_version_range:
1865 for j, cls in enumerate(of_g.all_class_order):
1866 if not loxi_utils.class_in_version(cls, version):
1867 continue
Rich Lane6171e632014-11-07 10:23:38 -08001868 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001869 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001870 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1871 out.write("""
1872 obj = (of_object_t *)%(cls)s_new(%(version)s);
1873 {
1874 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1875 %(cls)s_vport_set(obj, vport);
1876 of_object_delete(vport);
1877 }
1878 of_object_dump((loci_writer_f)fprintf, out, obj);
1879 of_object_delete(obj);
1880""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1881 else:
1882 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001883 obj = (of_object_t *)%(cls)s_new(%(version)s);
1884 of_object_dump((loci_writer_f)fprintf, out, obj);
1885 of_object_delete(obj);
1886""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001887
Rich Lanea06d0c32013-03-25 08:52:03 -07001888 out.write("""
1889 fclose(out);
1890 return TEST_PASS;
1891}
1892""")
1893
1894def gen_ident_tests(out):
1895 """
1896 Generate tests for identifiers
1897
1898 For all idents, instantiate, test version supported macros
1899 For flags, set it, test it, clear it, test it.
1900 """
1901 out.write("""
1902/**
1903 * Test cases for all flag accessor macros
1904 * These only test self consistency (and that they compile)
1905 */
1906int
1907test_ident_macros(void)
1908{
1909 int value __attribute__((unused));
1910 uint32_t flags;
1911
1912""")
1913
1914 for ident, info in of_g.identifiers.items():
1915 if not identifiers.defined_versions_agree(of_g.identifiers,
1916 of_g.target_version_list,
1917 ident):
1918 # @fixme
1919 continue
1920 out.write(" value = %s;\n" % ident)
1921 for version in of_g.target_version_list:
1922 if version in info["values_by_version"].keys():
1923 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1924 (ident, of_g.of_version_wire2name[version]))
1925 else:
1926 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1927 (ident, of_g.of_version_wire2name[version]))
1928 if flags.ident_is_flag(ident):
1929 # Grab first supported version
1930 for version in info["values_by_version"]:
1931 break
1932 out.write("""
1933 flags = 0;
1934 %(ident)s_SET(flags, %(ver_name)s);
1935 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1936 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1937 %(ident)s_CLEAR(flags, %(ver_name)s);
1938 TEST_ASSERT(flags == 0);
1939 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1940""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1941
1942 out.write("""
1943 return TEST_PASS;
1944}
1945""")
1946
Rich Laneccae0312013-07-21 23:34:13 -07001947def gen_datafiles_tests(out, name):
1948 tests = []
1949 for filename in test_data.list_files():
1950 data = test_data.read(filename)
1951 if not 'c' in data:
1952 continue
1953 name = filename[:-5].replace("/", "_")
1954 tests.append(dict(name=name,
1955 filename=filename,
1956 c=data['c'],
1957 binary=data['binary']))
1958
1959 util.render_template(out, "test_data.c", tests=tests)