+ @given(
+ integers(min_value=1, max_value=30),
+ lists(
+ one_of(
+ binary(min_size=1, max_size=5),
+ lists(
+ binary(min_size=1, max_size=5),
+ min_size=1,
+ max_size=3,
+ ),
+ ),
+ min_size=0,
+ max_size=3,
+ ),
+ lists(booleans(), min_size=1),
+ binary(),
+ )
+ def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
+ def chunk_constructed(contents):
+ return (
+ tag_encode(form=TagFormConstructed, num=3) +
+ LENINDEF +
+ b"".join(BitString(content).encode() for content in contents) +
+ EOC
+ )
+ chunks = []
+ payload_expected = b""
+ bit_len_expected = 0
+ for chunk_input in chunk_inputs:
+ if isinstance(chunk_input, binary_type):
+ chunks.append(BitString(chunk_input).encode())
+ payload_expected += chunk_input
+ bit_len_expected += len(chunk_input) * 8
+ else:
+ chunks.append(chunk_constructed(chunk_input))
+ payload = b"".join(chunk_input)
+ payload_expected += payload
+ bit_len_expected += len(payload) * 8
+ chunk_last = BitString("'%s'B" % "".join(
+ "1" if bit else "0" for bit in chunk_last_bits
+ ))
+ payload_expected += bytes(chunk_last)
+ bit_len_expected += chunk_last.bit_len
+ encoded_indefinite = (
+ tag_encode(form=TagFormConstructed, num=impl) +
+ LENINDEF +
+ b"".join(chunks) +
+ chunk_last.encode() +
+ EOC
+ )
+ encoded_definite = (
+ tag_encode(form=TagFormConstructed, num=impl) +
+ len_encode(len(b"".join(chunks) + chunk_last.encode())) +
+ b"".join(chunks) +
+ chunk_last.encode()
+ )
+ with assertRaisesRegex(self, DecodeError, "unallowed BER"):
+ BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
+ for lenindef_expected, encoded in (
+ (True, encoded_indefinite),
+ (False, encoded_definite),
+ ):
+ obj, tail = BitString(impl=tag_encode(impl)).decode(
+ encoded + junk,
+ ctx={"bered": True},
+ )
+ self.assertSequenceEqual(tail, junk)
+ self.assertEqual(obj.bit_len, bit_len_expected)
+ self.assertSequenceEqual(bytes(obj), payload_expected)
+ self.assertTrue(obj.ber_encoded)
+ self.assertEqual(obj.lenindef, lenindef_expected)
+ self.assertTrue(obj.bered)
+ obj = copy(obj)
+ self.assertTrue(obj.ber_encoded)
+ self.assertEqual(obj.lenindef, lenindef_expected)
+ self.assertTrue(obj.bered)
+ self.assertEqual(len(encoded), obj.tlvlen)
+
+ @given(
+ integers(min_value=0),
+ decode_path_strat,
+ )
+ def test_ber_definite_too_short(self, offset, decode_path):
+ with assertRaisesRegex(self, DecodeError, "longer than data") as err:
+ BitString().decode(
+ tag_encode(3, form=TagFormConstructed) + len_encode(1),
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(err.exception.decode_path, decode_path)
+ self.assertEqual(err.exception.offset, offset)
+
+ @given(
+ integers(min_value=0),
+ decode_path_strat,
+ )
+ def test_ber_definite_no_data(self, offset, decode_path):
+ with assertRaisesRegex(self, DecodeError, "zero length") as err:
+ BitString().decode(
+ tag_encode(3, form=TagFormConstructed) + len_encode(0),
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(err.exception.decode_path, decode_path)
+ self.assertEqual(err.exception.offset, offset)
+
+ @given(
+ integers(min_value=0),
+ decode_path_strat,
+ integers(min_value=1, max_value=3),
+ )
+ def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
+ bs = BitString(b"data").encode()
+ with self.assertRaises(NotEnoughData) as err:
+ BitString().decode(
+ tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
+ self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
+
+ @given(
+ integers(min_value=0),
+ decode_path_strat,
+ integers(min_value=1, max_value=3),
+ )
+ def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
+ bs = BitString(b"data").encode()
+ bs_longer = BitString(b"data-longer").encode()
+ with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
+ BitString().decode(
+ (
+ tag_encode(3, form=TagFormConstructed) +
+ len_encode((chunks + 1) * len(bs)) +
+ chunks * bs +
+ bs_longer
+ ),
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
+ self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
+
+ @given(
+ integers(min_value=0),
+ decode_path_strat,
+ )
+ def test_ber_indefinite_no_chunks(self, offset, decode_path):
+ with assertRaisesRegex(self, DecodeError, "no chunks") as err:
+ BitString().decode(
+ tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(err.exception.decode_path, decode_path)
+ self.assertEqual(err.exception.offset, offset)
+
+ @given(data_strategy())
+ def test_ber_indefinite_not_multiple(self, d):
+ bs_short = BitString("'A'H").encode()
+ bs_full = BitString("'AA'H").encode()
+ chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
+ chunks.append(bs_short)
+ d.draw(permutations(chunks))
+ chunks.append(bs_short)
+ offset = d.draw(integers(min_value=0))
+ decode_path = d.draw(decode_path_strat)
+ with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
+ BitString().decode(
+ (
+ tag_encode(3, form=TagFormConstructed) +
+ LENINDEF +
+ b"".join(chunks) +
+ EOC
+ ),
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(
+ err.exception.decode_path,
+ decode_path + (str(chunks.index(bs_short)),),
+ )
+ self.assertEqual(
+ err.exception.offset,
+ offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
+ )
+
+ def test_x690_vector(self):
+ vector = BitString("'0A3B5F291CD'H")
+ obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
+ self.assertSequenceEqual(tail, b"")
+ self.assertEqual(obj, vector)
+ obj, tail = BitString().decode(
+ hexdec("23800303000A3B0305045F291CD00000"),
+ ctx={"bered": True},
+ )
+ self.assertSequenceEqual(tail, b"")
+ self.assertEqual(obj, vector)
+ self.assertTrue(obj.ber_encoded)
+ self.assertTrue(obj.lenindef)
+ self.assertTrue(obj.bered)
+ obj = copy(obj)
+ self.assertTrue(obj.ber_encoded)
+ self.assertTrue(obj.lenindef)
+ self.assertTrue(obj.bered)
+