blob: cf03e0e94a17a9204f23105cbbb76c5db079f654 [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 Lanea06d0c32013-03-25 08:52:03 -070071
72def var_name_map(m_type):
73 """
74 Map a type to a generic variable name for the type.
75 @param m_type The data type
76
77 Used mostly in test code generation, but also for the dup functions.
78 """
79 _var_name_map= dict(
80 uint8_t="val8",
81 uint16_t="val16",
82 uint32_t="val32",
83 uint64_t="val64",
Andreas Wundsamb566a162013-07-18 19:30:23 -070084 of_ipv4_t="ipv4",
Rich Lanea06d0c32013-03-25 08:52:03 -070085 of_port_no_t="port_no",
86 of_fm_cmd_t="fm_cmd",
87 of_wc_bmap_t="wc_bmap",
88 of_match_bmap_t = "match_bmap",
Andreas Wundsam53256162013-05-02 14:05:53 -070089 of_port_name_t="port_name",
Rich Lanea06d0c32013-03-25 08:52:03 -070090 of_table_name_t="table_name",
91 of_desc_str_t="desc_str",
Andreas Wundsam53256162013-05-02 14:05:53 -070092 of_serial_num_t="ser_num",
93 of_mac_addr_t="mac_addr",
Rich Lanea06d0c32013-03-25 08:52:03 -070094 of_ipv6_t="ipv6",
95 # Non-scalars; more TBD
96 of_octets_t="octets",
97 of_meter_features_t="features",
Dan Talaycoc0e802e2013-05-18 23:52:39 -070098 of_match_t="match",
99 # BSN extensions
100 of_bsn_vport_q_in_q_t="vport",
Rich Lane3b2fd832013-09-24 13:44:08 -0700101 of_bitmap_128_t="bitmap_128",
Rich Lanefab0c822013-12-30 11:46:48 -0800102 of_checksum_128_t="checksum_128",
Dan Talaycoc0e802e2013-05-18 23:52:39 -0700103 )
Rich Lanea06d0c32013-03-25 08:52:03 -0700104
105 if m_type.find("of_list_") == 0:
106 return "list"
107 if m_type in of_g.of_mixed_types:
108 return of_g.of_mixed_types[m_type]["short_name"]
109 return _var_name_map[m_type]
110
111integer_types = ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
112 "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
Andreas Wundsamb566a162013-07-18 19:30:23 -0700113 "of_match_bmap_t", "of_ipv4_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700114string_types = [ "of_port_name_t", "of_table_name_t",
Andreas Wundsam53256162013-05-02 14:05:53 -0700115 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
Rich Lanefab0c822013-12-30 11:46:48 -0800116 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t"]
Rich Lanea06d0c32013-03-25 08:52:03 -0700117
118scalar_types = integer_types[:]
119scalar_types.extend(string_types)
120
121def ignore_member(cls, version, m_name, m_type):
122 """
123 Filter out names or types that either don't have accessors
124 or those that should not be messed with
125 or whose types we're not ready to deal with yet.
126 """
127 # This will probably need more granularity as more extensions are added
128 if (type_maps.class_is_extension(cls, version) and (
129 m_name == "experimenter" or
130 m_name == "subtype")):
131 return True
Rich Lane353a79f2013-11-13 10:39:56 -0800132
Wilson Ng27e4beb2013-12-03 12:33:01 -0800133 classes = ["of_bsn_lacp_stats_request",
134 "of_bsn_lacp_stats_reply",
135 "of_bsn_switch_pipeline_stats_request",
xinwu358e6162013-12-04 16:49:48 -0800136 "of_bsn_switch_pipeline_stats_reply",
137 "of_bsn_port_counter_stats_request",
138 "of_bsn_port_counter_stats_reply",
139 "of_bsn_vlan_counter_stats_request",
Rich Lane713d9282013-12-30 15:21:35 -0800140 "of_bsn_vlan_counter_stats_reply",
141 "of_bsn_gentable_entry_desc_stats_request",
142 "of_bsn_gentable_entry_desc_stats_reply",
143 "of_bsn_gentable_entry_stats_request",
144 "of_bsn_gentable_entry_stats_reply",
145 "of_bsn_gentable_desc_stats_request",
146 "of_bsn_gentable_desc_stats_reply",
147 "of_bsn_gentable_stats_request",
148 "of_bsn_gentable_stats_reply",
149 "of_bsn_gentable_bucket_stats_request",
Rich Lane013dea02014-02-05 13:44:13 -0800150 "of_bsn_gentable_bucket_stats_reply",
151 "of_bsn_flow_checksum_bucket_stats_request",
152 "of_bsn_flow_checksum_bucket_stats_reply",
153 "of_bsn_table_checksum_stats_request",
154 "of_bsn_table_checksum_stats_reply",
155 ]
Wilson Ng27e4beb2013-12-03 12:33:01 -0800156
157 if (cls in classes and (
Rich Lane353a79f2013-11-13 10:39:56 -0800158 m_name == "experimenter" or
159 m_name == "subtype")):
160 return True
Rich Lanea06d0c32013-03-25 08:52:03 -0700161 return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
162
163def gen_fill_string(out):
164 out.write("""
165
166/**
167 * The increment to use on values inside a string
168 */
169#define OF_TEST_STR_INCR 3
170
171/**
172 * Fill in a buffer with incrementing values starting
173 * at the given offset with the given value
174 * @param buf The buffer to fill
175 * @param value The value to use for data
176 * @param len The number of bytes to fill
177 */
178
179void
180of_test_str_fill(uint8_t *buf, int value, int len)
181{
182 int i;
183
184 for (i = 0; i < len; i++) {
185 *buf = value;
186 value += OF_TEST_STR_INCR;
187 buf++;
188 }
189}
190
191/**
192 * Given a buffer, verify that it's filled as above
193 * @param buf The buffer to check
194 * @param value The value to use for data
195 * @param len The number of bytes to fill
196 * @return Boolean True on equality (success)
197 */
198
199int
200of_test_str_check(uint8_t *buf, int value, int len)
201{
202 int i;
203 uint8_t val8;
204
205 val8 = value;
206
207 for (i = 0; i < len; i++) {
208 if (*buf != val8) {
209 return 0;
210 }
211 val8 += OF_TEST_STR_INCR;
212 buf++;
213 }
214
215 return 1;
216}
217
218/**
219 * Global that determines how octets should be populated
220 * -1 means use value % MAX (below) to determine length
221 * 0, 1, ... means used that fixed length
222 *
223 * Note: Was 16K, but that made objects too big. May add flexibility
224 * to call populate with a max parameter for length
225 */
226int octets_pop_style = -1;
227#define OCTETS_MAX_VALUE (128) /* 16K was too big */
228#define OCTETS_MULTIPLIER 6367 /* A prime */
229
230int
231of_octets_populate(of_octets_t *octets, int value)
232{
233 if (octets_pop_style < 0) {
234 octets->bytes = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
235 } else {
236 octets->bytes = octets_pop_style;
237 }
238
239 if (octets->bytes != 0) {
240 if ((octets->data = (uint8_t *)MALLOC(octets->bytes)) == NULL) {
241 return 0;
242 }
243 of_test_str_fill(octets->data, value, octets->bytes);
244 value += 1;
245 }
246
247 return value;
248}
249
250int
251of_octets_check(of_octets_t *octets, int value)
252{
253 int len;
254
255 if (octets_pop_style < 0) {
256 len = (value * OCTETS_MULTIPLIER) % OCTETS_MAX_VALUE;
257 TEST_ASSERT(octets->bytes == len);
258 } else {
259 TEST_ASSERT(octets->bytes == octets_pop_style);
260 }
261
262 if (octets->bytes != 0) {
263 TEST_ASSERT(of_test_str_check(octets->data, value, octets->bytes)
264 == 1);
265 value += 1;
266 }
267
268 return value;
269}
270
271int
272of_match_populate(of_match_t *match, of_version_t version, int value)
273{
274 MEMSET(match, 0, sizeof(*match));
275 match->version = version;
276""")
277
278 for key, entry in match.of_match_members.items():
279 out.write("""
Andreas Wundsam53256162013-05-02 14:05:53 -0700280 if (!(of_match_incompat[version] &
Rich Lanea06d0c32013-03-25 08:52:03 -0700281 OF_OXM_BIT(OF_OXM_INDEX_%(ku)s))) {
282 OF_MATCH_MASK_%(ku)s_EXACT_SET(match);
283 VAR_%(u_type)s_INIT(match->fields.%(key)s, value);
284 value += 1;
285 }
286
287""" % dict(key=key, u_type=entry["m_type"].upper(), ku=key.upper()))
288
289 out.write("""
290 if (value % 2) {
291 /* Sometimes set ipv4 addr masks to non-exact */
292 match->masks.ipv4_src = 0xffff0000;
293 match->masks.ipv4_dst = 0xfffff800;
294 }
Dan Talaycofb50d382013-08-05 16:00:17 -0700295
296 /* Restrict values according to masks */
297 of_match_values_mask(match);
Rich Lanea06d0c32013-03-25 08:52:03 -0700298 return value;
299}
300
301int
302of_match_check(of_match_t *match, of_version_t version, int value)
303{
304 of_match_t check;
305
306 value = of_match_populate(&check, match->version, value);
307 TEST_ASSERT(value != 0);
308 TEST_ASSERT(MEMCMP(match, &check, sizeof(check)) == 0);
309
310 return value;
311}
312""")
313
314def gen_common_test_header(out, name):
315 loxi_utils.gen_c_copy_license(out)
316 out.write("""
317/*
318 * Test header file
319 *
320 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
321 */
322
323#if !defined(_TEST_COMMON_H_)
324#define _TEST_COMMON_H_
325
326#define DISABLE_WARN_UNUSED_RESULT
327#include <loci/loci.h>
328#include <locitest/of_dup.h>
329#include <locitest/unittest.h>
330
331extern int global_error;
332extern int exit_on_error;
333
334/* @todo Make option for -k to continue tests if errors */
335#define RUN_TEST(test) do { \\
336 int rv; \\
337 TESTCASE(test, rv); \\
338 if (rv != TEST_PASS) { \\
339 global_error=1; \\
340 if (exit_on_error) return(1); \\
341 } \\
342 } while(0)
343
344#define TEST_OK(op) TEST_ASSERT((op) == OF_ERROR_NONE)
345#define TEST_INDIGO_OK(op) TEST_ASSERT((op) == INDIGO_ERROR_NONE)
346
347/*
348 * Declarations of functions to populate scalar values in a a class
349 */
350
351extern void of_test_str_fill(uint8_t *buf, int value, int len);
352extern int of_test_str_check(uint8_t *buf, int value, int len);
353
354
355extern int of_octets_populate(of_octets_t *octets, int value);
356extern int of_octets_check(of_octets_t *octets, int value);
357extern int of_match_populate(of_match_t *match, of_version_t version,
358 int value);
359extern int of_match_check(of_match_t *match, of_version_t version, int value);
360extern int test_ident_macros(void);
361extern int test_dump_objs(void);
362
363/* In test_match_utils.c */
364extern int test_match_utils(void);
365
366extern int run_unified_accessor_tests(void);
367extern int run_match_tests(void);
368extern int run_utility_tests(void);
369
370extern int run_scalar_acc_tests(void);
371extern int run_list_tests(void);
372extern int run_message_tests(void);
373extern int run_setup_from_add_tests(void);
374
375extern int run_validator_tests(void);
376
377extern int run_list_limits_tests(void);
378
379extern int test_ext_objs(void);
Rich Laneccae0312013-07-21 23:34:13 -0700380extern int test_datafiles(void);
Rich Lanea06d0c32013-03-25 08:52:03 -0700381
382""")
383
384 for version in of_g.of_version_range:
385 for cls in of_g.standard_class_order:
386 if not loxi_utils.class_in_version(cls, version):
387 continue
388 if cls in type_maps.inheritance_map:
389 continue
390 out.write("""
391extern int %(cls)s_%(v_name)s_populate(
392 %(cls)s_t *obj, int value);
393extern int %(cls)s_%(v_name)s_check(
394 %(cls)s_t *obj, int value);
395extern int %(cls)s_%(v_name)s_populate_scalars(
396 %(cls)s_t *obj, int value);
397extern int %(cls)s_%(v_name)s_check_scalars(
398 %(cls)s_t *obj, int value);
399""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
400
401 out.write("""
402/*
403 * Declarations for list population and check primitives
404 */
405""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700406
Rich Lanea06d0c32013-03-25 08:52:03 -0700407 for version in of_g.of_version_range:
408 for cls in of_g.ordered_list_objects:
409 if cls in type_maps.inheritance_map:
410 continue
411
412 if version in of_g.unified[cls]:
413 out.write("""
414extern int
415 list_setup_%(cls)s_%(v_name)s(
416 %(cls)s_t *list, int value);
417extern int
418 list_check_%(cls)s_%(v_name)s(
419 %(cls)s_t *list, int value);
420""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
421
422 out.write("\n#endif /* _TEST_COMMON_H_ */\n")
423
424def gen_common_test(out, name):
425 """
426 Generate common test content including main
427 """
428 loxi_utils.gen_c_copy_license(out)
429 out.write("""
430/*
431 * Common test code for LOCI
432 *
433 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
434 */
435
436#define DISABLE_WARN_UNUSED_RESULT
437#include "loci_log.h"
438#include <loci/loci_obj_dump.h>
439#include <locitest/unittest.h>
440#include <locitest/test_common.h>
441
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900442/* mcheck is a glibc extension */
443#if defined(__linux__)
Rich Lanea06d0c32013-03-25 08:52:03 -0700444#include <mcheck.h>
445#define MCHECK_INIT mcheck(NULL)
YAMAMOTO Takashi071b5912013-07-02 08:37:39 +0900446#else
Rich Lanea06d0c32013-03-25 08:52:03 -0700447#define MCHECK_INIT do { } while (0)
448#endif
449
450/**
451 * Exit on error if set to 1
452 */
453int exit_on_error = 1;
454
455/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700456 * Global error state: 0 is okay, 1 is error
Rich Lanea06d0c32013-03-25 08:52:03 -0700457 */
458int global_error = 0;
459
460extern int run_unified_accessor_tests(void);
461extern int run_match_tests(void);
462extern int run_utility_tests(void);
463
464extern int run_scalar_acc_tests(void);
465extern int run_list_tests(void);
466extern int run_message_tests(void);
467
468/**
469 * Macros for initializing and checking scalar types
470 *
471 * @param var The variable being initialized or checked
472 * @param val The integer value to set/check against, see below
473 *
474 * Note that equality means something special for strings. Each byte
475 * is initialized to an incrementing value. So check is done against that.
476 *
477 */
478
479""")
480 for t in scalar_types:
481 if t in integer_types:
482 out.write("""
483#define VAR_%s_INIT(var, val) var = (%s)(val)
484#define VAR_%s_CHECK(var, val) ((var) == (%s)(val))
485""" % (t.upper(), t, t.upper(), t))
486 else:
487 out.write("""
488#define VAR_%s_INIT(var, val) \\
489 of_test_str_fill((uint8_t *)&(var), val, sizeof(var))
490#define VAR_%s_CHECK(var, val) \\
491 of_test_str_check((uint8_t *)&(var), val, sizeof(var))
492""" % (t.upper(), t.upper()))
493
494 gen_fill_string(out)
495 gen_scalar_set_check_funs(out)
496 gen_list_set_check_funs(out)
497 gen_unified_accessor_funs(out)
498
499 gen_ident_tests(out)
500 gen_log_test(out)
501
502def gen_message_scalar_test(out, name):
503 """
504 Generate test cases for message objects, scalar accessors
505 """
506
507 loxi_utils.gen_c_copy_license(out)
508 out.write("""
509/**
510 *
511 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
512 *
513 * Message-scalar tests for all versions
514 */
515
516#include <locitest/test_common.h>
517""")
518 for version in of_g.of_version_range:
519 v_name = loxi_utils.version_to_name(version)
520 out.write("""
521/**
522 * Message-scalar tests for version %s
523 */
524""" % v_name)
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 message_scalar_test(out, version, cls)
530
531 out.write("""
532int
533run_scalar_acc_tests(void)
534{
535""")
536 for version in of_g.of_version_range:
537 v_name = loxi_utils.version_to_name(version)
538 for cls in of_g.standard_class_order:
539 if cls in type_maps.inheritance_map:
540 continue
541 if version in of_g.unified[cls]:
542 test_name = "%s_%s" % (cls, v_name)
543 out.write(" RUN_TEST(%s_scalar);\n" % test_name)
544
545 out.write(" return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -0700546
Rich Lanea06d0c32013-03-25 08:52:03 -0700547def message_scalar_test(out, version, cls):
548 """
549 Generate one test case for the given version and class
550 """
551
552 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -0700553 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -0700554 v_name = loxi_utils.version_to_name(version)
555
556 out.write("""
557static int
558test_%(cls)s_%(v_name)s_scalar(void)
559{
560 %(cls)s_t *obj;
561
562 obj = %(cls)s_new(%(v_name)s);
563 TEST_ASSERT(obj != NULL);
564 TEST_ASSERT(obj->version == %(v_name)s);
565 TEST_ASSERT(obj->length == %(length)d);
566 TEST_ASSERT(obj->parent == NULL);
567 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -0700568""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700569 v_name=v_name, length=length, version=version))
570 if not type_maps.class_is_virtual(cls):
571 out.write("""
572 if (obj->wire_length_get != NULL) {
573 int length;
574
575 obj->wire_length_get((of_object_t *)obj, &length);
576 TEST_ASSERT(length == %(length)d);
577 }
578
579 /* Set up incrementing values for scalar members */
580 %(cls)s_%(v_name)s_populate_scalars(obj, 1);
581
582 /* Check values just set */
583 TEST_ASSERT(%(cls)s_%(v_name)s_check_scalars(obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700584""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -0700585 v_name=v_name, length=length, version=version))
586
587 out.write("""
588 %(cls)s_delete(obj);
589
590 /* To do: Check memory */
591 return TEST_PASS;
592}
593""" % dict(cls=cls))
594
595# Get the members and list of scalar types for members of a given class
596def scalar_member_types_get(cls, version):
597 member_types = []
598
599 if not version in of_g.unified[cls]:
600 return ([], [])
601
602 if "use_version" in of_g.unified[cls][version]:
603 v = of_g.unified[cls][version]["use_version"]
604 members = of_g.unified[cls][v]["members"]
605 else:
606 members = of_g.unified[cls][version]["members"]
607 # Accumulate variables that are supported
608 for member in members:
609 m_type = member["m_type"]
610 m_name = member["name"]
Andreas Wundsam53256162013-05-02 14:05:53 -0700611 if (not loxi_utils.type_is_scalar(m_type) or
Rich Lanea06d0c32013-03-25 08:52:03 -0700612 ignore_member(cls, version, m_name, m_type)):
613 continue
614 if not m_type in member_types:
615 member_types.append(m_type)
616
617 return (members, member_types)
618
619def scalar_funs_instance(out, cls, version, members, member_types):
620 """
621 Generate one instance of scalar set/check functions
622 """
623 out.write("""
624/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700625 * Populate the scalar values in obj of type %(cls)s,
626 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700627 * @param obj Pointer to an object to populate
628 * @param value The seed value to use in populating the object
629 * @returns The value after increments for this object's values
630 */
631int %(cls)s_%(v_name)s_populate_scalars(
632 %(cls)s_t *obj, int value) {
633""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
634 # Declare string types
635 for t in member_types:
636 out.write(" %s %s;\n" % (t, var_name_map(t)))
637 for member in members:
638 m_type = member["m_type"]
639 m_name = member["name"]
640 if (not loxi_utils.type_is_scalar(m_type) or
641 ignore_member(cls, version, m_name, m_type)):
642 continue
643 v_name = var_name_map(m_type);
644 out.write("""
645 VAR_%(u_type)s_INIT(%(v_name)s, value);
646 %(cls)s_%(m_name)s_set(obj, %(v_name)s);
647 value += 1;
648""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
649 out.write("""
650 return value;
651}
652""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700653
Rich Lanea06d0c32013-03-25 08:52:03 -0700654 out.write("""
655/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700656 * Check scalar values in obj of type %(cls)s,
657 * version %(v_name)s
Rich Lanea06d0c32013-03-25 08:52:03 -0700658 * @param obj Pointer to an object to check
659 * @param value Starting value for checking
660 * @returns The value after increments for this object's values
661 */
662int %(cls)s_%(v_name)s_check_scalars(
663 %(cls)s_t *obj, int value) {
664""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
665
666 for t in member_types:
667 out.write(" %s %s;\n" % (t, var_name_map(t)))
668 for member in members:
669 m_type = member["m_type"]
670 m_name = member["name"]
671 if (not loxi_utils.type_is_scalar(m_type) or
672 ignore_member(cls, version, m_name, m_type)):
673 continue
674 v_name = var_name_map(m_type);
675 out.write("""
676 %(cls)s_%(m_name)s_get(obj, &%(v_name)s);
677 TEST_ASSERT(VAR_%(u_type)s_CHECK(%(v_name)s, value));
678 value += 1;
679""" % dict(cls=cls, m_name=m_name, u_type=m_type.upper(), v_name=v_name))
680
681 out.write("""
682 return value;
683}
684
685""")
686
687def gen_scalar_set_check_funs(out):
688 """
Andreas Wundsam53256162013-05-02 14:05:53 -0700689 For each object class with scalar members, generate functions that
Rich Lanea06d0c32013-03-25 08:52:03 -0700690 set and check their values
691 """
692 for version in of_g.of_version_range:
693 for cls in of_g.standard_class_order:
694 (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
699def setup_instance(out, cls, subcls, instance, v_name, inst_len, version):
700 base_type = loxi_utils.list_to_entry_type(cls)
701 setup_template = """
702 %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
Andreas Wundsam53256162013-05-02 14:05:53 -0700703 %(cls)s_append_bind(list,
Rich Lanea06d0c32013-03-25 08:52:03 -0700704 (%(base_type)s_t *)%(inst)s);
705 value = %(subcls)s_%(v_name)s_populate(
706 %(inst)s, value);
707 cur_len += %(inst)s->length;
708 TEST_ASSERT(list->length == cur_len);
709"""
710 out.write("""
711 /* Append two instances of type %s */
712""" % subcls)
713 for i in range(2):
714 out.write(setup_template %
Andreas Wundsam53256162013-05-02 14:05:53 -0700715 dict(inst=instance, subcls=subcls, v_name=v_name,
716 base_type=base_type, cls=cls, inst_len=inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -0700717 version=version))
718
719def check_instance(out, cls, subcls, instance, v_name, inst_len, version, last):
720 check_template = ""
721 if inst_len >= 0:
722 check_template = """
723 TEST_ASSERT(%(inst)s->length == %(inst_len)d);
724 if (%(inst)s->wire_length_get != NULL) {
725 int length;
726
727 %(inst)s->wire_length_get(
728 (of_object_t *)&elt, &length);
729 TEST_ASSERT(length == %(inst_len)d);
730 }
731"""
732 check_template += """
733 TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
734 value = %(subcls)s_%(v_name)s_check(
735 %(inst)s, value);
736 TEST_ASSERT(value != 0);
737"""
738 out.write("\n /* Check two instances of type %s */" % instance)
739
Andreas Wundsam53256162013-05-02 14:05:53 -0700740 out.write(check_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700741 dict(elt_name=loxi_utils.enum_name(subcls), inst_len=inst_len,
742 inst=instance, subcls=subcls,
743 v_name=loxi_utils.version_to_name(version)))
744 out.write("""\
745 TEST_OK(%(cls)s_next(list, &elt));
746""" % dict(cls=cls))
747
Andreas Wundsam53256162013-05-02 14:05:53 -0700748 out.write(check_template %
Rich Lanea06d0c32013-03-25 08:52:03 -0700749 dict(elt_name=loxi_utils.enum_name(subcls), inst_len=inst_len,
750 inst=instance, subcls=subcls,
751 v_name=loxi_utils.version_to_name(version)))
752 if last:
753 out.write("""\
754 TEST_ASSERT(%(cls)s_next(list, &elt) == OF_ERROR_RANGE);
755""" % dict(cls=cls))
756 else:
757 out.write("""\
758 TEST_OK(%(cls)s_next(list, &elt));
759""" % dict(cls=cls))
760
761def setup_list_fn(out, version, cls):
762 """
763 Generate a helper function that populates a list with two
764 of each type of subclass it supports
765 """
766 out.write("""
767/**
768 * Set up a list of type %(cls)s with two of each type of subclass
769 */
770int
771list_setup_%(cls)s_%(v_name)s(
772 %(cls)s_t *list, int value)
773{
774""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
775 base_type = loxi_utils.list_to_entry_type(cls)
776 out.write("""
777 %(base_type)s_t elt;
778 int cur_len = 0;
779""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700780
Rich Lanea06d0c32013-03-25 08:52:03 -0700781 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700782 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 -0700783 v_name = loxi_utils.version_to_name(version)
784
785 if len(sub_classes) == 0:
786 out.write(" /* No subclasses for %s */\n"% base_type)
787 out.write(" %s_t *elt_p;\n" % base_type)
788 out.write("\n elt_p = &elt;\n")
789 else:
790 out.write(" /* Declare pointers for each subclass */\n")
791 for instance, subcls in sub_classes:
792 out.write(" %s_t *%s;\n" % (subcls, instance))
793 out.write("\n /* Instantiate pointers for each subclass */\n")
794 for instance, subcls in sub_classes:
795 out.write(" %s = &elt.%s;\n" % (instance, instance))
796
797 if len(sub_classes) == 0: # No inheritance case
798 inst_len = loxi_utils.base_type_to_length(base_type, version)
799 setup_instance(out, cls, base_type, "elt_p", v_name, inst_len, version)
800 else:
801 for instance, subcls in sub_classes:
802 inst_len = of_g.base_length[(subcls, version)]
803 setup_instance(out, cls, subcls, instance, v_name, inst_len, version)
804 out.write("""
805
806 return value;
807}
808""")
809
810def check_list_fn(out, version, cls):
811 """
812 Generate a helper function that checks a list populated by above fn
813 """
814 out.write("""
815/**
Andreas Wundsam53256162013-05-02 14:05:53 -0700816 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -0700817 * list_setup_%(cls)s_%(v_name)s
818 */
819int
820list_check_%(cls)s_%(v_name)s(
821 %(cls)s_t *list, int value)
822{
823""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
824 base_type = loxi_utils.list_to_entry_type(cls)
825 out.write("""
826 %(base_type)s_t elt;
827""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -0700828
Rich Lanea06d0c32013-03-25 08:52:03 -0700829 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -0700830 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 -0700831 v_name = loxi_utils.version_to_name(version)
832
833 if len(sub_classes) == 0:
834 out.write(" /* No subclasses for %s */\n"% base_type)
835 out.write(" %s_t *elt_p;\n" % base_type)
836 out.write("\n elt_p = &elt;\n")
837 else:
838 out.write(" /* Declare pointers for each subclass */\n")
839 for instance, subcls in sub_classes:
840 out.write(" %s_t *%s;\n" % (subcls, instance))
841 out.write("\n /* Instantiate pointers for each subclass */\n")
842 for instance, subcls in sub_classes:
843 out.write(" %s = &elt.%s;\n" % (instance, instance))
844
845 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
846 if len(sub_classes) == 0: # No inheritance case
847 if loxi_utils.class_is_var_len(base_type, version):
848 inst_len = -1
849 else:
850 inst_len = loxi_utils.base_type_to_length(base_type, version)
Andreas Wundsam53256162013-05-02 14:05:53 -0700851 check_instance(out, cls, base_type, "elt_p", v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -0700852 version, True)
853 else:
854 count = 0
855 for instance, subcls in sub_classes:
856 count += 1
857 if loxi_utils.class_is_var_len(subcls, version):
858 inst_len = -1
859 else:
860 inst_len = of_g.base_length[(subcls, version)]
Andreas Wundsam53256162013-05-02 14:05:53 -0700861 check_instance(out, cls, subcls, instance, v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -0700862 version, count==len(sub_classes))
863
864 out.write("""
865 return value;
866}
867""" % dict(base_type=base_type))
868
869def gen_list_set_check_funs(out):
870 for version in of_g.of_version_range:
871 for cls in of_g.ordered_list_objects:
872 if cls in type_maps.inheritance_map:
873 continue
874
875 if version in of_g.unified[cls]:
876 setup_list_fn(out, version, cls)
877 check_list_fn(out, version, cls)
878
879# Maybe: Get a map from list class to parent, mem_name of container
880
881def list_test(out, version, cls):
882 out.write("""
883static int
884test_%(cls)s_%(v_name)s(void)
885{
886""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
887 base_type = loxi_utils.list_to_entry_type(cls)
888
889 out.write(""" %(cls)s_t *list;
890 int value = 1;
891""" % dict(cls=cls, base_type=base_type))
892
893 out.write("""
894 list = %(cls)s_new(%(v_name)s);
895 TEST_ASSERT(list != NULL);
896 TEST_ASSERT(list->version == %(v_name)s);
897 TEST_ASSERT(list->length == 0);
898 TEST_ASSERT(list->parent == NULL);
899 TEST_ASSERT(list->object_id == %(enum_cls)s);
900
901 value = list_setup_%(cls)s_%(v_name)s(list, value);
902 TEST_ASSERT(value != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -0700903""" % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
Rich Lanea06d0c32013-03-25 08:52:03 -0700904 enum_cls=loxi_utils.enum_name(cls)))
905
906 out.write("""
907 /* Now check values */
908 value = 1;
909 value = list_check_%(cls)s_%(v_name)s(list, value);
910 TEST_ASSERT(value != 0);
911""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
912
913 out.write("""
914 %(cls)s_delete(list);
915
916 return TEST_PASS;
917}
918""" % dict(cls=cls))
919
920def gen_list_test(out, name):
921 """
922 Generate base line test cases for lists
923 @param out The file handle to write to
924 """
925
926 loxi_utils.gen_c_copy_license(out)
927 out.write("""
928/**
929 *
930 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
931 *
932 * Message-scalar tests for all versions
933 */
934
935#include <locitest/test_common.h>
936""")
Andreas Wundsam53256162013-05-02 14:05:53 -0700937
Rich Lanea06d0c32013-03-25 08:52:03 -0700938 for version in of_g.of_version_range:
939 v_name = loxi_utils.version_to_name(version)
940 out.write("""
941/**
942 * Baseline list tests for version %s
943 */
944""" % v_name)
945 for cls in of_g.ordered_list_objects:
946 if cls in type_maps.inheritance_map:
947 continue
948 if version in of_g.unified[cls]:
949 list_test(out, version, cls)
950
951 out.write("""
952int
953run_list_tests(void)
954{
955""")
956 for version in of_g.of_version_range:
957 v_name = loxi_utils.version_to_name(version)
958 for cls in of_g.ordered_list_objects:
959 if cls in type_maps.inheritance_map:
960 continue
961 if version in of_g.unified[cls]:
962 test_name = "%s_%s" % (cls, v_name)
963 out.write(" RUN_TEST(%s);\n" % test_name)
964
965 out.write("\n return TEST_PASS;\n}\n");
966
967def gen_match_test(out, name):
968 """
969 Generate baseline tests for match functions
970 """
971
972 loxi_utils.gen_c_copy_license(out)
973 out.write("""\
974/**
975 *
976 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
977 *
978 * Message-scalar tests for all versions
979 * @fixme These are mostly hard coded now.
980 */
981
982#include <locitest/test_common.h>
983
984static int
985test_match_1(void)
986{
987 of_match_v1_t *m_v1;
988 of_match_v2_t *m_v2;
989 of_match_v3_t *m_v3;
990 of_match_v4_t *m_v4;
991 of_match_t match;
992 int value = 1;
993 int idx;
994 uint32_t exp_value;
995
996 /* Verify default values for ip mask map */
997 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
998 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
999 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
1000 if (idx < 32) {
1001 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
1002 }
1003 }
1004
1005 TEST_ASSERT(of_ip_mask_map_set(17, 0xabcdef00) == OF_ERROR_NONE);
1006 TEST_ASSERT(of_ip_mask_to_index(0xabcdef00) == 17);
1007 TEST_ASSERT(of_ip_index_to_mask(17) == 0xabcdef00);
1008
1009 TEST_ASSERT(of_ip_mask_map_set(62, 0xabcdefff) == OF_ERROR_NONE);
1010 TEST_ASSERT(of_ip_mask_to_index(0xabcdefff) == 62);
1011 TEST_ASSERT(of_ip_index_to_mask(62) == 0xabcdefff);
1012
1013 /* Test re-init */
1014 of_ip_mask_map_init();
1015 for (idx = 0; idx < OF_IP_MASK_MAP_COUNT; idx++) {
1016 exp_value = (idx < 32) ? ~((1 << idx) - 1) : 0;
1017 TEST_ASSERT(of_ip_index_to_mask(idx) == exp_value);
1018 if (idx < 32) {
1019 TEST_ASSERT(of_ip_mask_to_index(exp_value) == idx);
1020 }
1021 }
1022""")
1023
1024 for version in of_g.of_version_range:
1025 out.write("""
1026 /* Create/populate/convert and delete for version %(v_name)s */
1027 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1028 TEST_ASSERT(m_v%(version)d != NULL);
1029 TEST_ASSERT((value = of_match_populate(&match, %(v_name)s, value)) > 0);
1030 TEST_OK(of_match_to_wire_match_v%(version)d(&match, m_v%(version)d));
1031 of_match_v%(version)d_delete(m_v%(version)d);
1032""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1033
1034 out.write("""
1035 return TEST_PASS;
1036}
1037""")
1038
1039 out.write("""
1040static int
1041test_match_2(void)
1042{
1043 of_match_v1_t *m_v1;
1044 of_match_v2_t *m_v2;
1045 of_match_v3_t *m_v3;
1046 of_match_v3_t *m_v4;
1047 of_match_t match1;
1048 of_match_t match2;
1049 int value = 1;
1050""")
1051
1052 for version in of_g.of_version_range:
1053 out.write("""
1054 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
1055 m_v%(version)d = of_match_v%(version)d_new(%(v_name)s);
1056 TEST_ASSERT(m_v%(version)d != NULL);
1057 TEST_OK(of_match_to_wire_match_v%(version)d(&match1, m_v%(version)d));
1058 TEST_OK(of_match_v%(version)d_to_match(m_v%(version)d, &match2));
1059 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1060 of_match_v%(version)d_delete(m_v%(version)d);
1061""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1062
1063 out.write("""
1064 return TEST_PASS;
1065}
1066""")
1067
1068 out.write("""
1069static int
1070test_match_3(void)
1071{
1072 of_match_t match1;
1073 of_match_t match2;
1074 int value = 1;
1075 of_octets_t octets;
1076""")
1077 for version in of_g.of_version_range:
1078 out.write("""
1079 /* Serialize to version %(v_name)s */
1080 TEST_ASSERT((value = of_match_populate(&match1, %(v_name)s, value)) > 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001081 TEST_ASSERT(of_match_serialize(%(v_name)s, &match1, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001082 OF_ERROR_NONE);
Andreas Wundsam53256162013-05-02 14:05:53 -07001083 TEST_ASSERT(of_match_deserialize(%(v_name)s, &match2, &octets) ==
Rich Lanea06d0c32013-03-25 08:52:03 -07001084 OF_ERROR_NONE);
1085 TEST_ASSERT(memcmp(&match1, &match2, sizeof(match1)) == 0);
1086 FREE(octets.data);
1087""" % dict(v_name=loxi_utils.version_to_name(version), version=version))
1088
1089 out.write("""
1090 return TEST_PASS;
1091}
1092""")
1093
1094 out.write("""
1095int run_match_tests(void)
1096{
1097 RUN_TEST(match_1);
1098 RUN_TEST(match_2);
1099 RUN_TEST(match_3);
1100 RUN_TEST(match_utils);
1101
1102 return TEST_PASS;
1103}
1104""")
1105
1106def gen_msg_test(out, name):
1107 loxi_utils.gen_c_copy_license(out)
1108 out.write("""
1109/**
1110 *
1111 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1112 *
1113 * Message-scalar tests for all versions
1114 */
1115
1116#include <locitest/test_common.h>
1117""")
1118 for version in of_g.of_version_range:
1119 for cls in of_g.ordered_messages:
1120 if not (cls, version) in of_g.base_length:
1121 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001122 if type_maps.class_is_virtual(cls):
1123 continue
Rich Lanef70be942013-07-18 13:33:14 -07001124 bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001125 out.write("""
1126static int
1127test_%(cls)s_create_%(v_name)s(void)
1128{
1129 %(cls)s_t *obj;
1130 uint8_t *msg_buf;
1131 int value;
1132 int len;
1133
1134 obj = %(cls)s_new(%(v_name)s);
1135 TEST_ASSERT(obj != NULL);
1136 TEST_ASSERT(obj->version == %(v_name)s);
1137 TEST_ASSERT(obj->length == %(bytes)d);
1138 TEST_ASSERT(obj->parent == NULL);
1139 TEST_ASSERT(obj->object_id == %(enum)s);
1140
1141 /* Set up incrementing values for scalar members */
1142 value = %(cls)s_%(v_name)s_populate_scalars(obj, 1);
1143 TEST_ASSERT(value != 0);
1144
1145 /* Grab the underlying buffer from the message */
1146 len = obj->length;
1147 of_object_wire_buffer_steal((of_object_t *)obj, &msg_buf);
1148 TEST_ASSERT(msg_buf != NULL);
1149 %(cls)s_delete(obj);
1150 /* TODO: */
1151 TEST_ASSERT(of_message_to_object_id(msg_buf, len) == %(enum)s);
1152 obj = %(cls)s_new_from_message(OF_BUFFER_TO_MESSAGE(msg_buf));
1153
1154 TEST_ASSERT(obj != NULL);
1155
1156 /* @fixme Set up all message objects (recursively?) */
1157
1158 value = %(cls)s_%(v_name)s_check_scalars(obj, 1);
1159 TEST_ASSERT(value != 0);
1160
1161 %(cls)s_delete(obj);
1162
1163 return TEST_PASS;
1164}
1165""" % dict(cls=cls, version=version, enum=loxi_utils.enum_name(cls),
1166 v_name=loxi_utils.version_to_name(version), bytes=bytes))
1167
1168 out.write("""
1169int
1170run_message_tests(void)
1171{
1172""")
1173 for version in of_g.of_version_range:
1174 for cls in of_g.ordered_messages:
1175 if not (cls, version) in of_g.base_length:
1176 continue
Rich Lane488b3c52013-06-21 18:11:02 -07001177 if type_maps.class_is_virtual(cls):
1178 continue
Rich Lanea06d0c32013-03-25 08:52:03 -07001179 test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
1180 out.write(" RUN_TEST(%s);\n" % test_name)
1181
1182 out.write("\n return TEST_PASS;\n}\n");
Andreas Wundsam53256162013-05-02 14:05:53 -07001183
Rich Lanea06d0c32013-03-25 08:52:03 -07001184
1185def gen_list_setup_check(out, cls, version):
1186 """
1187 Generate functions that populate and check a list with two
1188 of each type of subclass it supports
1189 """
1190 out.write("""
1191/**
1192 * Populate a list of type %(cls)s with two of each type of subclass
1193 * @param list Pointer to the list to be populated
1194 * @param value The seed value to use in populating the list
1195 * @returns The value after increments for this object's values
1196 */
1197int
1198%(cls)s_%(v_name)s_populate(
1199 %(cls)s_t *list, int value)
1200{
1201""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1202 base_type = loxi_utils.list_to_entry_type(cls)
1203 out.write("""
1204 %(base_type)s_t elt;
1205 int cur_len = 0;
1206""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001207
Rich Lanea06d0c32013-03-25 08:52:03 -07001208 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001209 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 -07001210 v_name = loxi_utils.version_to_name(version)
1211
1212 if len(sub_classes) == 0:
1213 out.write(" /* No subclasses for %s */\n"% base_type)
1214 out.write(" %s_t *elt_p;\n" % base_type)
1215 out.write("\n elt_p = &elt;\n")
1216 else:
1217 out.write(" /* Declare pointers for each subclass */\n")
1218 for instance, subcls in sub_classes:
1219 out.write(" %s_t *%s;\n" % (subcls, instance))
1220 out.write("\n /* Instantiate pointers for each subclass */\n")
1221 for instance, subcls in sub_classes:
1222 out.write(" %s = &elt.%s;\n" % (instance, instance))
1223
1224# if type_maps.class_is_virtual(base_type):
1225# out.write("""\
1226# TEST_OK(%(base_type)s_header_init(
1227# (%(base_type)s_header_t *)&elt, %(v_name)s, -1, 1));
1228# """ % dict(base_type=base_type, v_name=loxi_utils.version_to_name(version)))
1229# else:
1230# out.write("""\
1231# TEST_OK(%(base_type)s_init(&elt, %(v_name)s, -1, 1));
1232# """ % dict(base_type=base_type, v_name=loxi_utils.version_to_name(version)))
1233
1234 if len(sub_classes) == 0: # No inheritance case
1235 inst_len = loxi_utils.base_type_to_length(base_type, version)
1236 setup_instance(out, cls, base_type, "elt_p", v_name, inst_len, version)
1237 else:
1238 for instance, subcls in sub_classes:
1239 inst_len = of_g.base_length[(subcls, version)]
Andreas Wundsam53256162013-05-02 14:05:53 -07001240 setup_instance(out, cls, subcls, instance, v_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001241 inst_len, version)
1242 out.write("""
1243 return value;
1244}
1245""")
1246 out.write("""
1247/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001248 * Check a list of type %(cls)s generated by
Rich Lanea06d0c32013-03-25 08:52:03 -07001249 * %(cls)s_%(v_name)s_populate
1250 * @param list Pointer to the list that was populated
1251 * @param value Starting value for checking
1252 * @returns The value after increments for this object's values
1253 */
1254int
1255%(cls)s_%(v_name)s_check(
1256 %(cls)s_t *list, int value)
1257{
1258""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1259 base_type = loxi_utils.list_to_entry_type(cls)
1260 out.write("""
1261 %(base_type)s_t elt;
1262 int count = 0;
1263 int rv;
1264""" % dict(cls=cls, base_type=base_type))
Andreas Wundsam53256162013-05-02 14:05:53 -07001265
Rich Lanea06d0c32013-03-25 08:52:03 -07001266
1267 sub_classes = type_maps.sub_class_map(base_type, version)
Rich Lane1bd2bae2013-07-09 10:06:07 -07001268 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 -07001269 v_name = loxi_utils.version_to_name(version)
1270
1271 if len(sub_classes) == 0:
1272 entry_count = 2
1273 out.write(" /* No subclasses for %s */\n"% base_type)
1274 out.write(" %s_t *elt_p;\n" % base_type)
1275 out.write("\n elt_p = &elt;\n")
1276 else:
1277 entry_count = 2 * len(sub_classes) # Two of each type appended
1278 out.write(" /* Declare pointers for each subclass */\n")
1279 for instance, subcls in sub_classes:
1280 out.write(" %s_t *%s;\n" % (subcls, instance))
1281 out.write("\n /* Instantiate pointers for each subclass */\n")
1282 for instance, subcls in sub_classes:
1283 out.write(" %s = &elt.%s;\n" % (instance, instance))
1284
1285 out.write(" TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
1286 if len(sub_classes) == 0: # No inheritance case
1287 if loxi_utils.class_is_var_len(base_type, version):
1288 inst_len = -1
1289 else:
1290 inst_len = loxi_utils.base_type_to_length(base_type, version)
Andreas Wundsam53256162013-05-02 14:05:53 -07001291 check_instance(out, cls, base_type, "elt_p", v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -07001292 version, True)
1293 else:
1294 count = 0
1295 for instance, subcls in sub_classes:
1296 count += 1
1297 if loxi_utils.class_is_var_len(subcls, version):
1298 inst_len = -1
1299 else:
1300 inst_len = of_g.base_length[(subcls, version)]
Andreas Wundsam53256162013-05-02 14:05:53 -07001301 check_instance(out, cls, subcls, instance, v_name, inst_len,
Rich Lanea06d0c32013-03-25 08:52:03 -07001302 version, count==len(sub_classes))
1303 out.write("""
1304""" % dict(base_type=base_type))
1305
1306 out.write("""
1307 /* Do an iterate to test the iterator */
1308 %(u_cls)s_ITER(list, &elt, rv) {
1309 count += 1;
1310 }
1311
1312 TEST_ASSERT(rv == OF_ERROR_RANGE);
1313 TEST_ASSERT(count == %(entry_count)d);
1314
1315 /* We shoehorn a test of the dup functions here */
1316 {
1317 %(cls)s_t *dup;
1318
1319 TEST_ASSERT((dup = %(cls)s_dup(list)) != NULL);
1320 TEST_ASSERT(dup->length == list->length);
1321 TEST_ASSERT(dup->object_id == list->object_id);
1322 TEST_ASSERT(dup->version == list->version);
1323 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1324 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1325 of_object_delete((of_object_t *)dup);
1326
1327 /* And now for the generic dup function */
1328 TEST_ASSERT((dup = (%(cls)s_t *)
1329 of_object_dup(list)) != NULL);
1330 TEST_ASSERT(dup->length == list->length);
1331 TEST_ASSERT(dup->object_id == list->object_id);
1332 TEST_ASSERT(dup->version == list->version);
1333 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1334 OF_OBJECT_BUFFER_INDEX(list, 0), list->length) == 0);
1335 of_object_delete((of_object_t *)dup);
1336 }
1337
1338 return value;
1339}
1340""" % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
1341
1342
1343def gen_class_setup_check(out, cls, version):
1344 out.write("""
1345/**
1346 * Populate all members of an object of type %(cls)s
1347 * with incrementing values
1348 * @param obj Pointer to an object to populate
1349 * @param value The seed value to use in populating the object
1350 * @returns The value after increments for this object's values
1351 */
1352
1353int
1354%(cls)s_%(v_name)s_populate(
1355 %(cls)s_t *obj, int value)
1356{
1357""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1358 members, member_types = loxi_utils.all_member_types_get(cls, version)
1359 for m_type in member_types:
1360 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1361 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1362 else:
1363 out.write(" %s *%s;\n" % (m_type, var_name_map(m_type)))
1364 out.write("""
1365 /* Run thru accessors after new to ensure okay */
1366""")
1367 for member in members:
1368 m_type = member["m_type"]
1369 m_name = member["name"]
1370 if loxi_utils.skip_member_name(m_name):
1371 continue
1372 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1373 out.write("""\
1374 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1375""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1376 else:
1377 sub_cls = m_type[:-2] # Trim _t
1378 out.write("""\
1379 {
1380 %(sub_cls)s_t sub_cls;
1381
1382 /* Test bind */
1383 %(cls)s_%(m_name)s_bind(obj, &sub_cls);
1384 }
Andreas Wundsam53256162013-05-02 14:05:53 -07001385""" % dict(var_name=var_name_map(m_type), cls=cls,
Rich Lanea06d0c32013-03-25 08:52:03 -07001386 m_name=m_name, sub_cls=sub_cls,
1387 v_name=loxi_utils.version_to_name(version)))
1388
1389 out.write("""
1390 value = %(cls)s_%(v_name)s_populate_scalars(
1391 obj, value);
1392 TEST_ASSERT(value != 0);
1393""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1394
1395 for member in members:
1396 m_type = member["m_type"]
1397 m_name = member["name"]
1398 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1399 continue
1400 if loxi_utils.skip_member_name(m_name):
1401 continue
1402 if m_type == "of_match_t":
1403 out.write("""\
1404 value = of_match_populate(&%(var_name)s, %(v_name)s, value);
1405 TEST_ASSERT(value != 0);
1406 %(cls)s_%(m_name)s_set(
1407 obj, &%(var_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001408""" % dict(cls=cls, var_name=var_name_map(m_type),
Rich Lanea06d0c32013-03-25 08:52:03 -07001409 m_name=m_name, v_name=loxi_utils.version_to_name(version)))
1410 elif m_type == "of_octets_t":
1411 out.write("""\
1412 value = of_octets_populate(&%(var_name)s, value);
1413 TEST_ASSERT(value != 0);
1414 %(cls)s_%(m_name)s_set(
1415 obj, &%(var_name)s);
1416 if (octets.bytes) {
1417 FREE(octets.data);
1418 }
1419""" % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
1420 else:
1421 sub_cls = m_type[:-2] # Trim _t
1422 out.write("""
1423 %(var_name)s = %(sub_cls)s_new(%(v_name)s);
1424 TEST_ASSERT(%(var_name)s != NULL);
1425 value = %(sub_cls)s_%(v_name)s_populate(
1426 %(var_name)s, value);
1427 TEST_ASSERT(value != 0);
1428 %(cls)s_%(m_name)s_set(
1429 obj, %(var_name)s);
1430 %(sub_cls)s_delete(%(var_name)s);
1431""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1432 var_name=var_name_map(m_type),
1433 v_name=loxi_utils.version_to_name(version)))
1434
1435 out.write("""
1436 return value;
1437}
1438""")
1439
1440 out.write("""
1441/**
1442 * Check all members of an object of type %(cls)s
1443 * populated by the above function
1444 * @param obj Pointer to an object to check
1445 * @param value Starting value for checking
1446 * @returns The value after increments for this object's values
1447 */
1448
1449int
1450%(cls)s_%(v_name)s_check(
1451 %(cls)s_t *obj, int value)
1452{
1453""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1454 members, member_types = loxi_utils.all_member_types_get(cls, version)
1455 for m_type in member_types:
1456 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1457 continue
1458 if loxi_utils.type_is_of_object(m_type):
1459 continue
1460 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1461 out.write("""
1462 value = %(cls)s_%(v_name)s_check_scalars(
1463 obj, value);
1464 TEST_ASSERT(value != 0);
1465""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
1466
1467 for member in members:
1468 m_type = member["m_type"]
1469 m_name = member["name"]
1470 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1471 continue
1472 if loxi_utils.skip_member_name(m_name):
1473 continue
1474 if m_type == "of_match_t":
1475 out.write("""\
1476 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1477 value = of_match_check(&%(var_name)s, %(v_name)s, value);
1478""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1479 v_name=loxi_utils.version_to_name(version)))
1480 elif m_type == "of_octets_t":
1481 out.write("""\
1482 %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
1483 value = of_octets_check(&%(var_name)s, value);
1484""" % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
1485 v_name=loxi_utils.version_to_name(version)))
1486 else:
1487 sub_cls = m_type[:-2] # Trim _t
1488 out.write("""
1489 { /* Use get/delete to access on check */
1490 %(m_type)s *%(m_name)s_ptr;
1491
1492 %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
1493 TEST_ASSERT(%(m_name)s_ptr != NULL);
1494 value = %(sub_cls)s_%(v_name)s_check(
1495 %(m_name)s_ptr, value);
1496 TEST_ASSERT(value != 0);
1497 %(sub_cls)s_delete(%(m_name)s_ptr);
1498 }
1499""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
1500 var_name=var_name_map(m_type),
1501 v_name=loxi_utils.version_to_name(version)))
1502
1503 out.write("""
1504 /* We shoehorn a test of the dup functions here */
1505 {
1506 %(cls)s_t *dup;
1507
1508 TEST_ASSERT((dup = %(cls)s_dup(obj)) != NULL);
1509 TEST_ASSERT(dup->length == obj->length);
1510 TEST_ASSERT(dup->object_id == obj->object_id);
1511 TEST_ASSERT(dup->version == obj->version);
1512 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1513 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1514 of_object_delete((of_object_t *)dup);
1515
1516 /* And now for the generic dup function */
1517 TEST_ASSERT((dup = (%(cls)s_t *)
1518 of_object_dup(obj)) != NULL);
1519 TEST_ASSERT(dup->length == obj->length);
1520 TEST_ASSERT(dup->object_id == obj->object_id);
1521 TEST_ASSERT(dup->version == obj->version);
1522 TEST_ASSERT(MEMCMP(OF_OBJECT_BUFFER_INDEX(dup, 0),
1523 OF_OBJECT_BUFFER_INDEX(obj, 0), obj->length) == 0);
1524 of_object_delete((of_object_t *)dup);
1525 }
1526
1527 return value;
1528}
1529""" % dict(cls=cls))
1530
1531def unified_accessor_test_case(out, cls, version):
1532 """
1533 Generate one test case for the given version and class
1534 """
1535
1536 members, member_types = scalar_member_types_get(cls, version)
Rich Lanef70be942013-07-18 13:33:14 -07001537 length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
Rich Lanea06d0c32013-03-25 08:52:03 -07001538 v_name = loxi_utils.version_to_name(version)
1539
1540 out.write("""
1541static int
1542test_%(cls)s_%(v_name)s(void)
1543{
1544 %(cls)s_t *obj;
1545 obj = %(cls)s_new(%(v_name)s);
1546 TEST_ASSERT(obj != NULL);
1547 TEST_ASSERT(obj->version == %(v_name)s);
1548 TEST_ASSERT(obj->length == %(length)d);
1549 TEST_ASSERT(obj->parent == NULL);
1550 TEST_ASSERT(obj->object_id == %(u_cls)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001551""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001552 v_name=v_name, length=length, version=version))
1553 if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
1554 out.write("""
1555 if (obj->wire_length_get != NULL) {
1556 int length;
1557
1558 obj->wire_length_get((of_object_t *)obj, &length);
1559 TEST_ASSERT(length == %(length)d);
1560 }
1561 if (obj->wire_type_get != NULL) {
1562 of_object_id_t obj_id;
1563
1564 obj->wire_type_get((of_object_t *)obj, &obj_id);
1565 TEST_ASSERT(obj_id == %(u_cls)s);
1566 }
1567
1568 /* Set up incrementing values for members */
1569 TEST_ASSERT(%(cls)s_%(v_name)s_populate(
1570 obj, 1) != 0);
1571
1572 /* Check values just set */
1573 TEST_ASSERT(%(cls)s_%(v_name)s_check(
1574 obj, 1) != 0);
Andreas Wundsam53256162013-05-02 14:05:53 -07001575""" % dict(cls=cls, u_cls=cls.upper(),
Rich Lanea06d0c32013-03-25 08:52:03 -07001576 v_name=v_name, length=length, version=version))
1577
1578 out.write("""
1579 %(cls)s_delete(obj);
1580
1581 /* To do: Check memory */
1582 return TEST_PASS;
1583}
1584""" % dict(cls=cls))
1585
1586
1587def gen_unified_accessor_funs(out):
1588 for version in of_g.of_version_range:
1589 for cls in of_g.standard_class_order:
1590 if not loxi_utils.class_in_version(cls, version):
1591 continue
1592 if cls in type_maps.inheritance_map:
1593 continue
1594 elif loxi_utils.class_is_list(cls):
1595 gen_list_setup_check(out, cls, version)
1596 else:
1597 gen_class_setup_check(out, cls, version)
1598
1599def gen_unified_accessor_tests(out, name):
1600 loxi_utils.gen_c_copy_license(out)
1601 out.write("""
1602/**
1603 *
1604 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1605 *
1606 * Unified simple class instantiation tests for all versions
1607 */
1608
1609#include <locitest/test_common.h>
1610""")
1611 for version in of_g.of_version_range:
1612 for cls in of_g.standard_class_order:
1613 if not loxi_utils.class_in_version(cls, version):
1614 continue
1615 if cls in type_maps.inheritance_map:
1616 continue
1617 unified_accessor_test_case(out, cls, version)
1618
1619 out.write("""
1620int
1621run_unified_accessor_tests(void)
1622{
1623""")
1624 for version in of_g.of_version_range:
1625 v_name = loxi_utils.version_to_name(version)
1626 for cls in of_g.standard_class_order:
1627 if not loxi_utils.class_in_version(cls, version):
1628 continue
1629 if cls in type_maps.inheritance_map:
1630 continue
1631 test_name = "%s_%s" % (cls, v_name)
1632 out.write(" RUN_TEST(%s);\n" % test_name)
1633
1634 out.write(" return TEST_PASS;\n}\n");
1635
1636
1637
1638################################################################
1639#
1640# Object duplication functions
1641#
1642# These exercise the accessors to create duplicate objects.
1643# They are used in the LOCI test shim which sits in an OF
1644# protocol stream.
1645#
1646# TODO
1647# Resolve version stuff
1648# Complete list dup
1649
1650def gen_dup_list(out, cls, version):
1651 ver_name = loxi_utils.version_to_name(version)
1652 elt_type = loxi_utils.list_to_entry_type(cls)
1653 out.write("""
1654/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001655 * Duplicate a list of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001656 * using accessor functions
1657 * @param src Pointer to object to be duplicated
1658 * @returns A new object of type %(cls)s.
1659 *
1660 * The caller is responsible for deleting the returned value
1661 */
1662%(cls)s_t *
1663%(cls)s_%(ver_name)s_dup(
1664 %(cls)s_t *src)
1665{
1666 %(elt_type)s_t src_elt;
1667 %(elt_type)s_t *dst_elt;
1668 int rv;
1669 %(cls)s_t *dst;
1670
1671 if ((dst = %(cls)s_new(src->version)) == NULL) {
1672 return NULL;
1673 }
1674""" % dict(elt_type=elt_type, cls=cls, ver_name=ver_name))
1675
1676 out.write("""
1677 %(u_cls)s_ITER(src, &src_elt, rv) {
1678 if ((dst_elt = %(elt_type)s_%(ver_name)s_dup(&src_elt)) == NULL) {
1679 of_object_delete((of_object_t *)dst);
1680 return NULL;
1681 }
1682 _TRY_FREE(%(cls)s_append(dst, dst_elt),
1683 dst, NULL);
1684 of_object_delete((of_object_t *)dst_elt);
1685 }
1686
1687 return dst;
1688}
1689""" % dict(u_cls=cls.upper(), elt_type=elt_type, cls=cls, ver_name=ver_name))
1690
1691
1692def gen_dup_inheritance(out, cls, version):
1693 ver_name = loxi_utils.version_to_name(version)
1694 out.write("""
1695/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001696 * Duplicate a super class object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001697 * @param src Pointer to object to be duplicated
1698 * @returns A new object of type %(cls)s.
1699 *
1700 * The caller is responsible for deleting the returned value
1701 */
1702%(cls)s_t *
1703%(cls)s_%(ver_name)s_dup(
1704 %(cls)s_t *src)
1705{
1706""" % dict(cls=cls, ver_name=ver_name))
1707
1708 # For each subclass, check if this is an instance of that subclass
1709 version_classes = type_maps.inheritance_data[cls][version]
1710 for sub_cls in version_classes:
1711 sub_enum = (cls + "_" + sub_cls).upper()
1712 out.write("""
1713 if (src->header.object_id == %(sub_enum)s) {
1714 return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
1715 &src->%(sub_cls)s);
1716 }
1717""" % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
1718
1719 out.write("""
1720 return NULL;
1721}
1722""")
1723
1724
1725def gen_dup_cls(out, cls, version):
1726 """
1727 Generate duplication routine for class cls
1728 """
1729 ver_name = loxi_utils.version_to_name(version)
1730
1731 out.write("""
1732/**
Andreas Wundsam53256162013-05-02 14:05:53 -07001733 * Duplicate an object of type %(cls)s
Rich Lanea06d0c32013-03-25 08:52:03 -07001734 * using accessor functions
1735 * @param src Pointer to object to be duplicated
1736 * @returns A new object of type %(cls)s.
1737 *
1738 * The caller is responsible for deleting the returned value
1739 */
1740%(cls)s_t *
1741%(cls)s_%(ver_name)s_dup(
1742 %(cls)s_t *src)
1743{
1744 %(cls)s_t *dst;
1745""" % dict(cls=cls, ver_name=ver_name))
1746
1747 # Get members and types for the class
1748 members, member_types = loxi_utils.all_member_types_get(cls, version)
1749
1750 # Add declarations for each member type
1751 for m_type in member_types:
1752 if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
1753 # Declare instance of these
1754 out.write(" %s %s;\n" % (m_type, var_name_map(m_type)))
1755 else:
1756 out.write("""
1757 %(m_type)s src_%(v_name)s;
1758 %(m_type)s *dst_%(v_name)s;
1759""" % dict(m_type=m_type, v_name=var_name_map(m_type)))
1760
1761 out.write("""
1762 if ((dst = %(cls)s_new(src->version)) == NULL) {
1763 return NULL;
1764 }
1765""" % dict(cls=cls))
1766
1767 for member in members:
1768 m_type = member["m_type"]
1769 m_name = member["name"]
1770 if loxi_utils.skip_member_name(m_name):
1771 continue
1772 if loxi_utils.type_is_scalar(m_type): # Handled by call to scalar setup
1773 out.write("""
1774 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1775 %(cls)s_%(m_name)s_set(dst, %(v_name)s);
1776""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1777 elif m_type in ["of_match_t", "of_octets_t"]:
1778 out.write("""
1779 %(cls)s_%(m_name)s_get(src, &%(v_name)s);
1780 %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
1781""" % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
1782 else:
1783 sub_cls = m_type[:-2] # Trim _t
1784 out.write("""
1785 %(cls)s_%(m_name)s_bind(
1786 src, &src_%(v_name)s);
1787 dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
1788 if (dst_%(v_name)s == NULL) {
1789 %(cls)s_delete(dst);
1790 return NULL;
1791 }
1792 %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
1793 %(sub_cls)s_delete(dst_%(v_name)s);
Andreas Wundsam53256162013-05-02 14:05:53 -07001794""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
Rich Lanea06d0c32013-03-25 08:52:03 -07001795 v_name=var_name_map(m_type), ver_name=ver_name))
1796
1797 out.write("""
1798 return dst;
1799}
1800""")
1801
1802def gen_version_dup(out=sys.stdout):
1803 """
1804 Generate duplication routines for each object type
1805 """
1806 out.write("""
1807/* Special try macro for duplicating */
1808#define _TRY_FREE(op, obj, rv) do { \\
1809 int _rv; \\
1810 if ((_rv = (op)) < 0) { \\
1811 LOCI_LOG_ERROR("ERROR %d at %s:%d\\n", _rv, __FILE__, __LINE__); \\
1812 of_object_delete((of_object_t *)(obj)); \\
1813 return (rv); \\
1814 } \\
1815 } while (0)
1816""")
1817
1818 for version in of_g.of_version_range:
1819 for cls in of_g.standard_class_order:
1820 if not loxi_utils.class_in_version(cls, version):
1821 continue
1822 if cls in type_maps.inheritance_map:
1823 gen_dup_inheritance(out, cls, version)
1824 elif loxi_utils.class_is_list(cls):
1825 gen_dup_list(out, cls, version)
1826 else:
1827 gen_dup_cls(out, cls, version)
1828
1829def gen_dup(out=sys.stdout):
1830 """
1831 Generate non-version specific duplication routines for each object type
1832 """
1833
1834 for cls in of_g.standard_class_order:
1835 out.write("""
1836%(cls)s_t *
1837%(cls)s_dup(
1838 %(cls)s_t *src)
1839{
1840""" % dict(cls=cls))
1841 for version in of_g.of_version_range:
1842 if not loxi_utils.class_in_version(cls, version):
1843 continue
1844 hdr = "header." if cls in type_maps.inheritance_map else ""
1845
1846 ver_name = loxi_utils.version_to_name(version)
1847 out.write("""
1848 if (src->%(hdr)sversion == %(ver_name)s) {
1849 return %(cls)s_%(ver_name)s_dup(src);
1850 }
1851""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
1852
1853 out.write("""
1854 /* Class not supported in given version */
1855 return NULL;
1856}
1857""")
1858
1859def dup_c_gen(out, name):
1860 """
1861 Generate the C file for duplication functions
1862 """
1863 loxi_utils.gen_c_copy_license(out)
1864 out.write("""\
1865/*
1866 * Duplication functions for all OF objects
1867 *
1868 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1869 *
1870 * These are test functions for exercising accessors. You can call
1871 * of_object_dup for an efficient duplication.
1872 */
1873
1874#define DISABLE_WARN_UNUSED_RESULT
1875#include "loci_log.h"
1876#include <locitest/of_dup.h>
1877
1878""")
1879
1880 gen_version_dup(out)
1881 gen_dup(out)
1882
1883
1884def dup_h_gen(out, name):
1885 """
1886 Generate the header file for duplication functions
1887 """
1888
1889 loxi_utils.gen_c_copy_license(out)
1890 out.write("""
1891/*
1892 * Duplication function header file
1893 *
1894 * AUTOMATICALLY GENERATED FILE. Edits will be lost on regen.
1895 */
1896
1897#if !defined(_OF_DUP_H_)
1898#define _OF_DUP_H_
1899
1900#include <loci/loci.h>
1901""")
1902
1903 for cls in of_g.standard_class_order:
1904 out.write("""
1905extern %(cls)s_t *
1906 %(cls)s_dup(
1907 %(cls)s_t *src);
1908""" % dict(cls=cls))
1909
1910 for version in of_g.of_version_range:
1911 for cls in of_g.standard_class_order:
1912 if not loxi_utils.class_in_version(cls, version):
1913 continue
1914 ver_name = loxi_utils.version_to_name(version)
1915 out.write("""
1916extern %(cls)s_t *
1917 %(cls)s_%(ver_name)s_dup(
1918 %(cls)s_t *src);
1919""" % dict(cls=cls, ver_name=ver_name))
1920
1921 out.write("\n#endif /* _OF_DUP_H_ */\n")
1922
1923def gen_log_test(out):
1924 """
1925 Generate test for obj log calls
1926
1927 Define a trivial handler for object logging; call all obj log fns
1928 """
1929 out.write("""
1930
1931/**
1932 * Test object dump functions
1933 */
1934
1935int
1936test_dump_objs(void)
1937{
1938 of_object_t *obj;
1939
1940 FILE *out = fopen("/dev/null", "w");
1941
1942 /* Call each obj dump function */
1943""")
1944 for version in of_g.of_version_range:
1945 for j, cls in enumerate(of_g.all_class_order):
1946 if not loxi_utils.class_in_version(cls, version):
1947 continue
1948 if cls in type_maps.inheritance_map:
1949 continue
1950 out.write("""
1951 obj = (of_object_t *)%(cls)s_new(%(version)s);
1952 of_object_dump((loci_writer_f)fprintf, out, obj);
1953 of_object_delete(obj);
1954""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
Andreas Wundsam53256162013-05-02 14:05:53 -07001955
Rich Lanea06d0c32013-03-25 08:52:03 -07001956 out.write("""
1957 fclose(out);
1958 return TEST_PASS;
1959}
1960""")
1961
1962def gen_ident_tests(out):
1963 """
1964 Generate tests for identifiers
1965
1966 For all idents, instantiate, test version supported macros
1967 For flags, set it, test it, clear it, test it.
1968 """
1969 out.write("""
1970/**
1971 * Test cases for all flag accessor macros
1972 * These only test self consistency (and that they compile)
1973 */
1974int
1975test_ident_macros(void)
1976{
1977 int value __attribute__((unused));
1978 uint32_t flags;
1979
1980""")
1981
1982 for ident, info in of_g.identifiers.items():
1983 if not identifiers.defined_versions_agree(of_g.identifiers,
1984 of_g.target_version_list,
1985 ident):
1986 # @fixme
1987 continue
1988 out.write(" value = %s;\n" % ident)
1989 for version in of_g.target_version_list:
1990 if version in info["values_by_version"].keys():
1991 out.write(" TEST_ASSERT(%s_SUPPORTED(%s));\n" %
1992 (ident, of_g.of_version_wire2name[version]))
1993 else:
1994 out.write(" TEST_ASSERT(!%s_SUPPORTED(%s));\n" %
1995 (ident, of_g.of_version_wire2name[version]))
1996 if flags.ident_is_flag(ident):
1997 # Grab first supported version
1998 for version in info["values_by_version"]:
1999 break
2000 out.write("""
2001 flags = 0;
2002 %(ident)s_SET(flags, %(ver_name)s);
2003 TEST_ASSERT(flags == %(ident)s_BY_VERSION(%(ver_name)s));
2004 TEST_ASSERT(%(ident)s_TEST(flags, %(ver_name)s));
2005 %(ident)s_CLEAR(flags, %(ver_name)s);
2006 TEST_ASSERT(flags == 0);
2007 TEST_ASSERT(!%(ident)s_TEST(flags, %(ver_name)s));
2008""" % dict(ident=ident, ver_name=of_g.of_version_wire2name[version]))
2009
2010 out.write("""
2011 return TEST_PASS;
2012}
2013""")
2014
Rich Laneccae0312013-07-21 23:34:13 -07002015def gen_datafiles_tests(out, name):
2016 tests = []
2017 for filename in test_data.list_files():
2018 data = test_data.read(filename)
2019 if not 'c' in data:
2020 continue
2021 name = filename[:-5].replace("/", "_")
2022 tests.append(dict(name=name,
2023 filename=filename,
2024 c=data['c'],
2025 binary=data['binary']))
2026
2027 util.render_template(out, "test_data.c", tests=tests)