Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 1 | #!/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 | |
| 29 | import sys |
| 30 | import os |
| 31 | import unittest |
| 32 | |
| 33 | from nose.tools import eq_, ok_, raises |
| 34 | |
| 35 | root_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') |
| 36 | sys.path.insert(0, root_dir) |
| 37 | |
| 38 | import loxi_ir.ir as ir |
| 39 | import loxi_front_end.frontend_ir as fe |
| 40 | |
| 41 | class BuildIRTest(unittest.TestCase): |
| 42 | |
| 43 | def test_simple(self): |
| 44 | version = ir.OFVersion("1.0", 1) |
| 45 | input = fe.OFInput(filename="test.dat", |
| 46 | wire_versions=(1,), |
| 47 | classes=( |
| 48 | fe.OFClass(name="OFMessage", |
| 49 | superclass=None, |
| 50 | members=( |
| 51 | fe.OFDataMember(name='version', oftype='uint32_t'), |
| 52 | fe.OFLengthMember(name='length', oftype='uint16_t') |
| 53 | ), |
| 54 | virtual=False, |
| 55 | params={} |
| 56 | ), |
| 57 | ), |
| 58 | enums=() |
| 59 | ) |
| 60 | |
| 61 | p = ir.build_protocol(version, [ input ]) |
| 62 | eq_(1, len(p.classes)) |
| 63 | c = p.classes[0] |
| 64 | eq_("OFMessage", c.name) |
| 65 | eq_(None, c.superclass) |
| 66 | eq_(False, c.virtual) |
| 67 | eq_({}, c.params) |
| 68 | eq_(2, len(c.members)) |
| 69 | eq_(p, c.protocol) |
| 70 | |
| 71 | m1 = c.members[0] |
| 72 | ok_(isinstance(m1, ir.OFDataMember)) |
| 73 | eq_("version", m1.name) |
| 74 | eq_("uint32_t", m1.oftype) |
| 75 | eq_(4, m1.length) |
| 76 | eq_(True, m1.is_fixed_length) |
| 77 | eq_(0, m1.offset) |
| 78 | eq_(c, m1.of_class) |
| 79 | |
| 80 | m2 = c.members[1] |
| 81 | ok_(isinstance(m2, ir.OFLengthMember)) |
| 82 | eq_("length", m2.name) |
| 83 | eq_("uint16_t", m2.oftype) |
| 84 | eq_(2, m2.length) |
| 85 | eq_(True, m2.is_fixed_length) |
| 86 | eq_(4, m2.offset) |
| 87 | eq_(c, m2.of_class) |
| 88 | |
| 89 | eq_(True, c.is_fixed_length) |
| 90 | eq_(6, c.length) |
| 91 | |
| 92 | def test_resolve_superclass(self): |
| 93 | version = ir.OFVersion("1.0", 1) |
| 94 | input = fe.OFInput(filename="test.dat", |
| 95 | wire_versions=(1,), |
| 96 | classes=( |
| 97 | fe.OFClass(name="OFMessage", |
| 98 | superclass=None, |
| 99 | members=(), |
| 100 | virtual=True, |
| 101 | params={} |
| 102 | ), |
| 103 | fe.OFClass(name="OFHello", |
| 104 | superclass="OFMessage", |
| 105 | members=(), |
| 106 | virtual=False, |
| 107 | params={} |
| 108 | ), |
| 109 | ), |
| 110 | enums=() |
| 111 | ) |
| 112 | p = ir.build_protocol(version, [ input ]) |
| 113 | eq_(2, len(p.classes)) |
| 114 | c, c2 = p.classes |
| 115 | eq_("OFMessage", c.name) |
| 116 | eq_(None, c.superclass) |
| 117 | eq_(True, c.virtual) |
| 118 | eq_("OFHello", c2.name) |
| 119 | eq_(c, c2.superclass) |
| 120 | eq_(False, c2.virtual) |
| 121 | |
| 122 | @raises(ir.ClassNotFoundException) |
| 123 | def test_resolve_superclass(self): |
| 124 | version = ir.OFVersion("1.0", 1) |
| 125 | input = fe.OFInput(filename="test.dat", |
| 126 | wire_versions=(1,), |
| 127 | classes=( |
| 128 | fe.OFClass(name="OFMessage", |
| 129 | superclass="NotFoundSuperClass", |
| 130 | members=(), |
| 131 | virtual=True, |
| 132 | params={} |
| 133 | ), |
| 134 | ), |
| 135 | enums=() |
| 136 | ) |
| 137 | p = ir.build_protocol(version, [ input ]) |
| 138 | |
| 139 | |
| 140 | @raises(ir.DependencyCycleException) |
| 141 | def test_dependency_cycle(self): |
| 142 | version = ir.OFVersion("1.0", 1) |
| 143 | input = fe.OFInput(filename="test.dat", |
| 144 | wire_versions=(1,), |
| 145 | classes=( |
| 146 | fe.OFClass(name="OFMessage", |
| 147 | superclass="OFHeader", |
| 148 | members=(), |
| 149 | virtual=True, |
| 150 | params={} |
| 151 | ), |
| 152 | fe.OFClass(name="OFHeader", |
| 153 | superclass="OFMessage", |
| 154 | members=(), |
| 155 | virtual=True, |
| 156 | params={} |
| 157 | ), |
| 158 | ), |
| 159 | enums=() |
| 160 | ) |
| 161 | p = ir.build_protocol(version, [ input ]) |
| 162 | |
| 163 | @raises(ir.RedefinedException) |
| 164 | def test_class_redefined(self): |
| 165 | version = ir.OFVersion("1.0", 1) |
| 166 | inputs = ( |
| 167 | fe.OFInput(filename="test.dat", |
| 168 | wire_versions=(1,), |
| 169 | classes=( |
| 170 | fe.OFClass(name="OFMessage", |
| 171 | superclass=None, |
| 172 | members=(), |
| 173 | virtual=True, |
| 174 | params={} |
| 175 | ), |
| 176 | ), |
| 177 | enums=(), |
| 178 | ), |
| 179 | fe.OFInput(filename="test2.dat", |
| 180 | wire_versions=(1,), |
| 181 | classes=( |
| 182 | fe.OFClass(name="OFMessage", |
| 183 | superclass=None, |
| 184 | members=(), |
| 185 | virtual=True, |
| 186 | params={} |
| 187 | ), |
| 188 | ), |
| 189 | enums=() |
| 190 | ) |
| 191 | ) |
| 192 | p = ir.build_protocol(version, inputs) |
| 193 | |
| 194 | |
| 195 | def test_enums(self): |
| 196 | version = ir.OFVersion("1.0", 1) |
| 197 | input = fe.OFInput(filename="test.dat", |
| 198 | wire_versions=(1,), |
| 199 | classes=(), |
| 200 | enums=( |
| 201 | fe.OFEnum(name='ofp_flow_wildcards', |
| 202 | entries=(fe.OFEnumEntry(name="OFPFW_IN_PORT", value=0x01, params={}), |
| 203 | fe.OFEnumEntry(name="OFPFW_DL_VLAN", value=0x2, params={})), |
| 204 | params = dict(wire_type="uint32_t", bitmask=True) |
| 205 | ), |
| 206 | fe.OFEnum(name='ofp_queue_properties', |
| 207 | entries=(fe.OFEnumEntry(name="OFPQT_NONE", value=0x00, params={}), |
| 208 | fe.OFEnumEntry(name="OFPQT_MIN_RATE", value=0x1, params={})), |
| 209 | params = dict(wire_type="uint32_t") |
| 210 | ), |
| 211 | ) |
| 212 | ) |
| 213 | |
| 214 | p = ir.build_protocol(version, [ input ]) |
| 215 | eq_(0, len(p.classes)) |
| 216 | eq_(2, len(p.enums)) |
| 217 | e = p.enums[0] |
| 218 | eq_("ofp_flow_wildcards", e.name) |
| 219 | eq_(True, e.is_bitmask) |
| 220 | eq_("uint32_t", e.wire_type) |
| 221 | eq_(ir.OFEnumEntry(name="OFPFW_IN_PORT", value=0x01, params={}), e.entries[0]) |
| 222 | eq_(ir.OFEnumEntry(name="OFPFW_DL_VLAN", value=0x02, params={}), e.entries[1]) |
| 223 | |
| 224 | e = p.enums[1] |
| 225 | eq_("ofp_queue_properties", e.name) |
| 226 | eq_(False, e.is_bitmask) |
| 227 | eq_("uint32_t", e.wire_type) |
| 228 | eq_(ir.OFEnumEntry(name="OFPQT_NONE", value=0x00, params={}), e.entries[0]) |
| 229 | eq_(ir.OFEnumEntry(name="OFPQT_MIN_RATE", value=0x01, params={}), e.entries[1]) |
| 230 | |
| 231 | if __name__ == '__main__': |
| 232 | unittest.main() |