Coverage for /home/runner/work/zserio/zserio/compiler/extensions/python/runtime/tests/test_array.py: 100%
581 statements
« prev ^ index » next coverage.py v6.5.0, created at 2026-04-23 10:05 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2026-04-23 10:05 +0000
1import unittest
3from test_object.api import ArrayObject, ArrayEnum, ArrayBitmask
5from zserio.array import (
6 Array,
7 BitFieldArrayTraits,
8 SignedBitFieldArrayTraits,
9 VarUInt16ArrayTraits,
10 VarUInt32ArrayTraits,
11 VarUInt64ArrayTraits,
12 VarUIntArrayTraits,
13 VarSizeArrayTraits,
14 VarInt16ArrayTraits,
15 VarInt32ArrayTraits,
16 VarInt64ArrayTraits,
17 VarIntArrayTraits,
18 Float16ArrayTraits,
19 Float32ArrayTraits,
20 Float64ArrayTraits,
21 BytesArrayTraits,
22 StringArrayTraits,
23 BoolArrayTraits,
24 BitBufferArrayTraits,
25 ObjectArrayTraits,
26 DeltaContext,
27)
28from zserio.bitposition import alignto
29from zserio.bitbuffer import BitBuffer
30from zserio.bitreader import BitStreamReader
31from zserio.bitsizeof import bitsizeof_varsize
32from zserio.bitwriter import BitStreamWriter
33from zserio import PythonRuntimeException
34from zserio.limits import (
35 UINT64_MIN,
36 UINT64_MAX,
37 INT64_MIN,
38 INT64_MAX,
39 UINT8_MAX,
40 INT16_MIN,
41)
44class ArrayTest(unittest.TestCase):
46 def test_bitfield_array(self):
47 array_traits = BitFieldArrayTraits(5)
48 array1_values = [1, 2]
49 array1_bitsizeof = 2 * 5
50 array1_aligned_bitsizeof = 5 + 3 + 5
51 array2_values = [3, 4]
52 self._test_array(
53 array_traits,
54 array1_values,
55 array1_bitsizeof,
56 array1_aligned_bitsizeof,
57 array2_values,
58 )
60 def test_signed_bitfield_array(self):
61 array_traits = SignedBitFieldArrayTraits(5)
62 array1_values = [-1, 1]
63 array1_bitsizeof = 2 * 5
64 array1_aligned_bitsizeof = 5 + 3 + 5
65 array2_values = [-2, 2]
66 self._test_array(
67 array_traits,
68 array1_values,
69 array1_bitsizeof,
70 array1_aligned_bitsizeof,
71 array2_values,
72 )
74 def test_varuint16_array(self):
75 array_traits = VarUInt16ArrayTraits()
76 array1_values = [1, 1024]
77 array1_bitsizeof = 8 + 16
78 array1_aligned_bitsizeof = array1_bitsizeof
79 array2_values = [1, 8192]
80 self._test_array(
81 array_traits,
82 array1_values,
83 array1_bitsizeof,
84 array1_aligned_bitsizeof,
85 array2_values,
86 )
88 def test_varuint32_array(self):
89 array_traits = VarUInt32ArrayTraits()
90 array1_values = [1, 16384]
91 array1_bitsizeof = 8 + 24
92 array1_aligned_bitsizeof = array1_bitsizeof
93 array2_values = [1, 32768]
94 self._test_array(
95 array_traits,
96 array1_values,
97 array1_bitsizeof,
98 array1_aligned_bitsizeof,
99 array2_values,
100 )
102 def test_varuint64_array(self):
103 array_traits = VarUInt64ArrayTraits()
104 array1_values = [1, 16384]
105 array1_bitsizeof = 8 + 24
106 array1_aligned_bitsizeof = array1_bitsizeof
107 array2_values = [1, 65536]
108 self._test_array(
109 array_traits,
110 array1_values,
111 array1_bitsizeof,
112 array1_aligned_bitsizeof,
113 array2_values,
114 )
116 def test_varuint_array(self):
117 array_traits = VarUIntArrayTraits()
118 array1_values = [1, 1024]
119 array1_bitsizeof = 8 + 16
120 array1_aligned_bitsizeof = array1_bitsizeof
121 array2_values = [1, 8192]
122 self._test_array(
123 array_traits,
124 array1_values,
125 array1_bitsizeof,
126 array1_aligned_bitsizeof,
127 array2_values,
128 )
130 def test_varsize_array(self):
131 array_traits = VarSizeArrayTraits()
132 array1_values = [1, 16384]
133 array1_bitsizeof = 8 + 24
134 array1_aligned_bitsizeof = array1_bitsizeof
135 array2_values = [1, 32768]
136 self._test_array(
137 array_traits,
138 array1_values,
139 array1_bitsizeof,
140 array1_aligned_bitsizeof,
141 array2_values,
142 )
144 def test_varint16_array(self):
145 array_traits = VarInt16ArrayTraits()
146 array1_values = [-1, 1024]
147 array1_bitsizeof = 8 + 16
148 array1_aligned_bitsizeof = array1_bitsizeof
149 array2_values = [-1, 8192]
150 self._test_array(
151 array_traits,
152 array1_values,
153 array1_bitsizeof,
154 array1_aligned_bitsizeof,
155 array2_values,
156 )
158 def test_varint32_array(self):
159 array_traits = VarInt32ArrayTraits()
160 array1_values = [-1, 16384]
161 array1_bitsizeof = 8 + 24
162 array1_aligned_bitsizeof = array1_bitsizeof
163 array2_values = [-1, 32768]
164 self._test_array(
165 array_traits,
166 array1_values,
167 array1_bitsizeof,
168 array1_aligned_bitsizeof,
169 array2_values,
170 )
172 def test_varint64_array(self):
173 array_traits = VarInt64ArrayTraits()
174 array1_values = [-1, 16384]
175 array1_bitsizeof = 8 + 24
176 array1_aligned_bitsizeof = array1_bitsizeof
177 array2_values = [-1, 65536]
178 self._test_array(
179 array_traits,
180 array1_values,
181 array1_bitsizeof,
182 array1_aligned_bitsizeof,
183 array2_values,
184 )
186 def test_varint_array(self):
187 array_traits = VarIntArrayTraits()
188 array1_values = [-1, 1024]
189 array1_bitsizeof = 8 + 16
190 array1_aligned_bitsizeof = array1_bitsizeof
191 array2_values = [-1, 8192]
192 self._test_array(
193 array_traits,
194 array1_values,
195 array1_bitsizeof,
196 array1_aligned_bitsizeof,
197 array2_values,
198 )
200 def test_float16_array(self):
201 array_traits = Float16ArrayTraits()
202 array1_values = [-1.0, 1.0]
203 array1_bitsizeof = 2 * 16
204 array1_aligned_bitsizeof = array1_bitsizeof
205 array2_values = [-3.5, 3.5]
206 self._test_array(
207 array_traits,
208 array1_values,
209 array1_bitsizeof,
210 array1_aligned_bitsizeof,
211 array2_values,
212 )
214 def test_float32_array(self):
215 array_traits = Float32ArrayTraits()
216 array1_values = [-1.0, 1.0]
217 array1_bitsizeof = 2 * 32
218 array1_aligned_bitsizeof = array1_bitsizeof
219 array2_values = [-3.5, 3.5]
220 self._test_array(
221 array_traits,
222 array1_values,
223 array1_bitsizeof,
224 array1_aligned_bitsizeof,
225 array2_values,
226 )
228 def test_float64_array(self):
229 array_traits = Float64ArrayTraits()
230 array1_values = [-1.0, 1.0]
231 array1_bitsizeof = 2 * 64
232 array1_aligned_bitsizeof = array1_bitsizeof
233 array2_values = [-3.5, 3.5]
234 self._test_array(
235 array_traits,
236 array1_values,
237 array1_bitsizeof,
238 array1_aligned_bitsizeof,
239 array2_values,
240 )
242 def test_bytes_array(self):
243 array_traits = BytesArrayTraits()
244 array1_values = [bytearray([1, 255]), bytearray([127, 128])]
245 array1_bitsizeof = 2 * (1 + 2) * 8
246 array1_aligned_bitsizeof = array1_bitsizeof
247 array2_values = [bytearray([0, 0]), bytearray([255, 255])]
248 self._test_array(
249 array_traits,
250 array1_values,
251 array1_bitsizeof,
252 array1_aligned_bitsizeof,
253 array2_values,
254 )
256 def test_string_array(self):
257 array_traits = StringArrayTraits()
258 array1_values = ["Text1", "Text2"]
259 array1_bitsizeof = 2 * (1 + len("TextN")) * 8
260 array1_aligned_bitsizeof = array1_bitsizeof
261 array2_values = ["Text3", "Text4"]
262 self._test_array(
263 array_traits,
264 array1_values,
265 array1_bitsizeof,
266 array1_aligned_bitsizeof,
267 array2_values,
268 )
270 def test_bool_array(self):
271 array_traits = BoolArrayTraits()
272 array1_values = [True, False]
273 array1_bitsizeof = 2 * 1
274 array1_aligned_bitsizeof = 1 + 7 + 1
275 array2_values = [True, True]
276 self._test_array(
277 array_traits,
278 array1_values,
279 array1_bitsizeof,
280 array1_aligned_bitsizeof,
281 array2_values,
282 )
284 def test_bitbuffer_array(self):
285 array_traits = BitBufferArrayTraits()
286 array1_values = [
287 BitBuffer(bytes([0xAB, 0xE0]), 11),
288 BitBuffer(bytes([0xAB, 0xCD, 0xFE]), 23),
289 ]
290 array1_bitsizeof = 8 + 11 + 8 + 23
291 array1_aligned_bitsizeof = 8 + 11 + 5 + 8 + 23
292 array2_values = [
293 BitBuffer(bytes([0xBA, 0xE0]), 11),
294 BitBuffer(bytes([0xBA, 0xDC, 0xFE]), 23),
295 ]
296 self._test_array(
297 array_traits,
298 array1_values,
299 array1_bitsizeof,
300 array1_aligned_bitsizeof,
301 array2_values,
302 )
304 class ArrayEnumElementFactory:
305 IS_OBJECT_PACKABLE = True
307 @staticmethod
308 def create(reader, _index):
309 return ArrayEnum.from_reader(reader)
311 @staticmethod
312 def create_packing_context():
313 return DeltaContext()
315 @staticmethod
316 def create_packed(context, reader, _index):
317 return ArrayEnum.from_reader_packed(context, reader)
319 def test_enum_array(self):
320 array_traits = ObjectArrayTraits(ArrayTest.ArrayEnumElementFactory)
321 array1_values = [ArrayEnum.VALUE1, ArrayEnum.VALUE2, ArrayEnum.VALUE3]
322 array1_bitsizeof = 3 * 8
323 array1_aligned_bitsizeof = array1_bitsizeof
324 array2_values = [ArrayEnum.VALUE1, ArrayEnum.VALUE1, ArrayEnum.VALUE1]
325 self._test_array(
326 array_traits,
327 array1_values,
328 array1_bitsizeof,
329 array1_aligned_bitsizeof,
330 array2_values,
331 )
333 class ArrayBitmaskElementFactory:
334 IS_OBJECT_PACKABLE = True
336 @staticmethod
337 def create(reader, _index):
338 return ArrayBitmask.from_reader(reader)
340 @staticmethod
341 def create_packing_context():
342 return DeltaContext()
344 @staticmethod
345 def create_packed(context, reader, _index):
346 return ArrayBitmask.from_reader_packed(context, reader)
348 def test_bitmask_array(self):
349 array_traits = ObjectArrayTraits(ArrayTest.ArrayBitmaskElementFactory)
350 array1_values = [
351 ArrayBitmask.Values.READ,
352 ArrayBitmask.Values.WRITE,
353 ArrayBitmask.Values.CREATE,
354 ]
355 array1_bitsizeof = 3 * 8
356 array1_aligned_bitsizeof = array1_bitsizeof
357 array2_values = [
358 ArrayBitmask.Values.READ,
359 ArrayBitmask.Values.READ,
360 ArrayBitmask.Values.READ,
361 ]
362 self._test_array(
363 array_traits,
364 array1_values,
365 array1_bitsizeof,
366 array1_aligned_bitsizeof,
367 array2_values,
368 )
370 class ArrayObjectElementFactory:
371 IS_OBJECT_PACKABLE = True
373 @staticmethod
374 def create(reader, _index):
375 return ArrayObject.from_reader(reader)
377 @staticmethod
378 def create_packing_context():
379 return ArrayObject.ZserioPackingContext()
381 @staticmethod
382 def create_packed(context, reader, _index):
383 return ArrayObject.from_reader_packed(context, reader)
385 def test_object_array(self):
386 array_traits = ObjectArrayTraits(ArrayTest.ArrayObjectElementFactory)
387 array1_values = [ArrayObject(0xAB), ArrayObject(0xCD), ArrayObject(0xEF)]
388 array1_bitsizeof = 3 * 31
389 array1_aligned_bitsizeof = 31 + 1 + 31 + 1 + 31
390 array2_values = [ArrayObject(0x01), ArrayObject(0x02), ArrayObject(0x03)]
391 self._test_array(
392 array_traits,
393 array1_values,
394 array1_bitsizeof,
395 array1_aligned_bitsizeof,
396 array2_values,
397 )
399 def test_bitfield_packed_array(self):
400 array_traits64 = BitFieldArrayTraits(64)
402 # none-zero delta
403 array1_values = [10, 11, 12]
404 array1_max_delta_bit_size = 1
405 array1_bitsizeof = self._calc_packed_bit_size(64, len(array1_values), array1_max_delta_bit_size)
406 array1_aligned_bitsizeof = self._calc_aligned_packed_bit_size(
407 64, len(array1_values), array1_max_delta_bit_size
408 )
409 self._test_packed_array(array_traits64, array1_values, array1_bitsizeof, array1_aligned_bitsizeof)
411 # zero delta
412 array2_values = [10, 10, 10]
413 array2_bitsizeof = self.PACKING_DESCRIPTOR_BITSIZE + 64
414 array2_aligned_bitsizeof = self.PACKING_DESCRIPTOR_BITSIZE + 64 + 1
415 self._test_packed_array(array_traits64, array2_values, array2_bitsizeof, array2_aligned_bitsizeof)
417 # one-element array
418 array3_values = [10]
419 array3_bitsizeof = 1 + 64
420 array3_aligned_bitsizeof = 1 + 64
421 self._test_packed_array(array_traits64, array3_values, array3_bitsizeof, array3_aligned_bitsizeof)
423 # empty array
424 array4_values = []
425 array4_bitsizeof = 0
426 array4_aligned_bitsizeof = 0
427 self._test_packed_array(array_traits64, array4_values, array4_bitsizeof, array4_aligned_bitsizeof)
429 # packing not applied, delta is too big
430 self._test_packed_array(array_traits64, [UINT64_MIN, UINT64_MAX])
431 self._test_packed_array(array_traits64, [UINT64_MAX, UINT64_MAX // 2, UINT64_MIN])
433 # will have maxBitNumber 62 bits
434 self._test_packed_array(array_traits64, [0, INT64_MAX // 2, 100, 200, 300, 400, 500, 600, 700])
436 # will not be packed because unpacked 8bit values will be more efficient
437 array_traits8 = BitFieldArrayTraits(8)
438 array5_values = [
439 UINT8_MAX,
440 0,
441 10,
442 20,
443 30,
444 40,
445 ] # max_bit_number 8, delta needs 9 bits
446 array5_bitsizeof = 1 + 6 * 8
447 array5_aligned_bitsizeof = 1 + 8 + 7 + 5 * 8
448 self._test_packed_array(array_traits8, array5_values, array5_bitsizeof, array5_aligned_bitsizeof)
450 # will not be packed because unpacked 8bit values will be more efficient
451 # (6 bits more are needed to store max_bit_number in descriptor if packing was enabled)
452 array6_values = [
453 UINT8_MAX,
454 UINT8_MAX // 2 + 1,
455 10,
456 20,
457 30,
458 40,
459 ] # max_bit_number 7, delta needs 8 bits
460 array6_bitsizeof = 1 + 6 * 8
461 array6_aligned_bitsizeof = 1 + 8 + 7 + 5 * 8
462 self._test_packed_array(array_traits8, array6_values, array6_bitsizeof, array6_aligned_bitsizeof)
464 def test_signed_bitfield_packed_array(self):
465 array_traits64 = SignedBitFieldArrayTraits(64)
466 self._test_packed_array(array_traits64, [-10, 11, -12])
467 self._test_packed_array(array_traits64, [-10, -10, -10]) # zero delta
469 self._test_packed_array(array_traits64, []) # empty
470 self._test_packed_array(array_traits64, [-10]) # single element
472 # packing not applied, delta is too big
473 self._test_packed_array(array_traits64, [INT64_MIN, INT64_MAX])
474 self._test_packed_array(array_traits64, [INT64_MIN, 0, INT64_MAX])
476 # will not be packed because unpacked 16bit values will be more efficient
477 # (6 bits more are needed to store max_bit_number in descriptor if packing was enabled)
478 array_traits16 = SignedBitFieldArrayTraits(16)
479 array16_values = [
480 INT16_MIN,
481 -1,
482 10,
483 20,
484 30,
485 40,
486 ] # max_bit_number 15, delta needs 16 bits
487 array16_bitsizeof = 1 + 6 * 16
488 array16_aligned_bitsizeof = 1 + 16 + 7 + 5 * 16
489 self._test_packed_array(array_traits16, array16_values, array16_bitsizeof, array16_aligned_bitsizeof)
491 def test_varuint_packed_array(self):
492 array_traits = VarUIntArrayTraits()
493 self._test_packed_array(array_traits, [100, 200, 300])
494 self._test_packed_array(array_traits, [300, 200, 100])
496 # won't be packed because unpacked varuint values will be more efficient
497 unpacked_array = [5000000, 0, 0, 0, 0, 0, 0]
498 unpacked_bitsizeof = 1 + 32 + 6 * 8
499 unpacked_aligned_bitsizeof = 1 + 32 + 7 + 6 * 8
500 self._test_packed_array(array_traits, unpacked_array, unpacked_bitsizeof, unpacked_aligned_bitsizeof)
502 self._test_packed_array(array_traits, [UINT64_MIN, UINT64_MAX])
503 self._test_packed_array(array_traits, [UINT64_MAX, UINT64_MAX // 2, UINT64_MIN])
505 def test_enum_packed_array(self):
506 array_traits = ObjectArrayTraits(ArrayTest.ArrayEnumElementFactory)
507 self._test_packed_array(array_traits, [ArrayEnum.VALUE1, ArrayEnum.VALUE2, ArrayEnum.VALUE3])
509 def test_bitmask_packed_array(self):
510 array_traits = ObjectArrayTraits(ArrayTest.ArrayBitmaskElementFactory)
511 self._test_packed_array(
512 array_traits,
513 [
514 ArrayBitmask.Values.READ,
515 ArrayBitmask.Values.WRITE,
516 ArrayBitmask.Values.CREATE,
517 ],
518 )
520 def test_object_packed_array(self):
521 array_traits = ObjectArrayTraits(ArrayTest.ArrayObjectElementFactory)
522 self._test_packed_array(array_traits, [ArrayObject(0xAB), ArrayObject(0xCD), ArrayObject(0xEF)])
523 self._test_packed_array(array_traits, [ArrayObject(0x01), ArrayObject(0x02), ArrayObject(0x03)])
525 @staticmethod
526 def _set_offset_method(_index, _bitoffset):
527 pass
529 @staticmethod
530 def _check_offset_method(_index, _bitoffset):
531 pass
533 def _test_array(
534 self,
535 array_traits,
536 array1_values,
537 array1_bitsizeof,
538 array1_aligned_bitsizeof,
539 array2_values,
540 ):
541 self._test_eq(array_traits, array1_values, array2_values)
542 self._test_hashcode(array_traits, array1_values, array2_values)
543 self._test_len(array_traits, array1_values)
544 self._test_get_item(array_traits, array1_values)
545 self._test_set_item(array_traits, array1_values)
546 self._test_raw_array(array_traits, array1_values, array2_values)
548 auto_bitsize = bitsizeof_varsize(len(array1_values))
550 self._test_array_normal(array_traits, array1_values, array1_bitsizeof)
551 self._test_array_auto(array_traits, array1_values, auto_bitsize + array1_bitsizeof)
552 self._test_array_aligned(array_traits, array1_values, array1_aligned_bitsizeof)
553 self._test_array_aligned_auto(array_traits, array1_values, auto_bitsize + array1_aligned_bitsizeof)
554 self._test_array_implicit(array_traits, array1_values, array1_bitsizeof)
556 def _test_packed_array(
557 self,
558 array_traits,
559 array_values,
560 array_bitsizeof=None,
561 array_aligned_bitsizeof=None,
562 ):
564 self._test_packed_array_normal(array_traits, array_values, array_bitsizeof)
566 auto_size_bitsize = bitsizeof_varsize(len(array_values))
567 auto_bitsize = auto_size_bitsize + array_bitsizeof if array_bitsizeof is not None else None
568 self._test_packed_array_auto(array_traits, array_values, auto_bitsize)
570 self._test_packed_array_aligned(array_traits, array_values, array_aligned_bitsizeof)
572 auto_aligned_bitsize = (
573 auto_size_bitsize + array_aligned_bitsizeof if array_aligned_bitsizeof is not None else None
574 )
575 self._test_packed_array_aligned_auto(array_traits, array_values, auto_aligned_bitsize)
577 self._test_packed_array_implicit(array_traits, array_values, array_bitsizeof)
579 def _test_eq(self, array_traits, array1_values, array2_values):
580 array1 = Array(array_traits, array1_values)
581 array2 = Array(array_traits, array2_values)
582 array3 = Array(array_traits, array1_values)
583 self.assertNotEqual(array1, None)
584 self.assertNotEqual(array1, array2)
585 self.assertEqual(array1, array3)
587 def _test_hashcode(self, array_traits, array1_values, array2_values):
588 array1 = Array(array_traits, array1_values)
589 array2 = Array(array_traits, array2_values)
590 array3 = Array(array_traits, array1_values)
591 self.assertNotEqual(hash(array1), hash(array2))
592 self.assertEqual(hash(array1), hash(array3))
594 def _test_len(self, array_traits, array_values):
595 array = Array(array_traits, array_values)
596 raw_array = array.raw_array
597 self.assertEqual(len(raw_array), len(array))
599 def _test_get_item(self, array_traits, array_values):
600 array = Array(array_traits, array_values)
601 raw_array = array.raw_array
602 for value, raw_value in zip(array, raw_array):
603 self.assertEqual(value, raw_value)
605 def _test_set_item(self, array_traits, array_values):
606 array = Array(array_traits, array_values)
607 raw_array = array.raw_array
608 self.assertTrue(len(array) > 1)
609 first_value = array[0]
610 second_value = array[1]
611 array[0] = second_value
612 self.assertEqual(array[0], raw_array[0])
613 raw_array[0] = first_value # return the original value for other tests
614 self.assertEqual(array[0], raw_array[0])
616 def _test_raw_array(self, array_traits, array1_values, array2_values):
617 array1 = Array(array_traits, array1_values)
618 array2 = Array(array_traits, array2_values)
619 array3 = Array(array_traits, array1_values)
620 self.assertNotEqual(array1.raw_array, array2.raw_array)
621 self.assertEqual(array1.raw_array, array3.raw_array)
623 def _test_array_normal(self, array_traits, array_values, expected_bitsize):
624 for i in range(8):
625 array = Array(array_traits, array_values)
627 bitsize = array.bitsizeof(i)
628 self.assertEqual(expected_bitsize, bitsize)
629 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
631 writer = BitStreamWriter()
632 if i > 0:
633 writer.write_bits(0, i)
634 array.write(writer)
635 self.assertEqual(i + bitsize, writer.bitposition, i)
637 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
638 if i > 0:
639 self.assertEqual(0, from_reader.read_bits(i))
640 read_array_from_reader = Array.from_reader(array_traits, from_reader, len(array_values))
641 self.assertEqual(array, read_array_from_reader, i)
643 reader = BitStreamReader(writer.byte_array, writer.bitposition)
644 if i > 0:
645 self.assertEqual(0, reader.read_bits(i))
646 read_array = Array(array_traits)
647 read_array.read(reader, len(array_values))
648 self.assertEqual(array, read_array, i)
650 reader.bitposition = i
651 with self.assertRaises(PythonRuntimeException):
652 read_array.read(reader, 10 * len(array_values))
654 def _test_auto_array_invalid_size(self, array_traits):
655 reader = BitStreamReader(bytes([0xFF, 0xFF, 0xFF, 0x3F, 0])) # big array size
656 with self.assertRaises(PythonRuntimeException):
657 Array.from_reader(array_traits, reader, is_auto=True)
659 def _test_array_auto(self, array_traits, array_values, expected_bitsize):
660 self._test_auto_array_invalid_size(array_traits)
662 for i in range(8):
663 array = Array(array_traits, array_values, is_auto=True)
665 bitsize = array.bitsizeof(i)
666 self.assertEqual(expected_bitsize, bitsize, i)
667 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
669 writer = BitStreamWriter()
670 if i > 0:
671 writer.write_bits(0, i)
672 array.write(writer)
673 self.assertEqual(i + bitsize, writer.bitposition, i)
675 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
676 if i > 0:
677 self.assertEqual(0, from_reader.read_bits(i))
678 read_array_from_reader = Array.from_reader(array_traits, from_reader, is_auto=True)
679 self.assertEqual(array, read_array_from_reader, i)
681 reader = BitStreamReader(writer.byte_array, writer.bitposition)
682 if i > 0:
683 self.assertEqual(0, reader.read_bits(i))
684 read_array = Array(array_traits, is_auto=True)
685 read_array.read(reader)
686 self.assertEqual(array, read_array, i)
688 def _test_array_aligned(self, array_traits, array_values, expected_bitsize):
689 for i in range(8):
690 array = Array(
691 array_traits,
692 array_values,
693 set_offset_method=ArrayTest._set_offset_method,
694 check_offset_method=ArrayTest._check_offset_method,
695 )
697 bitsize = array.bitsizeof(i)
698 self.assertEqual(alignto(8, i) - i + expected_bitsize, bitsize, i)
699 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
701 writer = BitStreamWriter()
702 if i > 0:
703 writer.write_bits(0, i)
704 array.write(writer)
705 self.assertEqual(i + bitsize, writer.bitposition, i)
707 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
708 if i > 0:
709 self.assertEqual(0, from_reader.read_bits(i))
710 read_array_from_reader = Array.from_reader(
711 array_traits,
712 from_reader,
713 len(array_values),
714 set_offset_method=ArrayTest._set_offset_method,
715 check_offset_method=ArrayTest._check_offset_method,
716 )
717 self.assertEqual(array, read_array_from_reader, i)
719 reader = BitStreamReader(writer.byte_array, writer.bitposition)
720 if i > 0:
721 self.assertEqual(0, reader.read_bits(i))
722 read_array = Array(
723 array_traits,
724 set_offset_method=ArrayTest._set_offset_method,
725 check_offset_method=ArrayTest._check_offset_method,
726 )
727 read_array.read(reader, len(array_values))
728 self.assertEqual(array, read_array, i)
730 reader.bitposition = i
731 with self.assertRaises(PythonRuntimeException):
732 read_array.read(reader, 10 * len(array_values))
734 def _test_array_aligned_auto(self, array_traits, array_values, expected_bitsize):
735 self._test_auto_array_invalid_size(array_traits)
737 for i in range(8):
738 array = Array(
739 array_traits,
740 array_values,
741 is_auto=True,
742 set_offset_method=ArrayTest._set_offset_method,
743 check_offset_method=ArrayTest._check_offset_method,
744 )
746 bitsize = array.bitsizeof(i)
747 self.assertEqual(alignto(8, i) - i + expected_bitsize, bitsize, i)
748 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
750 writer = BitStreamWriter()
751 if i > 0:
752 writer.write_bits(0, i)
753 array.write(writer)
754 self.assertEqual(i + bitsize, writer.bitposition, i)
756 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
757 if i > 0:
758 self.assertEqual(0, from_reader.read_bits(i))
759 read_array_from_reader = Array.from_reader(
760 array_traits,
761 from_reader,
762 is_auto=True,
763 set_offset_method=ArrayTest._set_offset_method,
764 check_offset_method=ArrayTest._check_offset_method,
765 )
766 self.assertEqual(array, read_array_from_reader, i)
768 reader = BitStreamReader(writer.byte_array, writer.bitposition)
769 if i > 0:
770 self.assertEqual(0, reader.read_bits(i))
771 read_array = Array(
772 array_traits,
773 is_auto=True,
774 set_offset_method=ArrayTest._set_offset_method,
775 check_offset_method=ArrayTest._check_offset_method,
776 )
777 read_array.read(reader)
778 self.assertEqual(array, read_array, i)
780 def _test_array_implicit(self, array_traits, array_values, expected_bitsize):
781 for i in range(8):
782 array = Array(array_traits, array_values, is_implicit=True)
784 bitsize = array.bitsizeof(i)
785 self.assertEqual(expected_bitsize, bitsize, i)
786 self.assertEqual(i + bitsize, array.initialize_offsets(i), i)
788 writer = BitStreamWriter()
789 if i > 0:
790 writer.write_bits(0, i)
791 array.write(writer)
792 self.assertEqual(i + bitsize, writer.bitposition, i)
794 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
795 if i > 0:
796 self.assertEqual(0, from_reader.read_bits(i))
797 if array_traits.HAS_BITSIZEOF_CONSTANT:
798 read_array_from_reader = Array.from_reader(array_traits, from_reader, is_implicit=True)
799 self.assertEqual(array, read_array_from_reader, i)
800 else:
801 with self.assertRaises(PythonRuntimeException):
802 Array.from_reader(array_traits, from_reader, is_implicit=True)
804 reader = BitStreamReader(writer.byte_array, writer.bitposition)
805 if i > 0:
806 self.assertEqual(0, reader.read_bits(i))
807 read_array = Array(array_traits, is_implicit=True)
808 if array_traits.HAS_BITSIZEOF_CONSTANT:
809 read_array.read(reader)
810 self.assertEqual(array, read_array, i)
811 else:
812 with self.assertRaises(PythonRuntimeException):
813 read_array.read(reader)
815 def _test_packed_auto_array_invalid_size(self, array_traits):
816 reader = BitStreamReader(bytes([0xFF, 0xFF, 0xFF, 0x3F, 0])) # big array size
817 with self.assertRaises(PythonRuntimeException):
818 Array.from_reader_packed(array_traits, reader, is_auto=True)
820 def _test_packed_array_normal(self, array_traits, array_values, expected_bitsize):
821 for i in range(8):
822 array = Array(array_traits, array_values)
824 bitsize = array.bitsizeof_packed(i)
825 if expected_bitsize is not None:
826 self.assertEqual(expected_bitsize, bitsize)
827 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
829 writer = BitStreamWriter()
830 if i > 0:
831 writer.write_bits(0, i)
832 array.write_packed(writer)
833 self.assertEqual(i + bitsize, writer.bitposition, i)
835 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
836 if i > 0:
837 self.assertEqual(0, from_reader.read_bits(i))
838 read_array_from_reader = Array.from_reader_packed(array_traits, from_reader, len(array_values))
839 self.assertEqual(array, read_array_from_reader, i)
841 reader = BitStreamReader(writer.byte_array, writer.bitposition)
842 if i > 0:
843 self.assertEqual(0, reader.read_bits(i))
844 read_array = Array(array_traits)
845 read_array.read_packed(reader, len(array_values))
846 self.assertEqual(array, read_array, i)
848 if len(set(array_values)) > 1: # constant elements are encoded in 0 bits so eof read never occurs
849 reader.bitposition = i
850 with self.assertRaises(PythonRuntimeException):
851 read_array.read_packed(reader, 10 * len(array_values))
853 def _test_packed_array_auto(self, array_traits, array_values, expected_bitsize):
854 self._test_packed_auto_array_invalid_size(array_traits)
856 for i in range(8):
857 array = Array(array_traits, array_values, is_auto=True)
859 bitsize = array.bitsizeof_packed(i)
860 if expected_bitsize is not None:
861 self.assertEqual(expected_bitsize, bitsize)
862 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
864 writer = BitStreamWriter()
865 if i > 0:
866 writer.write_bits(0, i)
867 array.write_packed(writer)
868 self.assertEqual(i + bitsize, writer.bitposition, i)
870 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
871 if i > 0:
872 self.assertEqual(0, from_reader.read_bits(i))
873 read_array_from_reader = Array.from_reader_packed(array_traits, from_reader, is_auto=True)
874 self.assertEqual(array, read_array_from_reader, i)
876 reader = BitStreamReader(writer.byte_array, writer.bitposition)
877 if i > 0:
878 self.assertEqual(0, reader.read_bits(i))
879 read_array = Array(array_traits, is_auto=True)
880 read_array.read_packed(reader)
881 self.assertEqual(array, read_array, i)
883 def _test_packed_array_aligned(self, array_traits, array_values, expected_bitsize):
884 for i in range(8):
885 array = Array(
886 array_traits,
887 array_values,
888 set_offset_method=ArrayTest._set_offset_method,
889 check_offset_method=ArrayTest._check_offset_method,
890 )
892 bitsize = array.bitsizeof_packed(i)
893 if expected_bitsize is not None and i == 0:
894 self.assertEqual(expected_bitsize, bitsize)
895 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
897 writer = BitStreamWriter()
898 if i > 0:
899 writer.write_bits(0, i)
900 array.write_packed(writer)
901 self.assertEqual(i + bitsize, writer.bitposition, i)
903 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
904 if i > 0:
905 self.assertEqual(0, from_reader.read_bits(i))
906 read_array_from_reader = Array.from_reader_packed(
907 array_traits,
908 from_reader,
909 len(array_values),
910 set_offset_method=ArrayTest._set_offset_method,
911 check_offset_method=ArrayTest._check_offset_method,
912 )
913 self.assertEqual(array, read_array_from_reader, i)
915 reader = BitStreamReader(writer.byte_array, writer.bitposition)
916 if i > 0:
917 self.assertEqual(0, reader.read_bits(i))
918 read_array = Array(
919 array_traits,
920 set_offset_method=ArrayTest._set_offset_method,
921 check_offset_method=ArrayTest._check_offset_method,
922 )
923 read_array.read_packed(reader, len(array_values))
924 self.assertEqual(array, read_array, i)
926 if len(set(array_values)) > 1: # constant elements are encoded in 0 bits so eof read never occurs
927 reader.bitposition = i
928 with self.assertRaises(PythonRuntimeException):
929 read_array.read_packed(reader, 10 * len(array_values))
931 def _test_packed_array_aligned_auto(self, array_traits, array_values, expected_bitsize):
932 self._test_packed_auto_array_invalid_size(array_traits)
934 for i in range(8):
935 array = Array(
936 array_traits,
937 array_values,
938 is_auto=True,
939 set_offset_method=ArrayTest._set_offset_method,
940 check_offset_method=ArrayTest._check_offset_method,
941 )
943 bitsize = array.bitsizeof_packed(i)
944 if expected_bitsize is not None and i == 0:
945 self.assertEqual(expected_bitsize, bitsize)
946 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
948 writer = BitStreamWriter()
949 if i > 0:
950 writer.write_bits(0, i)
951 array.write_packed(writer)
952 self.assertEqual(i + bitsize, writer.bitposition, i)
954 from_reader = BitStreamReader(writer.byte_array, writer.bitposition)
955 if i > 0:
956 self.assertEqual(0, from_reader.read_bits(i))
957 read_array_from_reader = Array.from_reader_packed(
958 array_traits,
959 from_reader,
960 is_auto=True,
961 set_offset_method=ArrayTest._set_offset_method,
962 check_offset_method=ArrayTest._check_offset_method,
963 )
964 self.assertEqual(array, read_array_from_reader, i)
966 reader = BitStreamReader(writer.byte_array, writer.bitposition)
967 if i > 0:
968 self.assertEqual(0, reader.read_bits(i))
969 read_array = Array(
970 array_traits,
971 is_auto=True,
972 set_offset_method=ArrayTest._set_offset_method,
973 check_offset_method=ArrayTest._check_offset_method,
974 )
975 read_array.read_packed(reader)
976 self.assertEqual(array, read_array, i)
978 def _test_packed_array_implicit(self, array_traits, array_values, expected_bitsize):
979 for i in range(8):
980 array = Array(array_traits, array_values, is_implicit=True)
982 bitsize = array.bitsizeof_packed(i)
983 if expected_bitsize is not None:
984 self.assertEqual(expected_bitsize, bitsize)
985 self.assertEqual(i + bitsize, array.initialize_offsets_packed(i), i)
987 writer = BitStreamWriter()
988 if i > 0:
989 writer.write_bits(0, i)
990 array.write_packed(writer)
991 self.assertEqual(i + bitsize, writer.bitposition, i)
993 reader = BitStreamReader(writer.byte_array, writer.bitposition)
994 if i > 0:
995 self.assertEqual(0, reader.read_bits(i))
996 read_array = Array(array_traits, is_implicit=True)
997 with self.assertRaises(PythonRuntimeException):
998 read_array.read_packed(reader)
1000 def _calc_packed_bit_size(self, element_bit_size, array_size, max_delta_bit_size):
1001 return self.PACKING_DESCRIPTOR_BITSIZE + element_bit_size + (array_size - 1) * (max_delta_bit_size + 1)
1003 def _calc_aligned_packed_bit_size(self, element_bit_size, array_size, max_delta_bit_size):
1004 first_element_with_descriptor_bit_size = self.PACKING_DESCRIPTOR_BITSIZE + element_bit_size
1005 aligned_first_element_with_descriptor_bit_size = (first_element_with_descriptor_bit_size + 7) // 8 * 8
1006 aligned_max_delta_bit_size = (max_delta_bit_size + 1 + 7) // 8 * 8
1008 return (
1009 aligned_first_element_with_descriptor_bit_size
1010 + (array_size - 2) * aligned_max_delta_bit_size
1011 + (max_delta_bit_size + 1)
1012 )
1014 PACKING_DESCRIPTOR_BITSIZE = 1 + 6