class Class(binobj.Struct): n_items = fields.UInt16(endian="little") items = fields.Array(fields.UInt16(endian="little"), count=n_items) @n_items.computes def _n_items(self, all_fields): return len(all_fields["items"])
def test_array__sized_dump_too_big__sized_iterable(): """Crash if writing a sized iterable with too many values.""" field = fields.Array(fields.Int8(), count=2) with pytest.raises(errors.ArraySizeError) as err: field.to_bytes({4, 8, 15, 16, 23, 42}) assert err.value.n_expected == 2 assert err.value.n_given == 6
def test_array__sized_dump_too_small__sized_iterable(): """Crash if writing a sized iterable with too few values.""" field = fields.Array(fields.Int32(), count=100) with pytest.raises(errors.ArraySizeError) as err: field.to_bytes((4, 8, 15, 16, 23, 42)) assert err.value.n_expected == 100 assert err.value.n_given == 6
def test_array__sized_dump_too_small__unsized_iterable(): """Crash if writing a generator with too few values.""" field = fields.Array(fields.Int32(), count=100) with pytest.raises(errors.ArraySizeError) as err: field.to_bytes(x for x in range(6)) assert err.value.n_expected == 100 assert err.value.n_given == 6
class StructWithComputedSizeArray(binobj.Struct): half_size = fields.UInt8() size = fields.UInt8() stuff = fields.Array(fields.UInt8(), count=size) @size.computes def compute_size(self, all_fields): return all_fields["half_size"] * 2
def test_array__sized_dump_too_big__unsized_iterable(): """Crash if writing a generator with too many values.""" field = fields.Array(fields.Int8(), count=2) with pytest.raises(errors.ArraySizeError) as err: field.to_bytes(x for x in range(10)) assert err.value.n_expected == 2 assert err.value.n_given == 3
class CircularReferenceComputedSize(binobj.Struct): """A struct with a size field and array that reference each other.""" count = fields.UInt16(endian="big") stuff = fields.Array(fields.StringZ(), count=count) @count.computes def compute_count(self, all_fields): return len(all_fields["stuff"])
def test_array__sentinel(): """Test deserializing a sequence that has a sentinel terminator.""" def halt(_seq, _str, values, _context, _loaded_fields): return values and (values[-1] == 0xDEAD) sequence = fields.Array(fields.UInt16(endian="little"), halt_check=halt) result = sequence.from_bytes(b"\x00\x00\xff\x00\xad\xde\xff\xff", exact=False) assert result == [0, 0xFF, 0xDEAD]
def test_array__load_nested(): """Try loading an array of structs.""" field = fields.Array(fields.Nested(SubStruct), count=2) loaded = field.from_bytes(b"\xc0\xff\xee\xde\xad\xbe\xef\x00ABCDEFG" b"\xfa\xde\xdb\xed\xa5\x51\xed\x00HIJKLMN") assert loaded == [ { "first": 0xC0FFEEDEADBEEF00, "second": "ABCDEFG" }, { "first": 0xFADEDBEDA551ED00, "second": "HIJKLMN" }, ]
def test_array__dump_nested(): """Try dumping an array of structs.""" field = fields.Array(fields.Nested(SubStruct), count=2) dumped = field.to_bytes([ { "first": 0xC0FFEEDEADBEEF00, "second": "ABCDEFG" }, { "first": 0xFADEDBEDA551ED00, "second": "HIJKLMN" }, ]) assert (dumped == b"\xc0\xff\xee\xde\xad\xbe\xef\x00ABCDEFG" b"\xfa\xde\xdb\xed\xa5\x51\xed\x00HIJKLMN")
def test_array__sized_dump_ok(iterable): """Write a sized array with the expected number of values.""" field = fields.Array(fields.StringZ(), count=2) assert field.to_bytes(iterable) == b"abc\x00123456\0"
class NestedConstArrayStruct(binobj.Struct): field_1 = fields.String(size=16) field_2 = fields.Array(fields.Nested(ConstArrayStruct), count=4)
def test_array__sized__read(): """Verify the behavior of a fixed-size array on loading.""" sequence = fields.Array(fields.UInt8(), count=3) result = sequence.from_bytes(b"\xde\xad\xbe") assert result == [0xDE, 0xAD, 0xBE]
def test_array__basic(): """Test deserializing a list of stuff.""" sequence = fields.Array(fields.UInt8()) result = sequence.from_bytes(b"\xde\xad\xbe\xef") assert result == [0xDE, 0xAD, 0xBE, 0xEF]
class BasicStructWithArray(binobj.Struct): """A basic structure with a sized array.""" header = fields.Bytes(const=b"ABC") numbers = fields.Array(fields.UInt16(endian="big"), count=2) trailer = fields.Bytes(const=b"XYZ")
class BasicStructWithArray(binobj.Struct): header = fields.String(const="ABC") numbers = fields.Array(fields.UInt16(endian="big"), count=2) trailer = fields.String(const="XYZ")
class BasicStructWithSentinelArray(binobj.Struct): numbers = fields.Array(fields.UInt8(), halt_check=bswsa_should_halt) eof = fields.String(const="ABC")
class BasicStructWithArraySizeFieldAsName(binobj.Struct): n_numbers = fields.UInt8() numbers = fields.Array(fields.UInt8(), count="n_numbers") eof = fields.String(const="ABC")
class _Crash(binobj.Struct): n_numbers = fields.UInt8() numbers = fields.Array(fields.UInt8(), count="eof") eof = fields.String(const="ABC")
class ConstArrayStruct(binobj.Struct): items = fields.Array(fields.Int32(), count=10)
def test_array__bogus_count(count): with pytest.raises(TypeError): fields.Array(fields.UInt8(), count=count)
def test_array__unsized_dump_ok(): field = fields.Array(fields.StringZ()) assert field.to_bytes(["abc", "123456"]) == b"abc\x00123456\0"
class VarlenStruct(binobj.Struct): n_items = fields.Int32() items = fields.Array(fields.Int32(), count=n_items)