blob: c454ffc86380b8bc29278db61be268583e995255 [file] [log] [blame]
Paul Vinciguerra7e0c48e2019-02-01 19:37:45 -08001#!/usr/bin/env python3
Ole Troan9d420872017-10-12 13:06:35 +02002
3import unittest
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05004from vppapigen import VPPAPI, Option, ParseError, Union, foldup_crcs, \
5 global_types
Ole Troan9f84e702020-06-25 14:27:46 +02006import vppapigen
Ole Troan9d420872017-10-12 13:06:35 +02007
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05008
Ole Troan9d420872017-10-12 13:06:35 +02009# TODO
Ole Troan9f84e702020-06-25 14:27:46 +020010# - test parsing of options, typedefs, enums, defines
Ole Troan9d420872017-10-12 13:06:35 +020011# - test JSON, C output
12
13
14class TestVersion(unittest.TestCase):
15 @classmethod
16 def setUpClass(cls):
17 cls.parser = VPPAPI()
18
19 def test_version(self):
20 version_string = 'option version = "1.0.0";'
21 r = self.parser.parse_string(version_string)
22 self.assertTrue(isinstance(r[0], Option))
23
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -050024
Ole Troand5a78a52019-09-18 12:12:47 +020025class TestUnion(unittest.TestCase):
26 @classmethod
27 def setUpClass(cls):
28 cls.parser = VPPAPI()
29
30 def test_union(self):
31 test_string = '''
32 union foo_union {
33 u32 a;
34 u8 b;
35 };
36 '''
37 r = self.parser.parse_string(test_string)
38 self.assertTrue(isinstance(r[0], Union))
39
40 def test_union_vla(self):
41 test_string = '''
42 union foo_union_vla {
43 u32 a;
44 u8 b[a];
45 };
46 autoreply define foo {
47 vl_api_foo_union_vla_t v;
48 };
49 '''
50 r = self.parser.parse_string(test_string)
51 self.assertTrue(isinstance(r[0], Union))
52 self.assertTrue(r[0].vla)
53 s = self.parser.process(r)
54
Ole Troand5a78a52019-09-18 12:12:47 +020055 test_string2 = '''
56 union foo_union_vla2 {
57 u32 a;
58 u8 b[a];
59 u32 c;
60 };
61 autoreply define foo2 {
62 vl_api_foo_union_vla2_t v;
63 };
64 '''
65 self.assertRaises(ValueError, self.parser.parse_string, test_string2)
66
67 test_string3 = '''
68 union foo_union_vla3 {
69 u32 a;
70 u8 b[a];
71 };
72 autoreply define foo3 {
73 vl_api_foo_union_vla3_t v;
74 u32 x;
75 };
76 '''
77 self.assertRaises(ValueError, self.parser.parse_string, test_string3)
Ole Troan9d420872017-10-12 13:06:35 +020078
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -050079
Ole Troan9d420872017-10-12 13:06:35 +020080class TestTypedef(unittest.TestCase):
81 @classmethod
82 def setUpClass(cls):
83 cls.parser = VPPAPI()
84
85 def test_duplicatetype(self):
86 test_string = '''
Paul Vinciguerra4bf84902019-07-31 00:34:05 -040087 typedef foo1 { u8 dummy; };
88 typedef foo1 { u8 dummy; };
Ole Troan9d420872017-10-12 13:06:35 +020089 '''
90 self.assertRaises(KeyError, self.parser.parse_string, test_string)
91
92
93class TestDefine(unittest.TestCase):
94 @classmethod
95 def setUpClass(cls):
96 cls.parser = VPPAPI()
97
98 def test_unknowntype(self):
99 test_string = 'define foo { foobar foo;};'
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400100 with self.assertRaises(ParseError) as ctx:
101 self.parser.parse_string(test_string)
102 self.assertIn('Undefined type: foobar', str(ctx.exception))
103
Ole Troan9d420872017-10-12 13:06:35 +0200104 test_string = 'define { u8 foo;};'
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400105 with self.assertRaises(ParseError) as ctx:
106 self.parser.parse_string(test_string)
Ole Troan9d420872017-10-12 13:06:35 +0200107
108 def test_flags(self):
109 test_string = '''
110 manual_print dont_trace manual_endian define foo { u8 foo; };
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400111 define foo_reply {u32 context; i32 retval; };
Ole Troan9d420872017-10-12 13:06:35 +0200112 '''
113 r = self.parser.parse_string(test_string)
114 self.assertIsNotNone(r)
115 s = self.parser.process(r)
116 self.assertIsNotNone(s)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400117 for d in s['Define']:
118 if d.name == 'foo':
119 self.assertTrue(d.dont_trace)
120 self.assertTrue(d.manual_endian)
121 self.assertTrue(d.manual_print)
122 self.assertFalse(d.autoreply)
Ole Troan9d420872017-10-12 13:06:35 +0200123
124 test_string = '''
125 nonexisting_flag define foo { u8 foo; };
126 '''
Paul Vinciguerra7e0c48e2019-02-01 19:37:45 -0800127 with self.assertRaises(ParseError):
128 self.parser.parse_string(test_string)
Ole Troan9d420872017-10-12 13:06:35 +0200129
Ole Troan68ebcd52020-08-10 17:06:44 +0200130 def test_options(self):
131 test_string = '''
132 define foo { option deprecated; u8 foo; };
133 define foo_reply {u32 context; i32 retval; };
134 '''
135 r = self.parser.parse_string(test_string)
136 self.assertIsNotNone(r)
137 s = self.parser.process(r)
138 self.assertIsNotNone(s)
139
Ole Troan9d420872017-10-12 13:06:35 +0200140
141class TestService(unittest.TestCase):
142 @classmethod
143 def setUpClass(cls):
144 cls.parser = VPPAPI()
145
146 def test_service(self):
147 test_string = '''
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400148 autoreply define show_version { u8 foo;};
149 service { rpc show_version returns show_version_reply; };
Ole Troan9d420872017-10-12 13:06:35 +0200150 '''
151 r = self.parser.parse_string(test_string)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400152 s = self.parser.process(r)
153 self.assertEqual(s['Service'][0].caller, 'show_version')
154 self.assertEqual(s['Service'][0].reply, 'show_version_reply')
Ole Troan9d420872017-10-12 13:06:35 +0200155
156
Ole Troan9f84e702020-06-25 14:27:46 +0200157def get_crc(apistring, name):
158 vppapigen.global_types = {}
159 parser = vppapigen.VPPAPI()
160 r = parser.parse_string(apistring)
161 s = parser.process(r)
162 foldup_crcs(s['Define'])
163 d = [f for f in s['Define'] if f.name == name]
164 return d[0].crc
165
166
167class TestCRC(unittest.TestCase):
168 def test_crc(self):
169 test_string = '''
170 typedef list { u8 foo; };
171 autoreply define foo { u8 foo; vl_api_list_t l;};
172 '''
173 crc = get_crc(test_string, 'foo')
174
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500175 # modify underlying type
Ole Troan9f84e702020-06-25 14:27:46 +0200176 test_string = '''
177 typedef list { u8 foo2; };
178 autoreply define foo { u8 foo; vl_api_list_t l;};
179 '''
180 crc2 = get_crc(test_string, 'foo')
181 self.assertNotEqual(crc, crc2)
182
183 # two user-defined types
184 test_string = '''
185 typedef address { u8 foo2; };
186 typedef list { u8 foo2; vl_api_address_t add; };
187 autoreply define foo { u8 foo; vl_api_list_t l;};
188 '''
189 crc3 = get_crc(test_string, 'foo')
190
191 test_string = '''
192 typedef address { u8 foo3; };
193 typedef list { u8 foo2; vl_api_address_t add; };
194 autoreply define foo { u8 foo; vl_api_list_t l;};
195 '''
196 crc4 = get_crc(test_string, 'foo')
197 self.assertNotEqual(crc3, crc4)
198
199 test_string = '''
200 typedef address { u8 foo3; };
201 typedef list { u8 foo2; vl_api_address_t add; u8 foo3; };
202 autoreply define foo { u8 foo; vl_api_list_t l;};
203 '''
204 crc5 = get_crc(test_string, 'foo')
205 self.assertNotEqual(crc4, crc5)
206
207 test_string = '''
208typedef ip6_address
209{
210 u8 foo;
211};
212typedef srv6_sid_list
213{
214 u8 num_sids;
215 u32 weight;
216 u32 sl_index;
217 vl_api_ip6_address_t sids[16];
218};
219autoreply define sr_policy_add
220{
221 u32 client_index;
222 u32 context;
223 vl_api_ip6_address_t bsid_addr;
224 u32 weight;
225 bool is_encap;
226 bool is_spray;
227 u32 fib_table;
228 vl_api_srv6_sid_list_t sids;
229};
230'''
231
232 crc = get_crc(test_string, 'sr_policy_add')
233
234 test_string = '''
235typedef ip6_address
236{
237 u8 foo;
238};
239typedef srv6_sid_list
240{
241 u8 num_sids;
242 u32 weight;
243 vl_api_ip6_address_t sids[16];
244};
245autoreply define sr_policy_add
246{
247 u32 client_index;
248 u32 context;
249 vl_api_ip6_address_t bsid_addr;
250 u32 weight;
251 bool is_encap;
252 bool is_spray;
253 u32 fib_table;
254 vl_api_srv6_sid_list_t sids;
255};
256'''
257 crc2 = get_crc(test_string, 'sr_policy_add')
258
259 self.assertNotEqual(crc, crc2)
260
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500261
262class TestEnum(unittest.TestCase):
263
264 @classmethod
265 def setUpClass(cls):
266 cls.parser = VPPAPI()
267
268 def test_enum_as_enum(self):
269 test_string = """\
270enum tunnel_mode : u8
271{
272 /** point-to-point */
273 TUNNEL_API_MODE_P2P = 0,
274 /** multi-point */
275 TUNNEL_API_MODE_MP,
276};
277"""
278 r = self.parser.parse_string(test_string)
279 self.assertIsNotNone(r)
280 s = self.parser.process(r)
281 for o in s['types']:
282 if o.type == 'Enum':
283 self.assertEqual(o.name, "tunnel_mode")
284 break
285 else:
286 self.fail()
287
288 def test_enumflag_as_enum(self):
289 test_string = """\
290enum virtio_flags {
291 VIRTIO_API_FLAG_GSO = 1, /* enable gso on the interface */
292 VIRTIO_API_FLAG_CSUM_OFFLOAD = 2, /* enable checksum offload without gso on the interface */
293 VIRTIO_API_FLAG_GRO_COALESCE = 4, /* enable packet coalescing on tx side, provided gso enabled */
294 VIRTIO_API_FLAG_PACKED = 8, /* enable packed ring support, provided it is available from backend */
295 VIRTIO_API_FLAG_IN_ORDER = 16, /* enable in order support, provided it is available from backend */
296 VIRTIO_API_FLAG_BUFFERING = 32 [backwards_compatible], /* enable buffering to handle backend jitter/delays */
297};"""
298 r = self.parser.parse_string(test_string)
299 self.assertIsNotNone(r)
300 s = self.parser.process(r)
301 for o in s['types']:
302 if o.type == 'Enum':
303 self.assertEqual(o.name, "virtio_flags")
304 break
305 else:
306 self.fail()
307
308
309class TestEnumFlag(unittest.TestCase):
310
311 @classmethod
312 def setUpClass(cls):
313 cls.parser = VPPAPI()
314
315 def test_enum_as_enumflag(self):
316 test_string = """\
317enumflag tunnel_mode_ef : u8
318{
319 /** point-to-point */
320 TUNNEL_API_MODE_P2P = 0,
321 /** multi-point */
322 TUNNEL_API_MODE_MP,
323 TUNNEL_API_MODE_FOO,
324 TUNNEL_API_MODE_BAR,
325};"""
326 with self.assertRaises(TypeError) as ctx:
327 r = self.parser.parse_string(test_string)
328
329 self.assertTrue(str(ctx.exception).startswith(
330 'tunnel_mode_ef is not a flag enum.'))
331
332 def test_enumflag_as_enumflag(self):
333 test_string = """\
334enumflag virtio_flags_ef {
335 VIRTIO_API_FLAG_GSO = 1, /* enable gso on the interface */
336 VIRTIO_API_FLAG_CSUM_OFFLOAD = 2, /* enable checksum offload without gso on the interface */
337 VIRTIO_API_FLAG_GRO_COALESCE = 4, /* enable packet coalescing on tx side, provided gso enabled */
338 VIRTIO_API_FLAG_PACKED = 8, /* enable packed ring support, provided it is available from backend */
339 VIRTIO_API_FLAG_IN_ORDER = 16, /* enable in order support, provided it is available from backend */
340 VIRTIO_API_FLAG_BUFFERING = 32 [backwards_compatible], /* enable buffering to handle backend jitter/delays */
341};"""
342 r = self.parser.parse_string(test_string)
343 self.assertIsNotNone(r)
344 s = self.parser.process(r)
345 for o in s['types']:
346 if o.type == 'EnumFlag':
347 self.assertEqual(o.name, "virtio_flags_ef")
348 break
349 else:
350 self.fail()
351
352
Ole Troan9d420872017-10-12 13:06:35 +0200353if __name__ == '__main__':
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400354 unittest.main(verbosity=2)