# coding: utf-8
-# PyDERASN -- Python ASN.1 DER codec with abstract structures
-# Copyright (C) 2017 Sergey Matveev <stargrave@stargrave.org>
+# PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
+# Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
from datetime import datetime
from string import ascii_letters
+from string import digits
from string import printable
from string import whitespace
from unittest import TestCase
from hypothesis.strategies import text
from hypothesis.strategies import tuples
from six import assertRaisesRegex
+from six import binary_type
from six import byte2int
from six import indexbytes
from six import int2byte
from six import iterbytes
from six import PY2
from six import text_type
+from six import unichr as six_unichr
from pyderasn import _pp
+from pyderasn import abs_decode_path
from pyderasn import Any
from pyderasn import BitString
from pyderasn import BMPString
from pyderasn import BoundsError
from pyderasn import Choice
from pyderasn import DecodeError
+from pyderasn import DecodePathDefBy
from pyderasn import Enumerated
+from pyderasn import EOC
+from pyderasn import EOC_LEN
from pyderasn import GeneralizedTime
from pyderasn import GeneralString
from pyderasn import GraphicString
from pyderasn import InvalidValueType
from pyderasn import len_decode
from pyderasn import len_encode
+from pyderasn import LENINDEF
from pyderasn import NotEnoughData
from pyderasn import Null
from pyderasn import NumericString
from pyderasn import Set
from pyderasn import SetOf
from pyderasn import tag_ctxc
+from pyderasn import tag_ctxp
from pyderasn import tag_decode
from pyderasn import tag_encode
from pyderasn import tag_strip
from pyderasn import VisibleString
-settings.register_profile('local', settings(
+settings.register_profile("local", settings(
deadline=5000,
perform_health_check=False,
))
-settings.load_profile('local')
+settings.load_profile("local")
LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
tag_classes = sampled_from((
TagClassUniversal,
))
tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
+decode_path_strat = lists(integers(), max_size=3).map(
+ lambda decode_path: tuple(str(dp) for dp in decode_path)
+)
class TestHex(TestCase):
with self.assertRaises(ValueError):
self.base_klass(impl=b"whatever", expl=b"whenever")
- @given(binary(), integers(), integers(), integers())
+ @given(binary(min_size=1), integers(), integers(), integers())
def test_decoded(self, impl, offset, llen, vlen):
obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
self.assertEqual(obj.offset, offset)
self.assertEqual(obj.tlen, len(impl))
self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
- @given(binary())
+ @given(binary(min_size=1))
def test_impl_inherited(self, impl_tag):
class Inherited(self.base_klass):
impl = impl_tag
@composite
-def boolean_values_strat(draw, do_expl=False):
+def boolean_values_strategy(draw, do_expl=False):
value = draw(one_of(none(), booleans()))
impl = None
expl = None
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(boolean_values_strat())
+ ) = d.draw(boolean_values_strategy())
obj_initial = klass(
value_initial,
impl_initial,
default,
optional,
_decoded,
- ) = d.draw(boolean_values_strat(do_expl=impl_initial is None))
+ ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
obj = obj_initial(value, impl, expl, default, optional)
if obj.ready:
value_expected = default if value is None else value
optional = True
self.assertEqual(obj.optional, optional)
- @given(boolean_values_strat())
+ @given(boolean_values_strategy())
def test_copy(self, values):
for klass in (Boolean, BooleanInherited):
obj = klass(*values)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Boolean().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_expl_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Boolean(expl=Boolean.tag_default).decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Boolean().decode(
Boolean.tag_default + len_encode(l)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_expl_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Boolean(expl=Boolean.tag_default).decode(
Boolean.tag_default + len_encode(l)[:-1],
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
- boolean_values_strat(),
+ boolean_values_strategy(),
booleans(),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, value, tag_expl, offset):
+ def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
for klass in (Boolean, BooleanInherited):
_, _, _, default, optional, _decoded = values
obj = klass(
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(bool(obj_decoded), bool(obj_expled))
)))
@given(integers(min_value=0 + 1, max_value=255 - 1))
- def test_invalid_value(self, value):
+ def test_ber_value(self, value):
with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
Boolean().decode(b"".join((
Boolean.tag_default,
len_encode(1),
int2byte(value),
)))
+ obj, _ = Boolean().decode(
+ b"".join((
+ Boolean.tag_default,
+ len_encode(1),
+ int2byte(value),
+ )),
+ ctx={"bered": True},
+ )
+ self.assertTrue(bool(obj))
+ self.assertTrue(obj.bered)
+ self.assertFalse(obj.lenindef)
+
+ @given(
+ integers(min_value=1).map(tag_ctxc),
+ binary().filter(lambda x: not x.startswith(EOC)),
+ )
+ def test_ber_expl_no_eoc(self, expl, junk):
+ encoded = expl + LENINDEF + Boolean(False).encode()
+ with assertRaisesRegex(self, DecodeError, "no EOC"):
+ Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
+ obj, tail = Boolean(expl=expl).decode(
+ encoded + EOC + junk,
+ ctx={"bered": True},
+ )
+ self.assertTrue(obj.expl_lenindef)
+ self.assertSequenceEqual(tail, junk)
+
+ @given(
+ integers(min_value=1).map(tag_ctxc),
+ lists(
+ booleans(),
+ min_size=1,
+ max_size=5,
+ ),
+ )
+ def test_ber_expl(self, expl, values):
+ encoded = b""
+ for value in values:
+ encoded += (
+ expl +
+ LENINDEF +
+ Boolean(value).encode() +
+ EOC
+ )
+ encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
+
+ class SeqOf(SequenceOf):
+ schema = Boolean(expl=expl)
+ seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
+ self.assertSequenceEqual(tail, b"")
+ self.assertSequenceEqual([bool(v) for v in seqof], values)
+ self.assertSetEqual(
+ set(
+ (
+ v.tlvlen,
+ v.expl_tlvlen,
+ v.expl_tlen,
+ v.expl_llen,
+ v.bered,
+ v.lenindef,
+ v.expl_lenindef,
+ ) for v in seqof
+ ),
+ set(((
+ 3 + EOC_LEN,
+ len(expl) + 1 + 3 + EOC_LEN,
+ len(expl),
+ 1,
+ False,
+ False,
+ True,
+ ),)),
+ )
@composite
-def integer_values_strat(draw, do_expl=False):
+def integer_values_strategy(draw, do_expl=False):
bound_min, value, default, bound_max = sorted(draw(sets(
integers(),
min_size=4,
optional_initial,
_specs_initial,
_decoded_initial,
- ) = d.draw(integer_values_strat())
+ ) = d.draw(integer_values_strategy())
obj_initial = klass(
value_initial,
bounds_initial,
optional,
_,
_decoded,
- ) = d.draw(integer_values_strat(do_expl=impl_initial is None))
+ ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
if (default is None) and (obj_initial.default is not None):
bounds = None
if (
{} if _specs_initial is None else dict(_specs_initial),
)
- @given(integer_values_strat())
+ @given(integer_values_strategy())
def test_copy(self, values):
for klass in (Integer, IntegerInherited):
obj = klass(*values)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Integer().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Integer().decode(
Integer.tag_default + len_encode(l)[:-1],
@given(
sets(integers(), min_size=2, max_size=2),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
value, bound_min = list(sorted(ints))
class Int(Integer):
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
- integer_values_strat(),
+ integer_values_strategy(),
integers(),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, value, tag_expl, offset):
+ def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
for klass in (Integer, IntegerInherited):
_, _, _, _, default, optional, _, _decoded = values
obj = klass(
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(int(obj_decoded), int(obj_expled))
@composite
-def bit_string_values_strat(draw, schema=None, value_required=False, do_expl=False):
+def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
if schema is None:
schema = ()
if draw(booleans()):
@given(
tuples(integers(min_value=0), binary()),
tuples(integers(min_value=0), binary()),
- binary(),
- binary(),
+ binary(min_size=1),
+ binary(min_size=1),
)
def test_comparison(self, value1, value2, tag1, tag2):
for klass in (BitString, BitStringInherited):
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(bit_string_values_strat())
+ ) = d.draw(bit_string_values_strategy())
class BS(klass):
schema = schema_initial
default,
optional,
_decoded,
- ) = d.draw(bit_string_values_strat(
+ ) = d.draw(bit_string_values_strategy(
schema=schema_initial,
do_expl=impl_initial is None,
))
self.assertEqual(obj.optional, optional)
self.assertEqual(obj.specs, obj_initial.specs)
- @given(bit_string_values_strat())
+ @given(bit_string_values_strategy())
def test_copy(self, values):
for klass in (BitString, BitStringInherited):
_schema, value, impl, expl, default, optional, _decoded = values
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
BitString().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
BitString().decode(
BitString.tag_default + len_encode(l)[:-1],
default,
optional,
_decoded,
- ) = d.draw(bit_string_values_strat(value_required=True))
+ ) = d.draw(bit_string_values_strategy(value_required=True))
+ tail_junk = d.draw(binary(max_size=5))
tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
offset = d.draw(integers(min_value=0))
for klass in (BitString, BitStringInherited):
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
self.assertTrue(obj[9])
self.assertFalse(obj[17])
+ @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.bered)
+ self.assertEqual(obj.lenindef, lenindef_expected)
+ 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.bered)
+ self.assertTrue(obj.lenindef)
+
@composite
-def octet_string_values_strat(draw, do_expl=False):
+def octet_string_values_strategy(draw, do_expl=False):
bound_min, bound_max = sorted(draw(sets(
integers(min_value=0, max_value=1 << 7),
min_size=2,
repr(obj)
pprint(obj)
- @given(binary(), binary(), binary(), binary())
+ @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
def test_comparison(self, value1, value2, tag1, tag2):
for klass in (OctetString, OctetStringInherited):
obj1 = klass(value1)
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(octet_string_values_strat())
+ ) = d.draw(octet_string_values_strategy())
obj_initial = klass(
value_initial,
bounds_initial,
default,
optional,
_decoded,
- ) = d.draw(octet_string_values_strat(do_expl=impl_initial is None))
+ ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
if (default is None) and (obj_initial.default is not None):
bounds = None
if (
bounds or bounds_initial or (0, float("+inf")),
)
- @given(octet_string_values_strat())
+ @given(octet_string_values_strategy())
def test_copy(self, values):
for klass in (OctetString, OctetStringInherited):
obj = klass(*values)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
OctetString().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
OctetString().decode(
OctetString.tag_default + len_encode(l)[:-1],
@given(
sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
value, bound_min = list(sorted(ints))
class String(OctetString):
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
- octet_string_values_strat(),
+ octet_string_values_strategy(),
binary(),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, value, tag_expl, offset):
+ def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
for klass in (OctetString, OctetStringInherited):
_, _, _, _, default, optional, _decoded = values
obj = klass(
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
)
self.assertEqual(obj_decoded.expl_offset, offset)
+ @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=1,
+ max_size=3,
+ ),
+ binary(),
+ )
+ def test_constructed(self, impl, chunk_inputs, junk):
+ def chunk_constructed(contents):
+ return (
+ tag_encode(form=TagFormConstructed, num=4) +
+ LENINDEF +
+ b"".join(OctetString(content).encode() for content in contents) +
+ EOC
+ )
+ chunks = []
+ payload_expected = b""
+ for chunk_input in chunk_inputs:
+ if isinstance(chunk_input, binary_type):
+ chunks.append(OctetString(chunk_input).encode())
+ payload_expected += chunk_input
+ else:
+ chunks.append(chunk_constructed(chunk_input))
+ payload = b"".join(chunk_input)
+ payload_expected += payload
+ encoded_indefinite = (
+ tag_encode(form=TagFormConstructed, num=impl) +
+ LENINDEF +
+ b"".join(chunks) +
+ EOC
+ )
+ encoded_definite = (
+ tag_encode(form=TagFormConstructed, num=impl) +
+ len_encode(len(b"".join(chunks))) +
+ b"".join(chunks)
+ )
+ with assertRaisesRegex(self, DecodeError, "unallowed BER"):
+ OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
+ for lenindef_expected, encoded in (
+ (True, encoded_indefinite),
+ (False, encoded_definite),
+ ):
+ obj, tail = OctetString(impl=tag_encode(impl)).decode(
+ encoded + junk,
+ ctx={"bered": True},
+ )
+ self.assertSequenceEqual(tail, junk)
+ self.assertSequenceEqual(bytes(obj), payload_expected)
+ self.assertTrue(obj.bered)
+ self.assertEqual(obj.lenindef, lenindef_expected)
+ 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:
+ OctetString().decode(
+ tag_encode(4, 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,
+ integers(min_value=1, max_value=3),
+ )
+ def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
+ bs = OctetString(b"data").encode()
+ with self.assertRaises(NotEnoughData) as err:
+ OctetString().decode(
+ tag_encode(4, 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 = OctetString(b"data").encode()
+ bs_longer = OctetString(b"data-longer").encode()
+ with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
+ OctetString().decode(
+ (
+ tag_encode(4, 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))
+
@composite
-def null_values_strat(draw, do_expl=False):
+def null_values_strategy(draw, do_expl=False):
impl = None
expl = None
if do_expl:
expl_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(null_values_strat())
+ ) = d.draw(null_values_strategy())
obj_initial = klass(
impl=impl_initial,
expl=expl_initial,
expl,
optional,
_decoded,
- ) = d.draw(null_values_strat(do_expl=impl_initial is None))
+ ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
obj = obj_initial(impl=impl, expl=expl, optional=optional)
self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
self.assertEqual(obj.expl_tag, expl or expl_initial)
optional = False if optional is None else optional
self.assertEqual(obj.optional, optional)
- @given(null_values_strat())
+ @given(null_values_strategy())
def test_copy(self, values):
for klass in (Null, NullInherited):
impl, expl, optional, _decoded = values
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Null().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Null().decode(
Null.tag_default + len_encode(l)[:-1],
Null(impl=impl).decode(Null().encode())
@given(
- null_values_strat(),
+ null_values_strategy(),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, tag_expl, offset):
+ def test_symmetric(self, values, tag_expl, offset, tail_junk):
for klass in (Null, NullInherited):
_, _, optional, _decoded = values
obj = klass(optional=optional, _decoded=_decoded)
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
@composite
-def oid_values_strat(draw, do_expl=False):
+def oid_values_strategy(draw, do_expl=False):
value = draw(one_of(none(), oid_strategy()))
impl = None
expl = None
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(oid_values_strat())
+ ) = d.draw(oid_values_strategy())
obj_initial = klass(
- value_initial,
- impl_initial,
- expl_initial,
- default_initial,
- optional_initial or False,
- _decoded_initial,
+ value=value_initial,
+ impl=impl_initial,
+ expl=expl_initial,
+ default=default_initial,
+ optional=optional_initial or False,
+ _decoded=_decoded_initial,
)
(
value,
default,
optional,
_decoded,
- ) = d.draw(oid_values_strat(do_expl=impl_initial is None))
- obj = obj_initial(value, impl, expl, default, optional)
+ ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
+ obj = obj_initial(
+ value=value,
+ impl=impl,
+ expl=expl,
+ default=default,
+ optional=optional,
+ )
if obj.ready:
value_expected = default if value is None else value
value_expected = (
optional = True
self.assertEqual(obj.optional, optional)
- @given(oid_values_strat())
+ @given(oid_values_strategy())
def test_copy(self, values):
for klass in (ObjectIdentifier, ObjectIdentifierInherited):
- obj = klass(*values)
+ (
+ value,
+ impl,
+ expl,
+ default,
+ optional,
+ _decoded,
+ ) = values
+ obj = klass(
+ value=value,
+ impl=impl,
+ expl=expl,
+ default=default,
+ optional=optional,
+ _decoded=_decoded,
+ )
obj_copied = obj.copy()
self.assert_copied_basic_fields(obj, obj_copied)
self.assertEqual(obj._value, obj_copied._value)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
ObjectIdentifier().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
ObjectIdentifier().decode(
ObjectIdentifier.tag_default + len_encode(l)[:-1],
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
- oid_values_strat(),
+ oid_values_strategy(),
oid_strategy(),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, value, tag_expl, offset):
+ def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
for klass in (ObjectIdentifier, ObjectIdentifierInherited):
_, _, _, default, optional, _decoded = values
obj = klass(
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
data,
)))
+ def test_x690_vector(self):
+ self.assertEqual(
+ ObjectIdentifier().decode(hexdec("0603883703"))[0],
+ ObjectIdentifier((2, 999, 3)),
+ )
+
@composite
-def enumerated_values_strat(draw, schema=None, do_expl=False):
+def enumerated_values_strategy(draw, schema=None, do_expl=False):
if schema is None:
schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
values = list(draw(sets(
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(enumerated_values_strat())
+ ) = d.draw(enumerated_values_strategy())
class E(Enumerated):
schema = schema_initial
default,
optional,
_decoded,
- ) = d.draw(enumerated_values_strat(
+ ) = d.draw(enumerated_values_strategy(
schema=schema_initial,
do_expl=impl_initial is None,
))
self.assertEqual(obj.optional, optional)
self.assertEqual(obj.specs, dict(schema_initial))
- @given(enumerated_values_strat())
+ @given(enumerated_values_strategy())
def test_copy(self, values):
schema_input, value, impl, expl, default, optional, _decoded = values
@given(data_strategy())
def test_symmetric(self, d):
schema_input, _, _, _, default, optional, _decoded = d.draw(
- enumerated_values_strat(),
+ enumerated_values_strategy(),
)
tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
offset = d.draw(integers(min_value=0))
value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
+ tail_junk = d.draw(binary(max_size=5))
class E(Enumerated):
schema = schema_input
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(int(obj_decoded), int(obj_expled))
@composite
-def string_values_strat(draw, alphabet, do_expl=False):
+def string_values_strategy(draw, alphabet, do_expl=False):
bound_min, bound_max = sorted(draw(sets(
integers(min_value=0, max_value=1 << 7),
min_size=2,
def test_comparison(self, d):
value1 = d.draw(text(alphabet=self.text_alphabet()))
value2 = d.draw(text(alphabet=self.text_alphabet()))
- tag1 = d.draw(binary())
- tag2 = d.draw(binary())
+ tag1 = d.draw(binary(min_size=1))
+ tag2 = d.draw(binary(min_size=1))
obj1 = self.base_klass(value1)
obj2 = self.base_klass(value2)
self.assertEqual(obj1 == obj2, value1 == value2)
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(string_values_strat(self.text_alphabet()))
+ ) = d.draw(string_values_strategy(self.text_alphabet()))
obj_initial = self.base_klass(
value_initial,
bounds_initial,
default,
optional,
_decoded,
- ) = d.draw(string_values_strat(
+ ) = d.draw(string_values_strategy(
self.text_alphabet(),
do_expl=impl_initial is None,
))
@given(data_strategy())
def test_copy(self, d):
- values = d.draw(string_values_strat(self.text_alphabet()))
+ values = d.draw(string_values_strategy(self.text_alphabet()))
obj = self.base_klass(*values)
obj_copied = obj.copy()
self.assert_copied_basic_fields(obj, obj_copied)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
self.base_klass().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
self.base_klass().decode(
self.base_klass.tag_default + len_encode(l)[:-1],
@given(
sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
value, bound_min = list(sorted(ints))
class String(self.base_klass):
@given(data_strategy())
def test_symmetric(self, d):
- values = d.draw(string_values_strat(self.text_alphabet()))
+ values = d.draw(string_values_strategy(self.text_alphabet()))
value = d.draw(text(alphabet=self.text_alphabet()))
tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
offset = d.draw(integers(min_value=0))
+ tail_junk = d.draw(binary(max_size=5))
_, _, _, _, default, optional, _decoded = values
obj = self.base_klass(
value=value,
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertNotEqual(obj_decoded, obj)
self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
base_klass = UTF8String
+class UnicodeDecodeErrorMixin(object):
+ @given(text(
+ alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
+ min_size=1,
+ max_size=5,
+ ))
+ def test_unicode_decode_error(self, cyrillic_text):
+ with self.assertRaises(DecodeError):
+ self.base_klass(cyrillic_text)
+
+
class TestNumericString(StringMixin, CommonMixin, TestCase):
base_klass = NumericString
+ def text_alphabet(self):
+ return digits
+
+ @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
+ def test_non_numeric(self, cyrillic_text):
+ with assertRaisesRegex(self, DecodeError, "non-numeric"):
+ self.base_klass(cyrillic_text)
+
+ @given(
+ sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
+ integers(min_value=0),
+ decode_path_strat,
+ )
+ def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
+ value, bound_min = list(sorted(ints))
+
+ class String(self.base_klass):
+ bounds = (bound_min, bound_min)
+ with self.assertRaises(DecodeError) as err:
+ String().decode(
+ self.base_klass(b"1" * value).encode(),
+ offset=offset,
+ decode_path=decode_path,
+ )
+ repr(err.exception)
+ self.assertEqual(err.exception.offset, offset)
+ self.assertEqual(err.exception.decode_path, decode_path)
+
-class TestPrintableString(StringMixin, CommonMixin, TestCase):
+class TestPrintableString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = PrintableString
-class TestTeletexString(StringMixin, CommonMixin, TestCase):
+class TestTeletexString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = TeletexString
-class TestVideotexString(StringMixin, CommonMixin, TestCase):
+class TestVideotexString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = VideotexString
-class TestIA5String(StringMixin, CommonMixin, TestCase):
+class TestIA5String(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = IA5String
-class TestGraphicString(StringMixin, CommonMixin, TestCase):
+class TestGraphicString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = GraphicString
-class TestVisibleString(StringMixin, CommonMixin, TestCase):
+class TestVisibleString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = VisibleString
+ def test_x690_vector(self):
+ obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
+ self.assertSequenceEqual(tail, b"")
+ self.assertEqual(str(obj), "Jones")
+ self.assertFalse(obj.bered)
+ self.assertFalse(obj.lenindef)
+
+ obj, tail = VisibleString().decode(
+ hexdec("3A0904034A6F6E04026573"),
+ ctx={"bered": True},
+ )
+ self.assertSequenceEqual(tail, b"")
+ self.assertEqual(str(obj), "Jones")
+ self.assertTrue(obj.bered)
+ self.assertFalse(obj.lenindef)
+
+ obj, tail = VisibleString().decode(
+ hexdec("3A8004034A6F6E040265730000"),
+ ctx={"bered": True},
+ )
+ self.assertSequenceEqual(tail, b"")
+ self.assertEqual(str(obj), "Jones")
+ self.assertTrue(obj.bered)
+ self.assertTrue(obj.lenindef)
+
-class TestGeneralString(StringMixin, CommonMixin, TestCase):
+class TestGeneralString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = GeneralString
@composite
-def generalized_time_values_strat(
+def generalized_time_values_strategy(
draw,
min_datetime,
max_datetime,
min_value=self.min_datetime,
max_value=self.max_datetime,
))
- tag1 = d.draw(binary())
- tag2 = d.draw(binary())
+ tag1 = d.draw(binary(min_size=1))
+ tag2 = d.draw(binary(min_size=1))
if self.omit_ms:
value1 = value1.replace(microsecond=0)
value2 = value2.replace(microsecond=0)
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(generalized_time_values_strat(
+ ) = d.draw(generalized_time_values_strategy(
min_datetime=self.min_datetime,
max_datetime=self.max_datetime,
omit_ms=self.omit_ms,
default,
optional,
_decoded,
- ) = d.draw(generalized_time_values_strat(
+ ) = d.draw(generalized_time_values_strategy(
min_datetime=self.min_datetime,
max_datetime=self.max_datetime,
omit_ms=self.omit_ms,
@given(data_strategy())
def test_copy(self, d):
- values = d.draw(generalized_time_values_strat(
+ values = d.draw(generalized_time_values_strategy(
min_datetime=self.min_datetime,
max_datetime=self.max_datetime,
))
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(data_strategy())
def test_symmetric(self, d):
- values = d.draw(generalized_time_values_strat(
+ values = d.draw(generalized_time_values_strategy(
min_datetime=self.min_datetime,
max_datetime=self.max_datetime,
))
))
tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
offset = d.draw(integers(min_value=0))
+ tail_junk = d.draw(binary(max_size=5))
_, _, _, default, optional, _decoded = values
obj = self.base_klass(
value=value,
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
@composite
-def any_values_strat(draw, do_expl=False):
+def any_values_strategy(draw, do_expl=False):
value = draw(one_of(none(), binary()))
expl = None
if do_expl:
expl_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(any_values_strat())
+ ) = d.draw(any_values_strategy())
obj_initial = klass(
value_initial,
expl_initial,
expl,
optional,
_decoded,
- ) = d.draw(any_values_strat(do_expl=True))
+ ) = d.draw(any_values_strategy(do_expl=True))
obj = obj_initial(value, expl, optional)
if obj.ready:
value_expected = None if value is None else value
# override it, as Any does not have implicit tag
pass
- @given(any_values_strat())
+ @given(any_values_strategy())
def test_copy(self, values):
for klass in (Any, AnyInherited):
obj = klass(*values)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Any().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
Any().decode(
Any.tag_default + len_encode(l)[:-1],
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
- any_values_strat(),
+ any_values_strategy(),
integers().map(lambda x: Integer(x).encode()),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, value, tag_expl, offset):
+ def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
for klass in (Any, AnyInherited):
_, _, optional, _decoded = values
obj = klass(value=value, optional=optional, _decoded=_decoded)
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
self.assertEqual(bytes(obj_decoded), bytes(obj))
self.assertEqual(obj_decoded.llen, 0)
self.assertEqual(obj_decoded.vlen, len(value))
+ @given(
+ integers(min_value=1).map(tag_ctxc),
+ integers(min_value=0, max_value=3),
+ integers(min_value=0),
+ decode_path_strat,
+ binary(),
+ )
+ def test_indefinite(self, expl, chunks, offset, decode_path, junk):
+ chunk = Boolean(False, expl=expl).encode()
+ encoded = (
+ OctetString.tag_default +
+ LENINDEF +
+ b"".join([chunk] * chunks) +
+ EOC
+ )
+ obj, tail = Any().decode(
+ encoded + junk,
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertSequenceEqual(tail, junk)
+ self.assertEqual(obj.offset, offset)
+ self.assertEqual(obj.tlvlen, len(encoded))
+ with self.assertRaises(NotEnoughData) as err:
+ Any().decode(
+ encoded[:-1],
+ offset=offset,
+ decode_path=decode_path,
+ ctx={"bered": True},
+ )
+ self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
+ self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
+
@composite
-def choice_values_strat(draw, value_required=False, schema=None, do_expl=False):
+def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
if schema is None:
names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
tags = [tag_encode(tag) for tag in draw(sets(
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(choice_values_strat())
+ ) = d.draw(choice_values_strategy())
class Wahl(klass):
schema = schema_initial
default,
optional,
_decoded,
- ) = d.draw(choice_values_strat(schema=schema_initial, do_expl=True))
+ ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
obj = obj_initial(value, expl, default, optional)
if obj.ready:
value_expected = default if value is None else value
# override it, as Any does not have implicit tag
pass
- @given(choice_values_strat())
+ @given(choice_values_strategy())
def test_copy(self, values):
_schema, value, expl, default, optional, _decoded = values
@given(data_strategy())
def test_symmetric(self, d):
_schema, value, _, default, optional, _decoded = d.draw(
- choice_values_strat(value_required=True)
+ choice_values_strategy(value_required=True)
)
tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
offset = d.draw(integers(min_value=0))
+ tail_junk = d.draw(binary(max_size=5))
class Wahl(self.base_klass):
schema = _schema
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self.assertEqual(obj_decoded, obj_expled)
self.assertEqual(obj_decoded.choice, obj_expled.choice)
self.assertEqual(obj_decoded.value, obj_expled.value)
with self.assertRaises(TagMismatch):
obj.decode(int_encoded)
+ def test_tag_mismatch_underlying(self):
+ class SeqOfBoolean(SequenceOf):
+ schema = Boolean()
+
+ class SeqOfInteger(SequenceOf):
+ schema = Integer()
+
+ class Wahl(Choice):
+ schema = (
+ ("erste", SeqOfBoolean()),
+ )
+
+ int_encoded = SeqOfInteger((Integer(123),)).encode()
+ bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
+ obj = Wahl()
+ obj.decode(bool_encoded)
+ with self.assertRaises(TagMismatch) as err:
+ obj.decode(int_encoded)
+ self.assertEqual(err.exception.decode_path, ("erste", "0"))
+
@composite
-def seq_values_strat(draw, seq_klass, do_expl=False):
+def seq_values_strategy(draw, seq_klass, do_expl=False):
value = None
if draw(booleans()):
value = seq_klass()
@composite
-def sequence_strat(draw, seq_klass):
+def sequence_strategy(draw, seq_klass):
inputs = draw(lists(
one_of(
tuples(just(Boolean), booleans(), one_of(none(), booleans())),
@composite
-def sequences_strat(draw, seq_klass):
+def sequences_strategy(draw, seq_klass):
tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
inits = [
({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
max_size=len(tags),
)))
seq_expectses = draw(lists(
- sequence_strat(seq_klass=seq_klass),
+ sequence_strategy(seq_klass=seq_klass),
min_size=len(tags),
max_size=len(tags),
))
class SeqMixing(object):
def test_invalid_value_type(self):
with self.assertRaises(InvalidValueType) as err:
- self.base_klass((1, 2, 3))
+ self.base_klass(123)
repr(err.exception)
def test_invalid_value_type_set(self):
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(seq_values_strat(seq_klass=klass))
+ ) = d.draw(seq_values_strategy(seq_klass=klass))
obj_initial = klass(
value_initial,
schema_initial,
default,
optional,
_decoded,
- ) = d.draw(seq_values_strat(
+ ) = d.draw(seq_values_strategy(
seq_klass=klass,
do_expl=impl_initial is None,
))
class SeqInherited(self.base_klass):
pass
for klass in (self.base_klass, SeqInherited):
- values = d.draw(seq_values_strat(seq_klass=klass))
+ values = d.draw(seq_values_strategy(seq_klass=klass))
obj = klass(*values)
obj_copied = obj.copy()
self.assert_copied_basic_fields(obj, obj_copied)
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
self.base_klass().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
self.base_klass().decode(
self.base_klass.tag_default + len_encode(l)[:-1],
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(data_strategy())
def test_symmetric(self, d):
- seq, expects = d.draw(sequence_strat(seq_klass=self.base_klass))
+ seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
+ tail_junk = d.draw(binary(max_size=5))
self.assertTrue(seq.ready)
self.assertFalse(seq.decoded)
self._assert_expects(seq, expects)
repr(seq)
pprint(seq)
- seq_encoded = seq.encode()
- seq_decoded, tail = seq.decode(seq_encoded)
- self.assertEqual(tail, b"")
self.assertTrue(seq.ready)
- self._assert_expects(seq_decoded, expects)
- self.assertEqual(seq, seq_decoded)
- self.assertEqual(seq_decoded.encode(), seq_encoded)
- for expect in expects:
- if not expect["presented"]:
- self.assertNotIn(expect["name"], seq_decoded)
- continue
- self.assertIn(expect["name"], seq_decoded)
- obj = seq_decoded[expect["name"]]
- self.assertTrue(obj.decoded)
- offset = obj.expl_offset if obj.expled else obj.offset
- tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
- self.assertSequenceEqual(
- seq_encoded[offset:offset + tlvlen],
- obj.encode(),
- )
+ seq_encoded = seq.encode()
+ seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
+ self.assertFalse(seq_decoded.lenindef)
+
+ t, _, lv = tag_strip(seq_encoded)
+ _, _, v = len_decode(lv)
+ seq_encoded_lenindef = t + LENINDEF + v + EOC
+ seq_decoded_lenindef, tail_lenindef = seq.decode(
+ seq_encoded_lenindef + tail_junk,
+ ctx={"bered": True},
+ )
+ self.assertTrue(seq_decoded_lenindef.lenindef)
+ with self.assertRaises(DecodeError):
+ seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
+ with self.assertRaises(DecodeError):
+ seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
+ repr(seq_decoded_lenindef)
+ pprint(seq_decoded_lenindef)
+ self.assertTrue(seq_decoded_lenindef.ready)
+
+ for decoded, decoded_tail, encoded in (
+ (seq_decoded, tail, seq_encoded),
+ (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
+ ):
+ self.assertEqual(decoded_tail, tail_junk)
+ self._assert_expects(decoded, expects)
+ self.assertEqual(seq, decoded)
+ self.assertEqual(decoded.encode(), seq_encoded)
+ self.assertEqual(decoded.tlvlen, len(encoded))
+ for expect in expects:
+ if not expect["presented"]:
+ self.assertNotIn(expect["name"], decoded)
+ continue
+ self.assertIn(expect["name"], decoded)
+ obj = decoded[expect["name"]]
+ self.assertTrue(obj.decoded)
+ offset = obj.expl_offset if obj.expled else obj.offset
+ tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
+ self.assertSequenceEqual(
+ seq_encoded[offset:offset + tlvlen],
+ obj.encode(),
+ )
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(data_strategy())
def test_symmetric_with_seq(self, d):
- seq, expect_outers = d.draw(sequences_strat(seq_klass=self.base_klass))
+ seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
self.assertTrue(seq.ready)
seq_encoded = seq.encode()
seq_decoded, tail = seq.decode(seq_encoded)
seq[missing] = Boolean()
repr(err.exception)
+ def test_x690_vector(self):
+ class Seq(Sequence):
+ schema = (
+ ("name", IA5String()),
+ ("ok", Boolean()),
+ )
+ seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
+ self.assertEqual(seq["name"], "Smith")
+ self.assertEqual(seq["ok"], True)
+
class TestSet(SeqMixing, CommonMixin, TestCase):
base_klass = Set
@composite
-def seqof_values_strat(draw, schema=None, do_expl=False):
+def seqof_values_strategy(draw, schema=None, do_expl=False):
if schema is None:
schema = draw(sampled_from((Boolean(), Integer())))
bound_min, bound_max = sorted(draw(sets(
default_initial,
optional_initial,
_decoded_initial,
- ) = d.draw(seqof_values_strat())
+ ) = d.draw(seqof_values_strategy())
class SeqOf(self.base_klass):
schema = schema_initial
default,
optional,
_decoded,
- ) = d.draw(seqof_values_strat(
+ ) = d.draw(seqof_values_strategy(
schema=schema_initial,
do_expl=impl_initial is None,
))
bounds or bounds_initial or (0, float("+inf")),
)
- @given(seqof_values_strat())
+ @given(seqof_values_strategy())
def test_copy(self, values):
_schema, value, bounds, impl, expl, default, optional, _decoded = values
@given(
integers(min_value=31),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_tag(self, tag, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
self.base_klass().decode(
tag_encode(tag)[:-1],
@given(
integers(min_value=128),
integers(min_value=0),
- lists(integers()),
+ decode_path_strat,
)
def test_bad_len(self, l, offset, decode_path):
- decode_path = tuple(str(i) for i in decode_path)
with self.assertRaises(DecodeError) as err:
self.base_klass().decode(
self.base_klass.tag_default + len_encode(l)[:-1],
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
@given(
- seqof_values_strat(schema=Integer()),
+ seqof_values_strategy(schema=Integer()),
lists(integers().map(Integer)),
integers(min_value=1).map(tag_ctxc),
integers(min_value=0),
+ binary(max_size=5),
)
- def test_symmetric(self, values, value, tag_expl, offset):
+ def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
_, _, _, _, _, default, optional, _decoded = values
class SeqOf(self.base_klass):
repr(obj_expled)
pprint(obj_expled)
obj_expled_encoded = obj_expled.encode()
- obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
+ obj_decoded, tail = obj_expled.decode(
+ obj_expled_encoded + tail_junk,
+ offset=offset,
+ )
repr(obj_decoded)
pprint(obj_decoded)
- self.assertEqual(tail, b"")
+ self.assertEqual(tail, tail_junk)
self._test_symmetric_compare_objs(obj_decoded, obj_expled)
self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
],
)
+ t, _, lv = tag_strip(obj_encoded)
+ _, _, v = len_decode(lv)
+ obj_encoded_lenindef = t + LENINDEF + v + EOC
+ obj_decoded_lenindef, tail_lenindef = obj.decode(
+ obj_encoded_lenindef + tail_junk,
+ ctx={"bered": True},
+ )
+ self.assertTrue(obj_decoded_lenindef.lenindef)
+ repr(obj_decoded_lenindef)
+ pprint(obj_decoded_lenindef)
+ self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
+ with self.assertRaises(DecodeError):
+ obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
+ with self.assertRaises(DecodeError):
+ obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
+
class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
class SeqOf(SequenceOf):
with self.assertRaises(AttributeError):
inher = Inher()
inher.unexistent = "whatever"
+
+
+class TestOIDDefines(TestCase):
+ @given(data_strategy())
+ def runTest(self, d):
+ value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
+ value_name_chosen = d.draw(sampled_from(value_names))
+ oids = [
+ ObjectIdentifier(oid)
+ for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
+ ]
+ oid_chosen = d.draw(sampled_from(oids))
+ values = d.draw(lists(
+ integers(),
+ min_size=len(value_names),
+ max_size=len(value_names),
+ ))
+ _schema = [
+ ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
+ oid: Integer() for oid in oids[:-1]
+ }),))),
+ ]
+ for i, value_name in enumerate(value_names):
+ _schema.append((value_name, Any(expl=tag_ctxp(i))))
+
+ class Seq(Sequence):
+ schema = _schema
+ seq = Seq()
+ for value_name, value in zip(value_names, values):
+ seq[value_name] = Any(Integer(value).encode())
+ seq["type"] = oid_chosen
+ seq, _ = Seq().decode(seq.encode())
+ for value_name in value_names:
+ if value_name == value_name_chosen:
+ continue
+ self.assertIsNone(seq[value_name].defined)
+ if value_name_chosen in oids[:-1]:
+ self.assertIsNotNone(seq[value_name_chosen].defined)
+ self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
+ self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
+
+
+class TestDefinesByPath(TestCase):
+ def test_generated(self):
+ class Seq(Sequence):
+ schema = (
+ ("type", ObjectIdentifier()),
+ ("value", OctetString(expl=tag_ctxc(123))),
+ )
+
+ class SeqInner(Sequence):
+ schema = (
+ ("typeInner", ObjectIdentifier()),
+ ("valueInner", Any()),
+ )
+
+ class PairValue(SetOf):
+ schema = Any()
+
+ class Pair(Sequence):
+ schema = (
+ ("type", ObjectIdentifier()),
+ ("value", PairValue()),
+ )
+
+ class Pairs(SequenceOf):
+ schema = Pair()
+
+ (
+ type_integered,
+ type_sequenced,
+ type_innered,
+ type_octet_stringed,
+ ) = [
+ ObjectIdentifier(oid)
+ for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
+ ]
+ seq_integered = Seq()
+ seq_integered["type"] = type_integered
+ seq_integered["value"] = OctetString(Integer(123).encode())
+ seq_integered_raw = seq_integered.encode()
+
+ pairs = Pairs()
+ pairs_input = (
+ (type_octet_stringed, OctetString(b"whatever")),
+ (type_integered, Integer(123)),
+ (type_octet_stringed, OctetString(b"whenever")),
+ (type_integered, Integer(234)),
+ )
+ for t, v in pairs_input:
+ pair = Pair()
+ pair["type"] = t
+ pair["value"] = PairValue((Any(v),))
+ pairs.append(pair)
+ seq_inner = SeqInner()
+ seq_inner["typeInner"] = type_innered
+ seq_inner["valueInner"] = Any(pairs)
+ seq_sequenced = Seq()
+ seq_sequenced["type"] = type_sequenced
+ seq_sequenced["value"] = OctetString(seq_inner.encode())
+ seq_sequenced_raw = seq_sequenced.encode()
+
+ defines_by_path = []
+ seq_integered, _ = Seq().decode(seq_integered_raw)
+ self.assertIsNone(seq_integered["value"].defined)
+ defines_by_path.append(
+ (("type",), ((("value",), {
+ type_integered: Integer(),
+ type_sequenced: SeqInner(),
+ }),))
+ )
+ seq_integered, _ = Seq().decode(
+ seq_integered_raw,
+ ctx={"defines_by_path": defines_by_path},
+ )
+ self.assertIsNotNone(seq_integered["value"].defined)
+ self.assertEqual(seq_integered["value"].defined[0], type_integered)
+ self.assertEqual(seq_integered["value"].defined[1], Integer(123))
+ self.assertTrue(seq_integered_raw[
+ seq_integered["value"].defined[1].offset:
+ ].startswith(Integer(123).encode()))
+
+ seq_sequenced, _ = Seq().decode(
+ seq_sequenced_raw,
+ ctx={"defines_by_path": defines_by_path},
+ )
+ self.assertIsNotNone(seq_sequenced["value"].defined)
+ self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
+ seq_inner = seq_sequenced["value"].defined[1]
+ self.assertIsNone(seq_inner["valueInner"].defined)
+
+ defines_by_path.append((
+ ("value", DecodePathDefBy(type_sequenced), "typeInner"),
+ ((("valueInner",), {type_innered: Pairs()}),),
+ ))
+ seq_sequenced, _ = Seq().decode(
+ seq_sequenced_raw,
+ ctx={"defines_by_path": defines_by_path},
+ )
+ self.assertIsNotNone(seq_sequenced["value"].defined)
+ self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
+ seq_inner = seq_sequenced["value"].defined[1]
+ self.assertIsNotNone(seq_inner["valueInner"].defined)
+ self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
+ pairs = seq_inner["valueInner"].defined[1]
+ for pair in pairs:
+ self.assertIsNone(pair["value"][0].defined)
+
+ defines_by_path.append((
+ (
+ "value",
+ DecodePathDefBy(type_sequenced),
+ "valueInner",
+ DecodePathDefBy(type_innered),
+ any,
+ "type",
+ ),
+ ((("value",), {
+ type_integered: Integer(),
+ type_octet_stringed: OctetString(),
+ }),),
+ ))
+ seq_sequenced, _ = Seq().decode(
+ seq_sequenced_raw,
+ ctx={"defines_by_path": defines_by_path},
+ )
+ self.assertIsNotNone(seq_sequenced["value"].defined)
+ self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
+ seq_inner = seq_sequenced["value"].defined[1]
+ self.assertIsNotNone(seq_inner["valueInner"].defined)
+ self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
+ pairs_got = seq_inner["valueInner"].defined[1]
+ for pair_input, pair_got in zip(pairs_input, pairs_got):
+ self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
+ self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
+
+ @given(oid_strategy(), integers())
+ def test_simple(self, oid, tgt):
+ class Inner(Sequence):
+ schema = (
+ ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
+ ObjectIdentifier(oid): Integer(),
+ }),))),
+ )
+
+ class Outer(Sequence):
+ schema = (
+ ("inner", Inner()),
+ ("tgt", OctetString()),
+ )
+
+ inner = Inner()
+ inner["oid"] = ObjectIdentifier(oid)
+ outer = Outer()
+ outer["inner"] = inner
+ outer["tgt"] = OctetString(Integer(tgt).encode())
+ decoded, _ = Outer().decode(outer.encode())
+ self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
+
+
+class TestAbsDecodePath(TestCase):
+ @given(
+ lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
+ lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
+ )
+ def test_concat(self, decode_path, rel_path):
+ self.assertSequenceEqual(
+ abs_decode_path(decode_path, rel_path),
+ decode_path + rel_path,
+ )
+
+ @given(
+ lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
+ lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
+ )
+ def test_abs(self, decode_path, rel_path):
+ self.assertSequenceEqual(
+ abs_decode_path(decode_path, ("/",) + rel_path),
+ rel_path,
+ )
+
+ @given(
+ lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
+ integers(min_value=1, max_value=3),
+ lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
+ )
+ def test_dots(self, decode_path, number_of_dots, rel_path):
+ self.assertSequenceEqual(
+ abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
+ decode_path[:-number_of_dots] + rel_path,
+ )
+
+
+class TestStrictDefaultExistence(TestCase):
+ @given(data_strategy())
+ def runTest(self, d):
+ count = d.draw(integers(min_value=1, max_value=10))
+ chosen = d.draw(integers(min_value=0, max_value=count - 1))
+ _schema = [
+ ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
+ for i in range(count)
+ ]
+
+ class Seq(Sequence):
+ schema = _schema
+ seq = Seq()
+ for i in range(count):
+ seq["int%d" % i] = Integer(123)
+ raw = seq.encode()
+ chosen = "int%d" % chosen
+ seq.specs[chosen] = seq.specs[chosen](default=123)
+ seq.decode(raw)
+ with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+ seq.decode(raw, ctx={"strict_default_existence": True})
+
+
+class TestX690PrefixedType(TestCase):
+ def runTest(self):
+ self.assertSequenceEqual(
+ VisibleString("Jones").encode(),
+ hexdec("1A054A6F6E6573"),
+ )
+ self.assertSequenceEqual(
+ VisibleString(
+ "Jones",
+ impl=tag_encode(3, klass=TagClassApplication),
+ ).encode(),
+ hexdec("43054A6F6E6573"),
+ )
+ self.assertSequenceEqual(
+ Any(
+ VisibleString(
+ "Jones",
+ impl=tag_encode(3, klass=TagClassApplication),
+ ),
+ expl=tag_ctxc(2),
+ ).encode(),
+ hexdec("A20743054A6F6E6573"),
+ )
+ self.assertSequenceEqual(
+ OctetString(
+ VisibleString(
+ "Jones",
+ impl=tag_encode(3, klass=TagClassApplication),
+ ).encode(),
+ impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
+ ).encode(),
+ hexdec("670743054A6F6E6573"),
+ )
+ self.assertSequenceEqual(
+ VisibleString("Jones", impl=tag_ctxp(2)).encode(),
+ hexdec("82054A6F6E6573"),
+ )