# coding: utf-8
# PyDERASN -- Python ASN.1 DER codec with abstract structures
-# Copyright (C) 2017 Sergey Matveev <stargrave@stargrave.org>
+# 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 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 GeneralizedTime
from pyderasn import GeneralString
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((
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
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))
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))
@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):
optional,
_decoded,
) = 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))
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)
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))
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)
_decoded_initial,
) = 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,
optional,
_decoded,
) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
- obj = obj_initial(value, impl, expl, default, optional)
+ 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 = (
@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)
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_strategy(draw, schema=None, do_expl=False):
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))
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)
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),
+ lists(integers()),
+ )
+ 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 TestPrintableString(StringMixin, CommonMixin, TestCase):
+ 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(
+ 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):
+ self.assertEqual(
+ str(VisibleString().decode(hexdec("1A054A6F6E6573"))[0]),
+ "Jones",
+ )
+ self.assertEqual(
+ str(VisibleString().decode(
+ hexdec("3A0904034A6F6E04026573"),
+ ctx={"bered": True},
+ )[0]),
+ "Jones",
+ )
+ self.assertEqual(
+ str(VisibleString().decode(
+ hexdec("3A8004034A6F6E040265730000"),
+ ctx={"bered": True},
+ )[0]),
+ "Jones",
+ )
+
-class TestGeneralString(StringMixin, CommonMixin, TestCase):
+class TestGeneralString(
+ UnicodeDecodeErrorMixin,
+ StringMixin,
+ CommonMixin,
+ TestCase,
+):
base_klass = GeneralString
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)
))
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())
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))
)
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_strategy(draw, seq_klass, do_expl=False):
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):
@given(data_strategy())
def test_symmetric(self, d):
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"")
+ seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
+ self.assertEqual(tail, tail_junk)
self.assertTrue(seq.ready)
self._assert_expects(seq_decoded, expects)
self.assertEqual(seq, seq_decoded)
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
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)
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"),
+ )