blob: 50d496b1bdef3ce6f596188d0ce8b7f8fc109326 [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",
Brian O'Connor58a73e32015-05-28 11:51:27 -070096 of_str32_t="str32",
97 of_str6_t="str6",
Andreas Wundsam53256162013-05-02 14:05:53 -070098 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070099 of_ipv6_t="ipv6",
100 # Non-scalars; more TBD
101 of_octets_t="octets",
102 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700103 of_match_t="match",
Rich Lanec247ade2014-11-07 09:33:24 -0800104 of_oxm_t="oxm",
105 of_bsn_vport_t="bsn_vport",
Rich Lane41b278f2014-10-17 18:29:56 -0700106 of_table_desc_t="table_desc",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700107 # BSN extensions
108 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700109 of_bitmap_128_t="bitmap_128",
Rich Lane119289c2014-12-01 13:44:08 -0800110 of_bitmap_512_t="bitmap_512",
Rich Lanefab0c822013-12-30 11:46:48 -0800111 of_checksum_128_t="checksum_128",
Praseed Balakrishnanf78068b2014-09-04 10:30:40 -0700112 #Circuit extensions
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700113 of_app_code_t="app_code",
Praseed Balakrishnan2ed6da02014-09-18 17:02:48 -0700114 of_sig_id_t="sig_id",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700115 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700116
117 if m_type.find("of_list_") == 0:
118 return "list"
119 if m_type in of_g.of_mixed_types:
120 return of_g.of_mixed_types[m_type]["short_name"]
121 return _var_name_map[m_type]
122
123integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
124 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700125 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700126string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700127 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700128 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
Brian O'Connor58a73e32015-05-28 11:51:27 -0700129 "of_str64_t", "of_str32_t", "of_str6_t",
130 "of_app_code_t", "of_bitmap_512_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700131
132scalar_types = integer_types[:]
133scalar_types.extend(string_types)
134
Rich Lane1f315aa2014-10-13 17:11:35 -0700135# When embedding an object inside of another object we have to pick a single
136# subclass to use, unlike lists where we use all subclasses.
137embedded_subclasses = {
Rich Lanec247ade2014-11-07 09:33:24 -0800138 'of_oxm_t': 'of_oxm_eth_type',
139 'of_bsn_vport_t': 'of_bsn_vport_q_in_q',
Rich Lane1f315aa2014-10-13 17:11:35 -0700140}
141
Rich Lanea06d0c32013-03-25 08:52:03 -0700142def ignore_member(cls, version, m_name, m_type):
143 """
144 Filter out names or types that either don't have accessors
145 or those that should not be messed with
146 or whose types we're not ready to deal with yet.
147 """
Rich Lane79c87192014-03-04 10:56:59 -0800148
149 uclass = loxi_globals.unified.class_by_name(cls)
150 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700151 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800152
Rich Lane79c87192014-03-04 10:56:59 -0800153 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800154 return True
Rich Lane79c87192014-03-04 10:56:59 -0800155
Rich Lanea06d0c32013-03-25 08:52:03 -0700156 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
157
158def gen_fill_string(out):
159 out.write("""
160
161/**
162 * The increment to use on values inside a string
163 */
164#define OF_TEST_STR_INCR 3
165
166/**
167 * Fill in a buffer with incrementing values starting
168 * at the given offset with the given value
169 * @param buf The buffer to fill
170 * @param value The value to use for data
171 * @param len The number of bytes to fill
172 */
173
174void
175of_test_str_fill(uint8_t *buf, int value, int len)
176{
177 int i;
178
179 for (i = 0; i < len; i++) {
180 *buf = value;
181 value += OF_TEST_STR_INCR;
182 buf++;
183 }
184}
185
186/**
187 * Given a buffer, verify that it's filled as above
188 * @param buf The buffer to check
189 * @param value The value to use for data
190 * @param len The number of bytes to fill
191 * @return Boolean True on equality (success)
192 */
193
194int
195of_test_str_check(uint8_t *buf, int value, int len)
196{
197 int i;
198 uint8_t val8;
199
200 val8 = value;
201
202 for (i = 0; i < len; i++) {
203 if (*buf != val8) {
204 return 0;
205 }
206 val8 += OF_TEST_STR_INCR;
207 buf++;
208 }
209
210 return 1;
211}
212
213/**
214 * Global that determines how octets should be populated
215 * -1 means use value % MAX (below) to determine length
216 * 0, 1, ... means used that fixed length
217 *
218 * Note: Was 16K, but that made objects too big. May add flexibility
219 * to call populate with a max parameter for length
220 */
221int octets_pop_style = -1;
222#define OCTETS_MAX_VALUE (128) /* 16K was too big */
223#define OCTETS_MULTIPLIER 6367 /* A prime */
224
225int
226of_octets_populate(of_octets_t *octets, int value)
227{
228 if (octets_pop_style < 0) {
229 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
230 } else {
231 octets->bytes = octets_pop_style;
232 }
233
234 if (octets->bytes != 0) {
235 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
236 return 0;
237 }
238 of_test_str_fill(octets->data, value, octets->bytes);
239 value += 1;
240 }
241
242 return value;
243}
244
245int
246of_octets_check(of_octets_t *octets, int value)
247{
248 int len;
249
250 if (octets_pop_style < 0) {
251 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
252 TEST_ASSERT(octets->bytes == len);
253 } else {
254 TEST_ASSERT(octets->bytes == octets_pop_style);
255 }
256
257 if (octets->bytes != 0) {
258 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
259 == 1);
260 value += 1;
261 }
262
263 return value;
264}
265
266int
267of_match_populate(of_match_t *match, of_version_t version, int value)
268{
269 MEMSET(match, 0, sizeof(*match));
270 match->version = version;
271""")
272
Rich Laned56f8d22014-05-06 14:52:55 -0700273 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700274 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700275 if (version == %d) {\
276""" % wire_version)
277 for key in keys:
278 entry = match.of_match_members[key]
279 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700280 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
281 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
282 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700283""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
284 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700285 }
286
Rich Laned56f8d22014-05-06 14:52:55 -0700287""")
288
Rich Laneb4a63a52014-05-22 14:41:57 -0700289 for wire_version, match_keys in match.match_keys.items():
290 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700291
292 out.write("""
293 if (value % 2) {
294 /* Sometimes set ipv4 addr masks to non-exact */
295 match->masks.ipv4_src = 0xffff0000;
296 match->masks.ipv4_dst = 0xfffff800;
297 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700298
299 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700300 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700301 return value;
302}
303
304int
305of_match_check(of_match_t *match, of_version_t version, int value)
306{
307 of_match_t check;
308
309 value = of_match_populate(&check, match->version, value);
310 TEST_ASSERT(value != 0);
311 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
312
313 return value;
314}
315""")
316
317def gen_common_test_header(out, name):
318 loxi_utils.gen_c_copy_license(out)
319 out.write("""
320/*
321 * Test header file
322 *
323 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
324 */
325
326#if !defined(_TEST_COMMON_H_)
327#define _TEST_COMMON_H_
328
329#define DISABLE_WARN_UNUSED_RESULT
330#include <loci/loci.h>
331#include <locitest/of_dup.h>
332#include <locitest/unittest.h>
333
334extern int global_error;
335extern int exit_on_error;
336
337/* @todo Make option for -k to continue tests if errors */
338#define RUN_TEST(test) do { \\
339 int rv; \\
340 TESTCASE(test, rv); \\
341 if (rv != TEST_PASS) { \\
342 global_error=1; \\
343 if (exit_on_error) return(1); \\
344 } \\
345 } while(0)
346
347#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
348#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
349
350/*
351 * Declarations of functions to populate scalar values in a a class
352 */
353
354extern void of_test_str_fill(uint8_t *buf, int value, int len);
355extern int of_test_str_check(uint8_t *buf, int value, int len);
356
357
358extern int of_octets_populate(of_octets_t *octets, int value);
359extern int of_octets_check(of_octets_t *octets, int value);
360extern int of_match_populate(of_match_t *match, of_version_t version,
361 int value);
362extern int of_match_check(of_match_t *match, of_version_t version, int value);
363extern int test_ident_macros(void);
364extern int test_dump_objs(void);
365
366/* In test_match_utils.c */
367extern int test_match_utils(void);
368
369extern int run_unified_accessor_tests(void);
370extern int run_match_tests(void);
371extern int run_utility_tests(void);
372
373extern int run_scalar_acc_tests(void);
374extern int run_list_tests(void);
375extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700376
377extern int run_validator_tests(void);
378
379extern int run_list_limits_tests(void);
380
381extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700382extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700383
384""")
385
386 for version in of_g.of_version_range:
387 for cls in of_g.standard_class_order:
388 if not loxi_utils.class_in_version(cls, version):
389 continue
Rich Lane6171e632014-11-07 10:23:38 -0800390 if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700391 continue
392 out.write("""
393extern int %(cls)s_%(v_name)s_populate(
394 %(cls)s_t *obj, int value);
395extern int %(cls)s_%(v_name)s_check(
396 %(cls)s_t *obj, int value);
397extern int %(cls)s_%(v_name)s_populate_scalars(
398 %(cls)s_t *obj, int value);
399extern int %(cls)s_%(v_name)s_check_scalars(
400 %(cls)s_t *obj, int value);
401""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
402
Rich Lanea06d0c32013-03-25 08:52:03 -0700403 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
404
405def gen_common_test(out, name):
406 """
407 Generate common test content including main
408 """
409 loxi_utils.gen_c_copy_license(out)
410 out.write("""
411/*
412 * Common test code for LOCI
413 *
414 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
415 */
416
417#define DISABLE_WARN_UNUSED_RESULT
418#include "loci_log.h"
419#include <loci/loci_obj_dump.h>
420#include <locitest/unittest.h>
421#include <locitest/test_common.h>
422
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900423/* mcheck is a glibc extension */
424#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700425#include <mcheck.h>
426#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900427#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700428#define MCHECK_INIT do { } while (0)
429#endif
430
431/**
432 * Exit on error if set to 1
433 */
434int exit_on_error = 1;
435
436/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700437 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700438 */
439int global_error = 0;
440
441extern int run_unified_accessor_tests(void);
442extern int run_match_tests(void);
443extern int run_utility_tests(void);
444
445extern int run_scalar_acc_tests(void);
446extern int run_list_tests(void);
447extern int run_message_tests(void);
448
449/**
450 * Macros for initializing and checking scalar types
451 *
452 * @param var The variable being initialized or checked
453 * @param val The integer value to set/check against, see below
454 *
455 * Note that equality means something special for strings. Each byte
456 * is initialized to an incrementing value. So check is done against that.
457 *
458 */
459
460""")
461 for t in scalar_types:
462 if t in integer_types:
463 out.write("""
464#define VAR_%s_INIT(var, val) var = (%s)(val)
465#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
466""" % (t.upper(), t, t.upper(), t))
467 else:
468 out.write("""
469#define VAR_%s_INIT(var, val) \\
470 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
471#define VAR_%s_CHECK(var, val) \\
472 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
473""" % (t.upper(), t.upper()))
474
475 gen_fill_string(out)
476 gen_scalar_set_check_funs(out)
Rich Lanea06d0c32013-03-25 08:52:03 -0700477 gen_unified_accessor_funs(out)
478
479 gen_ident_tests(out)
480 gen_log_test(out)
481
482def gen_message_scalar_test(out, name):
483 """
484 Generate test cases for message objects, scalar accessors
485 """
486
487 loxi_utils.gen_c_copy_license(out)
488 out.write("""
489/**
490 *
491 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
492 *
493 * Message-scalar tests for all versions
494 */
495
496#include <locitest/test_common.h>
497""")
498 for version in of_g.of_version_range:
499 v_name = loxi_utils.version_to_name(version)
500 out.write("""
501/**
502 * Message-scalar tests for version %s
503 */
504""" % v_name)
505 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800506 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700507 continue
508 if version in of_g.unified[cls]:
509 message_scalar_test(out, version, cls)
510
511 out.write("""
512int
513run_scalar_acc_tests(void)
514{
515""")
516 for version in of_g.of_version_range:
517 v_name = loxi_utils.version_to_name(version)
518 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800519 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -0700520 continue
521 if version in of_g.unified[cls]:
522 test_name = "%s_%s" % (cls, v_name)
523 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
524
525 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700526
Rich Lanea06d0c32013-03-25 08:52:03 -0700527def message_scalar_test(out, version, cls):
528 """
529 Generate one test case for the given version and class
530 """
531
532 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -0700533 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700534 v_name = loxi_utils.version_to_name(version)
535
536 out.write("""
537static int
538test_%(cls)s_%(v_name)s_scalar(void)
539{
540 %(cls)s_t *obj;
541
542 obj = %(cls)s_new(%(v_name)s);
543 TEST_ASSERT(obj != NULL);
544 TEST_ASSERT(obj->version == %(v_name)s);
545 TEST_ASSERT(obj->length == %(length)d);
546 TEST_ASSERT(obj->parent == NULL);
547 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700548""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700549 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700550
551 # If this class is a concrete member of an inheritance hierarchy,
552 # run the hierarchy's root wire type parser and assert it returns
553 # the expected object id.
554 ofclass = loxi_globals.unified.class_by_name(cls)
555 if ofclass and not ofclass.virtual:
556 root = ofclass
557 while root.superclass:
558 root = root.superclass
559 if root.virtual:
560 out.write("""
561 {
562 of_object_id_t object_id;
563 %(root_cls)s_wire_object_id_get(obj, &object_id);
564 TEST_ASSERT(object_id == %(u_cls)s);
565 }
566""" % dict(root_cls=root.name, u_cls=cls.upper()))
567
Rich Lanea06d0c32013-03-25 08:52:03 -0700568 if not type_maps.class_is_virtual(cls):
569 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700570 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700571 int length;
572
Rich Lanedc46fe22014-04-03 15:10:38 -0700573 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700574 TEST_ASSERT(length == %(length)d);
575 }
576
577 /* Set up incrementing values for scalar members */
578 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
579
580 /* Check values just set */
581 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700582""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700583 v_name=v_name, length=length, version=version))
584
585 out.write("""
586 %(cls)s_delete(obj);
587
588 /* To do: Check memory */
589 return TEST_PASS;
590}
591""" % dict(cls=cls))
592
593# Get the members and list of scalar types for members of a given class
594def scalar_member_types_get(cls, version):
595 member_types = []
596
597 if not version in of_g.unified[cls]:
598 return ([], [])
599
600 if "use_version" in of_g.unified[cls][version]:
601 v = of_g.unified[cls][version]["use_version"]
602 members = of_g.unified[cls][v]["members"]
603 else:
604 members = of_g.unified[cls][version]["members"]
605 # Accumulate variables that are supported
606 for member in members:
607 m_type = member["m_type"]
608 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700609 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700610 ignore_member(cls, version, m_name, m_type)):
611 continue
612 if not m_type in member_types:
613 member_types.append(m_type)
614
615 return (members, member_types)
616
617def scalar_funs_instance(out, cls, version, members, member_types):
618 """
619 Generate one instance of scalar set/check functions
620 """
621 out.write("""
622/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700623 * Populate the scalar values in obj of type %(cls)s,
624 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700625 * @param obj Pointer to an object to populate
626 * @param value The seed value to use in populating the object
627 * @returns The value after increments for this object's values
628 */
629int %(cls)s_%(v_name)s_populate_scalars(
630 %(cls)s_t *obj, int value) {
631""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
632 # Declare string types
633 for t in member_types:
634 out.write(" %s %s;\n" % (t, var_name_map(t)))
635 for member in members:
636 m_type = member["m_type"]
637 m_name = member["name"]
638 if (not loxi_utils.type_is_scalar(m_type) or
639 ignore_member(cls, version, m_name, m_type)):
640 continue
641 v_name = var_name_map(m_type);
642 out.write("""
643 VAR_%(u_type)s_INIT(%(v_name)s, value);
644 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
645 value += 1;
646""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
647 out.write("""
648 return value;
649}
650""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700651
Rich Lanea06d0c32013-03-25 08:52:03 -0700652 out.write("""
653/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700654 * Check scalar values in obj of type %(cls)s,
655 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700656 * @param obj Pointer to an object to check
657 * @param value Starting value for checking
658 * @returns The value after increments for this object's values
659 */
660int %(cls)s_%(v_name)s_check_scalars(
661 %(cls)s_t *obj, int value) {
662""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
663
664 for t in member_types:
665 out.write(" %s %s;\n" % (t, var_name_map(t)))
666 for member in members:
667 m_type = member["m_type"]
668 m_name = member["name"]
669 if (not loxi_utils.type_is_scalar(m_type) or
670 ignore_member(cls, version, m_name, m_type)):
671 continue
672 v_name = var_name_map(m_type);
673 out.write("""
674 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
675 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
676 value += 1;
677""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
678
679 out.write("""
680 return value;
681}
682
683""")
684
685def gen_scalar_set_check_funs(out):
686 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700687 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700688 set and check their values
689 """
690 for version in of_g.of_version_range:
691 for cls in of_g.standard_class_order:
Rich Lane6171e632014-11-07 10:23:38 -0800692 if type_maps.class_is_virtual(cls):
Rich Lanee499bd12014-10-28 15:25:09 -0700693 continue
Rich Lanea06d0c32013-03-25 08:52:03 -0700694 (members, member_types) = scalar_member_types_get(cls, version)
695 scalar_funs_instance(out, cls, version, members, member_types)
696
697
698# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700699def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700700 base_type = loxi_utils.list_to_entry_type(cls)
701 setup_template = """
702 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Rich Lanee499bd12014-10-28 15:25:09 -0700703 %(cls)s_append_bind(list, %(inst)s);
Rich Lanea06d0c32013-03-25 08:52:03 -0700704 value = %(subcls)s_%(v_name)s_populate(
705 %(inst)s, value);
706 cur_len += %(inst)s->length;
707 TEST_ASSERT(list->length == cur_len);
708"""
709 out.write("""
710 /* Append two instances of type %s */
711""" % subcls)
712 for i in range(2):
713 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700714 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700715 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700716 version=version))
717
Rich Lane9afc3b92014-04-09 22:55:53 -0700718def check_instance(out, cls, subcls, instance, v_name, version, last):
719 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700720 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
721 value = %(subcls)s_%(v_name)s_check(
722 %(inst)s, value);
723 TEST_ASSERT(value != 0);
724"""
725 out.write("\n /* Check two instances of type %s */" % instance)
726
Andreas Wundsam53256162013-05-02 14:05:53 -0700727 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700728 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700729 inst=instance, subcls=subcls,
730 v_name=loxi_utils.version_to_name(version)))
731 out.write("""\
732 TEST_OK(%(cls)s_next(list, &elt));
733""" % dict(cls=cls))
734
Andreas Wundsam53256162013-05-02 14:05:53 -0700735 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700736 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700737 inst=instance, subcls=subcls,
738 v_name=loxi_utils.version_to_name(version)))
739 if last:
740 out.write("""\
741 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
742""" % dict(cls=cls))
743 else:
744 out.write("""\
745 TEST_OK(%(cls)s_next(list, &elt));
746""" % dict(cls=cls))
747
Rich Lanea06d0c32013-03-25 08:52:03 -0700748# Maybe: Get a map from list class to parent, mem_name of container
749
750def list_test(out, version, cls):
751 out.write("""
752static int
753test_%(cls)s_%(v_name)s(void)
754{
755""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
756 base_type = loxi_utils.list_to_entry_type(cls)
757
758 out.write(""" %(cls)s_t *list;
759 int value = 1;
760""" % dict(cls=cls, base_type=base_type))
761
762 out.write("""
763 list = %(cls)s_new(%(v_name)s);
764 TEST_ASSERT(list != NULL);
765 TEST_ASSERT(list->version == %(v_name)s);
766 TEST_ASSERT(list->length == 0);
767 TEST_ASSERT(list->parent == NULL);
768 TEST_ASSERT(list->object_id == %(enum_cls)s);
769
Rich Lanec6e97f72014-12-03 12:08:25 -0800770 value = %(cls)s_%(v_name)s_populate(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700771 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700772""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700773 enum_cls=loxi_utils.enum_name(cls)))
774
775 out.write("""
776 /* Now check values */
777 value = 1;
Rich Lanec6e97f72014-12-03 12:08:25 -0800778 value = %(cls)s_%(v_name)s_check(list, value);
Rich Lanea06d0c32013-03-25 08:52:03 -0700779 TEST_ASSERT(value != 0);
780""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
781
782 out.write("""
783 %(cls)s_delete(list);
784
785 return TEST_PASS;
786}
787""" % dict(cls=cls))
788
789def gen_list_test(out, name):
790 """
791 Generate base line test cases for lists
792 @param out The file handle to write to
793 """
794
795 loxi_utils.gen_c_copy_license(out)
796 out.write("""
797/**
798 *
799 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
800 *
801 * Message-scalar tests for all versions
802 */
803
804#include <locitest/test_common.h>
805""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700806
Rich Lanea06d0c32013-03-25 08:52:03 -0700807 for version in of_g.of_version_range:
808 v_name = loxi_utils.version_to_name(version)
809 out.write("""
810/**
811 * Baseline list tests for version %s
812 */
813""" % v_name)
814 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700815 if version in of_g.unified[cls]:
816 list_test(out, version, cls)
817
818 out.write("""
819int
820run_list_tests(void)
821{
822""")
823 for version in of_g.of_version_range:
824 v_name = loxi_utils.version_to_name(version)
825 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700826 if version in of_g.unified[cls]:
827 test_name = "%s_%s" % (cls, v_name)
828 out.write(" RUN_TEST(%s);\n" % test_name)
829
830 out.write("\n return TEST_PASS;\n}\n");
831
832def gen_match_test(out, name):
833 """
834 Generate baseline tests for match functions
835 """
836
837 loxi_utils.gen_c_copy_license(out)
838 out.write("""\
839/**
840 *
841 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
842 *
843 * Message-scalar tests for all versions
844 * @fixme These are mostly hard coded now.
845 */
846
847#include <locitest/test_common.h>
848
849static int
850test_match_1(void)
851{
Rich Lanef87f4c32014-10-14 11:56:02 -0700852""")
853
854 for version in of_g.of_version_range:
855 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
856
857 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700858 of_match_t match;
859 int value = 1;
860 int idx;
861 uint32_t exp_value;
862
863 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700864 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700865 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
866 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
867 if (idx < 32) {
868 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
869 }
870 }
871""")
872
873 for version in of_g.of_version_range:
874 out.write("""
875 /* Create/populate/convert and delete for version %(v_name)s */
876 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
877 TEST_ASSERT(m_v%(version)d != NULL);
878 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
879 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
880 of_match_v%(version)d_delete(m_v%(version)d);
881""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
882
883 out.write("""
884 return TEST_PASS;
885}
886""")
887
888 out.write("""
889static int
890test_match_2(void)
891{
Rich Lanef87f4c32014-10-14 11:56:02 -0700892""")
893
894 for version in of_g.of_version_range:
895 out.write(" of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
896
897 out.write("""\
Rich Lanea06d0c32013-03-25 08:52:03 -0700898 of_match_t match1;
899 of_match_t match2;
900 int value = 1;
901""")
902
903 for version in of_g.of_version_range:
904 out.write("""
905 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
906 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
907 TEST_ASSERT(m_v%(version)d != NULL);
908 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
909 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
910 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
911 of_match_v%(version)d_delete(m_v%(version)d);
912""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
913
914 out.write("""
915 return TEST_PASS;
916}
917""")
918
919 out.write("""
920static int
921test_match_3(void)
922{
923 of_match_t match1;
924 of_match_t match2;
925 int value = 1;
926 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -0700927 of_object_storage_t storage;
928 memset(&storage, 0, sizeof(storage));
929 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -0700930""")
931 for version in of_g.of_version_range:
932 out.write("""
933 /* Serialize to version %(v_name)s */
934 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700935 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700936 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -0700937 storage.obj.wbuf->buf = octets.data;
938 storage.obj.wbuf->alloc_bytes = octets.bytes;
939 storage.obj.wbuf->current_bytes = octets.bytes;
940 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -0700941 OF_ERROR_NONE);
942 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
943 FREE(octets.data);
944""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
945
946 out.write("""
947 return TEST_PASS;
948}
949""")
950
951 out.write("""
952int run_match_tests(void)
953{
954 RUN_TEST(match_1);
955 RUN_TEST(match_2);
956 RUN_TEST(match_3);
957 RUN_TEST(match_utils);
958
959 return TEST_PASS;
960}
961""")
962
963def gen_msg_test(out, name):
964 loxi_utils.gen_c_copy_license(out)
965 out.write("""
966/**
967 *
968 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
969 *
970 * Message-scalar tests for all versions
971 */
972
973#include <locitest/test_common.h>
974""")
975 for version in of_g.of_version_range:
976 for cls in of_g.ordered_messages:
977 if not (cls, version) in of_g.base_length:
978 continue
Rich Lane488b3c52013-06-21 18:11:02 -0700979 if type_maps.class_is_virtual(cls):
980 continue
Rich Lanee3d3fb52014-10-16 12:45:17 -0700981 bytes = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -0700982 out.write("""
983static int
984test_%(cls)s_create_%(v_name)s(void)
985{
986 %(cls)s_t *obj;
987 uint8_t *msg_buf;
988 int value;
Rich Lanea4b68302014-03-12 15:17:58 -0700989 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -0700990 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -0700991
992 obj = %(cls)s_new(%(v_name)s);
993 TEST_ASSERT(obj != NULL);
994 TEST_ASSERT(obj->version == %(v_name)s);
995 TEST_ASSERT(obj->length == %(bytes)d);
996 TEST_ASSERT(obj->parent == NULL);
997 TEST_ASSERT(obj->object_id == %(enum)s);
998
Rich Lanea4b68302014-03-12 15:17:58 -0700999 of_header_wire_object_id_get(obj, &object_id);
1000 TEST_ASSERT(object_id == %(enum)s);
1001
Rich Lanea06d0c32013-03-25 08:52:03 -07001002 /* Set up incrementing values for scalar members */
1003 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1004 TEST_ASSERT(value != 0);
1005
Rich Lanebb8f17c2014-06-12 13:14:09 -07001006 len = obj->length;
1007
Rich Lanea06d0c32013-03-25 08:52:03 -07001008 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001009 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1010 TEST_ASSERT(msg_buf != NULL);
1011 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001012 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001013
1014 TEST_ASSERT(obj != NULL);
1015
1016 /* @fixme Set up all message objects (recursively?) */
1017
1018 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1019 TEST_ASSERT(value != 0);
1020
1021 %(cls)s_delete(obj);
1022
1023 return TEST_PASS;
1024}
1025""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1026 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1027
1028 out.write("""
1029int
1030run_message_tests(void)
1031{
1032""")
1033 for version in of_g.of_version_range:
1034 for cls in of_g.ordered_messages:
1035 if not (cls, version) in of_g.base_length:
1036 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001037 if type_maps.class_is_virtual(cls):
1038 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001039 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1040 out.write(" RUN_TEST(%s);\n" % test_name)
1041
1042 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001043
Rich Lanea06d0c32013-03-25 08:52:03 -07001044
1045def gen_list_setup_check(out, cls, version):
1046 """
1047 Generate functions that populate and check a list with two
1048 of each type of subclass it supports
1049 """
1050 out.write("""
1051/**
1052 * Populate a list of type %(cls)s with two of each type of subclass
1053 * @param list Pointer to the list to be populated
1054 * @param value The seed value to use in populating the list
1055 * @returns The value after increments for this object's values
1056 */
1057int
1058%(cls)s_%(v_name)s_populate(
1059 %(cls)s_t *list, int value)
1060{
1061""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1062 base_type = loxi_utils.list_to_entry_type(cls)
1063 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001064 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001065 int cur_len = 0;
Rich Lanead708032014-12-03 12:40:58 -08001066 static int recursion;
Rich Lanee98ee5d2014-10-14 10:43:44 -07001067 (void) elt;
1068 (void) cur_len;
Rich Lanead708032014-12-03 12:40:58 -08001069
1070 if (recursion > 0) {
1071 return value;
1072 }
1073
1074 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001075""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001076
Rich Lanea06d0c32013-03-25 08:52:03 -07001077 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001078 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 -07001079 v_name = loxi_utils.version_to_name(version)
1080
Rich Lanee98ee5d2014-10-14 10:43:44 -07001081 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001082 out.write(" /* No subclasses for %s */\n"% base_type)
1083 out.write(" %s_t *elt_p;\n" % base_type)
1084 out.write("\n elt_p = &elt;\n")
1085 else:
1086 out.write(" /* Declare pointers for each subclass */\n")
1087 for instance, subcls in sub_classes:
1088 out.write(" %s_t *%s;\n" % (subcls, instance))
1089 out.write("\n /* Instantiate pointers for each subclass */\n")
1090 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001091 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001092
Rich Lanee98ee5d2014-10-14 10:43:44 -07001093 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001094 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001095 else:
1096 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001097 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001098 out.write("""
Rich Lanead708032014-12-03 12:40:58 -08001099 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001100 return value;
1101}
1102""")
1103 out.write("""
1104/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001105 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001106 * %(cls)s_%(v_name)s_populate
1107 * @param list Pointer to the list that was populated
1108 * @param value Starting value for checking
1109 * @returns The value after increments for this object's values
1110 */
1111int
1112%(cls)s_%(v_name)s_check(
1113 %(cls)s_t *list, int value)
1114{
1115""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1116 base_type = loxi_utils.list_to_entry_type(cls)
1117 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001118 of_object_t elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001119 int count = 0;
1120 int rv;
Rich Lanead708032014-12-03 12:40:58 -08001121 static int recursion;
1122
1123 if (recursion > 0) {
1124 return value;
1125 }
1126
1127 recursion++;
Rich Lanea06d0c32013-03-25 08:52:03 -07001128""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001129
Rich Lanea06d0c32013-03-25 08:52:03 -07001130
1131 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001132 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 -07001133 v_name = loxi_utils.version_to_name(version)
1134
Rich Lanee98ee5d2014-10-14 10:43:44 -07001135 if not type_maps.class_is_virtual(base_type):
Rich Lanea06d0c32013-03-25 08:52:03 -07001136 entry_count = 2
1137 out.write(" /* No subclasses for %s */\n"% base_type)
1138 out.write(" %s_t *elt_p;\n" % base_type)
1139 out.write("\n elt_p = &elt;\n")
1140 else:
1141 entry_count = 2 * len(sub_classes) # Two of each type appended
1142 out.write(" /* Declare pointers for each subclass */\n")
1143 for instance, subcls in sub_classes:
1144 out.write(" %s_t *%s;\n" % (subcls, instance))
1145 out.write("\n /* Instantiate pointers for each subclass */\n")
1146 for instance, subcls in sub_classes:
Rich Lanee499bd12014-10-28 15:25:09 -07001147 out.write(" %s = &elt;\n" % (instance))
Rich Lanea06d0c32013-03-25 08:52:03 -07001148
Rich Lanee98ee5d2014-10-14 10:43:44 -07001149 if not type_maps.class_is_virtual(base_type) or sub_classes:
1150 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1151
1152 if not type_maps.class_is_virtual(base_type): # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001153 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001154 version, True)
1155 else:
1156 count = 0
1157 for instance, subcls in sub_classes:
1158 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001159 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001160 version, count==len(sub_classes))
1161 out.write("""
1162""" % dict(base_type=base_type))
1163
1164 out.write("""
1165 /* Do an iterate to test the iterator */
1166 %(u_cls)s_ITER(list, &elt, rv) {
1167 count += 1;
1168 }
1169
1170 TEST_ASSERT(rv == OF_ERROR_RANGE);
1171 TEST_ASSERT(count == %(entry_count)d);
1172
1173 /* We shoehorn a test of the dup functions here */
1174 {
1175 %(cls)s_t *dup;
1176
1177 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1178 TEST_ASSERT(dup->length == list->length);
1179 TEST_ASSERT(dup->object_id == list->object_id);
1180 TEST_ASSERT(dup->version == list->version);
1181 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1182 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1183 of_object_delete((of_object_t *)dup);
1184
1185 /* And now for the generic dup function */
1186 TEST_ASSERT((dup = (%(cls)s_t *)
1187 of_object_dup(list)) != NULL);
1188 TEST_ASSERT(dup->length == list->length);
1189 TEST_ASSERT(dup->object_id == list->object_id);
1190 TEST_ASSERT(dup->version == list->version);
1191 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1192 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1193 of_object_delete((of_object_t *)dup);
1194 }
1195
Rich Lanead708032014-12-03 12:40:58 -08001196 recursion--;
Rich Lanea06d0c32013-03-25 08:52:03 -07001197 return value;
1198}
1199""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1200
1201
1202def gen_class_setup_check(out, cls, version):
1203 out.write("""
1204/**
1205 * Populate all members of an object of type %(cls)s
1206 * with incrementing values
1207 * @param obj Pointer to an object to populate
1208 * @param value The seed value to use in populating the object
1209 * @returns The value after increments for this object's values
1210 */
1211
1212int
1213%(cls)s_%(v_name)s_populate(
1214 %(cls)s_t *obj, int value)
1215{
1216""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1217 members, member_types = loxi_utils.all_member_types_get(cls, version)
1218 for m_type in member_types:
1219 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1220 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001221 elif m_type in embedded_subclasses:
1222 subcls = embedded_subclasses[m_type]
1223 out.write(" %s_t *%s;\n" % (subcls, var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001224 else:
1225 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1226 out.write("""
1227 /* Run thru accessors after new to ensure okay */
1228""")
1229 for member in members:
1230 m_type = member["m_type"]
1231 m_name = member["name"]
1232 if loxi_utils.skip_member_name(m_name):
1233 continue
Rich Lane1f315aa2014-10-13 17:11:35 -07001234 if m_type in embedded_subclasses:
Wilson Ng734a1d62014-04-17 18:34:17 -07001235 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001236 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1237 out.write("""\
1238 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1239""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1240 else:
1241 sub_cls = m_type[:-2] # Trim _t
1242 out.write("""\
1243 {
1244 %(sub_cls)s_t sub_cls;
1245
1246 /* Test bind */
1247 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1248 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001249""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001250 m_name=m_name, sub_cls=sub_cls,
1251 v_name=loxi_utils.version_to_name(version)))
1252
1253 out.write("""
1254 value = %(cls)s_%(v_name)s_populate_scalars(
1255 obj, value);
1256 TEST_ASSERT(value != 0);
1257""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1258
1259 for member in members:
1260 m_type = member["m_type"]
1261 m_name = member["name"]
1262 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1263 continue
1264 if loxi_utils.skip_member_name(m_name):
1265 continue
1266 if m_type == "of_match_t":
1267 out.write("""\
1268 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1269 TEST_ASSERT(value != 0);
1270 %(cls)s_%(m_name)s_set(
1271 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001272""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001273 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1274 elif m_type == "of_octets_t":
1275 out.write("""\
1276 value = of_octets_populate(&%(var_name)s, value);
1277 TEST_ASSERT(value != 0);
1278 %(cls)s_%(m_name)s_set(
1279 obj, &%(var_name)s);
1280 if (octets.bytes) {
1281 FREE(octets.data);
1282 }
1283""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Rich Lane1f315aa2014-10-13 17:11:35 -07001284 elif m_type in embedded_subclasses:
1285 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001286 out.write("""\
1287 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1288 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001289 value = %(sub_cls)s_%(v_name)s_populate(
1290 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001291 TEST_ASSERT(value != 0);
1292 %(cls)s_%(m_name)s_set(
1293 obj, %(var_name)s);
1294 %(sub_cls)s_delete(%(var_name)s);
1295""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1296 var_name=var_name_map(m_type),
1297 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001298 else:
1299 sub_cls = m_type[:-2] # Trim _t
1300 out.write("""
1301 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1302 TEST_ASSERT(%(var_name)s != NULL);
1303 value = %(sub_cls)s_%(v_name)s_populate(
1304 %(var_name)s, value);
1305 TEST_ASSERT(value != 0);
1306 %(cls)s_%(m_name)s_set(
1307 obj, %(var_name)s);
1308 %(sub_cls)s_delete(%(var_name)s);
1309""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1310 var_name=var_name_map(m_type),
1311 v_name=loxi_utils.version_to_name(version)))
1312
1313 out.write("""
1314 return value;
1315}
1316""")
1317
1318 out.write("""
1319/**
1320 * Check all members of an object of type %(cls)s
1321 * populated by the above function
1322 * @param obj Pointer to an object to check
1323 * @param value Starting value for checking
1324 * @returns The value after increments for this object's values
1325 */
1326
1327int
1328%(cls)s_%(v_name)s_check(
1329 %(cls)s_t *obj, int value)
1330{
1331""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1332 members, member_types = loxi_utils.all_member_types_get(cls, version)
1333 for m_type in member_types:
1334 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1335 continue
1336 if loxi_utils.type_is_of_object(m_type):
1337 continue
1338 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1339 out.write("""
1340 value = %(cls)s_%(v_name)s_check_scalars(
1341 obj, value);
1342 TEST_ASSERT(value != 0);
1343""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1344
1345 for member in members:
1346 m_type = member["m_type"]
1347 m_name = member["name"]
1348 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1349 continue
1350 if loxi_utils.skip_member_name(m_name):
1351 continue
1352 if m_type == "of_match_t":
1353 out.write("""\
1354 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1355 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1356""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1357 v_name=loxi_utils.version_to_name(version)))
1358 elif m_type == "of_octets_t":
1359 out.write("""\
1360 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1361 value = of_octets_check(&%(var_name)s, value);
1362""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1363 v_name=loxi_utils.version_to_name(version)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001364 elif m_type in embedded_subclasses:
1365 sub_cls = embedded_subclasses[m_type]
Wilson Ngd6181882014-04-14 16:28:35 -07001366 out.write("""
1367 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001368 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001369
1370 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1371 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001372 value = %(sub_cls)s_%(v_name)s_check(
1373 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001374 TEST_ASSERT(value != 0);
1375 %(sub_cls)s_delete(%(m_name)s_ptr);
1376 }
1377""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1378 var_name=var_name_map(m_type),
1379 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001380 else:
1381 sub_cls = m_type[:-2] # Trim _t
1382 out.write("""
1383 { /* Use get/delete to access on check */
1384 %(m_type)s *%(m_name)s_ptr;
1385
1386 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1387 TEST_ASSERT(%(m_name)s_ptr != NULL);
1388 value = %(sub_cls)s_%(v_name)s_check(
1389 %(m_name)s_ptr, value);
1390 TEST_ASSERT(value != 0);
1391 %(sub_cls)s_delete(%(m_name)s_ptr);
1392 }
1393""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1394 var_name=var_name_map(m_type),
1395 v_name=loxi_utils.version_to_name(version)))
1396
1397 out.write("""
1398 /* We shoehorn a test of the dup functions here */
1399 {
1400 %(cls)s_t *dup;
1401
1402 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1403 TEST_ASSERT(dup->length == obj->length);
1404 TEST_ASSERT(dup->object_id == obj->object_id);
1405 TEST_ASSERT(dup->version == obj->version);
1406 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1407 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1408 of_object_delete((of_object_t *)dup);
1409
1410 /* And now for the generic dup function */
1411 TEST_ASSERT((dup = (%(cls)s_t *)
1412 of_object_dup(obj)) != NULL);
1413 TEST_ASSERT(dup->length == obj->length);
1414 TEST_ASSERT(dup->object_id == obj->object_id);
1415 TEST_ASSERT(dup->version == obj->version);
1416 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1417 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1418 of_object_delete((of_object_t *)dup);
1419 }
1420
1421 return value;
1422}
1423""" % dict(cls=cls))
1424
1425def unified_accessor_test_case(out, cls, version):
1426 """
1427 Generate one test case for the given version and class
1428 """
1429
1430 members, member_types = scalar_member_types_get(cls, version)
Rich Lanee3d3fb52014-10-16 12:45:17 -07001431 length = of_g.base_length[(cls, version)]
Rich Lanea06d0c32013-03-25 08:52:03 -07001432 v_name = loxi_utils.version_to_name(version)
1433
1434 out.write("""
1435static int
1436test_%(cls)s_%(v_name)s(void)
1437{
1438 %(cls)s_t *obj;
1439 obj = %(cls)s_new(%(v_name)s);
1440 TEST_ASSERT(obj != NULL);
1441 TEST_ASSERT(obj->version == %(v_name)s);
1442 TEST_ASSERT(obj->length == %(length)d);
1443 TEST_ASSERT(obj->parent == NULL);
1444 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001445""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001446 v_name=v_name, length=length, version=version))
1447 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1448 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001449 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001450 int length;
1451
Rich Lanedc46fe22014-04-03 15:10:38 -07001452 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001453 TEST_ASSERT(length == %(length)d);
1454 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001455 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001456 of_object_id_t obj_id;
1457
Rich Lanedc46fe22014-04-03 15:10:38 -07001458 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001459 TEST_ASSERT(obj_id == %(u_cls)s);
1460 }
1461
1462 /* Set up incrementing values for members */
1463 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1464 obj, 1) != 0);
1465
1466 /* Check values just set */
1467 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1468 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001469""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001470 v_name=v_name, length=length, version=version))
1471
1472 out.write("""
1473 %(cls)s_delete(obj);
1474
1475 /* To do: Check memory */
1476 return TEST_PASS;
1477}
1478""" % dict(cls=cls))
1479
1480
1481def gen_unified_accessor_funs(out):
1482 for version in of_g.of_version_range:
1483 for cls in of_g.standard_class_order:
1484 if not loxi_utils.class_in_version(cls, version):
1485 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001486 elif loxi_utils.class_is_list(cls):
1487 gen_list_setup_check(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001488 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001489 gen_class_setup_check(out, cls, version)
1490
1491def gen_unified_accessor_tests(out, name):
1492 loxi_utils.gen_c_copy_license(out)
1493 out.write("""
1494/**
1495 *
1496 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1497 *
1498 * Unified simple class instantiation tests for all versions
1499 */
1500
1501#include <locitest/test_common.h>
1502""")
1503 for version in of_g.of_version_range:
1504 for cls in of_g.standard_class_order:
1505 if not loxi_utils.class_in_version(cls, version):
1506 continue
Rich Lane6171e632014-11-07 10:23:38 -08001507 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001508 continue
1509 unified_accessor_test_case(out, cls, version)
1510
1511 out.write("""
1512int
1513run_unified_accessor_tests(void)
1514{
1515""")
1516 for version in of_g.of_version_range:
1517 v_name = loxi_utils.version_to_name(version)
1518 for cls in of_g.standard_class_order:
1519 if not loxi_utils.class_in_version(cls, version):
1520 continue
Rich Lane6171e632014-11-07 10:23:38 -08001521 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001522 continue
1523 test_name = "%s_%s" % (cls, v_name)
1524 out.write(" RUN_TEST(%s);\n" % test_name)
1525
1526 out.write(" return TEST_PASS;\n}\n");
1527
1528
1529
1530################################################################
1531#
1532# Object duplication functions
1533#
1534# These exercise the accessors to create duplicate objects.
1535# They are used in the LOCI test shim which sits in an OF
1536# protocol stream.
1537#
1538# TODO
1539# Resolve version stuff
1540# Complete list dup
1541
1542def gen_dup_list(out, cls, version):
1543 ver_name = loxi_utils.version_to_name(version)
1544 elt_type = loxi_utils.list_to_entry_type(cls)
1545 out.write("""
1546/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001547 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001548 * using accessor functions
1549 * @param src Pointer to object to be duplicated
1550 * @returns A new object of type %(cls)s.
1551 *
1552 * The caller is responsible for deleting the returned value
1553 */
1554%(cls)s_t *
1555%(cls)s_%(ver_name)s_dup(
1556 %(cls)s_t *src)
1557{
Rich Lanee499bd12014-10-28 15:25:09 -07001558 of_object_t src_elt;
1559 of_object_t *dst_elt;
Rich Lanea06d0c32013-03-25 08:52:03 -07001560 int rv;
1561 %(cls)s_t *dst;
1562
1563 if ((dst = %(cls)s_new(src->version)) == NULL) {
1564 return NULL;
1565 }
1566""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1567
1568 out.write("""
1569 %(u_cls)s_ITER(src, &src_elt, rv) {
1570 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1571 of_object_delete((of_object_t *)dst);
1572 return NULL;
1573 }
1574 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1575 dst, NULL);
1576 of_object_delete((of_object_t *)dst_elt);
1577 }
1578
1579 return dst;
1580}
1581""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1582
1583
1584def gen_dup_inheritance(out, cls, version):
1585 ver_name = loxi_utils.version_to_name(version)
1586 out.write("""
1587/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001588 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001589 * @param src Pointer to object to be duplicated
1590 * @returns A new object of type %(cls)s.
1591 *
1592 * The caller is responsible for deleting the returned value
1593 */
Rich Lanee499bd12014-10-28 15:25:09 -07001594of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001595%(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001596 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001597{
1598""" % dict(cls=cls, ver_name=ver_name))
1599
1600 # For each subclass, check if this is an instance of that subclass
Rich Lane10daa5b2014-10-12 11:36:50 -07001601 sub_classes = type_maps.sub_class_map(cls, version)
1602 for (_, sub_cls) in sub_classes:
1603 sub_enum = sub_cls.upper()
Rich Lane6171e632014-11-07 10:23:38 -08001604 if type_maps.class_is_virtual(sub_cls):
1605 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001606 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001607 if (src->object_id == %(sub_enum)s) {
1608 return %(sub_cls)s_%(ver_name)s_dup(src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001609 }
1610""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1611
1612 out.write("""
1613 return NULL;
1614}
1615""")
1616
1617
1618def gen_dup_cls(out, cls, version):
1619 """
1620 Generate duplication routine for class cls
1621 """
1622 ver_name = loxi_utils.version_to_name(version)
1623
1624 out.write("""
1625/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001626 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001627 * using accessor functions
1628 * @param src Pointer to object to be duplicated
1629 * @returns A new object of type %(cls)s.
1630 *
1631 * The caller is responsible for deleting the returned value
1632 */
1633%(cls)s_t *
1634%(cls)s_%(ver_name)s_dup(
1635 %(cls)s_t *src)
1636{
1637 %(cls)s_t *dst;
1638""" % dict(cls=cls, ver_name=ver_name))
1639
1640 # Get members and types for the class
1641 members, member_types = loxi_utils.all_member_types_get(cls, version)
1642
1643 # Add declarations for each member type
1644 for m_type in member_types:
1645 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1646 # Declare instance of these
1647 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001648 elif m_type in embedded_subclasses:
1649 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001650 out.write("""
Rich Lane1f315aa2014-10-13 17:11:35 -07001651 %(sub_cls)s_t src_%(v_name)s;
1652 %(sub_cls)s_t *dst_%(v_name)s;
1653""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
Rich Lanea06d0c32013-03-25 08:52:03 -07001654 else:
1655 out.write("""
1656 %(m_type)s src_%(v_name)s;
1657 %(m_type)s *dst_%(v_name)s;
1658""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1659
1660 out.write("""
1661 if ((dst = %(cls)s_new(src->version)) == NULL) {
1662 return NULL;
1663 }
1664""" % dict(cls=cls))
1665
1666 for member in members:
1667 m_type = member["m_type"]
1668 m_name = member["name"]
1669 if loxi_utils.skip_member_name(m_name):
1670 continue
1671 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1672 out.write("""
1673 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1674 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1675""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1676 elif m_type in ["of_match_t", "of_octets_t"]:
1677 out.write("""
1678 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1679 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1680""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Rich Lane1f315aa2014-10-13 17:11:35 -07001681 elif m_type in embedded_subclasses:
1682 sub_cls = embedded_subclasses[m_type]
Wilson Ng734a1d62014-04-17 18:34:17 -07001683 out.write("""
1684 %(cls)s_%(m_name)s_bind(
1685 src, &src_%(v_name)s);
1686 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1687 if (dst_%(v_name)s == NULL) {
1688 %(cls)s_delete(dst);
1689 return NULL;
1690 }
1691 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1692 %(sub_cls)s_delete(dst_%(v_name)s);
1693""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1694 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001695 else:
1696 sub_cls = m_type[:-2] # Trim _t
1697 out.write("""
1698 %(cls)s_%(m_name)s_bind(
1699 src, &src_%(v_name)s);
1700 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1701 if (dst_%(v_name)s == NULL) {
1702 %(cls)s_delete(dst);
1703 return NULL;
1704 }
1705 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1706 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001707""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001708 v_name=var_name_map(m_type), ver_name=ver_name))
1709
1710 out.write("""
1711 return dst;
1712}
1713""")
1714
1715def gen_version_dup(out=sys.stdout):
1716 """
1717 Generate duplication routines for each object type
1718 """
1719 out.write("""
1720/* Special try macro for duplicating */
1721#define _TRY_FREE(op, obj, rv) do { \\
1722 int _rv; \\
1723 if ((_rv = (op)) < 0) { \\
1724 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1725 of_object_delete((of_object_t *)(obj)); \\
1726 return (rv); \\
1727 } \\
1728 } while (0)
1729""")
1730
1731 for version in of_g.of_version_range:
1732 for cls in of_g.standard_class_order:
1733 if not loxi_utils.class_in_version(cls, version):
1734 continue
Rich Lane8841f352014-10-12 19:18:36 -07001735 if type_maps.class_is_inheritance_root(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001736 gen_dup_inheritance(out, cls, version)
1737 elif loxi_utils.class_is_list(cls):
1738 gen_dup_list(out, cls, version)
Rich Lane6171e632014-11-07 10:23:38 -08001739 elif not type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001740 gen_dup_cls(out, cls, version)
1741
1742def gen_dup(out=sys.stdout):
1743 """
1744 Generate non-version specific duplication routines for each object type
1745 """
1746
1747 for cls in of_g.standard_class_order:
1748 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001749of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001750%(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001751 of_object_t *src)
Rich Lanea06d0c32013-03-25 08:52:03 -07001752{
1753""" % dict(cls=cls))
1754 for version in of_g.of_version_range:
1755 if not loxi_utils.class_in_version(cls, version):
1756 continue
Rich Lane6171e632014-11-07 10:23:38 -08001757 elif type_maps.class_is_inheritance_root(cls):
1758 pass
1759 elif loxi_utils.class_is_list(cls):
1760 pass
1761 elif type_maps.class_is_virtual(cls):
1762 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001763 ver_name = loxi_utils.version_to_name(version)
1764 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001765 if (src->version == %(ver_name)s) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001766 return %(cls)s_%(ver_name)s_dup(src);
1767 }
Rich Lanee499bd12014-10-28 15:25:09 -07001768""" % dict(cls=cls, ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001769
1770 out.write("""
1771 /* Class not supported in given version */
1772 return NULL;
1773}
1774""")
1775
1776def dup_c_gen(out, name):
1777 """
1778 Generate the C file for duplication functions
1779 """
1780 loxi_utils.gen_c_copy_license(out)
1781 out.write("""\
1782/*
1783 * Duplication functions for all OF objects
1784 *
1785 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1786 *
1787 * These are test functions for exercising accessors. You can call
1788 * of_object_dup for an efficient duplication.
1789 */
1790
1791#define DISABLE_WARN_UNUSED_RESULT
1792#include "loci_log.h"
1793#include <locitest/of_dup.h>
1794
1795""")
1796
1797 gen_version_dup(out)
1798 gen_dup(out)
1799
1800
1801def dup_h_gen(out, name):
1802 """
1803 Generate the header file for duplication functions
1804 """
1805
1806 loxi_utils.gen_c_copy_license(out)
1807 out.write("""
1808/*
1809 * Duplication function header file
1810 *
1811 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1812 */
1813
1814#if !defined(_OF_DUP_H_)
1815#define _OF_DUP_H_
1816
1817#include <loci/loci.h>
1818""")
1819
1820 for cls in of_g.standard_class_order:
1821 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001822extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001823 %(cls)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001824 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001825""" % dict(cls=cls))
1826
1827 for version in of_g.of_version_range:
1828 for cls in of_g.standard_class_order:
1829 if not loxi_utils.class_in_version(cls, version):
1830 continue
Rich Lane6171e632014-11-07 10:23:38 -08001831 elif type_maps.class_is_inheritance_root(cls):
1832 pass
1833 elif loxi_utils.class_is_list(cls):
1834 pass
1835 elif type_maps.class_is_virtual(cls):
1836 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001837 ver_name = loxi_utils.version_to_name(version)
1838 out.write("""
Rich Lanee499bd12014-10-28 15:25:09 -07001839extern of_object_t *
Rich Lanea06d0c32013-03-25 08:52:03 -07001840 %(cls)s_%(ver_name)s_dup(
Rich Lanee499bd12014-10-28 15:25:09 -07001841 of_object_t *src);
Rich Lanea06d0c32013-03-25 08:52:03 -07001842""" % dict(cls=cls, ver_name=ver_name))
1843
1844 out.write("\n#endif /* _OF_DUP_H_ */\n")
1845
1846def gen_log_test(out):
1847 """
1848 Generate test for obj log calls
1849
1850 Define a trivial handler for object logging; call all obj log fns
1851 """
1852 out.write("""
1853
1854/**
1855 * Test object dump functions
1856 */
1857
1858int
1859test_dump_objs(void)
1860{
1861 of_object_t *obj;
1862
1863 FILE *out = fopen("/dev/null", "w");
1864
1865 /* Call each obj dump function */
1866""")
1867 for version in of_g.of_version_range:
1868 for j, cls in enumerate(of_g.all_class_order):
1869 if not loxi_utils.class_in_version(cls, version):
1870 continue
Rich Lane6171e632014-11-07 10:23:38 -08001871 if type_maps.class_is_virtual(cls):
Rich Lanea06d0c32013-03-25 08:52:03 -07001872 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001873 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1874 out.write("""
1875 obj = (of_object_t *)%(cls)s_new(%(version)s);
1876 {
1877 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1878 %(cls)s_vport_set(obj, vport);
1879 of_object_delete(vport);
1880 }
1881 of_object_dump((loci_writer_f)fprintf, out, obj);
1882 of_object_delete(obj);
1883""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1884 else:
1885 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001886 obj = (of_object_t *)%(cls)s_new(%(version)s);
1887 of_object_dump((loci_writer_f)fprintf, out, obj);
1888 of_object_delete(obj);
1889""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001890
Rich Lanea06d0c32013-03-25 08:52:03 -07001891 out.write("""
1892 fclose(out);
1893 return TEST_PASS;
1894}
1895""")
1896
1897def gen_ident_tests(out):
1898 """
1899 Generate tests for identifiers
1900
1901 For all idents, instantiate, test version supported macros
1902 For flags, set it, test it, clear it, test it.
1903 """
1904 out.write("""
1905/**
1906 * Test cases for all flag accessor macros
1907 * These only test self consistency (and that they compile)
1908 */
1909int
1910test_ident_macros(void)
1911{
1912 int value __attribute__((unused));
1913 uint32_t flags;
1914
1915""")
1916
1917 for ident, info in of_g.identifiers.items():
1918 if not identifiers.defined_versions_agree(of_g.identifiers,
1919 of_g.target_version_list,
1920 ident):
1921 # @fixme
1922 continue
1923 out.write(" value = %s;\n" % ident)
1924 for version in of_g.target_version_list:
1925 if version in info["values_by_version"].keys():
1926 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1927 (ident, of_g.of_version_wire2name[version]))
1928 else:
1929 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1930 (ident, of_g.of_version_wire2name[version]))
1931 if flags.ident_is_flag(ident):
1932 # Grab first supported version
1933 for version in info["values_by_version"]:
1934 break
1935 out.write("""
1936 flags = 0;
1937 %(ident)s_SET(flags, %(ver_name)s);
1938 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
1939 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
1940 %(ident)s_CLEAR(flags, %(ver_name)s);
1941 TEST_ASSERT(flags == 0);
1942 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
1943""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
1944
1945 out.write("""
1946 return TEST_PASS;
1947}
1948""")
1949
Rich Laneccae0312013-07-21 23:34:13 -07001950def gen_datafiles_tests(out, name):
1951 tests = []
1952 for filename in test_data.list_files():
1953 data = test_data.read(filename)
1954 if not 'c' in data:
1955 continue
1956 name = filename[:-5].replace("/", "_")
1957 tests.append(dict(name=name,
1958 filename=filename,
1959 c=data['c'],
1960 binary=data['binary']))
1961
1962 util.render_template(out, "test_data.c", tests=tests)