blob: 2f93536404ced181528451ef544d1569e187ca1d [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29@brief Test case generation functions
30
31@fixme Update the following
32The following components are generated.
33
34test_common.[ch]: A collection of common code for tests. Currently
35this includes the ability to set the scalar members of an object with
36incrementing values and then similarly verify those values
37
38test_scalar_acc.c: Instantiate each type of object, then set and get
39scalar values in the objects.
40
41test_list.c: Instantiate each type of list, add an element of each
42type the list supports, setting scalar values of the elements.
43
44test_match.c: Various tests for match objects
45
46test_msg.c: Instantiate top level messages
47
48These will move towards unified tests that do the following:
49
50Create or init an object.
51Populate the object with incrementing values.
52Possibly transform the object in some way (e.g., run the underlying
53wire buffer through a parse routine).
54Verify that the members all have the appropriate value
55
56Through out, checking the consistency of memory and memory operations
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +090057is done with mcheck (if available).
Rich Lanea06d0c32013-03-25 08:52:03 -070058
59"""
60
61import sys
Andreas Wundsam76db0062013-11-15 13:34:41 -080062import c_gen.of_g_legacy as of_g
Andreas Wundsam542a13c2013-11-15 13:28:55 -080063import c_gen.match as match
64import c_gen.flags as flags
Rich Lanea06d0c32013-03-25 08:52:03 -070065from generic_utils import *
Andreas Wundsam542a13c2013-11-15 13:28:55 -080066import c_gen.type_maps as type_maps
67import c_gen.loxi_utils_legacy as loxi_utils
68import c_gen.identifiers as identifiers
Rich Laneccae0312013-07-21 23:34:13 -070069import util
70import test_data
Rich Lane79c87192014-03-04 10:56:59 -080071import loxi_globals
72from loxi_ir import *
Rich Lanea06d0c32013-03-25 08:52:03 -070073
74def var_name_map(m_type):
75 """
76 Map a type to a generic variable name for the type.
77 @param m_type The data type
78
79 Used mostly in test code generation, but also for the dup functions.
80 """
81 _var_name_map= dict(
82 uint8_t="val8",
83 uint16_t="val16",
84 uint32_t="val32",
85 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070086 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070087 of_port_no_t="port_no",
88 of_fm_cmd_t="fm_cmd",
89 of_wc_bmap_t="wc_bmap",
90 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070091 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070092 of_table_name_t="table_name",
93 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070094 of_serial_num_t="ser_num",
Rich Lanef8a3d002014-03-19 13:33:52 -070095 of_str64_t="str64",
Andreas Wundsam53256162013-05-02 14:05:53 -070096 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070097 of_ipv6_t="ipv6",
98 # Non-scalars; more TBD
99 of_octets_t="octets",
100 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700101 of_match_t="match",
Rich Lane90020b42014-04-07 12:05:45 -0700102 of_oxm_header_t="oxm",
Wilson Ngd6181882014-04-14 16:28:35 -0700103 of_bsn_vport_header_t="bsn_vport",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700104 # BSN extensions
105 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700106 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800107 of_checksum_128_t="checksum_128",
Praseed Balakrishnanf78068b2014-09-04 10:30:40 -0700108 #Circuit extensions
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700109 of_app_code_t="app_code",
Praseed Balakrishnan2ed6da02014-09-18 17:02:48 -0700110 of_sig_id_t="sig_id",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700111 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700112
113 if m_type.find("of_list_") == 0:
114 return "list"
115 if m_type in of_g.of_mixed_types:
116 return of_g.of_mixed_types[m_type]["short_name"]
117 return _var_name_map[m_type]
118
119integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
120 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700121 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700122string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700123 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanef8a3d002014-03-19 13:33:52 -0700124 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
Praseed Balakrishnan7f718782014-09-18 17:02:48 -0700125 "of_str64_t","of_app_code_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700126
127scalar_types = integer_types[:]
128scalar_types.extend(string_types)
129
130def ignore_member(cls, version, m_name, m_type):
131 """
132 Filter out names or types that either don't have accessors
133 or those that should not be messed with
134 or whose types we're not ready to deal with yet.
135 """
Rich Lane79c87192014-03-04 10:56:59 -0800136
137 uclass = loxi_globals.unified.class_by_name(cls)
138 if not uclass:
Rich Lanea06d0c32013-03-25 08:52:03 -0700139 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800140
Rich Lane79c87192014-03-04 10:56:59 -0800141 if not isinstance(uclass.member_by_name(m_name), OFDataMember):
Rich Lane353a79f2013-11-13 10:39:56 -0800142 return True
Rich Lane79c87192014-03-04 10:56:59 -0800143
Rich Lanea06d0c32013-03-25 08:52:03 -0700144 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
145
146def gen_fill_string(out):
147 out.write("""
148
149/**
150 * The increment to use on values inside a string
151 */
152#define OF_TEST_STR_INCR 3
153
154/**
155 * Fill in a buffer with incrementing values starting
156 * at the given offset with the given value
157 * @param buf The buffer to fill
158 * @param value The value to use for data
159 * @param len The number of bytes to fill
160 */
161
162void
163of_test_str_fill(uint8_t *buf, int value, int len)
164{
165 int i;
166
167 for (i = 0; i < len; i++) {
168 *buf = value;
169 value += OF_TEST_STR_INCR;
170 buf++;
171 }
172}
173
174/**
175 * Given a buffer, verify that it's filled as above
176 * @param buf The buffer to check
177 * @param value The value to use for data
178 * @param len The number of bytes to fill
179 * @return Boolean True on equality (success)
180 */
181
182int
183of_test_str_check(uint8_t *buf, int value, int len)
184{
185 int i;
186 uint8_t val8;
187
188 val8 = value;
189
190 for (i = 0; i < len; i++) {
191 if (*buf != val8) {
192 return 0;
193 }
194 val8 += OF_TEST_STR_INCR;
195 buf++;
196 }
197
198 return 1;
199}
200
201/**
202 * Global that determines how octets should be populated
203 * -1 means use value % MAX (below) to determine length
204 * 0, 1, ... means used that fixed length
205 *
206 * Note: Was 16K, but that made objects too big. May add flexibility
207 * to call populate with a max parameter for length
208 */
209int octets_pop_style = -1;
210#define OCTETS_MAX_VALUE (128) /* 16K was too big */
211#define OCTETS_MULTIPLIER 6367 /* A prime */
212
213int
214of_octets_populate(of_octets_t *octets, int value)
215{
216 if (octets_pop_style < 0) {
217 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
218 } else {
219 octets->bytes = octets_pop_style;
220 }
221
222 if (octets->bytes != 0) {
223 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
224 return 0;
225 }
226 of_test_str_fill(octets->data, value, octets->bytes);
227 value += 1;
228 }
229
230 return value;
231}
232
233int
234of_octets_check(of_octets_t *octets, int value)
235{
236 int len;
237
238 if (octets_pop_style < 0) {
239 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
240 TEST_ASSERT(octets->bytes == len);
241 } else {
242 TEST_ASSERT(octets->bytes == octets_pop_style);
243 }
244
245 if (octets->bytes != 0) {
246 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
247 == 1);
248 value += 1;
249 }
250
251 return value;
252}
253
254int
255of_match_populate(of_match_t *match, of_version_t version, int value)
256{
257 MEMSET(match, 0, sizeof(*match));
258 match->version = version;
259""")
260
Rich Laned56f8d22014-05-06 14:52:55 -0700261 def populate_match_version(wire_version, keys):
Rich Lanea06d0c32013-03-25 08:52:03 -0700262 out.write("""
Rich Laned56f8d22014-05-06 14:52:55 -0700263 if (version == %d) {\
264""" % wire_version)
265 for key in keys:
266 entry = match.of_match_members[key]
267 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700268 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
269 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
270 value += 1;
Rich Laned56f8d22014-05-06 14:52:55 -0700271""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
272 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -0700273 }
274
Rich Laned56f8d22014-05-06 14:52:55 -0700275""")
276
Rich Laneb4a63a52014-05-22 14:41:57 -0700277 for wire_version, match_keys in match.match_keys.items():
278 populate_match_version(wire_version, match_keys)
Rich Lanea06d0c32013-03-25 08:52:03 -0700279
280 out.write("""
281 if (value % 2) {
282 /* Sometimes set ipv4 addr masks to non-exact */
283 match->masks.ipv4_src = 0xffff0000;
284 match->masks.ipv4_dst = 0xfffff800;
285 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700286
287 /* Restrict values according to masks */
Rich Lane68798a52014-04-16 14:57:52 -0700288 of_memmask(&match->fields, &match->masks, sizeof(match->fields));
Rich Lanea06d0c32013-03-25 08:52:03 -0700289 return value;
290}
291
292int
293of_match_check(of_match_t *match, of_version_t version, int value)
294{
295 of_match_t check;
296
297 value = of_match_populate(&check, match->version, value);
298 TEST_ASSERT(value != 0);
299 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
300
301 return value;
302}
303""")
304
305def gen_common_test_header(out, name):
306 loxi_utils.gen_c_copy_license(out)
307 out.write("""
308/*
309 * Test header file
310 *
311 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
312 */
313
314#if !defined(_TEST_COMMON_H_)
315#define _TEST_COMMON_H_
316
317#define DISABLE_WARN_UNUSED_RESULT
318#include <loci/loci.h>
319#include <locitest/of_dup.h>
320#include <locitest/unittest.h>
321
322extern int global_error;
323extern int exit_on_error;
324
325/* @todo Make option for -k to continue tests if errors */
326#define RUN_TEST(test) do { \\
327 int rv; \\
328 TESTCASE(test, rv); \\
329 if (rv != TEST_PASS) { \\
330 global_error=1; \\
331 if (exit_on_error) return(1); \\
332 } \\
333 } while(0)
334
335#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
336#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
337
338/*
339 * Declarations of functions to populate scalar values in a a class
340 */
341
342extern void of_test_str_fill(uint8_t *buf, int value, int len);
343extern int of_test_str_check(uint8_t *buf, int value, int len);
344
345
346extern int of_octets_populate(of_octets_t *octets, int value);
347extern int of_octets_check(of_octets_t *octets, int value);
348extern int of_match_populate(of_match_t *match, of_version_t version,
349 int value);
350extern int of_match_check(of_match_t *match, of_version_t version, int value);
351extern int test_ident_macros(void);
352extern int test_dump_objs(void);
353
354/* In test_match_utils.c */
355extern int test_match_utils(void);
356
357extern int run_unified_accessor_tests(void);
358extern int run_match_tests(void);
359extern int run_utility_tests(void);
360
361extern int run_scalar_acc_tests(void);
362extern int run_list_tests(void);
363extern int run_message_tests(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700364
365extern int run_validator_tests(void);
366
367extern int run_list_limits_tests(void);
368
369extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700370extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700371
372""")
373
374 for version in of_g.of_version_range:
375 for cls in of_g.standard_class_order:
376 if not loxi_utils.class_in_version(cls, version):
377 continue
378 if cls in type_maps.inheritance_map:
379 continue
380 out.write("""
381extern int %(cls)s_%(v_name)s_populate(
382 %(cls)s_t *obj, int value);
383extern int %(cls)s_%(v_name)s_check(
384 %(cls)s_t *obj, int value);
385extern int %(cls)s_%(v_name)s_populate_scalars(
386 %(cls)s_t *obj, int value);
387extern int %(cls)s_%(v_name)s_check_scalars(
388 %(cls)s_t *obj, int value);
389""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
390
391 out.write("""
392/*
393 * Declarations for list population and check primitives
394 */
395""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700396
Rich Lanea06d0c32013-03-25 08:52:03 -0700397 for version in of_g.of_version_range:
398 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700399 if version in of_g.unified[cls]:
400 out.write("""
401extern int
402 list_setup_%(cls)s_%(v_name)s(
403 %(cls)s_t *list, int value);
404extern int
405 list_check_%(cls)s_%(v_name)s(
406 %(cls)s_t *list, int value);
407""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
408
409 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
410
411def gen_common_test(out, name):
412 """
413 Generate common test content including main
414 """
415 loxi_utils.gen_c_copy_license(out)
416 out.write("""
417/*
418 * Common test code for LOCI
419 *
420 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
421 */
422
423#define DISABLE_WARN_UNUSED_RESULT
424#include "loci_log.h"
425#include <loci/loci_obj_dump.h>
426#include <locitest/unittest.h>
427#include <locitest/test_common.h>
428
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900429/* mcheck is a glibc extension */
430#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700431#include <mcheck.h>
432#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900433#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700434#define MCHECK_INIT do { } while (0)
435#endif
436
437/**
438 * Exit on error if set to 1
439 */
440int exit_on_error = 1;
441
442/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700443 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700444 */
445int global_error = 0;
446
447extern int run_unified_accessor_tests(void);
448extern int run_match_tests(void);
449extern int run_utility_tests(void);
450
451extern int run_scalar_acc_tests(void);
452extern int run_list_tests(void);
453extern int run_message_tests(void);
454
455/**
456 * Macros for initializing and checking scalar types
457 *
458 * @param var The variable being initialized or checked
459 * @param val The integer value to set/check against, see below
460 *
461 * Note that equality means something special for strings. Each byte
462 * is initialized to an incrementing value. So check is done against that.
463 *
464 */
465
466""")
467 for t in scalar_types:
468 if t in integer_types:
469 out.write("""
470#define VAR_%s_INIT(var, val) var = (%s)(val)
471#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
472""" % (t.upper(), t, t.upper(), t))
473 else:
474 out.write("""
475#define VAR_%s_INIT(var, val) \\
476 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
477#define VAR_%s_CHECK(var, val) \\
478 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
479""" % (t.upper(), t.upper()))
480
481 gen_fill_string(out)
482 gen_scalar_set_check_funs(out)
483 gen_list_set_check_funs(out)
484 gen_unified_accessor_funs(out)
485
486 gen_ident_tests(out)
487 gen_log_test(out)
488
489def gen_message_scalar_test(out, name):
490 """
491 Generate test cases for message objects, scalar accessors
492 """
493
494 loxi_utils.gen_c_copy_license(out)
495 out.write("""
496/**
497 *
498 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
499 *
500 * Message-scalar tests for all versions
501 */
502
503#include <locitest/test_common.h>
504""")
505 for version in of_g.of_version_range:
506 v_name = loxi_utils.version_to_name(version)
507 out.write("""
508/**
509 * Message-scalar tests for version %s
510 */
511""" % v_name)
512 for cls in of_g.standard_class_order:
513 if cls in type_maps.inheritance_map:
514 continue
515 if version in of_g.unified[cls]:
516 message_scalar_test(out, version, cls)
517
518 out.write("""
519int
520run_scalar_acc_tests(void)
521{
522""")
523 for version in of_g.of_version_range:
524 v_name = loxi_utils.version_to_name(version)
525 for cls in of_g.standard_class_order:
526 if cls in type_maps.inheritance_map:
527 continue
528 if version in of_g.unified[cls]:
529 test_name = "%s_%s" % (cls, v_name)
530 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
531
532 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700533
Rich Lanea06d0c32013-03-25 08:52:03 -0700534def message_scalar_test(out, version, cls):
535 """
536 Generate one test case for the given version and class
537 """
538
539 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700540 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700541 v_name = loxi_utils.version_to_name(version)
542
543 out.write("""
544static int
545test_%(cls)s_%(v_name)s_scalar(void)
546{
547 %(cls)s_t *obj;
548
549 obj = %(cls)s_new(%(v_name)s);
550 TEST_ASSERT(obj != NULL);
551 TEST_ASSERT(obj->version == %(v_name)s);
552 TEST_ASSERT(obj->length == %(length)d);
553 TEST_ASSERT(obj->parent == NULL);
554 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700555""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700556 v_name=v_name, length=length, version=version))
Rich Lanea4b68302014-03-12 15:17:58 -0700557
558 # If this class is a concrete member of an inheritance hierarchy,
559 # run the hierarchy's root wire type parser and assert it returns
560 # the expected object id.
561 ofclass = loxi_globals.unified.class_by_name(cls)
562 if ofclass and not ofclass.virtual:
563 root = ofclass
564 while root.superclass:
565 root = root.superclass
566 if root.virtual:
567 out.write("""
568 {
569 of_object_id_t object_id;
570 %(root_cls)s_wire_object_id_get(obj, &object_id);
571 TEST_ASSERT(object_id == %(u_cls)s);
572 }
573""" % dict(root_cls=root.name, u_cls=cls.upper()))
574
Rich Lanea06d0c32013-03-25 08:52:03 -0700575 if not type_maps.class_is_virtual(cls):
576 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -0700577 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700578 int length;
579
Rich Lanedc46fe22014-04-03 15:10:38 -0700580 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -0700581 TEST_ASSERT(length == %(length)d);
582 }
583
584 /* Set up incrementing values for scalar members */
585 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
586
587 /* Check values just set */
588 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700589""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700590 v_name=v_name, length=length, version=version))
591
592 out.write("""
593 %(cls)s_delete(obj);
594
595 /* To do: Check memory */
596 return TEST_PASS;
597}
598""" % dict(cls=cls))
599
600# Get the members and list of scalar types for members of a given class
601def scalar_member_types_get(cls, version):
602 member_types = []
603
604 if not version in of_g.unified[cls]:
605 return ([], [])
606
607 if "use_version" in of_g.unified[cls][version]:
608 v = of_g.unified[cls][version]["use_version"]
609 members = of_g.unified[cls][v]["members"]
610 else:
611 members = of_g.unified[cls][version]["members"]
612 # Accumulate variables that are supported
613 for member in members:
614 m_type = member["m_type"]
615 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700616 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700617 ignore_member(cls, version, m_name, m_type)):
618 continue
619 if not m_type in member_types:
620 member_types.append(m_type)
621
622 return (members, member_types)
623
624def scalar_funs_instance(out, cls, version, members, member_types):
625 """
626 Generate one instance of scalar set/check functions
627 """
628 out.write("""
629/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700630 * Populate the scalar values in obj of type %(cls)s,
631 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700632 * @param obj Pointer to an object to populate
633 * @param value The seed value to use in populating the object
634 * @returns The value after increments for this object's values
635 */
636int %(cls)s_%(v_name)s_populate_scalars(
637 %(cls)s_t *obj, int value) {
638""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
639 # Declare string types
640 for t in member_types:
641 out.write(" %s %s;\n" % (t, var_name_map(t)))
642 for member in members:
643 m_type = member["m_type"]
644 m_name = member["name"]
645 if (not loxi_utils.type_is_scalar(m_type) or
646 ignore_member(cls, version, m_name, m_type)):
647 continue
648 v_name = var_name_map(m_type);
649 out.write("""
650 VAR_%(u_type)s_INIT(%(v_name)s, value);
651 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
652 value += 1;
653""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
654 out.write("""
655 return value;
656}
657""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700658
Rich Lanea06d0c32013-03-25 08:52:03 -0700659 out.write("""
660/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700661 * Check scalar values in obj of type %(cls)s,
662 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700663 * @param obj Pointer to an object to check
664 * @param value Starting value for checking
665 * @returns The value after increments for this object's values
666 */
667int %(cls)s_%(v_name)s_check_scalars(
668 %(cls)s_t *obj, int value) {
669""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
670
671 for t in member_types:
672 out.write(" %s %s;\n" % (t, var_name_map(t)))
673 for member in members:
674 m_type = member["m_type"]
675 m_name = member["name"]
676 if (not loxi_utils.type_is_scalar(m_type) or
677 ignore_member(cls, version, m_name, m_type)):
678 continue
679 v_name = var_name_map(m_type);
680 out.write("""
681 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
682 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
683 value += 1;
684""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
685
686 out.write("""
687 return value;
688}
689
690""")
691
692def gen_scalar_set_check_funs(out):
693 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700694 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700695 set and check their values
696 """
697 for version in of_g.of_version_range:
698 for cls in of_g.standard_class_order:
699 (members, member_types) = scalar_member_types_get(cls, version)
700 scalar_funs_instance(out, cls, version, members, member_types)
701
702
703# Helper function to set up a subclass instance for a test
Rich Lane9afc3b92014-04-09 22:55:53 -0700704def setup_instance(out, cls, subcls, instance, v_name, version):
Rich Lanea06d0c32013-03-25 08:52:03 -0700705 base_type = loxi_utils.list_to_entry_type(cls)
706 setup_template = """
707 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700708 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700709 (%(base_type)s_t *)%(inst)s);
710 value = %(subcls)s_%(v_name)s_populate(
711 %(inst)s, value);
712 cur_len += %(inst)s->length;
713 TEST_ASSERT(list->length == cur_len);
714"""
715 out.write("""
716 /* Append two instances of type %s */
717""" % subcls)
718 for i in range(2):
719 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700720 dict(inst=instance, subcls=subcls, v_name=v_name,
Rich Lane9afc3b92014-04-09 22:55:53 -0700721 base_type=base_type, cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -0700722 version=version))
723
Rich Lane9afc3b92014-04-09 22:55:53 -0700724def check_instance(out, cls, subcls, instance, v_name, version, last):
725 check_template = """
Rich Lanea06d0c32013-03-25 08:52:03 -0700726 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
727 value = %(subcls)s_%(v_name)s_check(
728 %(inst)s, value);
729 TEST_ASSERT(value != 0);
730"""
731 out.write("\n /* Check two instances of type %s */" % instance)
732
Andreas Wundsam53256162013-05-02 14:05:53 -0700733 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700734 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700735 inst=instance, subcls=subcls,
736 v_name=loxi_utils.version_to_name(version)))
737 out.write("""\
738 TEST_OK(%(cls)s_next(list, &elt));
739""" % dict(cls=cls))
740
Andreas Wundsam53256162013-05-02 14:05:53 -0700741 out.write(check_template %
Rich Lane9afc3b92014-04-09 22:55:53 -0700742 dict(elt_name=loxi_utils.enum_name(subcls),
Rich Lanea06d0c32013-03-25 08:52:03 -0700743 inst=instance, subcls=subcls,
744 v_name=loxi_utils.version_to_name(version)))
745 if last:
746 out.write("""\
747 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
748""" % dict(cls=cls))
749 else:
750 out.write("""\
751 TEST_OK(%(cls)s_next(list, &elt));
752""" % dict(cls=cls))
753
754def setup_list_fn(out, version, cls):
755 """
756 Generate a helper function that populates a list with two
757 of each type of subclass it supports
758 """
759 out.write("""
760/**
761 * Set up a list of type %(cls)s with two of each type of subclass
762 */
763int
764list_setup_%(cls)s_%(v_name)s(
765 %(cls)s_t *list, int value)
766{
767""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
768 base_type = loxi_utils.list_to_entry_type(cls)
769 out.write("""
770 %(base_type)s_t elt;
771 int cur_len = 0;
772""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700773
Rich Lanea06d0c32013-03-25 08:52:03 -0700774 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700775 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 -0700776 v_name = loxi_utils.version_to_name(version)
777
778 if len(sub_classes) == 0:
779 out.write(" /* No subclasses for %s */\n"% base_type)
780 out.write(" %s_t *elt_p;\n" % base_type)
781 out.write("\n elt_p = &elt;\n")
782 else:
783 out.write(" /* Declare pointers for each subclass */\n")
784 for instance, subcls in sub_classes:
785 out.write(" %s_t *%s;\n" % (subcls, instance))
786 out.write("\n /* Instantiate pointers for each subclass */\n")
787 for instance, subcls in sub_classes:
788 out.write(" %s = &elt.%s;\n" % (instance, instance))
789
790 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700791 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700792 else:
793 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -0700794 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -0700795 out.write("""
796
797 return value;
798}
799""")
800
801def check_list_fn(out, version, cls):
802 """
803 Generate a helper function that checks a list populated by above fn
804 """
805 out.write("""
806/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700807 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700808 * list_setup_%(cls)s_%(v_name)s
809 */
810int
811list_check_%(cls)s_%(v_name)s(
812 %(cls)s_t *list, int value)
813{
814""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
815 base_type = loxi_utils.list_to_entry_type(cls)
816 out.write("""
817 %(base_type)s_t elt;
818""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700819
Rich Lanea06d0c32013-03-25 08:52:03 -0700820 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700821 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 -0700822 v_name = loxi_utils.version_to_name(version)
823
824 if len(sub_classes) == 0:
825 out.write(" /* No subclasses for %s */\n"% base_type)
826 out.write(" %s_t *elt_p;\n" % base_type)
827 out.write("\n elt_p = &elt;\n")
828 else:
829 out.write(" /* Declare pointers for each subclass */\n")
830 for instance, subcls in sub_classes:
831 out.write(" %s_t *%s;\n" % (subcls, instance))
832 out.write("\n /* Instantiate pointers for each subclass */\n")
833 for instance, subcls in sub_classes:
834 out.write(" %s = &elt.%s;\n" % (instance, instance))
835
836 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
837 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -0700838 check_instance(out, cls, base_type, "elt_p", v_name, version, True)
Rich Lanea06d0c32013-03-25 08:52:03 -0700839 else:
840 count = 0
841 for instance, subcls in sub_classes:
842 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -0700843 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -0700844 version, count==len(sub_classes))
845
846 out.write("""
847 return value;
848}
849""" % dict(base_type=base_type))
850
851def gen_list_set_check_funs(out):
852 for version in of_g.of_version_range:
853 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700854 if version in of_g.unified[cls]:
855 setup_list_fn(out, version, cls)
856 check_list_fn(out, version, cls)
857
858# Maybe: Get a map from list class to parent, mem_name of container
859
860def list_test(out, version, cls):
861 out.write("""
862static int
863test_%(cls)s_%(v_name)s(void)
864{
865""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
866 base_type = loxi_utils.list_to_entry_type(cls)
867
868 out.write(""" %(cls)s_t *list;
869 int value = 1;
870""" % dict(cls=cls, base_type=base_type))
871
872 out.write("""
873 list = %(cls)s_new(%(v_name)s);
874 TEST_ASSERT(list != NULL);
875 TEST_ASSERT(list->version == %(v_name)s);
876 TEST_ASSERT(list->length == 0);
877 TEST_ASSERT(list->parent == NULL);
878 TEST_ASSERT(list->object_id == %(enum_cls)s);
879
880 value = list_setup_%(cls)s_%(v_name)s(list, value);
881 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700882""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700883 enum_cls=loxi_utils.enum_name(cls)))
884
885 out.write("""
886 /* Now check values */
887 value = 1;
888 value = list_check_%(cls)s_%(v_name)s(list, value);
889 TEST_ASSERT(value != 0);
890""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
891
892 out.write("""
893 %(cls)s_delete(list);
894
895 return TEST_PASS;
896}
897""" % dict(cls=cls))
898
899def gen_list_test(out, name):
900 """
901 Generate base line test cases for lists
902 @param out The file handle to write to
903 """
904
905 loxi_utils.gen_c_copy_license(out)
906 out.write("""
907/**
908 *
909 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
910 *
911 * Message-scalar tests for all versions
912 */
913
914#include <locitest/test_common.h>
915""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700916
Rich Lanea06d0c32013-03-25 08:52:03 -0700917 for version in of_g.of_version_range:
918 v_name = loxi_utils.version_to_name(version)
919 out.write("""
920/**
921 * Baseline list tests for version %s
922 */
923""" % v_name)
924 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700925 if version in of_g.unified[cls]:
926 list_test(out, version, cls)
927
928 out.write("""
929int
930run_list_tests(void)
931{
932""")
933 for version in of_g.of_version_range:
934 v_name = loxi_utils.version_to_name(version)
935 for cls in of_g.ordered_list_objects:
Rich Lanea06d0c32013-03-25 08:52:03 -0700936 if version in of_g.unified[cls]:
937 test_name = "%s_%s" % (cls, v_name)
938 out.write(" RUN_TEST(%s);\n" % test_name)
939
940 out.write("\n return TEST_PASS;\n}\n");
941
942def gen_match_test(out, name):
943 """
944 Generate baseline tests for match functions
945 """
946
947 loxi_utils.gen_c_copy_license(out)
948 out.write("""\
949/**
950 *
951 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
952 *
953 * Message-scalar tests for all versions
954 * @fixme These are mostly hard coded now.
955 */
956
957#include <locitest/test_common.h>
958
959static int
960test_match_1(void)
961{
962 of_match_v1_t *m_v1;
963 of_match_v2_t *m_v2;
964 of_match_v3_t *m_v3;
965 of_match_v4_t *m_v4;
966 of_match_t match;
967 int value = 1;
968 int idx;
969 uint32_t exp_value;
970
971 /* Verify default values for ip mask map */
Rich Lane70c70942014-05-06 15:31:47 -0700972 for (idx = 0; idx < 64; idx++) {
Rich Lanea06d0c32013-03-25 08:52:03 -0700973 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
974 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
975 if (idx < 32) {
976 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
977 }
978 }
979""")
980
981 for version in of_g.of_version_range:
982 out.write("""
983 /* Create/populate/convert and delete for version %(v_name)s */
984 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
985 TEST_ASSERT(m_v%(version)d != NULL);
986 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
987 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
988 of_match_v%(version)d_delete(m_v%(version)d);
989""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
990
991 out.write("""
992 return TEST_PASS;
993}
994""")
995
996 out.write("""
997static int
998test_match_2(void)
999{
1000 of_match_v1_t *m_v1;
1001 of_match_v2_t *m_v2;
1002 of_match_v3_t *m_v3;
1003 of_match_v3_t *m_v4;
1004 of_match_t match1;
1005 of_match_t match2;
1006 int value = 1;
1007""")
1008
1009 for version in of_g.of_version_range:
1010 out.write("""
1011 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1012 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1013 TEST_ASSERT(m_v%(version)d != NULL);
1014 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1015 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1016 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1017 of_match_v%(version)d_delete(m_v%(version)d);
1018""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1019
1020 out.write("""
1021 return TEST_PASS;
1022}
1023""")
1024
1025 out.write("""
1026static int
1027test_match_3(void)
1028{
1029 of_match_t match1;
1030 of_match_t match2;
1031 int value = 1;
1032 of_octets_t octets;
Rich Lanee0b70cc2014-06-12 15:02:22 -07001033 of_object_storage_t storage;
1034 memset(&storage, 0, sizeof(storage));
1035 storage.obj.wbuf = &storage.wbuf;
Rich Lanea06d0c32013-03-25 08:52:03 -07001036""")
1037 for version in of_g.of_version_range:
1038 out.write("""
1039 /* Serialize to version %(v_name)s */
1040 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001041 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001042 OF_ERROR_NONE);
Rich Lanee0b70cc2014-06-12 15:02:22 -07001043 storage.obj.wbuf->buf = octets.data;
1044 storage.obj.wbuf->alloc_bytes = octets.bytes;
1045 storage.obj.wbuf->current_bytes = octets.bytes;
1046 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &storage.obj, 0, octets.bytes) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001047 OF_ERROR_NONE);
1048 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1049 FREE(octets.data);
1050""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1051
1052 out.write("""
1053 return TEST_PASS;
1054}
1055""")
1056
1057 out.write("""
1058int run_match_tests(void)
1059{
1060 RUN_TEST(match_1);
1061 RUN_TEST(match_2);
1062 RUN_TEST(match_3);
1063 RUN_TEST(match_utils);
1064
1065 return TEST_PASS;
1066}
1067""")
1068
1069def gen_msg_test(out, name):
1070 loxi_utils.gen_c_copy_license(out)
1071 out.write("""
1072/**
1073 *
1074 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1075 *
1076 * Message-scalar tests for all versions
1077 */
1078
1079#include <locitest/test_common.h>
1080""")
1081 for version in of_g.of_version_range:
1082 for cls in of_g.ordered_messages:
1083 if not (cls, version) in of_g.base_length:
1084 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001085 if type_maps.class_is_virtual(cls):
1086 continue
Rich Lanef70be942013-07-18 13:33:14 -07001087 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001088 out.write("""
1089static int
1090test_%(cls)s_create_%(v_name)s(void)
1091{
1092 %(cls)s_t *obj;
1093 uint8_t *msg_buf;
1094 int value;
Rich Lanea4b68302014-03-12 15:17:58 -07001095 of_object_id_t object_id;
Rich Lanebb8f17c2014-06-12 13:14:09 -07001096 int len;
Rich Lanea06d0c32013-03-25 08:52:03 -07001097
1098 obj = %(cls)s_new(%(v_name)s);
1099 TEST_ASSERT(obj != NULL);
1100 TEST_ASSERT(obj->version == %(v_name)s);
1101 TEST_ASSERT(obj->length == %(bytes)d);
1102 TEST_ASSERT(obj->parent == NULL);
1103 TEST_ASSERT(obj->object_id == %(enum)s);
1104
Rich Lanea4b68302014-03-12 15:17:58 -07001105 of_header_wire_object_id_get(obj, &object_id);
1106 TEST_ASSERT(object_id == %(enum)s);
1107
Rich Lanea06d0c32013-03-25 08:52:03 -07001108 /* Set up incrementing values for scalar members */
1109 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1110 TEST_ASSERT(value != 0);
1111
Rich Lanebb8f17c2014-06-12 13:14:09 -07001112 len = obj->length;
1113
Rich Lanea06d0c32013-03-25 08:52:03 -07001114 /* Grab the underlying buffer from the message */
Rich Lanea06d0c32013-03-25 08:52:03 -07001115 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1116 TEST_ASSERT(msg_buf != NULL);
1117 %(cls)s_delete(obj);
Rich Lanebb8f17c2014-06-12 13:14:09 -07001118 obj = of_object_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf), len);
Rich Lanea06d0c32013-03-25 08:52:03 -07001119
1120 TEST_ASSERT(obj != NULL);
1121
1122 /* @fixme Set up all message objects (recursively?) */
1123
1124 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1125 TEST_ASSERT(value != 0);
1126
1127 %(cls)s_delete(obj);
1128
1129 return TEST_PASS;
1130}
1131""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1132 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1133
1134 out.write("""
1135int
1136run_message_tests(void)
1137{
1138""")
1139 for version in of_g.of_version_range:
1140 for cls in of_g.ordered_messages:
1141 if not (cls, version) in of_g.base_length:
1142 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001143 if type_maps.class_is_virtual(cls):
1144 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001145 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1146 out.write(" RUN_TEST(%s);\n" % test_name)
1147
1148 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001149
Rich Lanea06d0c32013-03-25 08:52:03 -07001150
1151def gen_list_setup_check(out, cls, version):
1152 """
1153 Generate functions that populate and check a list with two
1154 of each type of subclass it supports
1155 """
1156 out.write("""
1157/**
1158 * Populate a list of type %(cls)s with two of each type of subclass
1159 * @param list Pointer to the list to be populated
1160 * @param value The seed value to use in populating the list
1161 * @returns The value after increments for this object's values
1162 */
1163int
1164%(cls)s_%(v_name)s_populate(
1165 %(cls)s_t *list, int value)
1166{
1167""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1168 base_type = loxi_utils.list_to_entry_type(cls)
1169 out.write("""
1170 %(base_type)s_t elt;
1171 int cur_len = 0;
1172""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001173
Rich Lanea06d0c32013-03-25 08:52:03 -07001174 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001175 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 -07001176 v_name = loxi_utils.version_to_name(version)
1177
1178 if len(sub_classes) == 0:
1179 out.write(" /* No subclasses for %s */\n"% base_type)
1180 out.write(" %s_t *elt_p;\n" % base_type)
1181 out.write("\n elt_p = &elt;\n")
1182 else:
1183 out.write(" /* Declare pointers for each subclass */\n")
1184 for instance, subcls in sub_classes:
1185 out.write(" %s_t *%s;\n" % (subcls, instance))
1186 out.write("\n /* Instantiate pointers for each subclass */\n")
1187 for instance, subcls in sub_classes:
1188 out.write(" %s = &elt.%s;\n" % (instance, instance))
1189
Rich Lanea06d0c32013-03-25 08:52:03 -07001190 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001191 setup_instance(out, cls, base_type, "elt_p", v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001192 else:
1193 for instance, subcls in sub_classes:
Rich Lane9afc3b92014-04-09 22:55:53 -07001194 setup_instance(out, cls, subcls, instance, v_name, version)
Rich Lanea06d0c32013-03-25 08:52:03 -07001195 out.write("""
1196 return value;
1197}
1198""")
1199 out.write("""
1200/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001201 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001202 * %(cls)s_%(v_name)s_populate
1203 * @param list Pointer to the list that was populated
1204 * @param value Starting value for checking
1205 * @returns The value after increments for this object's values
1206 */
1207int
1208%(cls)s_%(v_name)s_check(
1209 %(cls)s_t *list, int value)
1210{
1211""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1212 base_type = loxi_utils.list_to_entry_type(cls)
1213 out.write("""
1214 %(base_type)s_t elt;
1215 int count = 0;
1216 int rv;
1217""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001218
Rich Lanea06d0c32013-03-25 08:52:03 -07001219
1220 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001221 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 -07001222 v_name = loxi_utils.version_to_name(version)
1223
1224 if len(sub_classes) == 0:
1225 entry_count = 2
1226 out.write(" /* No subclasses for %s */\n"% base_type)
1227 out.write(" %s_t *elt_p;\n" % base_type)
1228 out.write("\n elt_p = &elt;\n")
1229 else:
1230 entry_count = 2 * len(sub_classes) # Two of each type appended
1231 out.write(" /* Declare pointers for each subclass */\n")
1232 for instance, subcls in sub_classes:
1233 out.write(" %s_t *%s;\n" % (subcls, instance))
1234 out.write("\n /* Instantiate pointers for each subclass */\n")
1235 for instance, subcls in sub_classes:
1236 out.write(" %s = &elt.%s;\n" % (instance, instance))
1237
1238 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1239 if len(sub_classes) == 0: # No inheritance case
Rich Lane9afc3b92014-04-09 22:55:53 -07001240 check_instance(out, cls, base_type, "elt_p", v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001241 version, True)
1242 else:
1243 count = 0
1244 for instance, subcls in sub_classes:
1245 count += 1
Rich Lane9afc3b92014-04-09 22:55:53 -07001246 check_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001247 version, count==len(sub_classes))
1248 out.write("""
1249""" % dict(base_type=base_type))
1250
1251 out.write("""
1252 /* Do an iterate to test the iterator */
1253 %(u_cls)s_ITER(list, &elt, rv) {
1254 count += 1;
1255 }
1256
1257 TEST_ASSERT(rv == OF_ERROR_RANGE);
1258 TEST_ASSERT(count == %(entry_count)d);
1259
1260 /* We shoehorn a test of the dup functions here */
1261 {
1262 %(cls)s_t *dup;
1263
1264 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1265 TEST_ASSERT(dup->length == list->length);
1266 TEST_ASSERT(dup->object_id == list->object_id);
1267 TEST_ASSERT(dup->version == list->version);
1268 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1269 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1270 of_object_delete((of_object_t *)dup);
1271
1272 /* And now for the generic dup function */
1273 TEST_ASSERT((dup = (%(cls)s_t *)
1274 of_object_dup(list)) != NULL);
1275 TEST_ASSERT(dup->length == list->length);
1276 TEST_ASSERT(dup->object_id == list->object_id);
1277 TEST_ASSERT(dup->version == list->version);
1278 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1279 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1280 of_object_delete((of_object_t *)dup);
1281 }
1282
1283 return value;
1284}
1285""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1286
1287
1288def gen_class_setup_check(out, cls, version):
1289 out.write("""
1290/**
1291 * Populate all members of an object of type %(cls)s
1292 * with incrementing values
1293 * @param obj Pointer to an object to populate
1294 * @param value The seed value to use in populating the object
1295 * @returns The value after increments for this object's values
1296 */
1297
1298int
1299%(cls)s_%(v_name)s_populate(
1300 %(cls)s_t *obj, int value)
1301{
1302""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1303 members, member_types = loxi_utils.all_member_types_get(cls, version)
1304 for m_type in member_types:
1305 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1306 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001307 elif m_type == "of_bsn_vport_header_t":
1308 out.write(" of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
Rich Lanea06d0c32013-03-25 08:52:03 -07001309 else:
1310 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1311 out.write("""
1312 /* Run thru accessors after new to ensure okay */
1313""")
1314 for member in members:
1315 m_type = member["m_type"]
1316 m_name = member["name"]
1317 if loxi_utils.skip_member_name(m_name):
1318 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001319 if m_type == "of_bsn_vport_header_t":
1320 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001321 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1322 out.write("""\
1323 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1324""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1325 else:
1326 sub_cls = m_type[:-2] # Trim _t
1327 out.write("""\
1328 {
1329 %(sub_cls)s_t sub_cls;
1330
1331 /* Test bind */
1332 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1333 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001334""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001335 m_name=m_name, sub_cls=sub_cls,
1336 v_name=loxi_utils.version_to_name(version)))
1337
1338 out.write("""
1339 value = %(cls)s_%(v_name)s_populate_scalars(
1340 obj, value);
1341 TEST_ASSERT(value != 0);
1342""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1343
1344 for member in members:
1345 m_type = member["m_type"]
1346 m_name = member["name"]
1347 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1348 continue
1349 if loxi_utils.skip_member_name(m_name):
1350 continue
1351 if m_type == "of_match_t":
1352 out.write("""\
1353 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1354 TEST_ASSERT(value != 0);
1355 %(cls)s_%(m_name)s_set(
1356 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001357""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001358 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1359 elif m_type == "of_octets_t":
1360 out.write("""\
1361 value = of_octets_populate(&%(var_name)s, value);
1362 TEST_ASSERT(value != 0);
1363 %(cls)s_%(m_name)s_set(
1364 obj, &%(var_name)s);
1365 if (octets.bytes) {
1366 FREE(octets.data);
1367 }
1368""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
Wilson Ng734a1d62014-04-17 18:34:17 -07001369 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1370 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001371 out.write("""\
1372 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1373 TEST_ASSERT(%(var_name)s != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001374 value = %(sub_cls)s_%(v_name)s_populate(
1375 %(var_name)s, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001376 TEST_ASSERT(value != 0);
1377 %(cls)s_%(m_name)s_set(
1378 obj, %(var_name)s);
1379 %(sub_cls)s_delete(%(var_name)s);
1380""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1381 var_name=var_name_map(m_type),
1382 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001383 else:
1384 sub_cls = m_type[:-2] # Trim _t
1385 out.write("""
1386 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1387 TEST_ASSERT(%(var_name)s != NULL);
1388 value = %(sub_cls)s_%(v_name)s_populate(
1389 %(var_name)s, value);
1390 TEST_ASSERT(value != 0);
1391 %(cls)s_%(m_name)s_set(
1392 obj, %(var_name)s);
1393 %(sub_cls)s_delete(%(var_name)s);
1394""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1395 var_name=var_name_map(m_type),
1396 v_name=loxi_utils.version_to_name(version)))
1397
1398 out.write("""
1399 return value;
1400}
1401""")
1402
1403 out.write("""
1404/**
1405 * Check all members of an object of type %(cls)s
1406 * populated by the above function
1407 * @param obj Pointer to an object to check
1408 * @param value Starting value for checking
1409 * @returns The value after increments for this object's values
1410 */
1411
1412int
1413%(cls)s_%(v_name)s_check(
1414 %(cls)s_t *obj, int value)
1415{
1416""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1417 members, member_types = loxi_utils.all_member_types_get(cls, version)
1418 for m_type in member_types:
1419 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1420 continue
1421 if loxi_utils.type_is_of_object(m_type):
1422 continue
1423 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1424 out.write("""
1425 value = %(cls)s_%(v_name)s_check_scalars(
1426 obj, value);
1427 TEST_ASSERT(value != 0);
1428""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1429
1430 for member in members:
1431 m_type = member["m_type"]
1432 m_name = member["name"]
1433 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1434 continue
1435 if loxi_utils.skip_member_name(m_name):
1436 continue
1437 if m_type == "of_match_t":
1438 out.write("""\
1439 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1440 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1441""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1442 v_name=loxi_utils.version_to_name(version)))
1443 elif m_type == "of_octets_t":
1444 out.write("""\
1445 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1446 value = of_octets_check(&%(var_name)s, value);
1447""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1448 v_name=loxi_utils.version_to_name(version)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001449 elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
1450 sub_cls = "of_bsn_vport_q_in_q"
Wilson Ngd6181882014-04-14 16:28:35 -07001451 out.write("""
1452 { /* Use get/delete to access on check */
Wilson Ng734a1d62014-04-17 18:34:17 -07001453 %(sub_cls)s_t *%(m_name)s_ptr;
Wilson Ngd6181882014-04-14 16:28:35 -07001454
1455 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1456 TEST_ASSERT(%(m_name)s_ptr != NULL);
Wilson Ng734a1d62014-04-17 18:34:17 -07001457 value = %(sub_cls)s_%(v_name)s_check(
1458 %(m_name)s_ptr, value);
Wilson Ngd6181882014-04-14 16:28:35 -07001459 TEST_ASSERT(value != 0);
1460 %(sub_cls)s_delete(%(m_name)s_ptr);
1461 }
1462""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1463 var_name=var_name_map(m_type),
1464 v_name=loxi_utils.version_to_name(version)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001465 else:
1466 sub_cls = m_type[:-2] # Trim _t
1467 out.write("""
1468 { /* Use get/delete to access on check */
1469 %(m_type)s *%(m_name)s_ptr;
1470
1471 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1472 TEST_ASSERT(%(m_name)s_ptr != NULL);
1473 value = %(sub_cls)s_%(v_name)s_check(
1474 %(m_name)s_ptr, value);
1475 TEST_ASSERT(value != 0);
1476 %(sub_cls)s_delete(%(m_name)s_ptr);
1477 }
1478""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1479 var_name=var_name_map(m_type),
1480 v_name=loxi_utils.version_to_name(version)))
1481
1482 out.write("""
1483 /* We shoehorn a test of the dup functions here */
1484 {
1485 %(cls)s_t *dup;
1486
1487 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1488 TEST_ASSERT(dup->length == obj->length);
1489 TEST_ASSERT(dup->object_id == obj->object_id);
1490 TEST_ASSERT(dup->version == obj->version);
1491 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1492 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1493 of_object_delete((of_object_t *)dup);
1494
1495 /* And now for the generic dup function */
1496 TEST_ASSERT((dup = (%(cls)s_t *)
1497 of_object_dup(obj)) != NULL);
1498 TEST_ASSERT(dup->length == obj->length);
1499 TEST_ASSERT(dup->object_id == obj->object_id);
1500 TEST_ASSERT(dup->version == obj->version);
1501 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1502 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1503 of_object_delete((of_object_t *)dup);
1504 }
1505
1506 return value;
1507}
1508""" % dict(cls=cls))
1509
1510def unified_accessor_test_case(out, cls, version):
1511 """
1512 Generate one test case for the given version and class
1513 """
1514
1515 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001516 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001517 v_name = loxi_utils.version_to_name(version)
1518
1519 out.write("""
1520static int
1521test_%(cls)s_%(v_name)s(void)
1522{
1523 %(cls)s_t *obj;
1524 obj = %(cls)s_new(%(v_name)s);
1525 TEST_ASSERT(obj != NULL);
1526 TEST_ASSERT(obj->version == %(v_name)s);
1527 TEST_ASSERT(obj->length == %(length)d);
1528 TEST_ASSERT(obj->parent == NULL);
1529 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001530""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001531 v_name=v_name, length=length, version=version))
1532 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1533 out.write("""
Rich Lanedc46fe22014-04-03 15:10:38 -07001534 if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001535 int length;
1536
Rich Lanedc46fe22014-04-03 15:10:38 -07001537 loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
Rich Lanea06d0c32013-03-25 08:52:03 -07001538 TEST_ASSERT(length == %(length)d);
1539 }
Rich Lanedc46fe22014-04-03 15:10:38 -07001540 if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
Rich Lanea06d0c32013-03-25 08:52:03 -07001541 of_object_id_t obj_id;
1542
Rich Lanedc46fe22014-04-03 15:10:38 -07001543 loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
Rich Lanea06d0c32013-03-25 08:52:03 -07001544 TEST_ASSERT(obj_id == %(u_cls)s);
1545 }
1546
1547 /* Set up incrementing values for members */
1548 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1549 obj, 1) != 0);
1550
1551 /* Check values just set */
1552 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1553 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001554""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001555 v_name=v_name, length=length, version=version))
1556
1557 out.write("""
1558 %(cls)s_delete(obj);
1559
1560 /* To do: Check memory */
1561 return TEST_PASS;
1562}
1563""" % dict(cls=cls))
1564
1565
1566def gen_unified_accessor_funs(out):
1567 for version in of_g.of_version_range:
1568 for cls in of_g.standard_class_order:
1569 if not loxi_utils.class_in_version(cls, version):
1570 continue
1571 if cls in type_maps.inheritance_map:
1572 continue
1573 elif loxi_utils.class_is_list(cls):
1574 gen_list_setup_check(out, cls, version)
1575 else:
1576 gen_class_setup_check(out, cls, version)
1577
1578def gen_unified_accessor_tests(out, name):
1579 loxi_utils.gen_c_copy_license(out)
1580 out.write("""
1581/**
1582 *
1583 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1584 *
1585 * Unified simple class instantiation tests for all versions
1586 */
1587
1588#include <locitest/test_common.h>
1589""")
1590 for version in of_g.of_version_range:
1591 for cls in of_g.standard_class_order:
1592 if not loxi_utils.class_in_version(cls, version):
1593 continue
1594 if cls in type_maps.inheritance_map:
1595 continue
1596 unified_accessor_test_case(out, cls, version)
1597
1598 out.write("""
1599int
1600run_unified_accessor_tests(void)
1601{
1602""")
1603 for version in of_g.of_version_range:
1604 v_name = loxi_utils.version_to_name(version)
1605 for cls in of_g.standard_class_order:
1606 if not loxi_utils.class_in_version(cls, version):
1607 continue
1608 if cls in type_maps.inheritance_map:
1609 continue
1610 test_name = "%s_%s" % (cls, v_name)
1611 out.write(" RUN_TEST(%s);\n" % test_name)
1612
1613 out.write(" return TEST_PASS;\n}\n");
1614
1615
1616
1617################################################################
1618#
1619# Object duplication functions
1620#
1621# These exercise the accessors to create duplicate objects.
1622# They are used in the LOCI test shim which sits in an OF
1623# protocol stream.
1624#
1625# TODO
1626# Resolve version stuff
1627# Complete list dup
1628
1629def gen_dup_list(out, cls, version):
1630 ver_name = loxi_utils.version_to_name(version)
1631 elt_type = loxi_utils.list_to_entry_type(cls)
1632 out.write("""
1633/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001634 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001635 * using accessor functions
1636 * @param src Pointer to object to be duplicated
1637 * @returns A new object of type %(cls)s.
1638 *
1639 * The caller is responsible for deleting the returned value
1640 */
1641%(cls)s_t *
1642%(cls)s_%(ver_name)s_dup(
1643 %(cls)s_t *src)
1644{
1645 %(elt_type)s_t src_elt;
1646 %(elt_type)s_t *dst_elt;
1647 int rv;
1648 %(cls)s_t *dst;
1649
1650 if ((dst = %(cls)s_new(src->version)) == NULL) {
1651 return NULL;
1652 }
1653""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1654
1655 out.write("""
1656 %(u_cls)s_ITER(src, &src_elt, rv) {
1657 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1658 of_object_delete((of_object_t *)dst);
1659 return NULL;
1660 }
1661 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1662 dst, NULL);
1663 of_object_delete((of_object_t *)dst_elt);
1664 }
1665
1666 return dst;
1667}
1668""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1669
1670
1671def gen_dup_inheritance(out, cls, version):
1672 ver_name = loxi_utils.version_to_name(version)
1673 out.write("""
1674/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001675 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001676 * @param src Pointer to object to be duplicated
1677 * @returns A new object of type %(cls)s.
1678 *
1679 * The caller is responsible for deleting the returned value
1680 */
1681%(cls)s_t *
1682%(cls)s_%(ver_name)s_dup(
1683 %(cls)s_t *src)
1684{
1685""" % dict(cls=cls, ver_name=ver_name))
1686
1687 # For each subclass, check if this is an instance of that subclass
1688 version_classes = type_maps.inheritance_data[cls][version]
1689 for sub_cls in version_classes:
1690 sub_enum = (cls + "_" + sub_cls).upper()
1691 out.write("""
1692 if (src->header.object_id == %(sub_enum)s) {
1693 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1694 &src->%(sub_cls)s);
1695 }
1696""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1697
1698 out.write("""
1699 return NULL;
1700}
1701""")
1702
1703
1704def gen_dup_cls(out, cls, version):
1705 """
1706 Generate duplication routine for class cls
1707 """
1708 ver_name = loxi_utils.version_to_name(version)
1709
1710 out.write("""
1711/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001712 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001713 * using accessor functions
1714 * @param src Pointer to object to be duplicated
1715 * @returns A new object of type %(cls)s.
1716 *
1717 * The caller is responsible for deleting the returned value
1718 */
1719%(cls)s_t *
1720%(cls)s_%(ver_name)s_dup(
1721 %(cls)s_t *src)
1722{
1723 %(cls)s_t *dst;
1724""" % dict(cls=cls, ver_name=ver_name))
1725
1726 # Get members and types for the class
1727 members, member_types = loxi_utils.all_member_types_get(cls, version)
1728
1729 # Add declarations for each member type
1730 for m_type in member_types:
1731 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1732 # Declare instance of these
1733 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001734 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1735 out.write("""
1736 of_bsn_vport_q_in_q_t src_%(v_name)s;
1737 of_bsn_vport_q_in_q_t *dst_%(v_name)s;
1738""" % dict(v_name=var_name_map(m_type)))
Rich Lanea06d0c32013-03-25 08:52:03 -07001739 else:
1740 out.write("""
1741 %(m_type)s src_%(v_name)s;
1742 %(m_type)s *dst_%(v_name)s;
1743""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1744
1745 out.write("""
1746 if ((dst = %(cls)s_new(src->version)) == NULL) {
1747 return NULL;
1748 }
1749""" % dict(cls=cls))
1750
1751 for member in members:
1752 m_type = member["m_type"]
1753 m_name = member["name"]
1754 if loxi_utils.skip_member_name(m_name):
1755 continue
1756 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1757 out.write("""
1758 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1759 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1760""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1761 elif m_type in ["of_match_t", "of_octets_t"]:
1762 out.write("""
1763 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1764 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1765""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
Wilson Ng734a1d62014-04-17 18:34:17 -07001766 elif m_type == "of_bsn_vport_header_t": # test q_in_q
1767 sub_cls = "of_bsn_vport_q_in_q"
1768 out.write("""
1769 %(cls)s_%(m_name)s_bind(
1770 src, &src_%(v_name)s);
1771 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1772 if (dst_%(v_name)s == NULL) {
1773 %(cls)s_delete(dst);
1774 return NULL;
1775 }
1776 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1777 %(sub_cls)s_delete(dst_%(v_name)s);
1778""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
1779 v_name=var_name_map(m_type), ver_name=ver_name))
Rich Lanea06d0c32013-03-25 08:52:03 -07001780 else:
1781 sub_cls = m_type[:-2] # Trim _t
1782 out.write("""
1783 %(cls)s_%(m_name)s_bind(
1784 src, &src_%(v_name)s);
1785 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1786 if (dst_%(v_name)s == NULL) {
1787 %(cls)s_delete(dst);
1788 return NULL;
1789 }
1790 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1791 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001792""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001793 v_name=var_name_map(m_type), ver_name=ver_name))
1794
1795 out.write("""
1796 return dst;
1797}
1798""")
1799
1800def gen_version_dup(out=sys.stdout):
1801 """
1802 Generate duplication routines for each object type
1803 """
1804 out.write("""
1805/* Special try macro for duplicating */
1806#define _TRY_FREE(op, obj, rv) do { \\
1807 int _rv; \\
1808 if ((_rv = (op)) < 0) { \\
1809 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1810 of_object_delete((of_object_t *)(obj)); \\
1811 return (rv); \\
1812 } \\
1813 } while (0)
1814""")
1815
1816 for version in of_g.of_version_range:
1817 for cls in of_g.standard_class_order:
1818 if not loxi_utils.class_in_version(cls, version):
1819 continue
1820 if cls in type_maps.inheritance_map:
1821 gen_dup_inheritance(out, cls, version)
1822 elif loxi_utils.class_is_list(cls):
1823 gen_dup_list(out, cls, version)
1824 else:
1825 gen_dup_cls(out, cls, version)
1826
1827def gen_dup(out=sys.stdout):
1828 """
1829 Generate non-version specific duplication routines for each object type
1830 """
1831
1832 for cls in of_g.standard_class_order:
1833 out.write("""
1834%(cls)s_t *
1835%(cls)s_dup(
1836 %(cls)s_t *src)
1837{
1838""" % dict(cls=cls))
1839 for version in of_g.of_version_range:
1840 if not loxi_utils.class_in_version(cls, version):
1841 continue
1842 hdr = "header." if cls in type_maps.inheritance_map else ""
1843
1844 ver_name = loxi_utils.version_to_name(version)
1845 out.write("""
1846 if (src->%(hdr)sversion == %(ver_name)s) {
1847 return %(cls)s_%(ver_name)s_dup(src);
1848 }
1849""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1850
1851 out.write("""
1852 /* Class not supported in given version */
1853 return NULL;
1854}
1855""")
1856
1857def dup_c_gen(out, name):
1858 """
1859 Generate the C file for duplication functions
1860 """
1861 loxi_utils.gen_c_copy_license(out)
1862 out.write("""\
1863/*
1864 * Duplication functions for all OF objects
1865 *
1866 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1867 *
1868 * These are test functions for exercising accessors. You can call
1869 * of_object_dup for an efficient duplication.
1870 */
1871
1872#define DISABLE_WARN_UNUSED_RESULT
1873#include "loci_log.h"
1874#include <locitest/of_dup.h>
1875
1876""")
1877
1878 gen_version_dup(out)
1879 gen_dup(out)
1880
1881
1882def dup_h_gen(out, name):
1883 """
1884 Generate the header file for duplication functions
1885 """
1886
1887 loxi_utils.gen_c_copy_license(out)
1888 out.write("""
1889/*
1890 * Duplication function header file
1891 *
1892 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1893 */
1894
1895#if !defined(_OF_DUP_H_)
1896#define _OF_DUP_H_
1897
1898#include <loci/loci.h>
1899""")
1900
1901 for cls in of_g.standard_class_order:
1902 out.write("""
1903extern %(cls)s_t *
1904 %(cls)s_dup(
1905 %(cls)s_t *src);
1906""" % dict(cls=cls))
1907
1908 for version in of_g.of_version_range:
1909 for cls in of_g.standard_class_order:
1910 if not loxi_utils.class_in_version(cls, version):
1911 continue
1912 ver_name = loxi_utils.version_to_name(version)
1913 out.write("""
1914extern %(cls)s_t *
1915 %(cls)s_%(ver_name)s_dup(
1916 %(cls)s_t *src);
1917""" % dict(cls=cls, ver_name=ver_name))
1918
1919 out.write("\n#endif /* _OF_DUP_H_ */\n")
1920
1921def gen_log_test(out):
1922 """
1923 Generate test for obj log calls
1924
1925 Define a trivial handler for object logging; call all obj log fns
1926 """
1927 out.write("""
1928
1929/**
1930 * Test object dump functions
1931 */
1932
1933int
1934test_dump_objs(void)
1935{
1936 of_object_t *obj;
1937
1938 FILE *out = fopen("/dev/null", "w");
1939
1940 /* Call each obj dump function */
1941""")
1942 for version in of_g.of_version_range:
1943 for j, cls in enumerate(of_g.all_class_order):
1944 if not loxi_utils.class_in_version(cls, version):
1945 continue
1946 if cls in type_maps.inheritance_map:
1947 continue
Wilson Ng734a1d62014-04-17 18:34:17 -07001948 if cls == "of_bsn_virtual_port_create_request": # test q_in_q
1949 out.write("""
1950 obj = (of_object_t *)%(cls)s_new(%(version)s);
1951 {
1952 of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
1953 %(cls)s_vport_set(obj, vport);
1954 of_object_delete(vport);
1955 }
1956 of_object_dump((loci_writer_f)fprintf, out, obj);
1957 of_object_delete(obj);
1958""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
1959 else:
1960 out.write("""
Rich Lanea06d0c32013-03-25 08:52:03 -07001961 obj = (of_object_t *)%(cls)s_new(%(version)s);
1962 of_object_dump((loci_writer_f)fprintf, out, obj);
1963 of_object_delete(obj);
1964""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001965
Rich Lanea06d0c32013-03-25 08:52:03 -07001966 out.write("""
1967 fclose(out);
1968 return TEST_PASS;
1969}
1970""")
1971
1972def gen_ident_tests(out):
1973 """
1974 Generate tests for identifiers
1975
1976 For all idents, instantiate, test version supported macros
1977 For flags, set it, test it, clear it, test it.
1978 """
1979 out.write("""
1980/**
1981 * Test cases for all flag accessor macros
1982 * These only test self consistency (and that they compile)
1983 */
1984int
1985test_ident_macros(void)
1986{
1987 int value __attribute__((unused));
1988 uint32_t flags;
1989
1990""")
1991
1992 for ident, info in of_g.identifiers.items():
1993 if not identifiers.defined_versions_agree(of_g.identifiers,
1994 of_g.target_version_list,
1995 ident):
1996 # @fixme
1997 continue
1998 out.write(" value = %s;\n" % ident)
1999 for version in of_g.target_version_list:
2000 if version in info["values_by_version"].keys():
2001 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
2002 (ident, of_g.of_version_wire2name[version]))
2003 else:
2004 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
2005 (ident, of_g.of_version_wire2name[version]))
2006 if flags.ident_is_flag(ident):
2007 # Grab first supported version
2008 for version in info["values_by_version"]:
2009 break
2010 out.write("""
2011 flags = 0;
2012 %(ident)s_SET(flags, %(ver_name)s);
2013 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2014 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2015 %(ident)s_CLEAR(flags, %(ver_name)s);
2016 TEST_ASSERT(flags == 0);
2017 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2018""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2019
2020 out.write("""
2021 return TEST_PASS;
2022}
2023""")
2024
Rich Laneccae0312013-07-21 23:34:13 -07002025def gen_datafiles_tests(out, name):
2026 tests = []
2027 for filename in test_data.list_files():
2028 data = test_data.read(filename)
2029 if not 'c' in data:
2030 continue
2031 name = filename[:-5].replace("/", "_")
2032 tests.append(dict(name=name,
2033 filename=filename,
2034 c=data['c'],
2035 binary=data['binary']))
2036
2037 util.render_template(out, "test_data.c", tests=tests)