blob: f8d5543edc1f35184eee9e50f7168c6f68e34f44 [file] [log] [blame]
Rich Lane1d5b0102013-05-10 16:28:17 -07001#!/usr/bin/env python
2# Copyright 2013, Big Switch Networks, Inc.
3#
4# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
5# the following special exception:
6#
7# LOXI Exception
8#
9# As a special exception to the terms of the EPL, you may distribute libraries
10# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
11# that copyright and licensing notices generated by LoxiGen are not altered or removed
12# from the LoxiGen Libraries and the notice provided below is (i) included in
13# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
14# documentation for the LoxiGen Libraries, if distributed in binary form.
15#
16# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
17#
18# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
19# a copy of the EPL at:
20#
21# http://www.eclipse.org/legal/epl-v10.html
22#
23# Unless required by applicable law or agreed to in writing, software
24# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26# EPL for the specific language governing permissions and limitations
27# under the EPL.
28
Rich Lane9a3f1fd2013-05-10 16:29:17 -070029import sys
Rich Lane1d5b0102013-05-10 16:28:17 -070030import difflib
Rich Lane5c4446e2013-05-16 13:53:51 -070031import re
32import os
33import unittest
Rich Lane9a3f1fd2013-05-10 16:29:17 -070034import test_data
Rich Lane5b2745c2013-11-30 00:36:24 -080035from loxi.generic_util import OFReader
Rich Lane1d5b0102013-05-10 16:28:17 -070036
37# Human-friendly format for binary strings. 8 bytes per line.
38def format_binary(buf):
39 byts = map(ord, buf)
40 lines = [[]]
41 for byt in byts:
42 if len(lines[-1]) == 8:
43 lines.append([])
44 lines[-1].append(byt)
45 return '\n'.join([' '.join(['%02x' % y for y in x]) for x in lines])
46
47def diff(a, b):
48 return '\n'.join(difflib.ndiff(a.splitlines(), b.splitlines()))
49
Rich Laned392eae2013-05-10 16:34:34 -070050# Test serialization / deserialization / reserialization of a sample object.
51# Depends in part on the __eq__ method being correct.
Rich Lane1d5b0102013-05-10 16:28:17 -070052def test_serialization(obj, buf):
53 packed = obj.pack()
54 if packed != buf:
55 a = format_binary(buf)
56 b = format_binary(packed)
57 raise AssertionError("Serialization of %s failed\nExpected:\n%s\nActual:\n%s\nDiff:\n%s" % \
58 (type(obj).__name__, a, b, diff(a, b)))
Rich Lane5b2745c2013-11-30 00:36:24 -080059 unpacked = type(obj).unpack(OFReader(buf))
Rich Lane1d5b0102013-05-10 16:28:17 -070060 if obj != unpacked:
61 a = obj.show()
62 b = unpacked.show()
63 raise AssertionError("Deserialization of %s failed\nExpected:\n%s\nActual:\n%s\nDiff:\n%s" % \
64 (type(obj).__name__, a, b, diff(a, b)))
Rich Laned392eae2013-05-10 16:34:34 -070065 packed = unpacked.pack()
66 if packed != buf:
67 a = format_binary(buf)
68 b = format_binary(packed)
69 raise AssertionError("Reserialization of %s failed\nExpected:\n%s\nActual:\n%s\nDiff:\n%s" % \
70 (type(obj).__name__, a, b, diff(a, b)))
Rich Lane9a3f1fd2013-05-10 16:29:17 -070071
72def test_pretty(obj, expected):
73 pretty = obj.show()
74 if expected != pretty:
75 raise AssertionError("Pretty printing of %s failed\nExpected:\n%s\nActual:\n%s\nDiff:\n%s" % \
76 (type(obj).__name__, expected, pretty, diff(expected, pretty)))
77
78# Run test_serialization and possibly test_pretty against the named data file
Rich Lane5c4446e2013-05-16 13:53:51 -070079def test_datafile(name, ofp):
Rich Lane9a3f1fd2013-05-10 16:29:17 -070080 data = test_data.read(name)
Rich Lane5c4446e2013-05-16 13:53:51 -070081 if not 'python' in data:
82 raise unittest.SkipTest("no python section in datafile")
Rich Lane9a3f1fd2013-05-10 16:29:17 -070083 binary = data['binary']
84 python = data['python']
Rich Lane5c4446e2013-05-16 13:53:51 -070085 obj = eval(python, { 'ofp': ofp })
Rich Lane9a3f1fd2013-05-10 16:29:17 -070086 test_serialization(obj, binary)
87 if 'python pretty-printer' in data:
88 test_pretty(obj, data['python pretty-printer'])
Rich Lane5c4446e2013-05-16 13:53:51 -070089
90# Add test_datafile tests for each datafile matching the given regex
91# The argument 'klass' should be a subclass of TestCase which will have the
92# test_* methods added to it.
93#
94# It would be cleaner to do this by constructing a TestSuite instance and
95# adding individual TestCase objects, but the TestLoader wouldn't pick it
96# up. We could use the load_tests protocol but that isn't available before
97# Python 2.7.
98def add_datafiles_tests(klass, regex, ofp):
99 for filename in test_data.list_files():
100 match = re.match(regex, filename)
101 if not match:
102 continue
103 def make_test(filename):
104 def fn(self):
105 test_datafile(filename, ofp)
106 return fn
107 setattr(klass, 'test_' + os.path.splitext(filename)[0], make_test(filename))