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