Coverage for tests/test_xmlparser/test_types.py: 100%
259 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-21 15:58 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-21 15:58 +0200
1from lxml.etree import XML as xml
2from sbe2.xmlparser.types import parse_valid_value, parse_enum, parse_choice, parse_set, parse_ref, parse_composite, parse_type, parse_message_schema, parse_message, parse_field, parse_data, parse_group
3from sbe2.xmlparser.errors import SchemaParsingError
4from sbe2.xmlparser.ctx import ParsingContext
5from pytest import raises
6from sbe2.schema import Type, Enum, Choice, Set, Ref, ValidValue, Composite, Presence, MessageSchema, ByteOrder, primitive_type
7from sbe2.schema import builtin
11def test_parse_valid_value():
12 node = xml(
13 '<validValue name="something" sinceVersion="5" deprecated="8" description="blah" >5</validValue>'
14 )
15 vv = parse_valid_value(node, 'int')
16 assert vv.name == "something"
17 assert vv.value == 5
18 assert vv.since_version == 5
19 assert vv.deprecated == 8
20 assert vv.description == "blah"
23def test_parse_enum():
24 node = xml(
25 """
26 <enum name="TestEnum" sinceVersion="1" deprecated="2" description="Test Enum" encodingType="int" offset="0">
27 <validValue name="Value1">1</validValue>
28 <validValue name="Value2">2</validValue>
29 </enum>
30 """
31 )
32 enum = parse_enum(node)
33 assert enum.name == "TestEnum"
34 assert enum.since_version == 1
35 assert enum.deprecated == 2
36 assert enum.description == "Test Enum"
37 assert enum.encoding_type_name == 'int'
38 assert enum.offset == 0
39 assert len(enum.valid_values) == 2
40 assert enum.valid_values[0].name == "Value1"
41 assert enum.valid_values[0].value == 1
42 assert enum.valid_values[1].name == "Value2"
43 assert enum.valid_values[1].value == 2
45 # duplicate names and values should raise an error
46 with raises(SchemaParsingError):
47 node = xml(
48 """
49 <enum name="TestEnum" sinceVersion="1" deprecated="2" description="Test Enum" encodingType="int" offset="0">
50 <validValue name="Value1">2</validValue>
51 <validValue name="Value2">2</validValue>
52 </enum>
53 """
54 )
55 parse_enum(node)
57 with raises(SchemaParsingError):
58 node = xml(
59 """
60 <enum name="TestEnum" sinceVersion="1" deprecated="2" description="Test Enum" encodingType="int" offset="0">
61 <validValue name="Value1">1</validValue>
62 <validValue name="Value1">2</validValue>
63 </enum>
64 """
65 )
66 parse_enum(node)
69def test_parse_choice():
70 node = xml(
71 """
72 <choice name="TestChoice" sinceVersion="1" deprecated="2" description="Test Choice">6</choice>
73 """
74 )
75 choice = parse_choice(node)
76 assert choice.name == "TestChoice"
77 assert choice.since_version == 1
78 assert choice.deprecated == 2
79 assert choice.description == "Test Choice"
80 assert choice.value == 6
82 with raises(SchemaParsingError):
83 node = xml(
84 """
85 <choice name="TestChoice" sinceVersion="1" deprecated="2" description="Test Choice">invalid</choice>
86 """
87 )
88 parse_choice(node)
91def test_parse_set():
92 node = xml(
93 """
94 <set name="TestSet" sinceVersion="1" deprecated="2" description="Test Set" encodingType="int" offset="0">
95 <choice name="Value1">1</choice>
96 <choice name="Value2">2</choice>
97 </set>
98 """
99 )
100 set_ = parse_set(node)
101 assert set_.name == "TestSet"
102 assert set_.since_version == 1
103 assert set_.deprecated == 2
104 assert set_.description == "Test Set"
105 assert set_.encoding_type_name == 'int'
106 assert set_.offset == 0
107 assert len(set_.choices) == 2
108 assert set_.choices[0].name == "Value1"
109 assert set_.choices[0].value == 1
110 assert set_.choices[1].name == "Value2"
111 assert set_.choices[1].value == 2
113 # duplicate names and values should raise an error
115 with raises(SchemaParsingError):
116 node = xml(
117 """
118 <set name="TestSet" sinceVersion="1" deprecated="2" description="Test Set" encodingType="int" offset="0">
119 <choice name="Value1">2</choice>
120 <choice name="Value2">2</choice>
121 </set>
122 """
123 )
124 parse_set(node)
125 with raises(SchemaParsingError):
126 node = xml(
127 """
128 <set name="TestSet" sinceVersion="1" deprecated="2" description="Test Set" encodingType="int" offset="0">
129 <choice name="Value1">1</choice>
130 <choice name="Value1">2</choice>
131 </set>
132 """
133 )
134 parse_set(node)
137def test_parse_ref():
138 node = xml(
139 """
140 <ref name="TestRef" description="Test Reference" type="int" offset="56"/>
141 """
142 )
143 ref = parse_ref(node)
144 assert ref.name == "TestRef"
145 assert ref.description == "Test Reference"
146 assert ref.type_name == 'int'
147 assert ref.offset == 56
149 with raises(SchemaParsingError):
150 node = xml(
151 """
152 <ref name="TestRef" sinceVersion="1" deprecated="2" description="Test Reference"/>
153 """
154 )
155 parse_ref(node) # type should be mandatory
158def test_parse_composite():
159 node = xml(
160 """
161 <composite name="TestComposite" sinceVersion="1" deprecated="2" description="Test Composite" offset="0">
162 <type name="Field1" primitiveType="int" offset="0"/>
163 <set name="Field2" encodingType="int" offset="4">
164 <choice name="Choice1">1</choice>
165 <choice name="Choice2">2</choice>
166 </set>
167 <enum name="Field3" encodingType="int" offset="8">
168 <validValue name="Value1">1</validValue>
169 <validValue name="Value2">2</validValue>
170 </enum>
171 <ref name="Field4" description="Reference Field" type="decimal" offset="12"/>
172 <composite name="NestedComposite" sinceVersion="1" deprecated="2" description="Nested Composite">
173 <type name="NestedField" primitiveType="float" offset="0"/>
174 </composite>
175 </composite>
176 """
177 )
178 composite = parse_composite(node)
179 assert composite.name == "TestComposite"
180 assert composite.since_version == 1
181 assert composite.deprecated == 2
182 assert composite.description == "Test Composite"
183 assert composite.offset == 0
184 assert len(composite.elements) == 5
185 assert type(composite.elements[0]) == Type
186 assert composite.elements[0].name == "Field1"
187 assert composite.elements[0].primitive_type is primitive_type.int_
188 assert composite.elements[0].offset == 0
189 assert type(composite.elements[1]) == Set
190 assert composite.elements[1].name == "Field2"
191 assert composite.elements[1].encoding_type_name == 'int'
192 assert composite.elements[1].offset == 4
193 assert len(composite.elements[1].choices) == 2
194 assert composite.elements[1].choices[0].name == "Choice1"
195 assert composite.elements[1].choices[0].value == 1
196 assert composite.elements[1].choices[1].name == "Choice2"
197 assert composite.elements[1].choices[1].value == 2
198 assert composite.elements[2].name == "Field3"
199 assert type(composite.elements[2]) == Enum
200 assert composite.elements[2].encoding_type_name == 'int'
201 assert composite.elements[2].offset == 8
202 assert len(composite.elements[2].valid_values) == 2
203 assert composite.elements[2].valid_values[0].name == "Value1"
204 assert composite.elements[2].valid_values[0].value == 1
205 assert composite.elements[2].valid_values[1].name == "Value2"
206 assert composite.elements[2].valid_values[1].value == 2
207 assert type(composite.elements[3]) == Ref
208 assert composite.elements[3].name == "Field4"
209 assert composite.elements[3].description == "Reference Field"
210 assert composite.elements[3].type_name == 'decimal'
211 assert composite.elements[3].offset == 12
212 assert type(composite.elements[4]) == Composite
213 assert composite.elements[4].name == "NestedComposite"
214 assert composite.elements[4].since_version == 1
215 assert composite.elements[4].deprecated == 2
216 assert composite.elements[4].description == "Nested Composite"
217 assert len(composite.elements[4].elements) == 1
218 assert type(composite.elements[4].elements[0]) == Type
219 assert composite.elements[4].elements[0].name == "NestedField"
220 assert composite.elements[4].elements[0].primitive_type is primitive_type.float_
221 assert composite.elements[4].elements[0].offset == 0
224def test_parse_type():
225 node = xml(
226 """
227 <type name="TestType" primitiveType="int" sinceVersion="1" deprecated="2" description="Test Type" offset="0" presence="required" length="3" />
228 """
229 )
230 type_ = parse_type(node)
231 assert type_.name == "TestType"
232 assert type_.primitive_type is primitive_type.int_
233 assert type_.since_version == 1
234 assert type_.deprecated == 2
235 assert type_.description == "Test Type"
236 assert type_.offset == 0
237 assert type_.presence == Presence.REQUIRED
238 assert type_.length == 3
239 assert type_.const_val is None
240 assert type_.value_ref is None
241 assert type_.total_length == 4
244 with raises(SchemaParsingError):
245 node = xml(
246 """
247 <type name="TestType" sinceVersion="1" deprecated="2" description="Test Type"/>
248 """
249 )
250 parse_type(node) # primitiveType should be mandatory
253def test_parse_type_const_value():
254 node = xml(
255 """
256 <type name="TestType" primitiveType="int" sinceVersion="1" deprecated="2" description="Test Type" offset="0" presence="constant">5</type>
257 """
258 )
259 type_ = parse_type(node)
260 assert type_.presence == Presence.CONSTANT
261 assert type_.value == '5'
262 assert type_.const_val is None
263 assert type_.value_ref is None
265 ctx = ParsingContext()
266 type_.lazy_bind(ctx.types)
267 assert type_.const_val == 5
270def test_parse_type_value_ref():
271 node = xml(
272 """
273 <type name="TestType" primitiveType="int" sinceVersion="1" deprecated="2" description="Test Type" offset="0" presence="constant" valueRef="Example.Something"/>
274 """
275 )
276 type_ = parse_type(node)
277 assert type_.presence == Presence.CONSTANT
278 assert type_.value is None
279 assert type_.const_val is None
280 assert type_.value_ref == "Example.Something"
282 ctx = ParsingContext()
283 enum = Enum(name="Example", description='', encoding_type_name='int', valid_values=[
284 ValidValue(name="Something", description='', value=5),
285 ValidValue(name="Nothing", description='', value=7),
286 ])
287 ctx.types.add(enum)
288 type_.lazy_bind(ctx.types)
289 assert type_.const_val == 5
293def test_parse_message_schema():
294 node = xml(
295 """
296 <messageSchema version="1" package="test.package" headerType="myHeader" byteOrder="bigEndian" id="123" semanticVersion="1.0.0">
297 </messageSchema>
298 """
299 )
300 ms = parse_message_schema(node)
301 assert ms.version == 1
302 assert ms.package == "test.package"
303 assert ms.header_type == "myHeader"
304 assert ms.byte_order == ByteOrder.BIG_ENDIAN
305 assert ms.id == 123
306 assert ms.semantic_version == "1.0.0"
309def test_parse_message_attributes():
310 node = xml(
311 """
312 <message id="1" name="TestMessage" description="This is a test message" semanticType="test" blockLength="8" sinceVersion="1" deprecated="2" alignment="4">
313 </message>
314 """
315 )
316 ctx = ParsingContext()
317 message = parse_message(node, ctx, 'package')
318 assert message.id == 1
319 assert message.name == "TestMessage"
320 assert message.description == "This is a test message"
321 assert message.semantic_type == "test"
322 assert message.block_length == 8
323 assert message.since_version == 1
324 assert message.deprecated == 2
325 assert message.alignment == 4
326 assert message.fields == []
327 assert message.groups == []
328 assert message.datas == []
329 assert message.package == 'package'
332def test_parse_message_elements():
333 node = xml(
334 """
335 <message id="1" name="TestMessage">
336 <field id="2" name="Field1" type="int"/>
337 <group id="3" name="SubGroup" dimensionType="int"/>
338 <data id="4" name="Data1" type="int"/>
339 </message>
340 """
341 )
342 ctx = ParsingContext()
343 message = parse_message(node, ctx, 'package')
344 assert len(message.fields) == 1
345 assert message.fields[0].id == 2
346 assert message.fields[0].name == "Field1"
347 assert message.fields[0].type == builtin.int_
348 assert len(message.groups) == 1
349 assert message.groups[0].id == 3
350 assert message.groups[0].name == "SubGroup"
351 assert message.groups[0].dimension_type == builtin.int_
352 assert len(message.datas) == 1
353 assert message.datas[0].id == 4
354 assert message.datas[0].name == "Data1"
355 assert message.datas[0].type_ == builtin.int_
356 assert message.package == 'package'
358def test_parse_field():
359 node = xml(
360 """
361 <field id="1" name="TestField" description="This is a test field" type="int" offset="0" alignment="4" presence="required" sinceVersion="1" deprecated="2" />
362 """
363 )
364 ctx = ParsingContext()
365 field = parse_field(node, ctx)
366 assert field.id == 1
367 assert field.name == "TestField"
368 assert field.description == "This is a test field"
369 assert field.type == builtin.int_
370 assert field.offset == 0
371 assert field.alignment == 4
372 assert field.presence == Presence.REQUIRED
373 assert field.since_version == 1
374 assert field.deprecated == 2
375 assert field.value_ref is None
376 assert field.constant_value is None
379def test_parse_data():
380 node = xml(
381 """
382 <data id="123" name="TestData" description="This is a test data" type="int" semanticType="text" sinceVersion="1" deprecated="2" />
383 """
384 )
385 ctx = ParsingContext()
386 data = parse_data(node, ctx)
387 assert data.id == 123
388 assert data.name == "TestData"
389 assert data.description == "This is a test data"
390 assert data.type_ == builtin.int_
391 assert data.semantic_type == "text"
392 assert data.since_version == 1
393 assert data.deprecated == 2
396def test_parse_group_attributes():
397 node = xml(
398 """
399 <group name="TestGroup" id="1" description="This is a test group" semanticType="test" blockLength="8" sinceVersion="1" deprecated="2" dimensionType="int">
400 </group>
401 """
402 )
403 ctx = ParsingContext()
404 group = parse_group(node, ctx)
405 assert group.name == "TestGroup"
406 assert group.id == 1
407 assert group.description == "This is a test group"
408 assert group.block_length == 8
409 assert len(group.fields) == 0
410 assert len(group.groups) == 0
411 assert len(group.datas) == 0
412 assert group.dimension_type == builtin.int_
413 assert group.since_version == 1
414 assert group.deprecated == 2
416def test_parse_group_elements():
417 node = xml(
418 """
419 <group name="TestGroup" id="1" dimensionType="int">
420 <field id="2" name="Field1" type="int"/>
421 <group id="3" name="SubGroup" dimensionType="int"/>
422 <data id="4" name="Data1" type="int"/>
423 </group>
424 """
425 )
426 ctx = ParsingContext()
427 group = parse_group(node, ctx)
428 assert len(group.fields) == 1
429 assert group.fields[0].id == 2
430 assert group.fields[0].name == "Field1"
431 assert group.fields[0].type == builtin.int_
432 assert len(group.groups) == 1
433 assert group.groups[0].id == 3
434 assert group.groups[0].name == "SubGroup"
435 assert group.groups[0].dimension_type == builtin.int_
436 assert len(group.datas) == 1
437 assert group.datas[0].id == 4
438 assert group.datas[0].name == "Data1"
439 assert group.datas[0].type_ == builtin.int_