2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from datetime import timedelta
22 from importlib import import_module
23 from operator import attrgetter
24 from os import environ
25 from os import urandom
26 from random import random
27 from string import ascii_letters
28 from string import digits
29 from string import printable
30 from string import whitespace
31 from time import mktime
33 from unittest import TestCase
35 from hypothesis import assume
36 from hypothesis import given
37 from hypothesis import settings
38 from hypothesis.strategies import binary
39 from hypothesis.strategies import booleans
40 from hypothesis.strategies import composite
41 from hypothesis.strategies import data as data_strategy
42 from hypothesis.strategies import datetimes
43 from hypothesis.strategies import dictionaries
44 from hypothesis.strategies import integers
45 from hypothesis.strategies import just
46 from hypothesis.strategies import lists
47 from hypothesis.strategies import none
48 from hypothesis.strategies import one_of
49 from hypothesis.strategies import permutations
50 from hypothesis.strategies import sampled_from
51 from hypothesis.strategies import sets
52 from hypothesis.strategies import text
53 from hypothesis.strategies import tuples
54 from six import assertRaisesRegex
55 from six import binary_type
56 from six import byte2int
57 from six import indexbytes
58 from six import int2byte
59 from six import iterbytes
61 from six import text_type
62 from six import unichr as six_unichr
63 from six.moves import xrange as six_xrange
64 from six.moves.cPickle import dumps as pickle_dumps
65 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
66 from six.moves.cPickle import loads as pickle_loads
68 from pyderasn import _pp
69 from pyderasn import abs_decode_path
70 from pyderasn import Any
71 from pyderasn import BitString
72 from pyderasn import BMPString
73 from pyderasn import Boolean
74 from pyderasn import BoundsError
75 from pyderasn import Choice
76 from pyderasn import DecodeError
77 from pyderasn import DecodePathDefBy
78 from pyderasn import encode_cer
79 from pyderasn import Enumerated
80 from pyderasn import EOC
81 from pyderasn import EOC_LEN
82 from pyderasn import ExceedingData
83 from pyderasn import GeneralizedTime
84 from pyderasn import GeneralString
85 from pyderasn import GraphicString
86 from pyderasn import hexdec
87 from pyderasn import hexenc
88 from pyderasn import IA5String
89 from pyderasn import Integer
90 from pyderasn import InvalidLength
91 from pyderasn import InvalidOID
92 from pyderasn import InvalidValueType
93 from pyderasn import len_decode
94 from pyderasn import len_encode
95 from pyderasn import LEN_YYMMDDHHMMSSZ
96 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
97 from pyderasn import LEN_YYYYMMDDHHMMSSZ
98 from pyderasn import LENINDEF
99 from pyderasn import LenIndefForm
100 from pyderasn import NotEnoughData
101 from pyderasn import Null
102 from pyderasn import NumericString
103 from pyderasn import ObjectIdentifier
104 from pyderasn import ObjNotReady
105 from pyderasn import ObjUnknown
106 from pyderasn import OctetString
107 from pyderasn import pp_console_row
108 from pyderasn import pprint
109 from pyderasn import PrintableString
110 from pyderasn import Sequence
111 from pyderasn import SequenceOf
112 from pyderasn import Set
113 from pyderasn import SetOf
114 from pyderasn import tag_ctxc
115 from pyderasn import tag_ctxp
116 from pyderasn import tag_decode
117 from pyderasn import tag_encode
118 from pyderasn import tag_strip
119 from pyderasn import TagClassApplication
120 from pyderasn import TagClassContext
121 from pyderasn import TagClassPrivate
122 from pyderasn import TagClassUniversal
123 from pyderasn import TagFormConstructed
124 from pyderasn import TagFormPrimitive
125 from pyderasn import TagMismatch
126 from pyderasn import TeletexString
127 from pyderasn import UniversalString
128 from pyderasn import UTCTime
129 from pyderasn import UTF8String
130 from pyderasn import VideotexString
131 from pyderasn import VisibleString
134 max_examples = environ.get("MAX_EXAMPLES")
135 settings.register_profile("local", settings(
137 **({"max_examples": int(max_examples)} if max_examples else {})
139 settings.load_profile("local")
140 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
142 tag_classes = sampled_from((
148 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
149 decode_path_strat = lists(integers(), max_size=3).map(
150 lambda decode_path: tuple(str(dp) for dp in decode_path)
152 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
155 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
157 self_module = import_module(__name__)
160 def register_class(klass):
161 klassname = klass.__name__ + str(time()).replace(".", "")
162 klass.__name__ = klassname
163 klass.__qualname__ = klassname
164 setattr(self_module, klassname, klass)
167 def assert_exceeding_data(self, call, junk):
170 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
175 class TestHex(TestCase):
177 def test_symmetric(self, data):
178 self.assertEqual(hexdec(hexenc(data)), data)
181 class TestTagCoder(TestCase):
182 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
186 integers(min_value=0, max_value=30),
189 def test_short(self, klass, form, num, junk):
190 raw = tag_encode(klass=klass, form=form, num=num)
191 self.assertEqual(tag_decode(raw), (klass, form, num))
192 self.assertEqual(len(raw), 1)
194 byte2int(tag_encode(klass=klass, form=form, num=0)),
195 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
197 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
198 self.assertSequenceEqual(stripped.tobytes(), raw)
199 self.assertEqual(tlen, len(raw))
200 self.assertSequenceEqual(tail, junk)
202 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
206 integers(min_value=31),
209 def test_long(self, klass, form, num, junk):
210 raw = tag_encode(klass=klass, form=form, num=num)
211 self.assertEqual(tag_decode(raw), (klass, form, num))
212 self.assertGreater(len(raw), 1)
214 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
217 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
218 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
219 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
220 self.assertSequenceEqual(stripped.tobytes(), raw)
221 self.assertEqual(tlen, len(raw))
222 self.assertSequenceEqual(tail, junk)
224 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
225 @given(integers(min_value=31))
226 def test_unfinished_tag(self, num):
227 raw = bytearray(tag_encode(num=num))
228 for i in range(1, len(raw)):
230 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
231 tag_strip(bytes(raw))
233 def test_go_vectors_valid(self):
234 for data, (eklass, etag, elen, eform) in (
235 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
236 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
237 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
238 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
239 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
240 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
241 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
242 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
243 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
244 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
246 tag, _, len_encoded = tag_strip(memoryview(data))
247 klass, form, num = tag_decode(tag)
248 _len, _, tail = len_decode(len_encoded)
249 self.assertSequenceEqual(tail, b"")
250 self.assertEqual(klass, eklass)
251 self.assertEqual(num, etag)
252 self.assertEqual(_len, elen)
253 self.assertEqual(form, eform)
255 def test_go_vectors_invalid(self):
263 with self.assertRaises(DecodeError):
264 _, _, len_encoded = tag_strip(memoryview(data))
265 len_decode(len_encoded)
268 integers(min_value=0, max_value=127),
269 integers(min_value=0, max_value=2),
271 def test_long_instead_of_short(self, l, dummy_num):
272 octets = (b"\x00" * dummy_num) + int2byte(l)
273 octets = int2byte((dummy_num + 1) | 0x80) + octets
274 with self.assertRaises(DecodeError):
278 class TestLenCoder(TestCase):
279 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
281 integers(min_value=0, max_value=127),
284 def test_short(self, l, junk):
285 raw = len_encode(l) + junk
286 decoded, llen, tail = len_decode(memoryview(raw))
287 self.assertEqual(decoded, l)
288 self.assertEqual(llen, 1)
289 self.assertEqual(len(raw), 1 + len(junk))
290 self.assertEqual(tail.tobytes(), junk)
292 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
294 integers(min_value=128),
297 def test_long(self, l, junk):
298 raw = len_encode(l) + junk
299 decoded, llen, tail = len_decode(memoryview(raw))
300 self.assertEqual(decoded, l)
301 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
302 self.assertEqual(llen, len(raw) - len(junk))
303 self.assertNotEqual(indexbytes(raw, 1), 0)
304 self.assertSequenceEqual(tail.tobytes(), junk)
306 def test_empty(self):
307 with self.assertRaises(NotEnoughData):
310 @given(integers(min_value=128))
311 def test_stripped(self, _len):
312 with self.assertRaises(NotEnoughData):
313 len_decode(len_encode(_len)[:-1])
316 text_printable = text(alphabet=printable, min_size=1)
320 def text_letters(draw):
321 result = draw(text(alphabet=ascii_letters, min_size=1))
323 result = result.encode("ascii")
327 class CommonMixin(object):
328 def test_tag_default(self):
329 obj = self.base_klass()
330 self.assertEqual(obj.tag, obj.tag_default)
332 def test_simultaneous_impl_expl(self):
333 with self.assertRaises(ValueError):
334 self.base_klass(impl=b"whatever", expl=b"whenever")
336 @given(binary(min_size=1), integers(), integers(), integers())
337 def test_decoded(self, impl, offset, llen, vlen):
338 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
339 self.assertEqual(obj.offset, offset)
340 self.assertEqual(obj.llen, llen)
341 self.assertEqual(obj.vlen, vlen)
342 self.assertEqual(obj.tlen, len(impl))
343 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
345 @given(binary(min_size=1))
346 def test_impl_inherited(self, impl_tag):
347 class Inherited(self.base_klass):
350 self.assertSequenceEqual(obj.impl, impl_tag)
351 self.assertFalse(obj.expled)
353 tag_class, _, tag_num = tag_decode(impl_tag)
354 self.assertEqual(obj.tag_order, (tag_class, tag_num))
356 @given(binary(min_size=1))
357 def test_expl_inherited(self, expl_tag):
358 class Inherited(self.base_klass):
361 self.assertSequenceEqual(obj.expl, expl_tag)
362 self.assertTrue(obj.expled)
364 tag_class, _, tag_num = tag_decode(expl_tag)
365 self.assertEqual(obj.tag_order, (tag_class, tag_num))
367 def assert_copied_basic_fields(self, obj, obj_copied):
368 self.assertEqual(obj, obj_copied)
369 self.assertSequenceEqual(obj.tag, obj_copied.tag)
370 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
371 self.assertEqual(obj.default, obj_copied.default)
372 self.assertEqual(obj.optional, obj_copied.optional)
373 self.assertEqual(obj.offset, obj_copied.offset)
374 self.assertEqual(obj.llen, obj_copied.llen)
375 self.assertEqual(obj.vlen, obj_copied.vlen)
377 self.assertEqual(obj.tag_order, obj_copied.tag_order)
381 def boolean_values_strategy(draw, do_expl=False):
382 value = draw(one_of(none(), booleans()))
386 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
388 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
389 default = draw(one_of(none(), booleans()))
390 optional = draw(one_of(none(), booleans()))
392 draw(integers(min_value=0)),
393 draw(integers(min_value=0)),
394 draw(integers(min_value=0)),
396 return (value, impl, expl, default, optional, _decoded)
399 class BooleanInherited(Boolean):
403 class TestBoolean(CommonMixin, TestCase):
406 def test_invalid_value_type(self):
407 with self.assertRaises(InvalidValueType) as err:
412 def test_optional(self, optional):
413 obj = Boolean(default=Boolean(False), optional=optional)
414 self.assertTrue(obj.optional)
417 def test_ready(self, value):
419 self.assertFalse(obj.ready)
422 pprint(obj, big_blobs=True, with_decode_path=True)
423 with self.assertRaises(ObjNotReady) as err:
427 self.assertTrue(obj.ready)
430 pprint(obj, big_blobs=True, with_decode_path=True)
432 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
433 def test_comparison(self, value1, value2, tag1, tag2):
434 for klass in (Boolean, BooleanInherited):
437 self.assertEqual(obj1 == obj2, value1 == value2)
438 self.assertEqual(obj1 != obj2, value1 != value2)
439 self.assertEqual(obj1 == bool(obj2), value1 == value2)
440 obj1 = klass(value1, impl=tag1)
441 obj2 = klass(value1, impl=tag2)
442 self.assertEqual(obj1 == obj2, tag1 == tag2)
443 self.assertEqual(obj1 != obj2, tag1 != tag2)
445 @given(data_strategy())
446 def test_call(self, d):
447 for klass in (Boolean, BooleanInherited):
455 ) = d.draw(boolean_values_strategy())
461 optional_initial or False,
471 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
472 obj = obj_initial(value, impl, expl, default, optional)
474 value_expected = default if value is None else value
476 default_initial if value_expected is None
479 self.assertEqual(obj, value_expected)
480 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
481 self.assertEqual(obj.expl_tag, expl or expl_initial)
484 default_initial if default is None else default,
486 if obj.default is None:
487 optional = optional_initial if optional is None else optional
488 optional = False if optional is None else optional
491 self.assertEqual(obj.optional, optional)
493 @given(boolean_values_strategy())
494 def test_copy(self, values):
495 for klass in (Boolean, BooleanInherited):
497 for copy_func in copy_funcs:
498 obj_copied = copy_func(obj)
499 self.assert_copied_basic_fields(obj, obj_copied)
503 integers(min_value=1).map(tag_encode),
505 def test_stripped(self, value, tag_impl):
506 obj = Boolean(value, impl=tag_impl)
507 with self.assertRaises(NotEnoughData):
508 obj.decode(obj.encode()[:-1])
512 integers(min_value=1).map(tag_ctxc),
514 def test_stripped_expl(self, value, tag_expl):
515 obj = Boolean(value, expl=tag_expl)
516 with self.assertRaises(NotEnoughData):
517 obj.decode(obj.encode()[:-1])
520 integers(min_value=31),
521 integers(min_value=0),
524 def test_bad_tag(self, tag, offset, decode_path):
525 with self.assertRaises(DecodeError) as err:
527 tag_encode(tag)[:-1],
529 decode_path=decode_path,
532 self.assertEqual(err.exception.offset, offset)
533 self.assertEqual(err.exception.decode_path, decode_path)
536 integers(min_value=31),
537 integers(min_value=0),
540 def test_bad_expl_tag(self, tag, offset, decode_path):
541 with self.assertRaises(DecodeError) as err:
542 Boolean(expl=Boolean.tag_default).decode(
543 tag_encode(tag)[:-1],
545 decode_path=decode_path,
548 self.assertEqual(err.exception.offset, offset)
549 self.assertEqual(err.exception.decode_path, decode_path)
552 integers(min_value=128),
553 integers(min_value=0),
556 def test_bad_len(self, l, offset, decode_path):
557 with self.assertRaises(DecodeError) as err:
559 Boolean.tag_default + len_encode(l)[:-1],
561 decode_path=decode_path,
564 self.assertEqual(err.exception.offset, offset)
565 self.assertEqual(err.exception.decode_path, decode_path)
568 integers(min_value=128),
569 integers(min_value=0),
572 def test_bad_expl_len(self, l, offset, decode_path):
573 with self.assertRaises(DecodeError) as err:
574 Boolean(expl=Boolean.tag_default).decode(
575 Boolean.tag_default + len_encode(l)[:-1],
577 decode_path=decode_path,
580 self.assertEqual(err.exception.offset, offset)
581 self.assertEqual(err.exception.decode_path, decode_path)
583 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
585 boolean_values_strategy(),
587 integers(min_value=1).map(tag_ctxc),
588 integers(min_value=0),
592 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
593 for klass in (Boolean, BooleanInherited):
594 _, _, _, default, optional, _decoded = values
603 pprint(obj, big_blobs=True, with_decode_path=True)
604 self.assertFalse(obj.expled)
605 obj_encoded = obj.encode()
606 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
607 obj_expled = obj(value, expl=tag_expl)
608 self.assertTrue(obj_expled.expled)
610 list(obj_expled.pps())
611 pprint(obj_expled, big_blobs=True, with_decode_path=True)
612 obj_expled_cer = encode_cer(obj_expled)
613 self.assertNotEqual(obj_expled_cer, obj_encoded)
614 self.assertSequenceEqual(
615 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
618 obj_expled_hex_encoded = obj_expled.hexencode()
619 ctx_copied = deepcopy(ctx_dummy)
620 obj_decoded, tail = obj_expled.hexdecode(
621 obj_expled_hex_encoded + hexenc(tail_junk),
625 self.assertDictEqual(ctx_copied, ctx_dummy)
627 list(obj_decoded.pps())
628 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
629 self.assertEqual(tail, tail_junk)
630 self.assertEqual(obj_decoded, obj_expled)
631 self.assertNotEqual(obj_decoded, obj)
632 self.assertEqual(bool(obj_decoded), bool(obj_expled))
633 self.assertEqual(bool(obj_decoded), bool(obj))
634 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
635 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
636 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
638 obj_decoded.expl_llen,
639 len(len_encode(len(obj_encoded))),
641 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
642 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
645 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
647 self.assertEqual(obj_decoded.expl_offset, offset)
648 assert_exceeding_data(
650 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
654 evgens = list(obj_expled.decode_evgen(
655 hexdec(obj_expled_hex_encoded) + tail_junk,
657 decode_path=decode_path,
660 self.assertEqual(len(evgens), 1)
661 _decode_path, obj, tail = evgens[0]
662 self.assertSequenceEqual(tail, tail_junk)
663 self.assertEqual(_decode_path, decode_path)
664 self.assertEqual(obj, obj_decoded)
665 self.assertEqual(obj.expl_offset, offset)
669 @given(integers(min_value=2))
670 def test_invalid_len(self, l):
671 with self.assertRaises(InvalidLength):
672 Boolean().decode(b"".join((
678 @given(integers(min_value=0 + 1, max_value=255 - 1))
679 def test_ber_value(self, value):
680 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
681 Boolean().decode(b"".join((
691 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
692 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
693 self.assertTrue(bool(obj))
694 self.assertTrue(obj.ber_encoded)
695 self.assertFalse(obj.lenindef)
696 self.assertTrue(obj.bered)
698 self.assertTrue(obj.ber_encoded)
699 self.assertFalse(obj.lenindef)
700 self.assertTrue(obj.bered)
703 integers(min_value=1).map(tag_ctxc),
704 binary().filter(lambda x: not x.startswith(EOC)),
706 def test_ber_expl_no_eoc(self, expl, junk):
707 encoded = expl + LENINDEF + Boolean(False).encode()
708 with self.assertRaises(LenIndefForm):
709 Boolean(expl=expl).decode(encoded + junk)
710 with assertRaisesRegex(self, DecodeError, "no EOC"):
711 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
712 obj, tail = Boolean(expl=expl).decode(
713 encoded + EOC + junk,
716 self.assertTrue(obj.expl_lenindef)
717 self.assertFalse(obj.lenindef)
718 self.assertFalse(obj.ber_encoded)
719 self.assertTrue(obj.bered)
721 self.assertTrue(obj.expl_lenindef)
722 self.assertFalse(obj.lenindef)
723 self.assertFalse(obj.ber_encoded)
724 self.assertTrue(obj.bered)
725 self.assertSequenceEqual(tail, junk)
728 pprint(obj, big_blobs=True, with_decode_path=True)
731 integers(min_value=1).map(tag_ctxc),
738 def test_ber_expl(self, expl, values):
744 Boolean(value).encode() +
747 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
749 class SeqOf(SequenceOf):
750 schema = Boolean(expl=expl)
751 with self.assertRaises(LenIndefForm):
752 SeqOf().decode(encoded)
753 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
754 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
755 self.assertSequenceEqual(tail, b"")
756 self.assertSequenceEqual([bool(v) for v in seqof], values)
772 len(expl) + 1 + 3 + EOC_LEN,
783 pprint(seqof, big_blobs=True, with_decode_path=True)
787 def integer_values_strategy(draw, do_expl=False):
788 bound_min, value, default, bound_max = sorted(draw(sets(
797 _specs = draw(sets(text_letters()))
800 min_size=len(_specs),
801 max_size=len(_specs),
803 _specs = list(zip(_specs, values))
806 bounds = (bound_min, bound_max)
810 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
812 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
815 optional = draw(one_of(none(), booleans()))
817 draw(integers(min_value=0)),
818 draw(integers(min_value=0)),
819 draw(integers(min_value=0)),
821 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
824 class IntegerInherited(Integer):
828 class TestInteger(CommonMixin, TestCase):
831 def test_invalid_value_type(self):
832 with self.assertRaises(InvalidValueType) as err:
836 @given(sets(text_letters(), min_size=2))
837 def test_unknown_name(self, names_input):
838 missing = names_input.pop()
841 schema = [(n, 123) for n in names_input]
842 with self.assertRaises(ObjUnknown) as err:
846 @given(sets(text_letters(), min_size=2))
847 def test_known_name(self, names_input):
849 schema = [(n, 123) for n in names_input]
850 Int(names_input.pop())
853 def test_optional(self, optional):
854 obj = Integer(default=Integer(0), optional=optional)
855 self.assertTrue(obj.optional)
858 def test_ready(self, value):
860 self.assertFalse(obj.ready)
863 pprint(obj, big_blobs=True, with_decode_path=True)
864 with self.assertRaises(ObjNotReady) as err:
868 self.assertTrue(obj.ready)
871 pprint(obj, big_blobs=True, with_decode_path=True)
874 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
875 def test_comparison(self, value1, value2, tag1, tag2):
876 for klass in (Integer, IntegerInherited):
879 self.assertEqual(obj1 == obj2, value1 == value2)
880 self.assertEqual(obj1 != obj2, value1 != value2)
881 self.assertEqual(obj1 == int(obj2), value1 == value2)
882 obj1 = klass(value1, impl=tag1)
883 obj2 = klass(value1, impl=tag2)
884 self.assertEqual(obj1 == obj2, tag1 == tag2)
885 self.assertEqual(obj1 != obj2, tag1 != tag2)
887 @given(lists(integers()))
888 def test_sorted_works(self, values):
889 self.assertSequenceEqual(
890 [int(v) for v in sorted(Integer(v) for v in values)],
894 @given(data_strategy())
895 def test_named(self, d):
896 names_input = list(d.draw(sets(text_letters(), min_size=1)))
897 values_input = list(d.draw(sets(
899 min_size=len(names_input),
900 max_size=len(names_input),
902 chosen_name = d.draw(sampled_from(names_input))
903 names_input = dict(zip(names_input, values_input))
907 _int = Int(chosen_name)
908 self.assertEqual(_int.named, chosen_name)
909 self.assertEqual(int(_int), names_input[chosen_name])
911 @given(integers(), integers(min_value=0), integers(min_value=0))
912 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
913 value = bound_min + value_delta
914 bound_max = value + bound_delta
915 Integer(value=value, bounds=(bound_min, bound_max))
917 @given(sets(integers(), min_size=3, max_size=3))
918 def test_bounds_unsatisfied(self, values):
919 values = sorted(values)
920 with self.assertRaises(BoundsError) as err:
921 Integer(value=values[0], bounds=(values[1], values[2]))
923 with assertRaisesRegex(self, DecodeError, "bounds") as err:
924 Integer(bounds=(values[1], values[2])).decode(
925 Integer(values[0]).encode()
928 with self.assertRaises(BoundsError) as err:
929 Integer(value=values[2], bounds=(values[0], values[1]))
931 with assertRaisesRegex(self, DecodeError, "bounds") as err:
932 Integer(bounds=(values[0], values[1])).decode(
933 Integer(values[2]).encode()
937 @given(data_strategy())
938 def test_call(self, d):
939 for klass in (Integer, IntegerInherited):
949 ) = d.draw(integer_values_strategy())
956 optional_initial or False,
969 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
970 if (default is None) and (obj_initial.default is not None):
974 (value is not None) and
975 (bounds_initial is not None) and
976 not (bounds_initial[0] <= value <= bounds_initial[1])
981 (default is not None) and
982 (bounds_initial is not None) and
983 not (bounds_initial[0] <= default <= bounds_initial[1])
986 obj = obj_initial(value, bounds, impl, expl, default, optional)
988 value_expected = default if value is None else value
990 default_initial if value_expected is None
993 self.assertEqual(obj, value_expected)
994 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
995 self.assertEqual(obj.expl_tag, expl or expl_initial)
998 default_initial if default is None else default,
1000 if obj.default is None:
1001 optional = optional_initial if optional is None else optional
1002 optional = False if optional is None else optional
1005 self.assertEqual(obj.optional, optional)
1007 (obj._bound_min, obj._bound_max),
1008 bounds or bounds_initial or (float("-inf"), float("+inf")),
1012 {} if _specs_initial is None else dict(_specs_initial),
1015 @given(integer_values_strategy())
1016 def test_copy(self, values):
1017 for klass in (Integer, IntegerInherited):
1018 obj = klass(*values)
1019 for copy_func in copy_funcs:
1020 obj_copied = copy_func(obj)
1021 self.assert_copied_basic_fields(obj, obj_copied)
1022 self.assertEqual(obj.specs, obj_copied.specs)
1023 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1024 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1025 self.assertEqual(obj._value, obj_copied._value)
1029 integers(min_value=1).map(tag_encode),
1031 def test_stripped(self, value, tag_impl):
1032 obj = Integer(value, impl=tag_impl)
1033 with self.assertRaises(NotEnoughData):
1034 obj.decode(obj.encode()[:-1])
1038 integers(min_value=1).map(tag_ctxc),
1040 def test_stripped_expl(self, value, tag_expl):
1041 obj = Integer(value, expl=tag_expl)
1042 with self.assertRaises(NotEnoughData):
1043 obj.decode(obj.encode()[:-1])
1045 def test_zero_len(self):
1046 with self.assertRaises(NotEnoughData):
1047 Integer().decode(b"".join((
1048 Integer.tag_default,
1053 integers(min_value=31),
1054 integers(min_value=0),
1057 def test_bad_tag(self, tag, offset, decode_path):
1058 with self.assertRaises(DecodeError) as err:
1060 tag_encode(tag)[:-1],
1062 decode_path=decode_path,
1065 self.assertEqual(err.exception.offset, offset)
1066 self.assertEqual(err.exception.decode_path, decode_path)
1069 integers(min_value=128),
1070 integers(min_value=0),
1073 def test_bad_len(self, l, offset, decode_path):
1074 with self.assertRaises(DecodeError) as err:
1076 Integer.tag_default + len_encode(l)[:-1],
1078 decode_path=decode_path,
1081 self.assertEqual(err.exception.offset, offset)
1082 self.assertEqual(err.exception.decode_path, decode_path)
1085 sets(integers(), min_size=2, max_size=2),
1086 integers(min_value=0),
1089 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1090 value, bound_min = list(sorted(ints))
1093 bounds = (bound_min, bound_min)
1094 with self.assertRaises(DecodeError) as err:
1096 Integer(value).encode(),
1098 decode_path=decode_path,
1101 self.assertEqual(err.exception.offset, offset)
1102 self.assertEqual(err.exception.decode_path, decode_path)
1104 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1106 integer_values_strategy(),
1108 integers(min_value=1).map(tag_ctxc),
1109 integers(min_value=0),
1113 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1114 for klass in (Integer, IntegerInherited):
1115 _, _, _, _, default, optional, _, _decoded = values
1124 pprint(obj, big_blobs=True, with_decode_path=True)
1125 self.assertFalse(obj.expled)
1126 obj_encoded = obj.encode()
1127 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1128 obj_expled = obj(value, expl=tag_expl)
1129 self.assertTrue(obj_expled.expled)
1131 list(obj_expled.pps())
1132 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1133 obj_expled_encoded = obj_expled.encode()
1134 obj_expled_cer = encode_cer(obj_expled)
1135 self.assertNotEqual(obj_expled_cer, obj_encoded)
1136 self.assertSequenceEqual(
1137 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1140 ctx_copied = deepcopy(ctx_dummy)
1141 obj_decoded, tail = obj_expled.decode(
1142 obj_expled_encoded + tail_junk,
1146 self.assertDictEqual(ctx_copied, ctx_dummy)
1148 list(obj_decoded.pps())
1149 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1150 self.assertEqual(tail, tail_junk)
1151 self.assertEqual(obj_decoded, obj_expled)
1152 self.assertNotEqual(obj_decoded, obj)
1153 self.assertEqual(int(obj_decoded), int(obj_expled))
1154 self.assertEqual(int(obj_decoded), int(obj))
1155 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1156 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1157 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1159 obj_decoded.expl_llen,
1160 len(len_encode(len(obj_encoded))),
1162 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1163 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1166 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1168 self.assertEqual(obj_decoded.expl_offset, offset)
1169 assert_exceeding_data(
1171 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1175 evgens = list(obj_expled.decode_evgen(
1176 obj_expled_encoded + tail_junk,
1178 decode_path=decode_path,
1181 self.assertEqual(len(evgens), 1)
1182 _decode_path, obj, tail = evgens[0]
1183 self.assertSequenceEqual(tail, tail_junk)
1184 self.assertEqual(_decode_path, decode_path)
1185 self.assertEqual(obj, obj_decoded)
1186 self.assertEqual(obj.expl_offset, offset)
1190 def test_go_vectors_valid(self):
1191 for data, expect in ((
1195 (b"\xff\x7f", -129),
1199 (b"\xff\x00", -256),
1203 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1204 (b"\x80\x00\x00\x00", -2147483648),
1207 Integer().decode(b"".join((
1208 Integer.tag_default,
1209 len_encode(len(data)),
1215 def test_go_vectors_invalid(self):
1220 with self.assertRaises(DecodeError):
1221 Integer().decode(b"".join((
1222 Integer.tag_default,
1223 len_encode(len(data)),
1229 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1232 if draw(booleans()):
1233 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1235 integers(min_value=0, max_value=255),
1236 min_size=len(schema),
1237 max_size=len(schema),
1239 schema = list(zip(schema, bits))
1241 def _value(value_required):
1242 if not value_required and draw(booleans()):
1244 generation_choice = 0
1246 generation_choice = draw(sampled_from((1, 2, 3)))
1247 if generation_choice == 1 or draw(booleans()):
1248 return "'%s'B" % "".join(draw(lists(
1249 sampled_from(("0", "1")),
1250 max_size=len(schema),
1252 if generation_choice == 2 or draw(booleans()):
1253 return draw(binary(max_size=len(schema) // 8))
1254 if generation_choice == 3 or draw(booleans()):
1255 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1257 value = _value(value_required)
1258 default = _value(value_required=False)
1262 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1264 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1265 optional = draw(one_of(none(), booleans()))
1267 draw(integers(min_value=0)),
1268 draw(integers(min_value=0)),
1269 draw(integers(min_value=0)),
1271 return (schema, value, impl, expl, default, optional, _decoded)
1274 class BitStringInherited(BitString):
1278 class TestBitString(CommonMixin, TestCase):
1279 base_klass = BitString
1281 @given(lists(booleans()))
1282 def test_b_encoding(self, bits):
1283 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1284 self.assertEqual(obj.bit_len, len(bits))
1285 self.assertSequenceEqual(list(obj), bits)
1286 for i, bit in enumerate(bits):
1287 self.assertEqual(obj[i], bit)
1289 @given(lists(booleans()))
1290 def test_out_of_bounds_bits(self, bits):
1291 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1292 for i in range(len(bits), len(bits) * 2):
1293 self.assertFalse(obj[i])
1295 def test_bad_b_encoding(self):
1296 with self.assertRaises(ValueError):
1297 BitString("'010120101'B")
1300 integers(min_value=1, max_value=255),
1301 integers(min_value=1, max_value=255),
1303 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1304 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1305 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1306 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1308 class BS(BitString):
1309 schema = (("whatever", 0),)
1310 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1311 self.assertEqual(obj.bit_len, leading_zeros + 1)
1312 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1314 def test_zero_len(self):
1315 with self.assertRaises(NotEnoughData):
1316 BitString().decode(b"".join((
1317 BitString.tag_default,
1321 def test_invalid_value_type(self):
1322 with self.assertRaises(InvalidValueType) as err:
1325 with self.assertRaises(InvalidValueType) as err:
1329 def test_obj_unknown(self):
1330 with self.assertRaises(ObjUnknown) as err:
1331 BitString(b"whatever")["whenever"]
1334 def test_get_invalid_type(self):
1335 with self.assertRaises(InvalidValueType) as err:
1336 BitString(b"whatever")[(1, 2, 3)]
1339 @given(data_strategy())
1340 def test_unknown_name(self, d):
1341 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1342 missing = _schema.pop()
1344 class BS(BitString):
1345 schema = [(n, i) for i, n in enumerate(_schema)]
1346 with self.assertRaises(ObjUnknown) as err:
1351 def test_optional(self, optional):
1352 obj = BitString(default=BitString(b""), optional=optional)
1353 self.assertTrue(obj.optional)
1356 def test_ready(self, value):
1358 self.assertFalse(obj.ready)
1361 pprint(obj, big_blobs=True, with_decode_path=True)
1362 with self.assertRaises(ObjNotReady) as err:
1365 obj = BitString(value)
1366 self.assertTrue(obj.ready)
1369 pprint(obj, big_blobs=True, with_decode_path=True)
1372 tuples(integers(min_value=0), binary()),
1373 tuples(integers(min_value=0), binary()),
1377 def test_comparison(self, value1, value2, tag1, tag2):
1378 for klass in (BitString, BitStringInherited):
1379 obj1 = klass(value1)
1380 obj2 = klass(value2)
1381 self.assertEqual(obj1 == obj2, value1 == value2)
1382 self.assertEqual(obj1 != obj2, value1 != value2)
1383 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1384 obj1 = klass(value1, impl=tag1)
1385 obj2 = klass(value1, impl=tag2)
1386 self.assertEqual(obj1 == obj2, tag1 == tag2)
1387 self.assertEqual(obj1 != obj2, tag1 != tag2)
1389 @given(data_strategy())
1390 def test_call(self, d):
1391 for klass in (BitString, BitStringInherited):
1400 ) = d.draw(bit_string_values_strategy())
1403 schema = schema_initial
1405 value=value_initial,
1408 default=default_initial,
1409 optional=optional_initial or False,
1410 _decoded=_decoded_initial,
1420 ) = d.draw(bit_string_values_strategy(
1421 schema=schema_initial,
1422 do_expl=impl_initial is None,
1431 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1432 self.assertEqual(obj.expl_tag, expl or expl_initial)
1433 if obj.default is None:
1434 optional = optional_initial if optional is None else optional
1435 optional = False if optional is None else optional
1438 self.assertEqual(obj.optional, optional)
1439 self.assertEqual(obj.specs, obj_initial.specs)
1441 @given(bit_string_values_strategy())
1442 def test_copy(self, values):
1443 for klass in (BitString, BitStringInherited):
1444 _schema, value, impl, expl, default, optional, _decoded = values
1454 optional=optional or False,
1457 for copy_func in copy_funcs:
1458 obj_copied = copy_func(obj)
1459 self.assert_copied_basic_fields(obj, obj_copied)
1460 self.assertEqual(obj.specs, obj_copied.specs)
1461 self.assertEqual(obj._value, obj_copied._value)
1465 integers(min_value=1).map(tag_encode),
1467 def test_stripped(self, value, tag_impl):
1468 obj = BitString(value, impl=tag_impl)
1469 with self.assertRaises(NotEnoughData):
1470 obj.decode(obj.encode()[:-1])
1474 integers(min_value=1).map(tag_ctxc),
1476 def test_stripped_expl(self, value, tag_expl):
1477 obj = BitString(value, expl=tag_expl)
1478 with self.assertRaises(NotEnoughData):
1479 obj.decode(obj.encode()[:-1])
1482 integers(min_value=31),
1483 integers(min_value=0),
1486 def test_bad_tag(self, tag, offset, decode_path):
1487 with self.assertRaises(DecodeError) as err:
1489 tag_encode(tag)[:-1],
1491 decode_path=decode_path,
1494 self.assertEqual(err.exception.offset, offset)
1495 self.assertEqual(err.exception.decode_path, decode_path)
1498 integers(min_value=128),
1499 integers(min_value=0),
1502 def test_bad_len(self, l, offset, decode_path):
1503 with self.assertRaises(DecodeError) as err:
1505 BitString.tag_default + len_encode(l)[:-1],
1507 decode_path=decode_path,
1510 self.assertEqual(err.exception.offset, offset)
1511 self.assertEqual(err.exception.decode_path, decode_path)
1513 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1514 @given(data_strategy())
1515 def test_symmetric(self, d):
1524 ) = d.draw(bit_string_values_strategy(value_required=True))
1525 tail_junk = d.draw(binary(max_size=5))
1526 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1527 offset = d.draw(integers(min_value=0))
1528 decode_path = d.draw(decode_path_strat)
1529 for klass in (BitString, BitStringInherited):
1540 pprint(obj, big_blobs=True, with_decode_path=True)
1541 self.assertFalse(obj.expled)
1542 obj_encoded = obj.encode()
1543 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1544 obj_expled = obj(value, expl=tag_expl)
1545 self.assertTrue(obj_expled.expled)
1547 list(obj_expled.pps())
1548 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1549 obj_expled_encoded = obj_expled.encode()
1550 obj_expled_cer = encode_cer(obj_expled)
1551 self.assertNotEqual(obj_expled_cer, obj_encoded)
1552 self.assertSequenceEqual(
1553 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1556 ctx_copied = deepcopy(ctx_dummy)
1557 obj_decoded, tail = obj_expled.decode(
1558 obj_expled_encoded + tail_junk,
1562 self.assertDictEqual(ctx_copied, ctx_dummy)
1564 list(obj_decoded.pps())
1565 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1566 self.assertEqual(tail, tail_junk)
1567 self.assertEqual(obj_decoded, obj_expled)
1568 self.assertNotEqual(obj_decoded, obj)
1569 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1570 self.assertEqual(bytes(obj_decoded), bytes(obj))
1571 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1572 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1573 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1575 obj_decoded.expl_llen,
1576 len(len_encode(len(obj_encoded))),
1578 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1579 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1582 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1584 self.assertEqual(obj_decoded.expl_offset, offset)
1585 if isinstance(value, tuple):
1586 self.assertSetEqual(set(value), set(obj_decoded.named))
1589 assert_exceeding_data(
1591 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1595 evgens = list(obj_expled.decode_evgen(
1596 obj_expled_encoded + tail_junk,
1598 decode_path=decode_path,
1601 self.assertEqual(len(evgens), 1)
1602 _decode_path, obj, tail = evgens[0]
1603 self.assertSequenceEqual(tail, tail_junk)
1604 self.assertEqual(_decode_path, decode_path)
1605 self.assertEqual(obj.expl_offset, offset)
1609 @given(integers(min_value=1, max_value=255))
1610 def test_bad_zero_value(self, pad_size):
1611 with self.assertRaises(DecodeError):
1612 BitString().decode(b"".join((
1613 BitString.tag_default,
1618 def test_go_vectors_invalid(self):
1624 with self.assertRaises(DecodeError):
1625 BitString().decode(b"".join((
1626 BitString.tag_default,
1631 def test_go_vectors_valid(self):
1632 obj, _ = BitString().decode(b"".join((
1633 BitString.tag_default,
1637 self.assertEqual(bytes(obj), b"")
1638 self.assertEqual(obj.bit_len, 0)
1640 obj, _ = BitString().decode(b"".join((
1641 BitString.tag_default,
1645 self.assertEqual(bytes(obj), b"\x00")
1646 self.assertEqual(obj.bit_len, 1)
1648 obj = BitString((16, b"\x82\x40"))
1649 self.assertTrue(obj[0])
1650 self.assertFalse(obj[1])
1651 self.assertTrue(obj[6])
1652 self.assertTrue(obj[9])
1653 self.assertFalse(obj[17])
1655 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1657 integers(min_value=1, max_value=30),
1660 binary(min_size=1, max_size=5),
1662 binary(min_size=1, max_size=5),
1670 lists(booleans(), min_size=1),
1674 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1675 def chunk_constructed(contents):
1677 tag_encode(form=TagFormConstructed, num=3) +
1679 b"".join(BitString(content).encode() for content in contents) +
1683 chunks_len_expected = []
1684 payload_expected = b""
1685 bit_len_expected = 0
1686 for chunk_input in chunk_inputs:
1687 if isinstance(chunk_input, binary_type):
1688 chunks.append(BitString(chunk_input).encode())
1689 payload_expected += chunk_input
1690 bit_len_expected += len(chunk_input) * 8
1691 chunks_len_expected.append(len(chunk_input) + 1)
1693 chunks.append(chunk_constructed(chunk_input))
1694 payload = b"".join(chunk_input)
1695 payload_expected += payload
1696 bit_len_expected += len(payload) * 8
1697 for c in chunk_input:
1698 chunks_len_expected.append(len(c) + 1)
1699 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1700 chunk_last = BitString("'%s'B" % "".join(
1701 "1" if bit else "0" for bit in chunk_last_bits
1703 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1704 payload_expected += bytes(chunk_last)
1705 bit_len_expected += chunk_last.bit_len
1706 encoded_indefinite = (
1707 tag_encode(form=TagFormConstructed, num=impl) +
1710 chunk_last.encode() +
1713 encoded_definite = (
1714 tag_encode(form=TagFormConstructed, num=impl) +
1715 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1719 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1720 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1721 for lenindef_expected, encoded in (
1722 (True, encoded_indefinite),
1723 (False, encoded_definite),
1725 obj, tail = BitString(impl=tag_encode(impl)).decode(
1727 ctx={"bered": True},
1729 self.assertSequenceEqual(tail, junk)
1730 self.assertEqual(obj.bit_len, bit_len_expected)
1731 self.assertSequenceEqual(bytes(obj), payload_expected)
1732 self.assertTrue(obj.ber_encoded)
1733 self.assertEqual(obj.lenindef, lenindef_expected)
1734 self.assertTrue(obj.bered)
1736 self.assertTrue(obj.ber_encoded)
1737 self.assertEqual(obj.lenindef, lenindef_expected)
1738 self.assertTrue(obj.bered)
1739 self.assertEqual(len(encoded), obj.tlvlen)
1742 pprint(obj, big_blobs=True, with_decode_path=True)
1744 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1746 decode_path=decode_path,
1747 ctx={"bered": True},
1749 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1750 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1751 self.assertGreater(len(dp), len(decode_path))
1752 self.assertEqual(obj.vlen, chunk_len_expected)
1755 integers(min_value=0),
1758 def test_ber_definite_too_short(self, offset, decode_path):
1759 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1761 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1763 decode_path=decode_path,
1764 ctx={"bered": True},
1766 self.assertEqual(err.exception.decode_path, decode_path)
1767 self.assertEqual(err.exception.offset, offset)
1770 integers(min_value=0),
1773 def test_ber_definite_no_data(self, offset, decode_path):
1774 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1776 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1778 decode_path=decode_path,
1779 ctx={"bered": True},
1781 self.assertEqual(err.exception.decode_path, decode_path)
1782 self.assertEqual(err.exception.offset, offset)
1785 integers(min_value=0),
1787 integers(min_value=1, max_value=3),
1789 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1790 bs = BitString(b"data").encode()
1791 with self.assertRaises(NotEnoughData) as err:
1793 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1795 decode_path=decode_path,
1796 ctx={"bered": True},
1798 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1799 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1802 integers(min_value=0),
1804 integers(min_value=1, max_value=3),
1806 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1807 bs = BitString(b"data").encode()
1808 bs_longer = BitString(b"data-longer").encode()
1809 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1812 tag_encode(3, form=TagFormConstructed) +
1813 len_encode((chunks + 1) * len(bs)) +
1818 decode_path=decode_path,
1819 ctx={"bered": True},
1821 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1822 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1825 integers(min_value=0),
1828 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1829 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1831 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1833 decode_path=decode_path,
1834 ctx={"bered": True},
1836 self.assertEqual(err.exception.decode_path, decode_path)
1837 self.assertEqual(err.exception.offset, offset)
1839 @given(data_strategy())
1840 def test_ber_indefinite_not_multiple(self, d):
1841 bs_short = BitString("'A'H").encode()
1842 bs_full = BitString("'AA'H").encode()
1843 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1844 chunks.append(bs_short)
1845 d.draw(permutations(chunks))
1846 chunks.append(bs_short)
1847 offset = d.draw(integers(min_value=0))
1848 decode_path = d.draw(decode_path_strat)
1849 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1852 tag_encode(3, form=TagFormConstructed) +
1858 decode_path=decode_path,
1859 ctx={"bered": True},
1862 err.exception.decode_path,
1863 decode_path + (str(chunks.index(bs_short)),),
1866 err.exception.offset,
1867 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1870 def test_x690_vector(self):
1871 vector = BitString("'0A3B5F291CD'H")
1872 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1873 self.assertSequenceEqual(tail, b"")
1874 self.assertEqual(obj, vector)
1875 obj, tail = BitString().decode(
1876 hexdec("23800303000A3B0305045F291CD00000"),
1877 ctx={"bered": True},
1879 self.assertSequenceEqual(tail, b"")
1880 self.assertEqual(obj, vector)
1881 self.assertTrue(obj.ber_encoded)
1882 self.assertTrue(obj.lenindef)
1883 self.assertTrue(obj.bered)
1885 self.assertTrue(obj.ber_encoded)
1886 self.assertTrue(obj.lenindef)
1887 self.assertTrue(obj.bered)
1889 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1890 @given(integers(min_value=1000, max_value=3000))
1891 def test_cer(self, data_len):
1892 data = urandom(data_len)
1893 encoded = encode_cer(BitString(data))
1894 ctx = {"bered": True}
1895 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1896 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1897 evgens_expected = data_len // 999
1898 if evgens_expected * 999 != data_len:
1899 evgens_expected += 1
1900 evgens_expected += 1
1901 self.assertEqual(len(evgens), evgens_expected)
1902 for (_, obj, _) in evgens[:-2]:
1903 self.assertEqual(obj.vlen, 1000)
1904 _, obj, _ = evgens[-2]
1905 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1909 def octet_string_values_strategy(draw, do_expl=False):
1910 bound_min, bound_max = sorted(draw(sets(
1911 integers(min_value=0, max_value=1 << 7),
1915 value = draw(one_of(
1917 binary(min_size=bound_min, max_size=bound_max),
1919 default = draw(one_of(
1921 binary(min_size=bound_min, max_size=bound_max),
1924 if draw(booleans()):
1925 bounds = (bound_min, bound_max)
1929 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1931 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1932 optional = draw(one_of(none(), booleans()))
1934 draw(integers(min_value=0)),
1935 draw(integers(min_value=0)),
1936 draw(integers(min_value=0)),
1938 return (value, bounds, impl, expl, default, optional, _decoded)
1941 class OctetStringInherited(OctetString):
1945 class TestOctetString(CommonMixin, TestCase):
1946 base_klass = OctetString
1948 def test_invalid_value_type(self):
1949 with self.assertRaises(InvalidValueType) as err:
1950 OctetString(text_type(123))
1954 def test_optional(self, optional):
1955 obj = OctetString(default=OctetString(b""), optional=optional)
1956 self.assertTrue(obj.optional)
1959 def test_ready(self, value):
1961 self.assertFalse(obj.ready)
1964 pprint(obj, big_blobs=True, with_decode_path=True)
1965 with self.assertRaises(ObjNotReady) as err:
1968 obj = OctetString(value)
1969 self.assertTrue(obj.ready)
1972 pprint(obj, big_blobs=True, with_decode_path=True)
1974 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1975 def test_comparison(self, value1, value2, tag1, tag2):
1976 for klass in (OctetString, OctetStringInherited):
1977 obj1 = klass(value1)
1978 obj2 = klass(value2)
1979 self.assertEqual(obj1 == obj2, value1 == value2)
1980 self.assertEqual(obj1 != obj2, value1 != value2)
1981 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1982 obj1 = klass(value1, impl=tag1)
1983 obj2 = klass(value1, impl=tag2)
1984 self.assertEqual(obj1 == obj2, tag1 == tag2)
1985 self.assertEqual(obj1 != obj2, tag1 != tag2)
1987 @given(lists(binary()))
1988 def test_sorted_works(self, values):
1989 self.assertSequenceEqual(
1990 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1994 @given(data_strategy())
1995 def test_bounds_satisfied(self, d):
1996 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1997 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1998 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1999 OctetString(value=value, bounds=(bound_min, bound_max))
2001 @given(data_strategy())
2002 def test_bounds_unsatisfied(self, d):
2003 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2004 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2005 value = d.draw(binary(max_size=bound_min - 1))
2006 with self.assertRaises(BoundsError) as err:
2007 OctetString(value=value, bounds=(bound_min, bound_max))
2009 with assertRaisesRegex(self, DecodeError, "bounds") as err:
2010 OctetString(bounds=(bound_min, bound_max)).decode(
2011 OctetString(value).encode()
2014 value = d.draw(binary(min_size=bound_max + 1))
2015 with self.assertRaises(BoundsError) as err:
2016 OctetString(value=value, bounds=(bound_min, bound_max))
2018 with assertRaisesRegex(self, DecodeError, "bounds") as err:
2019 OctetString(bounds=(bound_min, bound_max)).decode(
2020 OctetString(value).encode()
2024 @given(data_strategy())
2025 def test_call(self, d):
2026 for klass in (OctetString, OctetStringInherited):
2035 ) = d.draw(octet_string_values_strategy())
2036 obj_initial = klass(
2042 optional_initial or False,
2053 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2054 if (default is None) and (obj_initial.default is not None):
2057 (bounds is None) and
2058 (value is not None) and
2059 (bounds_initial is not None) and
2060 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2064 (bounds is None) and
2065 (default is not None) and
2066 (bounds_initial is not None) and
2067 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2070 obj = obj_initial(value, bounds, impl, expl, default, optional)
2072 value_expected = default if value is None else value
2074 default_initial if value_expected is None
2077 self.assertEqual(obj, value_expected)
2078 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2079 self.assertEqual(obj.expl_tag, expl or expl_initial)
2082 default_initial if default is None else default,
2084 if obj.default is None:
2085 optional = optional_initial if optional is None else optional
2086 optional = False if optional is None else optional
2089 self.assertEqual(obj.optional, optional)
2091 (obj._bound_min, obj._bound_max),
2092 bounds or bounds_initial or (0, float("+inf")),
2095 @given(octet_string_values_strategy())
2096 def test_copy(self, values):
2097 for klass in (OctetString, OctetStringInherited):
2098 obj = klass(*values)
2099 for copy_func in copy_funcs:
2100 obj_copied = copy_func(obj)
2101 self.assert_copied_basic_fields(obj, obj_copied)
2102 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2103 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2104 self.assertEqual(obj._value, obj_copied._value)
2108 integers(min_value=1).map(tag_encode),
2110 def test_stripped(self, value, tag_impl):
2111 obj = OctetString(value, impl=tag_impl)
2112 with self.assertRaises(NotEnoughData):
2113 obj.decode(obj.encode()[:-1])
2117 integers(min_value=1).map(tag_ctxc),
2119 def test_stripped_expl(self, value, tag_expl):
2120 obj = OctetString(value, expl=tag_expl)
2121 with self.assertRaises(NotEnoughData):
2122 obj.decode(obj.encode()[:-1])
2125 integers(min_value=31),
2126 integers(min_value=0),
2129 def test_bad_tag(self, tag, offset, decode_path):
2130 with self.assertRaises(DecodeError) as err:
2131 OctetString().decode(
2132 tag_encode(tag)[:-1],
2134 decode_path=decode_path,
2137 self.assertEqual(err.exception.offset, offset)
2138 self.assertEqual(err.exception.decode_path, decode_path)
2141 integers(min_value=128),
2142 integers(min_value=0),
2145 def test_bad_len(self, l, offset, decode_path):
2146 with self.assertRaises(DecodeError) as err:
2147 OctetString().decode(
2148 OctetString.tag_default + len_encode(l)[:-1],
2150 decode_path=decode_path,
2153 self.assertEqual(err.exception.offset, offset)
2154 self.assertEqual(err.exception.decode_path, decode_path)
2157 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2158 integers(min_value=0),
2161 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2162 value, bound_min = list(sorted(ints))
2164 class String(OctetString):
2165 bounds = (bound_min, bound_min)
2166 with self.assertRaises(DecodeError) as err:
2168 OctetString(b"\x00" * value).encode(),
2170 decode_path=decode_path,
2173 self.assertEqual(err.exception.offset, offset)
2174 self.assertEqual(err.exception.decode_path, decode_path)
2176 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2178 octet_string_values_strategy(),
2180 integers(min_value=1).map(tag_ctxc),
2181 integers(min_value=0),
2185 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2186 for klass in (OctetString, OctetStringInherited):
2187 _, _, _, _, default, optional, _decoded = values
2196 pprint(obj, big_blobs=True, with_decode_path=True)
2197 self.assertFalse(obj.expled)
2198 obj_encoded = obj.encode()
2199 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2200 obj_expled = obj(value, expl=tag_expl)
2201 self.assertTrue(obj_expled.expled)
2203 list(obj_expled.pps())
2204 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2205 obj_expled_encoded = obj_expled.encode()
2206 obj_expled_cer = encode_cer(obj_expled)
2207 self.assertNotEqual(obj_expled_cer, obj_encoded)
2208 self.assertSequenceEqual(
2209 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2212 ctx_copied = deepcopy(ctx_dummy)
2213 obj_decoded, tail = obj_expled.decode(
2214 obj_expled_encoded + tail_junk,
2218 self.assertDictEqual(ctx_copied, ctx_dummy)
2220 list(obj_decoded.pps())
2221 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2222 self.assertEqual(tail, tail_junk)
2223 self.assertEqual(obj_decoded, obj_expled)
2224 self.assertNotEqual(obj_decoded, obj)
2225 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2226 self.assertEqual(bytes(obj_decoded), bytes(obj))
2227 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2228 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2229 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2231 obj_decoded.expl_llen,
2232 len(len_encode(len(obj_encoded))),
2234 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2235 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2238 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2240 self.assertEqual(obj_decoded.expl_offset, offset)
2241 assert_exceeding_data(
2243 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2247 evgens = list(obj_expled.decode_evgen(
2248 obj_expled_encoded + tail_junk,
2250 decode_path=decode_path,
2253 self.assertEqual(len(evgens), 1)
2254 _decode_path, obj, tail = evgens[0]
2255 self.assertSequenceEqual(tail, tail_junk)
2256 self.assertEqual(_decode_path, decode_path)
2257 self.assertEqual(obj.expl_offset, offset)
2261 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2263 integers(min_value=1, max_value=30),
2266 binary(min_size=1, max_size=5),
2268 binary(min_size=1, max_size=5),
2279 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2280 def chunk_constructed(contents):
2282 tag_encode(form=TagFormConstructed, num=4) +
2284 b"".join(OctetString(content).encode() for content in contents) +
2288 chunks_len_expected = []
2289 payload_expected = b""
2290 for chunk_input in chunk_inputs:
2291 if isinstance(chunk_input, binary_type):
2292 chunks.append(OctetString(chunk_input).encode())
2293 payload_expected += chunk_input
2294 chunks_len_expected.append(len(chunk_input))
2296 chunks.append(chunk_constructed(chunk_input))
2297 payload = b"".join(chunk_input)
2298 payload_expected += payload
2299 for c in chunk_input:
2300 chunks_len_expected.append(len(c))
2301 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2302 encoded_indefinite = (
2303 tag_encode(form=TagFormConstructed, num=impl) +
2308 encoded_definite = (
2309 tag_encode(form=TagFormConstructed, num=impl) +
2310 len_encode(len(b"".join(chunks))) +
2313 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2314 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2315 for lenindef_expected, encoded in (
2316 (True, encoded_indefinite),
2317 (False, encoded_definite),
2319 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2321 ctx={"bered": True},
2323 self.assertSequenceEqual(tail, junk)
2324 self.assertSequenceEqual(bytes(obj), payload_expected)
2325 self.assertTrue(obj.ber_encoded)
2326 self.assertEqual(obj.lenindef, lenindef_expected)
2327 self.assertTrue(obj.bered)
2329 self.assertTrue(obj.ber_encoded)
2330 self.assertEqual(obj.lenindef, lenindef_expected)
2331 self.assertTrue(obj.bered)
2332 self.assertEqual(len(encoded), obj.tlvlen)
2335 pprint(obj, big_blobs=True, with_decode_path=True)
2337 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2339 decode_path=decode_path,
2340 ctx={"bered": True},
2342 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2343 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2344 self.assertGreater(len(dp), len(decode_path))
2345 self.assertEqual(obj.vlen, chunk_len_expected)
2348 integers(min_value=0),
2351 def test_ber_definite_too_short(self, offset, decode_path):
2352 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2353 OctetString().decode(
2354 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2356 decode_path=decode_path,
2357 ctx={"bered": True},
2359 self.assertEqual(err.exception.decode_path, decode_path)
2360 self.assertEqual(err.exception.offset, offset)
2363 integers(min_value=0),
2365 integers(min_value=1, max_value=3),
2367 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2368 bs = OctetString(b"data").encode()
2369 with self.assertRaises(NotEnoughData) as err:
2370 OctetString().decode(
2371 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2373 decode_path=decode_path,
2374 ctx={"bered": True},
2376 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2377 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2380 integers(min_value=0),
2382 integers(min_value=1, max_value=3),
2384 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2385 bs = OctetString(b"data").encode()
2386 bs_longer = OctetString(b"data-longer").encode()
2387 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2388 OctetString().decode(
2390 tag_encode(4, form=TagFormConstructed) +
2391 len_encode((chunks + 1) * len(bs)) +
2396 decode_path=decode_path,
2397 ctx={"bered": True},
2399 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2400 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2402 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2403 @given(integers(min_value=1001, max_value=3000))
2404 def test_cer(self, data_len):
2405 data = urandom(data_len)
2406 encoded = encode_cer(OctetString(data))
2407 ctx = {"bered": True}
2408 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2409 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2410 evgens_expected = data_len // 1000
2411 if evgens_expected * 1000 != data_len:
2412 evgens_expected += 1
2413 evgens_expected += 1
2414 self.assertEqual(len(evgens), evgens_expected)
2415 for (_, obj, _) in evgens[:-2]:
2416 self.assertEqual(obj.vlen, 1000)
2417 _, obj, _ = evgens[-2]
2418 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2422 def null_values_strategy(draw, do_expl=False):
2426 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2428 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2429 optional = draw(one_of(none(), booleans()))
2431 draw(integers(min_value=0)),
2432 draw(integers(min_value=0)),
2433 draw(integers(min_value=0)),
2435 return (impl, expl, optional, _decoded)
2438 class NullInherited(Null):
2442 class TestNull(CommonMixin, TestCase):
2445 def test_ready(self):
2447 self.assertTrue(obj.ready)
2450 pprint(obj, big_blobs=True, with_decode_path=True)
2452 @given(binary(min_size=1), binary(min_size=1))
2453 def test_comparison(self, tag1, tag2):
2454 for klass in (Null, NullInherited):
2455 obj1 = klass(impl=tag1)
2456 obj2 = klass(impl=tag2)
2457 self.assertEqual(obj1 == obj2, tag1 == tag2)
2458 self.assertEqual(obj1 != obj2, tag1 != tag2)
2459 self.assertNotEqual(obj1, tag2)
2461 @given(data_strategy())
2462 def test_call(self, d):
2463 for klass in (Null, NullInherited):
2469 ) = d.draw(null_values_strategy())
2470 obj_initial = klass(
2473 optional=optional_initial or False,
2474 _decoded=_decoded_initial,
2481 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2482 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2483 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2484 self.assertEqual(obj.expl_tag, expl or expl_initial)
2485 optional = optional_initial if optional is None else optional
2486 optional = False if optional is None else optional
2487 self.assertEqual(obj.optional, optional)
2489 @given(null_values_strategy())
2490 def test_copy(self, values):
2491 for klass in (Null, NullInherited):
2492 impl, expl, optional, _decoded = values
2496 optional=optional or False,
2499 for copy_func in copy_funcs:
2500 obj_copied = copy_func(obj)
2501 self.assert_copied_basic_fields(obj, obj_copied)
2503 @given(integers(min_value=1).map(tag_encode))
2504 def test_stripped(self, tag_impl):
2505 obj = Null(impl=tag_impl)
2506 with self.assertRaises(NotEnoughData):
2507 obj.decode(obj.encode()[:-1])
2509 @given(integers(min_value=1).map(tag_ctxc))
2510 def test_stripped_expl(self, tag_expl):
2511 obj = Null(expl=tag_expl)
2512 with self.assertRaises(NotEnoughData):
2513 obj.decode(obj.encode()[:-1])
2516 integers(min_value=31),
2517 integers(min_value=0),
2520 def test_bad_tag(self, tag, offset, decode_path):
2521 with self.assertRaises(DecodeError) as err:
2523 tag_encode(tag)[:-1],
2525 decode_path=decode_path,
2528 self.assertEqual(err.exception.offset, offset)
2529 self.assertEqual(err.exception.decode_path, decode_path)
2532 integers(min_value=128),
2533 integers(min_value=0),
2536 def test_bad_len(self, l, offset, decode_path):
2537 with self.assertRaises(DecodeError) as err:
2539 Null.tag_default + len_encode(l)[:-1],
2541 decode_path=decode_path,
2544 self.assertEqual(err.exception.offset, offset)
2545 self.assertEqual(err.exception.decode_path, decode_path)
2547 @given(binary(min_size=1))
2548 def test_tag_mismatch(self, impl):
2549 assume(impl != Null.tag_default)
2550 with self.assertRaises(TagMismatch):
2551 Null(impl=impl).decode(Null().encode())
2554 null_values_strategy(),
2555 integers(min_value=1).map(tag_ctxc),
2556 integers(min_value=0),
2560 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2561 for klass in (Null, NullInherited):
2562 _, _, optional, _decoded = values
2563 obj = klass(optional=optional, _decoded=_decoded)
2566 pprint(obj, big_blobs=True, with_decode_path=True)
2567 self.assertFalse(obj.expled)
2568 obj_encoded = obj.encode()
2569 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2570 obj_expled = obj(expl=tag_expl)
2571 self.assertTrue(obj_expled.expled)
2573 list(obj_expled.pps())
2574 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2575 obj_expled_encoded = obj_expled.encode()
2576 obj_expled_cer = encode_cer(obj_expled)
2577 self.assertNotEqual(obj_expled_cer, obj_encoded)
2578 self.assertSequenceEqual(
2579 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2582 ctx_copied = deepcopy(ctx_dummy)
2583 obj_decoded, tail = obj_expled.decode(
2584 obj_expled_encoded + tail_junk,
2588 self.assertDictEqual(ctx_copied, ctx_dummy)
2590 list(obj_decoded.pps())
2591 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2592 self.assertEqual(tail, tail_junk)
2593 self.assertEqual(obj_decoded, obj_expled)
2594 self.assertNotEqual(obj_decoded, obj)
2595 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2596 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2597 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2599 obj_decoded.expl_llen,
2600 len(len_encode(len(obj_encoded))),
2602 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2603 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2606 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2608 self.assertEqual(obj_decoded.expl_offset, offset)
2609 assert_exceeding_data(
2611 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2615 evgens = list(obj_expled.decode_evgen(
2616 obj_expled_encoded + tail_junk,
2618 decode_path=decode_path,
2621 self.assertEqual(len(evgens), 1)
2622 _decode_path, obj, tail = evgens[0]
2623 self.assertSequenceEqual(tail, tail_junk)
2624 self.assertEqual(_decode_path, decode_path)
2625 self.assertEqual(obj, obj_decoded)
2626 self.assertEqual(obj.expl_offset, offset)
2631 @given(integers(min_value=1))
2632 def test_invalid_len(self, l):
2633 with self.assertRaises(InvalidLength):
2634 Null().decode(b"".join((
2641 def oid_strategy(draw):
2642 first_arc = draw(integers(min_value=0, max_value=2))
2644 if first_arc in (0, 1):
2645 second_arc = draw(integers(min_value=0, max_value=39))
2647 second_arc = draw(integers(min_value=0))
2648 other_arcs = draw(lists(integers(min_value=0)))
2649 return tuple([first_arc, second_arc] + other_arcs)
2653 def oid_values_strategy(draw, do_expl=False):
2654 value = draw(one_of(none(), oid_strategy()))
2658 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2660 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2661 default = draw(one_of(none(), oid_strategy()))
2662 optional = draw(one_of(none(), booleans()))
2664 draw(integers(min_value=0)),
2665 draw(integers(min_value=0)),
2666 draw(integers(min_value=0)),
2668 return (value, impl, expl, default, optional, _decoded)
2671 class ObjectIdentifierInherited(ObjectIdentifier):
2675 class TestObjectIdentifier(CommonMixin, TestCase):
2676 base_klass = ObjectIdentifier
2678 def test_invalid_value_type(self):
2679 with self.assertRaises(InvalidValueType) as err:
2680 ObjectIdentifier(123)
2684 def test_optional(self, optional):
2685 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2686 self.assertTrue(obj.optional)
2688 @given(oid_strategy())
2689 def test_ready(self, value):
2690 obj = ObjectIdentifier()
2691 self.assertFalse(obj.ready)
2694 pprint(obj, big_blobs=True, with_decode_path=True)
2695 with self.assertRaises(ObjNotReady) as err:
2698 obj = ObjectIdentifier(value)
2699 self.assertTrue(obj.ready)
2700 self.assertFalse(obj.ber_encoded)
2703 pprint(obj, big_blobs=True, with_decode_path=True)
2706 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2707 def test_comparison(self, value1, value2, tag1, tag2):
2708 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2709 obj1 = klass(value1)
2710 obj2 = klass(value2)
2711 self.assertEqual(obj1 == obj2, value1 == value2)
2712 self.assertEqual(obj1 != obj2, value1 != value2)
2713 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2714 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2715 obj1 = klass(value1, impl=tag1)
2716 obj2 = klass(value1, impl=tag2)
2717 self.assertEqual(obj1 == obj2, tag1 == tag2)
2718 self.assertEqual(obj1 != obj2, tag1 != tag2)
2720 @given(lists(oid_strategy()))
2721 def test_sorted_works(self, values):
2722 self.assertSequenceEqual(
2723 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2727 @given(data_strategy())
2728 def test_call(self, d):
2729 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2737 ) = d.draw(oid_values_strategy())
2738 obj_initial = klass(
2739 value=value_initial,
2742 default=default_initial,
2743 optional=optional_initial or False,
2744 _decoded=_decoded_initial,
2753 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2762 value_expected = default if value is None else value
2764 default_initial if value_expected is None
2767 self.assertEqual(obj, value_expected)
2768 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2769 self.assertEqual(obj.expl_tag, expl or expl_initial)
2772 default_initial if default is None else default,
2774 if obj.default is None:
2775 optional = optional_initial if optional is None else optional
2776 optional = False if optional is None else optional
2779 self.assertEqual(obj.optional, optional)
2781 @given(oid_values_strategy())
2782 def test_copy(self, values):
2783 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2800 for copy_func in copy_funcs:
2801 obj_copied = copy_func(obj)
2802 self.assert_copied_basic_fields(obj, obj_copied)
2803 self.assertEqual(obj._value, obj_copied._value)
2805 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2808 integers(min_value=1).map(tag_encode),
2810 def test_stripped(self, value, tag_impl):
2811 obj = ObjectIdentifier(value, impl=tag_impl)
2812 with self.assertRaises(NotEnoughData):
2813 obj.decode(obj.encode()[:-1])
2817 integers(min_value=1).map(tag_ctxc),
2819 def test_stripped_expl(self, value, tag_expl):
2820 obj = ObjectIdentifier(value, expl=tag_expl)
2821 with self.assertRaises(NotEnoughData):
2822 obj.decode(obj.encode()[:-1])
2825 integers(min_value=31),
2826 integers(min_value=0),
2829 def test_bad_tag(self, tag, offset, decode_path):
2830 with self.assertRaises(DecodeError) as err:
2831 ObjectIdentifier().decode(
2832 tag_encode(tag)[:-1],
2834 decode_path=decode_path,
2837 self.assertEqual(err.exception.offset, offset)
2838 self.assertEqual(err.exception.decode_path, decode_path)
2841 integers(min_value=128),
2842 integers(min_value=0),
2845 def test_bad_len(self, l, offset, decode_path):
2846 with self.assertRaises(DecodeError) as err:
2847 ObjectIdentifier().decode(
2848 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2850 decode_path=decode_path,
2853 self.assertEqual(err.exception.offset, offset)
2854 self.assertEqual(err.exception.decode_path, decode_path)
2856 def test_zero_oid(self):
2857 with self.assertRaises(NotEnoughData):
2858 ObjectIdentifier().decode(
2859 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2862 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2863 @given(oid_strategy())
2864 def test_unfinished_oid(self, value):
2865 assume(list(value)[-1] > 255)
2866 obj_encoded = ObjectIdentifier(value).encode()
2867 obj, _ = ObjectIdentifier().decode(obj_encoded)
2868 data = obj_encoded[obj.tlen + obj.llen:-1]
2870 ObjectIdentifier.tag_default,
2871 len_encode(len(data)),
2874 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2877 @given(integers(min_value=0))
2878 def test_invalid_short(self, value):
2879 with self.assertRaises(InvalidOID):
2880 ObjectIdentifier((value,))
2881 with self.assertRaises(InvalidOID):
2882 ObjectIdentifier("%d" % value)
2884 @given(integers(min_value=3), integers(min_value=0))
2885 def test_invalid_first_arc(self, first_arc, second_arc):
2886 with self.assertRaises(InvalidOID):
2887 ObjectIdentifier((first_arc, second_arc))
2888 with self.assertRaises(InvalidOID):
2889 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2891 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2892 def test_invalid_second_arc(self, first_arc, second_arc):
2893 with self.assertRaises(InvalidOID):
2894 ObjectIdentifier((first_arc, second_arc))
2895 with self.assertRaises(InvalidOID):
2896 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2898 @given(text(alphabet=ascii_letters + ".", min_size=1))
2899 def test_junk(self, oid):
2900 with self.assertRaises(InvalidOID):
2901 ObjectIdentifier(oid)
2903 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2904 @given(oid_strategy())
2905 def test_validness(self, oid):
2906 obj = ObjectIdentifier(oid)
2907 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2910 pprint(obj, big_blobs=True, with_decode_path=True)
2912 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2914 oid_values_strategy(),
2916 integers(min_value=1).map(tag_ctxc),
2917 integers(min_value=0),
2921 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2922 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2923 _, _, _, default, optional, _decoded = values
2932 pprint(obj, big_blobs=True, with_decode_path=True)
2933 self.assertFalse(obj.expled)
2934 obj_encoded = obj.encode()
2935 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2936 obj_expled = obj(value, expl=tag_expl)
2937 self.assertTrue(obj_expled.expled)
2939 list(obj_expled.pps())
2940 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2941 obj_expled_encoded = obj_expled.encode()
2942 obj_expled_cer = encode_cer(obj_expled)
2943 self.assertNotEqual(obj_expled_cer, obj_encoded)
2944 self.assertSequenceEqual(
2945 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2948 ctx_copied = deepcopy(ctx_dummy)
2949 obj_decoded, tail = obj_expled.decode(
2950 obj_expled_encoded + tail_junk,
2954 self.assertDictEqual(ctx_copied, ctx_dummy)
2956 list(obj_decoded.pps())
2957 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2958 self.assertEqual(tail, tail_junk)
2959 self.assertEqual(obj_decoded, obj_expled)
2960 self.assertNotEqual(obj_decoded, obj)
2961 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2962 self.assertEqual(tuple(obj_decoded), tuple(obj))
2963 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2964 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2965 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2967 obj_decoded.expl_llen,
2968 len(len_encode(len(obj_encoded))),
2970 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2971 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2974 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2976 self.assertEqual(obj_decoded.expl_offset, offset)
2977 assert_exceeding_data(
2979 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2983 evgens = list(obj_expled.decode_evgen(
2984 obj_expled_encoded + tail_junk,
2986 decode_path=decode_path,
2989 self.assertEqual(len(evgens), 1)
2990 _decode_path, obj, tail = evgens[0]
2991 self.assertSequenceEqual(tail, tail_junk)
2992 self.assertEqual(_decode_path, decode_path)
2993 self.assertEqual(obj, obj_decoded)
2994 self.assertEqual(obj.expl_offset, offset)
2999 oid_strategy().map(ObjectIdentifier),
3000 oid_strategy().map(ObjectIdentifier),
3002 def test_add(self, oid1, oid2):
3003 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3004 for oid_to_add in (oid2, tuple(oid2)):
3005 self.assertEqual(oid1 + oid_to_add, oid_expect)
3006 with self.assertRaises(InvalidValueType):
3009 def test_go_vectors_valid(self):
3010 for data, expect in (
3012 (b"\x55\x02", (2, 5, 2)),
3013 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3014 (b"\x81\x34\x03", (2, 100, 3)),
3017 ObjectIdentifier().decode(b"".join((
3018 ObjectIdentifier.tag_default,
3019 len_encode(len(data)),
3025 def test_go_vectors_invalid(self):
3026 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3027 with self.assertRaises(DecodeError):
3028 ObjectIdentifier().decode(b"".join((
3029 Integer.tag_default,
3030 len_encode(len(data)),
3034 def test_x690_vector(self):
3036 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3037 ObjectIdentifier((2, 999, 3)),
3040 def test_nonnormalized_first_arc(self):
3042 ObjectIdentifier.tag_default +
3045 ObjectIdentifier((1, 0)).encode()[-1:]
3047 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3048 self.assertTrue(obj.ber_encoded)
3049 self.assertTrue(obj.bered)
3051 self.assertTrue(obj.ber_encoded)
3052 self.assertTrue(obj.bered)
3053 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
3054 ObjectIdentifier().decode(tampered)
3056 @given(data_strategy())
3057 def test_negative_arcs(self, d):
3058 oid = list(d.draw(oid_strategy()))
3061 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3063 if oid[idx - 1] == 0:
3065 with self.assertRaises(InvalidOID):
3066 ObjectIdentifier(tuple(oid))
3067 with self.assertRaises(InvalidOID):
3068 ObjectIdentifier(".".join(str(i) for i in oid))
3070 @given(data_strategy())
3071 def test_plused_arcs(self, d):
3072 oid = [str(arc) for arc in d.draw(oid_strategy())]
3073 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3074 oid[idx - 1] = "+" + oid[idx - 1]
3075 with self.assertRaises(InvalidOID):
3076 ObjectIdentifier(".".join(str(i) for i in oid))
3078 @given(data_strategy())
3079 def test_nonnormalized_arcs(self, d):
3080 arcs = d.draw(lists(
3081 integers(min_value=0, max_value=100),
3085 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3086 _, _, lv = tag_strip(dered)
3087 _, _, v = len_decode(lv)
3088 v_no_first_arc = v[1:]
3089 idx_for_tamper = d.draw(integers(
3091 max_value=len(v_no_first_arc) - 1,
3093 tampered = list(bytearray(v_no_first_arc))
3094 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3095 tampered.insert(idx_for_tamper, 0x80)
3096 tampered = bytes(bytearray(tampered))
3098 ObjectIdentifier.tag_default +
3099 len_encode(len(tampered)) +
3102 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3103 self.assertTrue(obj.ber_encoded)
3104 self.assertTrue(obj.bered)
3106 self.assertTrue(obj.ber_encoded)
3107 self.assertTrue(obj.bered)
3108 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
3109 ObjectIdentifier().decode(tampered)
3113 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3115 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3116 values = list(draw(sets(
3118 min_size=len(schema),
3119 max_size=len(schema),
3121 schema = list(zip(schema, values))
3122 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3126 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3128 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3129 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3130 optional = draw(one_of(none(), booleans()))
3132 draw(integers(min_value=0)),
3133 draw(integers(min_value=0)),
3134 draw(integers(min_value=0)),
3136 return (schema, value, impl, expl, default, optional, _decoded)
3139 class TestEnumerated(CommonMixin, TestCase):
3140 class EWhatever(Enumerated):
3141 schema = (("whatever", 0),)
3143 base_klass = EWhatever
3145 def test_schema_required(self):
3146 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3149 def test_invalid_value_type(self):
3150 with self.assertRaises(InvalidValueType) as err:
3151 self.base_klass((1, 2))
3154 @given(sets(text_letters(), min_size=2))
3155 def test_unknown_name(self, schema_input):
3156 missing = schema_input.pop()
3158 class E(Enumerated):
3159 schema = [(n, 123) for n in schema_input]
3160 with self.assertRaises(ObjUnknown) as err:
3165 sets(text_letters(), min_size=2),
3166 sets(integers(), min_size=2),
3168 def test_unknown_value(self, schema_input, values_input):
3170 missing_value = values_input.pop()
3171 _input = list(zip(schema_input, values_input))
3173 class E(Enumerated):
3175 with self.assertRaises(DecodeError) as err:
3180 def test_optional(self, optional):
3181 obj = self.base_klass(default="whatever", optional=optional)
3182 self.assertTrue(obj.optional)
3184 def test_ready(self):
3185 obj = self.base_klass()
3186 self.assertFalse(obj.ready)
3189 pprint(obj, big_blobs=True, with_decode_path=True)
3190 with self.assertRaises(ObjNotReady) as err:
3193 obj = self.base_klass("whatever")
3194 self.assertTrue(obj.ready)
3197 pprint(obj, big_blobs=True, with_decode_path=True)
3199 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3200 def test_comparison(self, value1, value2, tag1, tag2):
3201 class E(Enumerated):
3203 ("whatever0", value1),
3204 ("whatever1", value2),
3207 class EInherited(E):
3209 for klass in (E, EInherited):
3210 obj1 = klass(value1)
3211 obj2 = klass(value2)
3212 self.assertEqual(obj1 == obj2, value1 == value2)
3213 self.assertEqual(obj1 != obj2, value1 != value2)
3214 self.assertEqual(obj1 == int(obj2), value1 == value2)
3215 obj1 = klass(value1, impl=tag1)
3216 obj2 = klass(value1, impl=tag2)
3217 self.assertEqual(obj1 == obj2, tag1 == tag2)
3218 self.assertEqual(obj1 != obj2, tag1 != tag2)
3220 @given(data_strategy())
3221 def test_call(self, d):
3230 ) = d.draw(enumerated_values_strategy())
3232 class E(Enumerated):
3233 schema = schema_initial
3235 value=value_initial,
3238 default=default_initial,
3239 optional=optional_initial or False,
3240 _decoded=_decoded_initial,
3250 ) = d.draw(enumerated_values_strategy(
3251 schema=schema_initial,
3252 do_expl=impl_initial is None,
3262 value_expected = default if value is None else value
3264 default_initial if value_expected is None
3269 dict(schema_initial).get(value_expected, value_expected),
3271 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3272 self.assertEqual(obj.expl_tag, expl or expl_initial)
3275 default_initial if default is None else default,
3277 if obj.default is None:
3278 optional = optional_initial if optional is None else optional
3279 optional = False if optional is None else optional
3282 self.assertEqual(obj.optional, optional)
3283 self.assertEqual(obj.specs, dict(schema_initial))
3285 @given(enumerated_values_strategy())
3286 def test_copy(self, values):
3287 schema_input, value, impl, expl, default, optional, _decoded = values
3289 class E(Enumerated):
3290 schema = schema_input
3300 for copy_func in copy_funcs:
3301 obj_copied = copy_func(obj)
3302 self.assert_copied_basic_fields(obj, obj_copied)
3303 self.assertEqual(obj.specs, obj_copied.specs)
3305 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3306 @given(data_strategy())
3307 def test_symmetric(self, d):
3308 schema_input, _, _, _, default, optional, _decoded = d.draw(
3309 enumerated_values_strategy(),
3311 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3312 offset = d.draw(integers(min_value=0))
3313 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3314 tail_junk = d.draw(binary(max_size=5))
3315 decode_path = d.draw(decode_path_strat)
3317 class E(Enumerated):
3318 schema = schema_input
3327 pprint(obj, big_blobs=True, with_decode_path=True)
3328 self.assertFalse(obj.expled)
3329 obj_encoded = obj.encode()
3330 obj_expled = obj(value, expl=tag_expl)
3331 self.assertTrue(obj_expled.expled)
3333 list(obj_expled.pps())
3334 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3335 obj_expled_encoded = obj_expled.encode()
3336 ctx_copied = deepcopy(ctx_dummy)
3337 obj_decoded, tail = obj_expled.decode(
3338 obj_expled_encoded + tail_junk,
3342 self.assertDictEqual(ctx_copied, ctx_dummy)
3344 list(obj_decoded.pps())
3345 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3346 self.assertEqual(tail, tail_junk)
3347 self.assertEqual(obj_decoded, obj_expled)
3348 self.assertNotEqual(obj_decoded, obj)
3349 self.assertEqual(int(obj_decoded), int(obj_expled))
3350 self.assertEqual(int(obj_decoded), int(obj))
3351 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3352 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3353 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3355 obj_decoded.expl_llen,
3356 len(len_encode(len(obj_encoded))),
3358 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3359 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3362 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3364 self.assertEqual(obj_decoded.expl_offset, offset)
3365 assert_exceeding_data(
3367 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3371 evgens = list(obj_expled.decode_evgen(
3372 obj_expled_encoded + tail_junk,
3374 decode_path=decode_path,
3377 self.assertEqual(len(evgens), 1)
3378 _decode_path, obj, tail = evgens[0]
3379 self.assertSequenceEqual(tail, tail_junk)
3380 self.assertEqual(_decode_path, decode_path)
3381 self.assertEqual(obj, obj_decoded)
3382 self.assertEqual(obj.expl_offset, offset)
3388 def string_values_strategy(draw, alphabet, do_expl=False):
3389 bound_min, bound_max = sorted(draw(sets(
3390 integers(min_value=0, max_value=1 << 7),
3394 value = draw(one_of(
3396 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3398 default = draw(one_of(
3400 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3403 if draw(booleans()):
3404 bounds = (bound_min, bound_max)
3408 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3410 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3411 optional = draw(one_of(none(), booleans()))
3413 draw(integers(min_value=0)),
3414 draw(integers(min_value=0)),
3415 draw(integers(min_value=0)),
3417 return (value, bounds, impl, expl, default, optional, _decoded)
3420 class StringMixin(object):
3421 def test_invalid_value_type(self):
3422 with self.assertRaises(InvalidValueType) as err:
3423 self.base_klass((1, 2))
3426 def text_alphabet(self):
3427 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3428 return printable + whitespace
3432 def test_optional(self, optional):
3433 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3434 self.assertTrue(obj.optional)
3436 @given(data_strategy())
3437 def test_ready(self, d):
3438 obj = self.base_klass()
3439 self.assertFalse(obj.ready)
3442 pprint(obj, big_blobs=True, with_decode_path=True)
3444 with self.assertRaises(ObjNotReady) as err:
3447 value = d.draw(text(alphabet=self.text_alphabet()))
3448 obj = self.base_klass(value)
3449 self.assertTrue(obj.ready)
3452 pprint(obj, big_blobs=True, with_decode_path=True)
3455 @given(data_strategy())
3456 def test_comparison(self, d):
3457 value1 = d.draw(text(alphabet=self.text_alphabet()))
3458 value2 = d.draw(text(alphabet=self.text_alphabet()))
3459 tag1 = d.draw(binary(min_size=1))
3460 tag2 = d.draw(binary(min_size=1))
3461 obj1 = self.base_klass(value1)
3462 obj2 = self.base_klass(value2)
3463 self.assertEqual(obj1 == obj2, value1 == value2)
3464 self.assertEqual(obj1 != obj2, value1 != value2)
3465 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3466 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3467 obj1 = self.base_klass(value1, impl=tag1)
3468 obj2 = self.base_klass(value1, impl=tag2)
3469 self.assertEqual(obj1 == obj2, tag1 == tag2)
3470 self.assertEqual(obj1 != obj2, tag1 != tag2)
3472 @given(data_strategy())
3473 def test_bounds_satisfied(self, d):
3474 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3475 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3476 value = d.draw(text(
3477 alphabet=self.text_alphabet(),
3481 self.base_klass(value=value, bounds=(bound_min, bound_max))
3483 @given(data_strategy())
3484 def test_bounds_unsatisfied(self, d):
3485 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3486 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3487 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3488 with self.assertRaises(BoundsError) as err:
3489 self.base_klass(value=value, bounds=(bound_min, bound_max))
3491 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3492 self.base_klass(bounds=(bound_min, bound_max)).decode(
3493 self.base_klass(value).encode()
3496 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3497 with self.assertRaises(BoundsError) as err:
3498 self.base_klass(value=value, bounds=(bound_min, bound_max))
3500 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3501 self.base_klass(bounds=(bound_min, bound_max)).decode(
3502 self.base_klass(value).encode()
3506 @given(data_strategy())
3507 def test_call(self, d):
3516 ) = d.draw(string_values_strategy(self.text_alphabet()))
3517 obj_initial = self.base_klass(
3523 optional_initial or False,
3534 ) = d.draw(string_values_strategy(
3535 self.text_alphabet(),
3536 do_expl=impl_initial is None,
3538 if (default is None) and (obj_initial.default is not None):
3541 (bounds is None) and
3542 (value is not None) and
3543 (bounds_initial is not None) and
3544 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3548 (bounds is None) and
3549 (default is not None) and
3550 (bounds_initial is not None) and
3551 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3554 obj = obj_initial(value, bounds, impl, expl, default, optional)
3556 value_expected = default if value is None else value
3558 default_initial if value_expected is None
3561 self.assertEqual(obj, value_expected)
3562 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3563 self.assertEqual(obj.expl_tag, expl or expl_initial)
3566 default_initial if default is None else default,
3568 if obj.default is None:
3569 optional = optional_initial if optional is None else optional
3570 optional = False if optional is None else optional
3573 self.assertEqual(obj.optional, optional)
3575 (obj._bound_min, obj._bound_max),
3576 bounds or bounds_initial or (0, float("+inf")),
3579 @given(data_strategy())
3580 def test_copy(self, d):
3581 values = d.draw(string_values_strategy(self.text_alphabet()))
3582 obj = self.base_klass(*values)
3583 for copy_func in copy_funcs:
3584 obj_copied = copy_func(obj)
3585 self.assert_copied_basic_fields(obj, obj_copied)
3586 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3587 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3588 self.assertEqual(obj._value, obj_copied._value)
3590 @given(data_strategy())
3591 def test_stripped(self, d):
3592 value = d.draw(text(alphabet=self.text_alphabet()))
3593 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3594 obj = self.base_klass(value, impl=tag_impl)
3595 with self.assertRaises(NotEnoughData):
3596 obj.decode(obj.encode()[:-1])
3598 @given(data_strategy())
3599 def test_stripped_expl(self, d):
3600 value = d.draw(text(alphabet=self.text_alphabet()))
3601 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3602 obj = self.base_klass(value, expl=tag_expl)
3603 with self.assertRaises(NotEnoughData):
3604 obj.decode(obj.encode()[:-1])
3607 integers(min_value=31),
3608 integers(min_value=0),
3611 def test_bad_tag(self, tag, offset, decode_path):
3612 with self.assertRaises(DecodeError) as err:
3613 self.base_klass().decode(
3614 tag_encode(tag)[:-1],
3616 decode_path=decode_path,
3619 self.assertEqual(err.exception.offset, offset)
3620 self.assertEqual(err.exception.decode_path, decode_path)
3623 integers(min_value=128),
3624 integers(min_value=0),
3627 def test_bad_len(self, l, offset, decode_path):
3628 with self.assertRaises(DecodeError) as err:
3629 self.base_klass().decode(
3630 self.base_klass.tag_default + len_encode(l)[:-1],
3632 decode_path=decode_path,
3635 self.assertEqual(err.exception.offset, offset)
3636 self.assertEqual(err.exception.decode_path, decode_path)
3639 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3640 integers(min_value=0),
3643 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3644 value, bound_min = list(sorted(ints))
3646 class String(self.base_klass):
3647 # Multiply this value by four, to satisfy UTF-32 bounds
3648 # (4 bytes per character) validation
3649 bounds = (bound_min * 4, bound_min * 4)
3650 with self.assertRaises(DecodeError) as err:
3652 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3654 decode_path=decode_path,
3657 self.assertEqual(err.exception.offset, offset)
3658 self.assertEqual(err.exception.decode_path, decode_path)
3660 @given(data_strategy())
3661 def test_symmetric(self, d):
3662 values = d.draw(string_values_strategy(self.text_alphabet()))
3663 value = d.draw(text(alphabet=self.text_alphabet()))
3664 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3665 offset = d.draw(integers(min_value=0))
3666 tail_junk = d.draw(binary(max_size=5))
3667 decode_path = d.draw(decode_path_strat)
3668 _, _, _, _, default, optional, _decoded = values
3669 obj = self.base_klass(
3677 pprint(obj, big_blobs=True, with_decode_path=True)
3678 self.assertFalse(obj.expled)
3679 obj_encoded = obj.encode()
3680 obj_expled = obj(value, expl=tag_expl)
3681 self.assertTrue(obj_expled.expled)
3683 list(obj_expled.pps())
3684 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3685 obj_expled_encoded = obj_expled.encode()
3686 ctx_copied = deepcopy(ctx_dummy)
3687 obj_decoded, tail = obj_expled.decode(
3688 obj_expled_encoded + tail_junk,
3692 self.assertDictEqual(ctx_copied, ctx_dummy)
3694 list(obj_decoded.pps())
3695 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3696 self.assertEqual(tail, tail_junk)
3697 self.assertEqual(obj_decoded, obj_expled)
3698 self.assertNotEqual(obj_decoded, obj)
3699 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3700 self.assertEqual(bytes(obj_decoded), bytes(obj))
3701 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3702 self.assertEqual(text_type(obj_decoded), text_type(obj))
3703 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3704 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3705 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3707 obj_decoded.expl_llen,
3708 len(len_encode(len(obj_encoded))),
3710 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3711 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3714 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3716 self.assertEqual(obj_decoded.expl_offset, offset)
3717 assert_exceeding_data(
3719 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3723 evgens = list(obj_expled.decode_evgen(
3724 obj_expled_encoded + tail_junk,
3726 decode_path=decode_path,
3729 self.assertEqual(len(evgens), 1)
3730 _decode_path, obj, tail = evgens[0]
3731 self.assertSequenceEqual(tail, tail_junk)
3732 self.assertEqual(_decode_path, decode_path)
3733 if not getattr(self, "evgen_mode_skip_value", True):
3734 self.assertEqual(obj, obj_decoded)
3735 self.assertEqual(obj.expl_offset, offset)
3740 cyrillic_letters = text(
3741 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3747 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3748 base_klass = UTF8String
3750 @given(cyrillic_letters)
3751 def test_byte_per_primitive(self, chars):
3753 char_raw = char.encode("utf-8")
3754 encoded = b"".join((
3755 self.base_klass().tag_constructed,
3757 OctetString(char_raw[:1]).encode(),
3758 OctetString(char_raw[1:2]).encode(),
3762 self.base_klass().decod(encoded, ctx={"bered": True}),
3767 class UnicodeDecodeErrorMixin(object):
3768 @given(cyrillic_letters)
3769 def test_unicode_decode_error(self, cyrillic_text):
3770 with self.assertRaises(DecodeError):
3771 self.base_klass(cyrillic_text)
3774 class TestNumericString(StringMixin, CommonMixin, TestCase):
3775 base_klass = NumericString
3777 def text_alphabet(self):
3780 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3781 def test_non_numeric(self, non_numeric_text):
3782 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3783 self.base_klass(non_numeric_text)
3786 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3787 integers(min_value=0),
3790 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3791 value, bound_min = list(sorted(ints))
3793 class String(self.base_klass):
3794 bounds = (bound_min, bound_min)
3795 with self.assertRaises(DecodeError) as err:
3797 self.base_klass(b"1" * value).encode(),
3799 decode_path=decode_path,
3802 self.assertEqual(err.exception.offset, offset)
3803 self.assertEqual(err.exception.decode_path, decode_path)
3805 def test_byte_per_primitive(self):
3806 encoded = b"".join((
3807 self.base_klass().tag_constructed,
3809 OctetString(b"1").encode(),
3810 OctetString(b"2").encode(),
3814 self.base_klass().decod(encoded, ctx={"bered": True}),
3819 class TestPrintableString(
3820 UnicodeDecodeErrorMixin,
3825 base_klass = PrintableString
3827 def text_alphabet(self):
3828 return ascii_letters + digits + " '()+,-./:=?"
3830 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3831 def test_non_printable(self, non_printable_text):
3832 with assertRaisesRegex(self, DecodeError, "non-printable"):
3833 self.base_klass(non_printable_text)
3836 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3837 integers(min_value=0),
3840 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3841 value, bound_min = list(sorted(ints))
3843 class String(self.base_klass):
3844 bounds = (bound_min, bound_min)
3845 with self.assertRaises(DecodeError) as err:
3847 self.base_klass(b"1" * value).encode(),
3849 decode_path=decode_path,
3852 self.assertEqual(err.exception.offset, offset)
3853 self.assertEqual(err.exception.decode_path, decode_path)
3855 def test_allowable_invalid_chars(self):
3857 ("*", {"allow_asterisk": True}),
3858 ("&", {"allow_ampersand": True}),
3859 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3862 obj = self.base_klass(s)
3863 for prop in kwargs.keys():
3864 self.assertFalse(getattr(obj, prop))
3866 with assertRaisesRegex(self, DecodeError, "non-printable"):
3868 self.base_klass(s, **kwargs)
3869 klass = self.base_klass(**kwargs)
3871 for prop in kwargs.keys():
3872 self.assertTrue(getattr(obj, prop))
3875 for prop in kwargs.keys():
3876 self.assertTrue(getattr(obj, prop))
3879 class TestTeletexString(
3880 UnicodeDecodeErrorMixin,
3885 base_klass = TeletexString
3888 class TestVideotexString(
3889 UnicodeDecodeErrorMixin,
3894 base_klass = VideotexString
3897 class TestIA5String(
3898 UnicodeDecodeErrorMixin,
3903 base_klass = IA5String
3906 class TestGraphicString(
3907 UnicodeDecodeErrorMixin,
3912 base_klass = GraphicString
3915 class TestVisibleString(
3916 UnicodeDecodeErrorMixin,
3921 base_klass = VisibleString
3923 def test_x690_vector(self):
3924 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3925 self.assertSequenceEqual(tail, b"")
3926 self.assertEqual(str(obj), "Jones")
3927 self.assertFalse(obj.ber_encoded)
3928 self.assertFalse(obj.lenindef)
3929 self.assertFalse(obj.bered)
3931 obj, tail = VisibleString().decode(
3932 hexdec("3A0904034A6F6E04026573"),
3933 ctx={"bered": True},
3935 self.assertSequenceEqual(tail, b"")
3936 self.assertEqual(str(obj), "Jones")
3937 self.assertTrue(obj.ber_encoded)
3938 self.assertFalse(obj.lenindef)
3939 self.assertTrue(obj.bered)
3941 self.assertTrue(obj.ber_encoded)
3942 self.assertFalse(obj.lenindef)
3943 self.assertTrue(obj.bered)
3945 obj, tail = VisibleString().decode(
3946 hexdec("3A8004034A6F6E040265730000"),
3947 ctx={"bered": True},
3949 self.assertSequenceEqual(tail, b"")
3950 self.assertEqual(str(obj), "Jones")
3951 self.assertTrue(obj.ber_encoded)
3952 self.assertTrue(obj.lenindef)
3953 self.assertTrue(obj.bered)
3955 self.assertTrue(obj.ber_encoded)
3956 self.assertTrue(obj.lenindef)
3957 self.assertTrue(obj.bered)
3960 class TestGeneralString(
3961 UnicodeDecodeErrorMixin,
3966 base_klass = GeneralString
3969 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3970 base_klass = UniversalString
3973 class TestBMPString(StringMixin, CommonMixin, TestCase):
3974 base_klass = BMPString
3978 def generalized_time_values_strategy(
3986 if draw(booleans()):
3987 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3989 value = value.replace(microsecond=0)
3991 if draw(booleans()):
3992 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3994 default = default.replace(microsecond=0)
3998 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4000 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4001 optional = draw(one_of(none(), booleans()))
4003 draw(integers(min_value=0)),
4004 draw(integers(min_value=0)),
4005 draw(integers(min_value=0)),
4007 return (value, impl, expl, default, optional, _decoded)
4010 class TimeMixin(object):
4011 def test_invalid_value_type(self):
4012 with self.assertRaises(InvalidValueType) as err:
4013 self.base_klass(datetime.now().timetuple())
4016 @given(data_strategy())
4017 def test_optional(self, d):
4018 default = d.draw(datetimes(
4019 min_value=self.min_datetime,
4020 max_value=self.max_datetime,
4022 optional = d.draw(booleans())
4023 obj = self.base_klass(default=default, optional=optional)
4024 self.assertTrue(obj.optional)
4026 @given(data_strategy())
4027 def test_ready(self, d):
4028 obj = self.base_klass()
4029 self.assertFalse(obj.ready)
4032 pprint(obj, big_blobs=True, with_decode_path=True)
4033 with self.assertRaises(ObjNotReady) as err:
4036 value = d.draw(datetimes(
4037 min_value=self.min_datetime,
4038 max_value=self.max_datetime,
4040 obj = self.base_klass(value)
4041 self.assertTrue(obj.ready)
4044 pprint(obj, big_blobs=True, with_decode_path=True)
4046 @given(data_strategy())
4047 def test_comparison(self, d):
4048 value1 = d.draw(datetimes(
4049 min_value=self.min_datetime,
4050 max_value=self.max_datetime,
4052 value2 = d.draw(datetimes(
4053 min_value=self.min_datetime,
4054 max_value=self.max_datetime,
4056 tag1 = d.draw(binary(min_size=1))
4057 tag2 = d.draw(binary(min_size=1))
4059 value1 = value1.replace(microsecond=0)
4060 value2 = value2.replace(microsecond=0)
4061 obj1 = self.base_klass(value1)
4062 obj2 = self.base_klass(value2)
4063 self.assertEqual(obj1 == obj2, value1 == value2)
4064 self.assertEqual(obj1 != obj2, value1 != value2)
4065 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4066 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4067 obj1 = self.base_klass(value1, impl=tag1)
4068 obj2 = self.base_klass(value1, impl=tag2)
4069 self.assertEqual(obj1 == obj2, tag1 == tag2)
4070 self.assertEqual(obj1 != obj2, tag1 != tag2)
4072 @given(data_strategy())
4073 def test_call(self, d):
4081 ) = d.draw(generalized_time_values_strategy(
4082 min_datetime=self.min_datetime,
4083 max_datetime=self.max_datetime,
4084 omit_ms=self.omit_ms,
4086 obj_initial = self.base_klass(
4087 value=value_initial,
4090 default=default_initial,
4091 optional=optional_initial or False,
4092 _decoded=_decoded_initial,
4101 ) = d.draw(generalized_time_values_strategy(
4102 min_datetime=self.min_datetime,
4103 max_datetime=self.max_datetime,
4104 omit_ms=self.omit_ms,
4105 do_expl=impl_initial is None,
4115 value_expected = default if value is None else value
4117 default_initial if value_expected is None
4120 self.assertEqual(obj, value_expected)
4121 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4122 self.assertEqual(obj.expl_tag, expl or expl_initial)
4125 default_initial if default is None else default,
4127 if obj.default is None:
4128 optional = optional_initial if optional is None else optional
4129 optional = False if optional is None else optional
4132 self.assertEqual(obj.optional, optional)
4134 @given(data_strategy())
4135 def test_copy(self, d):
4136 values = d.draw(generalized_time_values_strategy(
4137 min_datetime=self.min_datetime,
4138 max_datetime=self.max_datetime,
4140 obj = self.base_klass(*values)
4141 for copy_func in copy_funcs:
4142 obj_copied = copy_func(obj)
4143 self.assert_copied_basic_fields(obj, obj_copied)
4144 self.assertEqual(obj._value, obj_copied._value)
4146 @given(data_strategy())
4147 def test_stripped(self, d):
4148 value = d.draw(datetimes(
4149 min_value=self.min_datetime,
4150 max_value=self.max_datetime,
4152 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4153 obj = self.base_klass(value, impl=tag_impl)
4154 with self.assertRaises(NotEnoughData):
4155 obj.decode(obj.encode()[:-1])
4157 @given(data_strategy())
4158 def test_stripped_expl(self, d):
4159 value = d.draw(datetimes(
4160 min_value=self.min_datetime,
4161 max_value=self.max_datetime,
4163 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4164 obj = self.base_klass(value, expl=tag_expl)
4165 with self.assertRaises(NotEnoughData):
4166 obj.decode(obj.encode()[:-1])
4168 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4169 @given(data_strategy())
4170 def test_symmetric(self, d):
4171 values = d.draw(generalized_time_values_strategy(
4172 min_datetime=self.min_datetime,
4173 max_datetime=self.max_datetime,
4175 value = d.draw(datetimes(
4176 min_value=self.min_datetime,
4177 max_value=self.max_datetime,
4179 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4180 offset = d.draw(integers(min_value=0))
4181 tail_junk = d.draw(binary(max_size=5))
4182 _, _, _, default, optional, _decoded = values
4183 obj = self.base_klass(
4191 pprint(obj, big_blobs=True, with_decode_path=True)
4192 self.assertFalse(obj.expled)
4193 obj_encoded = obj.encode()
4194 self.additional_symmetric_check(value, obj_encoded)
4195 obj_expled = obj(value, expl=tag_expl)
4196 self.assertTrue(obj_expled.expled)
4198 list(obj_expled.pps())
4199 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4200 obj_expled_encoded = obj_expled.encode()
4201 ctx_copied = deepcopy(ctx_dummy)
4202 obj_decoded, tail = obj_expled.decode(
4203 obj_expled_encoded + tail_junk,
4207 self.assertDictEqual(ctx_copied, ctx_dummy)
4209 list(obj_decoded.pps())
4210 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4211 self.assertEqual(tail, tail_junk)
4212 self.assertEqual(obj_decoded, obj_expled)
4213 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4214 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4215 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4216 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4217 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4219 obj_decoded.expl_llen,
4220 len(len_encode(len(obj_encoded))),
4222 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4223 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4226 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4228 self.assertEqual(obj_decoded.expl_offset, offset)
4229 assert_exceeding_data(
4231 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4236 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4237 base_klass = GeneralizedTime
4239 min_datetime = datetime(1900, 1, 1)
4240 max_datetime = datetime(9999, 12, 31)
4241 evgen_mode_skip_value = False
4243 def additional_symmetric_check(self, value, obj_encoded):
4244 if value.microsecond > 0:
4245 self.assertFalse(obj_encoded.endswith(b"0Z"))
4247 def test_repr_not_ready(self):
4248 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4249 repr(GeneralizedTime())
4251 def test_x690_vector_valid(self):
4255 b"19920722132100.3Z",
4257 GeneralizedTime(data)
4259 def test_x690_vector_invalid(self):
4262 b"19920622123421.0Z",
4263 b"19920722132100.30Z",
4265 with self.assertRaises(DecodeError) as err:
4266 GeneralizedTime(data)
4269 def test_go_vectors_invalid(self):
4281 b"-20100102030410Z",
4282 b"2010-0102030410Z",
4283 b"2010-0002030410Z",
4284 b"201001-02030410Z",
4285 b"20100102-030410Z",
4286 b"2010010203-0410Z",
4287 b"201001020304-10Z",
4288 # These ones are INVALID in *DER*, but accepted
4289 # by Go's encoding/asn1
4290 b"20100102030405+0607",
4291 b"20100102030405-0607",
4293 with self.assertRaises(DecodeError) as err:
4294 GeneralizedTime(data)
4297 def test_go_vectors_valid(self):
4299 GeneralizedTime(b"20100102030405Z").todatetime(),
4300 datetime(2010, 1, 2, 3, 4, 5, 0),
4303 def test_go_vectors_valid_ber(self):
4305 b"20100102030405+0607",
4306 b"20100102030405-0607",
4308 GeneralizedTime(data, ctx={"bered": True})
4310 def test_utc_offsets(self):
4311 """Some know equal UTC offsets
4314 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4318 "200101011130-0700",
4319 "200101011500-03:30",
4322 self.assertEqual(dts[0], dts[1])
4323 self.assertEqual(dts[0], dts[2])
4324 self.assertEqual(dts[0], dts[3])
4326 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4327 @given(data_strategy())
4328 def test_valid_ber(self, d):
4329 min_year = 1901 if PY2 else 2
4330 year = d.draw(integers(min_value=min_year, max_value=9999))
4331 month = d.draw(integers(min_value=1, max_value=12))
4332 day = d.draw(integers(min_value=1, max_value=28))
4333 hours = d.draw(integers(min_value=0, max_value=23))
4334 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4335 dt = datetime(year, month, day, hours)
4336 fractions_sign = d.draw(sampled_from(" ,."))
4338 if fractions_sign != " ":
4339 fractions = random()
4340 if d.draw(booleans()):
4341 minutes = d.draw(integers(min_value=0, max_value=59))
4342 data += "%02d" % minutes
4343 dt += timedelta(seconds=60 * minutes)
4344 if d.draw(booleans()):
4345 seconds = d.draw(integers(min_value=0, max_value=59))
4346 data += "%02d" % seconds
4347 dt += timedelta(seconds=seconds)
4348 if fractions is not None:
4349 dt += timedelta(microseconds=10**6 * fractions)
4350 elif fractions is not None:
4351 dt += timedelta(seconds=60 * fractions)
4352 elif fractions is not None:
4353 dt += timedelta(seconds=3600 * fractions)
4354 if fractions is not None:
4355 data += fractions_sign + str(fractions)[2:]
4356 if d.draw(booleans()):
4358 elif d.draw(booleans()):
4359 offset_hour = d.draw(integers(min_value=0, max_value=13))
4361 if d.draw(booleans()):
4366 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4367 data += "%02d" % offset_hour
4368 minutes_separator = d.draw(sampled_from((None, "", ":")))
4369 if minutes_separator is not None:
4370 offset_minute = d.draw(integers(min_value=0, max_value=59))
4371 dt -= timedelta(seconds=sign * 60 * offset_minute)
4372 data += "%s%02d" % (minutes_separator, offset_minute)
4373 data = data.encode("ascii")
4374 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4376 GeneralizedTime().decod(data_der)
4381 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4384 mktime(obj.todatetime().timetuple()),
4385 mktime(dt.timetuple()),
4388 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4389 self.assertEqual(obj.ber_encoded, not dered)
4390 self.assertEqual(obj.bered, not dered)
4391 self.assertEqual(obj.ber_raw, None if dered else data)
4392 self.assertEqual(obj.encode() == data_der, dered)
4397 def test_invalid_ber(self):
4399 # "00010203040506.07",
4400 "-0010203040506.07",
4401 "0001-203040506.07",
4402 "000102-3040506.07",
4403 "00010203-40506.07",
4404 "0001020304-506.07",
4405 "000102030405-6.07",
4406 "00010203040506.-7",
4407 "+0010203040506.07",
4408 "0001+203040506.07",
4409 "000102+3040506.07",
4410 "00010203+40506.07",
4411 "0001020304+506.07",
4412 "000102030405+6.07",
4413 "00010203040506.+7",
4414 " 0010203040506.07",
4415 "0001 203040506.07",
4416 "000102 3040506.07",
4417 "00010203 40506.07",
4418 "0001020304 506.07",
4419 "000102030405 6.07",
4420 "00010203040506. 7",
4421 "001 0203040506.07",
4422 "00012 03040506.07",
4423 "0001023 040506.07",
4424 "000102034 0506.07",
4425 "00010203045 06.07",
4426 "0001020304056 .07",
4427 "00010203040506.7 ",
4507 "00010203040506.07+15",
4508 "00010203040506.07-15",
4509 "00010203040506.07+14:60",
4510 "00010203040506.07+1460",
4511 "00010203040506.07-1460",
4512 "00010203040506.07+00:60",
4513 "00010203040506.07-00:60",
4515 "00010203040506+15",
4516 "00010203040506-15",
4517 "00010203040506+14:60",
4518 "00010203040506+1460",
4519 "00010203040506-1460",
4520 "00010203040506+00:60",
4521 "00010203040506-00:60",
4530 with self.assertRaises(DecodeError):
4531 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4532 data = data.replace(".", ",")
4533 with self.assertRaises(DecodeError):
4534 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4538 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4539 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4541 binary(min_size=1, max_size=1),
4543 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4544 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4547 def test_junk(self, part0, part1, part2):
4548 junk = part0 + part1 + part2
4549 assume(not (set(junk) <= set(digits.encode("ascii"))))
4550 with self.assertRaises(DecodeError):
4551 GeneralizedTime().decode(
4552 GeneralizedTime.tag_default +
4553 len_encode(len(junk)) +
4559 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4560 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4562 binary(min_size=1, max_size=1),
4564 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4565 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4568 def test_junk_dm(self, part0, part1, part2):
4569 junk = part0 + part1 + part2
4570 assume(not (set(junk) <= set(digits.encode("ascii"))))
4571 with self.assertRaises(DecodeError):
4572 GeneralizedTime().decode(
4573 GeneralizedTime.tag_default +
4574 len_encode(len(junk)) +
4578 def test_ns_fractions(self):
4579 GeneralizedTime(b"20010101000000.000001Z")
4580 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4581 GeneralizedTime(b"20010101000000.0000001Z")
4583 def test_non_pure_integers(self):
4585 # b"20000102030405Z,
4592 b"20000102030405.+6Z",
4593 b"20000102030405.-6Z",
4600 b"20000102030405._6Z",
4601 b"20000102030405.6_Z",
4608 b"20000102030405. 6Z",
4615 b"20000102030405.6 Z",
4617 with self.assertRaises(DecodeError):
4618 GeneralizedTime(data)
4621 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4622 base_klass = UTCTime
4624 min_datetime = datetime(2000, 1, 1)
4625 max_datetime = datetime(2049, 12, 31)
4626 evgen_mode_skip_value = False
4628 def additional_symmetric_check(self, value, obj_encoded):
4631 def test_repr_not_ready(self):
4632 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4635 def test_x690_vector_valid(self):
4643 def test_x690_vector_invalid(self):
4648 with self.assertRaises(DecodeError) as err:
4652 def test_go_vectors_invalid(self):
4678 # These ones are INVALID in *DER*, but accepted
4679 # by Go's encoding/asn1
4680 b"910506164540-0700",
4681 b"910506164540+0730",
4685 with self.assertRaises(DecodeError) as err:
4689 def test_go_vectors_valid(self):
4691 UTCTime(b"910506234540Z").todatetime(),
4692 datetime(1991, 5, 6, 23, 45, 40, 0),
4695 def test_non_pure_integers(self):
4724 with self.assertRaises(DecodeError):
4727 def test_x680_vector_valid_ber(self):
4729 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4730 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4731 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4732 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4734 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4735 obj = UTCTime().decod(data_der, ctx={"bered": True})
4736 self.assertEqual(obj, dt)
4737 self.assertEqual(obj.todatetime(), dt)
4738 self.assertTrue(obj.ber_encoded)
4739 self.assertTrue(obj.bered)
4740 self.assertEqual(obj.ber_raw, data)
4741 self.assertNotEqual(obj.encode(), data_der)
4744 def test_go_vectors_valid_ber(self):
4746 b"910506164540-0700",
4747 b"910506164540+0730",
4751 data = UTCTime.tag_default + len_encode(len(data)) + data
4752 obj = UTCTime().decod(data, ctx={"bered": True})
4753 self.assertTrue(obj.ber_encoded)
4754 self.assertTrue(obj.bered)
4755 self.assertNotEqual(obj.encode(), data)
4758 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4759 @given(data_strategy())
4760 def test_valid_ber(self, d):
4761 year = d.draw(integers(min_value=0, max_value=99))
4762 month = d.draw(integers(min_value=1, max_value=12))
4763 day = d.draw(integers(min_value=1, max_value=28))
4764 hours = d.draw(integers(min_value=0, max_value=23))
4765 minute = d.draw(integers(min_value=0, max_value=59))
4766 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4768 year + (2000 if year < 50 else 1900),
4775 if d.draw(booleans()):
4777 seconds = d.draw(integers(min_value=0, max_value=59))
4778 data += "%02d" % seconds
4779 dt += timedelta(seconds=seconds)
4780 if d.draw(booleans()):
4784 offset_hour = d.draw(integers(min_value=0, max_value=13))
4785 offset_minute = d.draw(integers(min_value=0, max_value=59))
4786 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4787 if d.draw(booleans()):
4793 data += "%02d%02d" % (offset_hour, offset_minute)
4794 data = data.encode("ascii")
4795 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4796 obj = UTCTime().decod(data_der, ctx={"bered": True})
4797 self.assertEqual(obj, dt)
4798 self.assertEqual(obj.todatetime(), dt)
4799 self.assertEqual(obj.ber_encoded, not dered)
4800 self.assertEqual(obj.bered, not dered)
4801 self.assertEqual(obj.ber_raw, None if dered else data)
4802 self.assertEqual(obj.encode() == data_der, dered)
4807 def test_invalid_ber(self):
4848 b"0001020304+0000Z",
4857 with self.assertRaises(DecodeError):
4858 UTCTime(data, ctx={"bered": True})
4859 data = data[:8] + data[8+2:]
4860 with self.assertRaises(DecodeError):
4861 UTCTime(data, ctx={"bered": True})
4906 b"000102030405+000",
4907 b"000102030405+000Z",
4908 b"000102030405+0000Z",
4909 b"000102030405+-101",
4910 b"000102030405+01-1",
4911 b"000102030405+0060",
4912 b"000102030405+1401",
4913 b"500101000002+0003",
4915 with self.assertRaises(DecodeError):
4916 UTCTime(data, ctx={"bered": True})
4918 @given(integers(min_value=0, max_value=49))
4919 def test_pre50(self, year):
4921 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4925 @given(integers(min_value=50, max_value=99))
4926 def test_post50(self, year):
4928 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4934 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4935 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4937 binary(min_size=1, max_size=1),
4939 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4940 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4943 def test_junk(self, part0, part1, part2):
4944 junk = part0 + part1 + part2
4945 assume(not (set(junk) <= set(digits.encode("ascii"))))
4946 with self.assertRaises(DecodeError):
4948 UTCTime.tag_default +
4949 len_encode(len(junk)) +
4955 def tlv_value_strategy(draw):
4956 tag_num = draw(integers(min_value=1))
4957 data = draw(binary())
4958 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
4962 def any_values_strategy(draw, do_expl=False):
4963 value = draw(one_of(none(), tlv_value_strategy()))
4966 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4967 optional = draw(one_of(none(), booleans()))
4969 draw(integers(min_value=0)),
4970 draw(integers(min_value=0)),
4971 draw(integers(min_value=0)),
4973 return (value, expl, optional, _decoded)
4976 class AnyInherited(Any):
4980 class TestAny(CommonMixin, TestCase):
4983 def test_invalid_value_type(self):
4984 with self.assertRaises(InvalidValueType) as err:
4989 def test_optional(self, optional):
4990 obj = Any(optional=optional)
4991 self.assertEqual(obj.optional, optional)
4993 @given(tlv_value_strategy())
4994 def test_ready(self, value):
4996 self.assertFalse(obj.ready)
4999 pprint(obj, big_blobs=True, with_decode_path=True)
5000 with self.assertRaises(ObjNotReady) as err:
5004 self.assertTrue(obj.ready)
5007 pprint(obj, big_blobs=True, with_decode_path=True)
5010 def test_basic(self, value):
5011 integer_encoded = Integer(value).encode()
5013 Any(integer_encoded),
5014 Any(Integer(value)),
5015 Any(Any(Integer(value))),
5017 self.assertSequenceEqual(bytes(obj), integer_encoded)
5019 obj.decode(obj.encode())[0].vlen,
5020 len(integer_encoded),
5024 pprint(obj, big_blobs=True, with_decode_path=True)
5025 self.assertSequenceEqual(obj.encode(), integer_encoded)
5027 @given(tlv_value_strategy(), tlv_value_strategy())
5028 def test_comparison(self, value1, value2):
5029 for klass in (Any, AnyInherited):
5030 obj1 = klass(value1)
5031 obj2 = klass(value2)
5032 self.assertEqual(obj1 == obj2, value1 == value2)
5033 self.assertEqual(obj1 != obj2, value1 != value2)
5034 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5036 @given(data_strategy())
5037 def test_call(self, d):
5038 for klass in (Any, AnyInherited):
5044 ) = d.draw(any_values_strategy())
5045 obj_initial = klass(
5048 optional_initial or False,
5056 ) = d.draw(any_values_strategy(do_expl=True))
5057 obj = obj_initial(value, expl, optional)
5059 value_expected = None if value is None else value
5060 self.assertEqual(obj, value_expected)
5061 self.assertEqual(obj.expl_tag, expl or expl_initial)
5062 if obj.default is None:
5063 optional = optional_initial if optional is None else optional
5064 optional = False if optional is None else optional
5065 self.assertEqual(obj.optional, optional)
5067 def test_simultaneous_impl_expl(self):
5068 # override it, as Any does not have implicit tag
5071 def test_decoded(self):
5072 # override it, as Any does not have implicit tag
5075 @given(any_values_strategy())
5076 def test_copy(self, values):
5077 for klass in (Any, AnyInherited):
5078 obj = klass(*values)
5079 for copy_func in copy_funcs:
5080 obj_copied = copy_func(obj)
5081 self.assert_copied_basic_fields(obj, obj_copied)
5082 self.assertEqual(obj._value, obj_copied._value)
5084 @given(binary().map(OctetString))
5085 def test_stripped(self, value):
5087 with self.assertRaises(NotEnoughData):
5088 obj.decode(obj.encode()[:-1])
5091 tlv_value_strategy(),
5092 integers(min_value=1).map(tag_ctxc),
5094 def test_stripped_expl(self, value, tag_expl):
5095 obj = Any(value, expl=tag_expl)
5096 with self.assertRaises(NotEnoughData):
5097 obj.decode(obj.encode()[:-1])
5100 integers(min_value=31),
5101 integers(min_value=0),
5104 def test_bad_tag(self, tag, offset, decode_path):
5105 with self.assertRaises(DecodeError) as err:
5107 tag_encode(tag)[:-1],
5109 decode_path=decode_path,
5112 self.assertEqual(err.exception.offset, offset)
5113 self.assertEqual(err.exception.decode_path, decode_path)
5116 integers(min_value=128),
5117 integers(min_value=0),
5120 def test_bad_len(self, l, offset, decode_path):
5121 with self.assertRaises(DecodeError) as err:
5123 Any.tag_default + len_encode(l)[:-1],
5125 decode_path=decode_path,
5128 self.assertEqual(err.exception.offset, offset)
5129 self.assertEqual(err.exception.decode_path, decode_path)
5131 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5133 any_values_strategy(),
5134 integers().map(lambda x: Integer(x).encode()),
5135 integers(min_value=1).map(tag_ctxc),
5136 integers(min_value=0),
5140 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5141 for klass in (Any, AnyInherited):
5142 _, _, optional, _decoded = values
5143 obj = klass(value=value, optional=optional, _decoded=_decoded)
5146 pprint(obj, big_blobs=True, with_decode_path=True)
5147 self.assertFalse(obj.expled)
5148 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5149 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5150 obj_encoded = obj.encode()
5151 obj_expled = obj(value, expl=tag_expl)
5152 self.assertTrue(obj_expled.expled)
5153 tag_class, _, tag_num = tag_decode(tag_expl)
5154 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5156 list(obj_expled.pps())
5157 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5158 obj_expled_encoded = obj_expled.encode()
5159 ctx_copied = deepcopy(ctx_dummy)
5160 obj_decoded, tail = obj_expled.decode(
5161 obj_expled_encoded + tail_junk,
5165 self.assertDictEqual(ctx_copied, ctx_dummy)
5167 list(obj_decoded.pps())
5168 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5169 self.assertEqual(tail, tail_junk)
5170 self.assertEqual(obj_decoded, obj_expled)
5171 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5172 self.assertEqual(bytes(obj_decoded), bytes(obj))
5173 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5174 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5175 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5177 obj_decoded.expl_llen,
5178 len(len_encode(len(obj_encoded))),
5180 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5181 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5184 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5186 self.assertEqual(obj_decoded.expl_offset, offset)
5187 self.assertEqual(obj_decoded.tlen, 0)
5188 self.assertEqual(obj_decoded.llen, 0)
5189 self.assertEqual(obj_decoded.vlen, len(value))
5190 assert_exceeding_data(
5192 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5196 evgens = list(obj_expled.decode_evgen(
5197 obj_expled_encoded + tail_junk,
5199 decode_path=decode_path,
5202 self.assertEqual(len(evgens), 1)
5203 _decode_path, obj, tail = evgens[0]
5204 self.assertSequenceEqual(tail, tail_junk)
5205 self.assertEqual(_decode_path, decode_path)
5206 self.assertEqual(obj.expl_offset, offset)
5211 integers(min_value=1).map(tag_ctxc),
5212 integers(min_value=0, max_value=3),
5213 integers(min_value=0),
5217 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5218 chunk = Boolean(False, expl=expl).encode()
5220 OctetString.tag_default +
5222 b"".join([chunk] * chunks) +
5225 with self.assertRaises(LenIndefForm):
5229 decode_path=decode_path,
5231 obj, tail = Any().decode(
5234 decode_path=decode_path,
5235 ctx={"bered": True},
5237 self.assertSequenceEqual(tail, junk)
5238 self.assertEqual(obj.offset, offset)
5239 self.assertEqual(obj.tlvlen, len(encoded))
5240 self.assertTrue(obj.lenindef)
5241 self.assertFalse(obj.ber_encoded)
5242 self.assertTrue(obj.bered)
5244 self.assertTrue(obj.lenindef)
5245 self.assertFalse(obj.ber_encoded)
5246 self.assertTrue(obj.bered)
5249 pprint(obj, big_blobs=True, with_decode_path=True)
5250 with self.assertRaises(NotEnoughData) as err:
5254 decode_path=decode_path,
5255 ctx={"bered": True},
5257 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5258 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5260 class SeqOf(SequenceOf):
5261 schema = Boolean(expl=expl)
5263 class Seq(Sequence):
5265 ("type", ObjectIdentifier(defines=((("value",), {
5266 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5271 ("type", ObjectIdentifier("1.2.3")),
5272 ("value", Any(encoded)),
5274 seq_encoded = seq.encode()
5275 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5276 self.assertIsNotNone(seq_decoded["value"].defined)
5278 list(seq_decoded.pps())
5279 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5280 self.assertTrue(seq_decoded.bered)
5281 self.assertFalse(seq_decoded["type"].bered)
5282 self.assertTrue(seq_decoded["value"].bered)
5284 chunk = chunk[:-1] + b"\x01"
5285 chunks = b"".join([chunk] * (chunks + 1))
5286 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5288 ("type", ObjectIdentifier("1.2.3")),
5289 ("value", Any(encoded)),
5291 seq_encoded = seq.encode()
5292 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5293 self.assertIsNotNone(seq_decoded["value"].defined)
5295 list(seq_decoded.pps())
5296 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5297 self.assertTrue(seq_decoded.bered)
5298 self.assertFalse(seq_decoded["type"].bered)
5299 self.assertTrue(seq_decoded["value"].bered)
5303 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5305 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5306 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5308 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5309 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5311 min_size=len(names),
5312 max_size=len(names),
5315 (name, Integer(**tag_kwargs))
5316 for name, tag_kwargs in zip(names, tags)
5319 if value_required or draw(booleans()):
5320 value = draw(tuples(
5321 sampled_from([name for name, _ in schema]),
5322 integers().map(Integer),
5326 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5327 default = draw(one_of(
5329 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5331 optional = draw(one_of(none(), booleans()))
5333 draw(integers(min_value=0)),
5334 draw(integers(min_value=0)),
5335 draw(integers(min_value=0)),
5337 return (schema, value, expl, default, optional, _decoded)
5340 class ChoiceInherited(Choice):
5344 class TestChoice(CommonMixin, TestCase):
5346 schema = (("whatever", Boolean()),)
5349 def test_schema_required(self):
5350 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5353 def test_impl_forbidden(self):
5354 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
5355 Choice(impl=b"whatever")
5357 def test_invalid_value_type(self):
5358 with self.assertRaises(InvalidValueType) as err:
5359 self.base_klass(123)
5361 with self.assertRaises(ObjUnknown) as err:
5362 self.base_klass(("whenever", Boolean(False)))
5364 with self.assertRaises(InvalidValueType) as err:
5365 self.base_klass(("whatever", Integer(123)))
5369 def test_optional(self, optional):
5370 obj = self.base_klass(
5371 default=self.base_klass(("whatever", Boolean(False))),
5374 self.assertTrue(obj.optional)
5377 def test_ready(self, value):
5378 obj = self.base_klass()
5379 self.assertFalse(obj.ready)
5382 pprint(obj, big_blobs=True, with_decode_path=True)
5383 self.assertIsNone(obj["whatever"])
5384 with self.assertRaises(ObjNotReady) as err:
5387 obj["whatever"] = Boolean()
5388 self.assertFalse(obj.ready)
5391 pprint(obj, big_blobs=True, with_decode_path=True)
5392 obj["whatever"] = Boolean(value)
5393 self.assertTrue(obj.ready)
5396 pprint(obj, big_blobs=True, with_decode_path=True)
5398 @given(booleans(), booleans())
5399 def test_comparison(self, value1, value2):
5400 class WahlInherited(self.base_klass):
5402 for klass in (self.base_klass, WahlInherited):
5403 obj1 = klass(("whatever", Boolean(value1)))
5404 obj2 = klass(("whatever", Boolean(value2)))
5405 self.assertEqual(obj1 == obj2, value1 == value2)
5406 self.assertEqual(obj1 != obj2, value1 != value2)
5407 self.assertEqual(obj1 == obj2._value, value1 == value2)
5408 self.assertFalse(obj1 == obj2._value[1])
5410 @given(data_strategy())
5411 def test_call(self, d):
5412 for klass in (Choice, ChoiceInherited):
5420 ) = d.draw(choice_values_strategy())
5423 schema = schema_initial
5425 value=value_initial,
5427 default=default_initial,
5428 optional=optional_initial or False,
5429 _decoded=_decoded_initial,
5438 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5439 obj = obj_initial(value, expl, default, optional)
5441 value_expected = default if value is None else value
5443 default_initial if value_expected is None
5446 self.assertEqual(obj.choice, value_expected[0])
5447 self.assertEqual(obj.value, int(value_expected[1]))
5448 self.assertEqual(obj.expl_tag, expl or expl_initial)
5449 default_expect = default_initial if default is None else default
5450 if default_expect is not None:
5451 self.assertEqual(obj.default.choice, default_expect[0])
5452 self.assertEqual(obj.default.value, int(default_expect[1]))
5453 if obj.default is None:
5454 optional = optional_initial if optional is None else optional
5455 optional = False if optional is None else optional
5458 self.assertEqual(obj.optional, optional)
5459 self.assertEqual(obj.specs, obj_initial.specs)
5461 def test_simultaneous_impl_expl(self):
5462 # override it, as Any does not have implicit tag
5465 def test_decoded(self):
5466 # override it, as Any does not have implicit tag
5469 @given(choice_values_strategy())
5470 def test_copy(self, values):
5471 _schema, value, expl, default, optional, _decoded = values
5473 class Wahl(self.base_klass):
5475 register_class(Wahl)
5480 optional=optional or False,
5483 for copy_func in copy_funcs:
5484 obj_copied = copy_func(obj)
5485 self.assertIsNone(obj.tag)
5486 self.assertIsNone(obj_copied.tag)
5487 # hack for assert_copied_basic_fields
5488 obj.tag = "whatever"
5489 obj_copied.tag = "whatever"
5490 self.assert_copied_basic_fields(obj, obj_copied)
5492 self.assertEqual(obj._value, obj_copied._value)
5493 self.assertEqual(obj.specs, obj_copied.specs)
5496 def test_stripped(self, value):
5497 obj = self.base_klass(("whatever", Boolean(value)))
5498 with self.assertRaises(NotEnoughData):
5499 obj.decode(obj.encode()[:-1])
5503 integers(min_value=1).map(tag_ctxc),
5505 def test_stripped_expl(self, value, tag_expl):
5506 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5507 with self.assertRaises(NotEnoughData):
5508 obj.decode(obj.encode()[:-1])
5510 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5511 @given(data_strategy())
5512 def test_symmetric(self, d):
5513 _schema, value, _, default, optional, _decoded = d.draw(
5514 choice_values_strategy(value_required=True)
5516 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5517 offset = d.draw(integers(min_value=0))
5518 tail_junk = d.draw(binary(max_size=5))
5519 decode_path = d.draw(decode_path_strat)
5521 class Wahl(self.base_klass):
5531 pprint(obj, big_blobs=True, with_decode_path=True)
5532 self.assertFalse(obj.expled)
5533 self.assertEqual(obj.tag_order, obj.value.tag_order)
5534 obj_encoded = obj.encode()
5535 obj_expled = obj(value, expl=tag_expl)
5536 self.assertTrue(obj_expled.expled)
5537 tag_class, _, tag_num = tag_decode(tag_expl)
5538 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5540 list(obj_expled.pps())
5541 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5542 obj_expled_encoded = obj_expled.encode()
5543 ctx_copied = deepcopy(ctx_dummy)
5544 obj_decoded, tail = obj_expled.decode(
5545 obj_expled_encoded + tail_junk,
5549 self.assertDictEqual(ctx_copied, ctx_dummy)
5551 list(obj_decoded.pps())
5552 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5553 self.assertEqual(tail, tail_junk)
5554 self.assertEqual(obj_decoded, obj_expled)
5555 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5556 self.assertEqual(obj_decoded.value, obj_expled.value)
5557 self.assertEqual(obj_decoded.choice, obj.choice)
5558 self.assertEqual(obj_decoded.value, obj.value)
5559 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5560 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5561 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5563 obj_decoded.expl_llen,
5564 len(len_encode(len(obj_encoded))),
5566 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5567 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5570 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5572 self.assertEqual(obj_decoded.expl_offset, offset)
5573 self.assertSequenceEqual(
5575 obj_decoded.value.fulloffset - offset:
5576 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5580 assert_exceeding_data(
5582 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5586 evgens = list(obj_expled.decode_evgen(
5587 obj_expled_encoded + tail_junk,
5589 decode_path=decode_path,
5592 self.assertEqual(len(evgens), 2)
5593 _decode_path, obj, tail = evgens[0]
5594 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5595 _decode_path, obj, tail = evgens[1]
5596 self.assertSequenceEqual(tail, tail_junk)
5597 self.assertEqual(_decode_path, decode_path)
5598 self.assertEqual(obj.expl_offset, offset)
5603 def test_set_get(self, value):
5606 ("erste", Boolean()),
5607 ("zweite", Integer()),
5610 with self.assertRaises(ObjUnknown) as err:
5611 obj["whatever"] = "whenever"
5612 with self.assertRaises(InvalidValueType) as err:
5613 obj["zweite"] = Boolean(False)
5614 obj["zweite"] = Integer(value)
5616 with self.assertRaises(ObjUnknown) as err:
5619 self.assertIsNone(obj["erste"])
5620 self.assertEqual(obj["zweite"], Integer(value))
5622 def test_tag_mismatch(self):
5625 ("erste", Boolean()),
5627 int_encoded = Integer(123).encode()
5628 bool_encoded = Boolean(False).encode()
5630 obj.decode(bool_encoded)
5631 with self.assertRaises(TagMismatch):
5632 obj.decode(int_encoded)
5634 def test_tag_mismatch_underlying(self):
5635 class SeqOfBoolean(SequenceOf):
5638 class SeqOfInteger(SequenceOf):
5643 ("erste", SeqOfBoolean()),
5646 int_encoded = SeqOfInteger((Integer(123),)).encode()
5647 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5649 obj.decode(bool_encoded)
5650 with self.assertRaises(TagMismatch) as err:
5651 obj.decode(int_encoded)
5652 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5656 def seq_values_strategy(draw, seq_klass, do_expl=False):
5658 if draw(booleans()):
5660 value._value = draw(dictionaries(
5663 booleans().map(Boolean),
5664 integers().map(Integer),
5668 if draw(booleans()):
5669 schema = list(draw(dictionaries(
5672 booleans().map(Boolean),
5673 integers().map(Integer),
5679 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5681 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5683 if draw(booleans()):
5684 default = seq_klass()
5685 default._value = draw(dictionaries(
5688 booleans().map(Boolean),
5689 integers().map(Integer),
5692 optional = draw(one_of(none(), booleans()))
5694 draw(integers(min_value=0)),
5695 draw(integers(min_value=0)),
5696 draw(integers(min_value=0)),
5698 return (value, schema, impl, expl, default, optional, _decoded)
5702 def sequence_strategy(draw, seq_klass):
5703 inputs = draw(lists(
5705 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5706 tuples(just(Integer), integers(), one_of(none(), integers())),
5711 integers(min_value=1),
5712 min_size=len(inputs),
5713 max_size=len(inputs),
5716 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5717 for tag, expled in zip(tags, draw(lists(
5719 min_size=len(inputs),
5720 max_size=len(inputs),
5724 for i, optional in enumerate(draw(lists(
5725 sampled_from(("required", "optional", "empty")),
5726 min_size=len(inputs),
5727 max_size=len(inputs),
5729 if optional in ("optional", "empty"):
5730 inits[i]["optional"] = True
5731 if optional == "empty":
5733 empties = set(empties)
5734 names = list(draw(sets(
5736 min_size=len(inputs),
5737 max_size=len(inputs),
5740 for i, (klass, value, default) in enumerate(inputs):
5741 schema.append((names[i], klass(default=default, **inits[i])))
5742 seq_name = draw(text_letters())
5743 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5746 for i, (klass, value, default) in enumerate(inputs):
5753 "default_value": None if spec.default is None else default,
5757 expect["optional"] = True
5759 expect["presented"] = True
5760 expect["value"] = value
5762 expect["optional"] = True
5763 if default is not None and default == value:
5764 expect["presented"] = False
5765 seq[name] = klass(value)
5766 expects.append(expect)
5771 def sequences_strategy(draw, seq_klass):
5772 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5774 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5775 for tag, expled in zip(tags, draw(lists(
5782 i for i, is_default in enumerate(draw(lists(
5788 names = list(draw(sets(
5793 seq_expectses = draw(lists(
5794 sequence_strategy(seq_klass=seq_klass),
5798 seqs = [seq for seq, _ in seq_expectses]
5800 for i, (name, seq) in enumerate(zip(names, seqs)):
5803 seq(default=(seq if i in defaulted else None), **inits[i]),
5805 seq_name = draw(text_letters())
5806 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5809 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5812 "expects": expects_inner,
5815 seq_outer[name] = seq_inner
5816 if seq_outer.specs[name].default is None:
5817 expect["presented"] = True
5818 expect_outers.append(expect)
5819 return seq_outer, expect_outers
5822 class SeqMixing(object):
5823 def test_invalid_value_type(self):
5824 with self.assertRaises(InvalidValueType) as err:
5825 self.base_klass(123)
5828 def test_invalid_value_type_set(self):
5829 class Seq(self.base_klass):
5830 schema = (("whatever", Boolean()),)
5832 with self.assertRaises(InvalidValueType) as err:
5833 seq["whatever"] = Integer(123)
5837 def test_optional(self, optional):
5838 obj = self.base_klass(default=self.base_klass(), optional=optional)
5839 self.assertTrue(obj.optional)
5841 @given(data_strategy())
5842 def test_ready(self, d):
5844 str(i): v for i, v in enumerate(d.draw(lists(
5851 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5858 for name in d.draw(permutations(
5859 list(ready.keys()) + list(non_ready.keys()),
5861 schema_input.append((name, Boolean()))
5863 class Seq(self.base_klass):
5864 schema = tuple(schema_input)
5866 for name in ready.keys():
5868 seq[name] = Boolean()
5869 self.assertFalse(seq.ready)
5872 pprint(seq, big_blobs=True, with_decode_path=True)
5873 for name, value in ready.items():
5874 seq[name] = Boolean(value)
5875 self.assertFalse(seq.ready)
5878 pprint(seq, big_blobs=True, with_decode_path=True)
5879 with self.assertRaises(ObjNotReady) as err:
5882 for name, value in non_ready.items():
5883 seq[name] = Boolean(value)
5884 self.assertTrue(seq.ready)
5887 pprint(seq, big_blobs=True, with_decode_path=True)
5889 @given(data_strategy())
5890 def test_call(self, d):
5891 class SeqInherited(self.base_klass):
5893 for klass in (self.base_klass, SeqInherited):
5902 ) = d.draw(seq_values_strategy(seq_klass=klass))
5903 obj_initial = klass(
5909 optional_initial or False,
5920 ) = d.draw(seq_values_strategy(
5922 do_expl=impl_initial is None,
5924 obj = obj_initial(value, impl, expl, default, optional)
5925 value_expected = default if value is None else value
5927 default_initial if value_expected is None
5930 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5931 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5932 self.assertEqual(obj.expl_tag, expl or expl_initial)
5934 {} if obj.default is None else obj.default._value,
5935 getattr(default_initial if default is None else default, "_value", {}),
5937 if obj.default is None:
5938 optional = optional_initial if optional is None else optional
5939 optional = False if optional is None else optional
5942 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5943 self.assertEqual(obj.optional, optional)
5945 @given(data_strategy())
5946 def test_copy(self, d):
5947 class SeqInherited(self.base_klass):
5949 register_class(SeqInherited)
5950 for klass in (self.base_klass, SeqInherited):
5951 values = d.draw(seq_values_strategy(seq_klass=klass))
5952 obj = klass(*values)
5953 for copy_func in copy_funcs:
5954 obj_copied = copy_func(obj)
5955 self.assert_copied_basic_fields(obj, obj_copied)
5956 self.assertEqual(obj.specs, obj_copied.specs)
5957 self.assertEqual(obj._value, obj_copied._value)
5959 @given(data_strategy())
5960 def test_stripped(self, d):
5961 value = d.draw(integers())
5962 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5964 class Seq(self.base_klass):
5966 schema = (("whatever", Integer()),)
5968 seq["whatever"] = Integer(value)
5969 with self.assertRaises(NotEnoughData):
5970 seq.decode(seq.encode()[:-1])
5972 @given(data_strategy())
5973 def test_stripped_expl(self, d):
5974 value = d.draw(integers())
5975 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5977 class Seq(self.base_klass):
5979 schema = (("whatever", Integer()),)
5981 seq["whatever"] = Integer(value)
5982 with self.assertRaises(NotEnoughData):
5983 seq.decode(seq.encode()[:-1])
5985 @given(integers(min_value=3), binary(min_size=2))
5986 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
5987 junk = tag_encode(junk_tag_num) + junk
5989 _, _, len_encoded = tag_strip(memoryview(junk))
5990 len_decode(len_encoded)
5996 class Seq(self.base_klass):
5998 ("whatever", Integer()),
6000 ("whenever", Integer()),
6003 seq["whatever"] = Integer(123)
6004 seq["junk"] = Any(junk)
6005 seq["whenever"] = Integer(123)
6006 with self.assertRaises(DecodeError):
6007 seq.decode(seq.encode())
6010 integers(min_value=31),
6011 integers(min_value=0),
6014 def test_bad_tag(self, tag, offset, decode_path):
6015 with self.assertRaises(DecodeError) as err:
6016 self.base_klass().decode(
6017 tag_encode(tag)[:-1],
6019 decode_path=decode_path,
6022 self.assertEqual(err.exception.offset, offset)
6023 self.assertEqual(err.exception.decode_path, decode_path)
6026 integers(min_value=128),
6027 integers(min_value=0),
6030 def test_bad_len(self, l, offset, decode_path):
6031 with self.assertRaises(DecodeError) as err:
6032 self.base_klass().decode(
6033 self.base_klass.tag_default + len_encode(l)[:-1],
6035 decode_path=decode_path,
6038 self.assertEqual(err.exception.offset, offset)
6039 self.assertEqual(err.exception.decode_path, decode_path)
6041 def _assert_expects(self, seq, expects):
6042 for expect in expects:
6044 seq.specs[expect["name"]].optional,
6047 if expect["default_value"] is not None:
6049 seq.specs[expect["name"]].default,
6050 expect["default_value"],
6052 if expect["presented"]:
6053 self.assertIn(expect["name"], seq)
6054 self.assertEqual(seq[expect["name"]], expect["value"])
6056 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6057 @given(data_strategy())
6058 def test_symmetric(self, d):
6059 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6060 tail_junk = d.draw(binary(max_size=5))
6061 decode_path = d.draw(decode_path_strat)
6062 self.assertTrue(seq.ready)
6063 self.assertFalse(seq.decoded)
6064 self._assert_expects(seq, expects)
6067 pprint(seq, big_blobs=True, with_decode_path=True)
6068 self.assertTrue(seq.ready)
6069 seq_encoded = seq.encode()
6070 seq_encoded_cer = encode_cer(seq)
6071 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6072 self.assertSequenceEqual(
6073 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6076 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6077 self.assertFalse(seq_decoded.lenindef)
6078 self.assertFalse(seq_decoded.ber_encoded)
6079 self.assertFalse(seq_decoded.bered)
6081 t, _, lv = tag_strip(seq_encoded)
6082 _, _, v = len_decode(lv)
6083 seq_encoded_lenindef = t + LENINDEF + v + EOC
6084 with self.assertRaises(DecodeError):
6085 seq.decode(seq_encoded_lenindef)
6086 ctx_copied = deepcopy(ctx_dummy)
6087 ctx_copied["bered"] = True
6088 seq_decoded_lenindef, tail_lenindef = seq.decode(
6089 seq_encoded_lenindef + tail_junk,
6092 del ctx_copied["bered"]
6093 self.assertDictEqual(ctx_copied, ctx_dummy)
6094 self.assertTrue(seq_decoded_lenindef.lenindef)
6095 self.assertTrue(seq_decoded_lenindef.bered)
6096 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6097 self.assertTrue(seq_decoded_lenindef.lenindef)
6098 self.assertTrue(seq_decoded_lenindef.bered)
6099 with self.assertRaises(DecodeError):
6100 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6101 with self.assertRaises(DecodeError):
6102 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6103 repr(seq_decoded_lenindef)
6104 list(seq_decoded_lenindef.pps())
6105 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6106 self.assertTrue(seq_decoded_lenindef.ready)
6108 for decoded, decoded_tail, encoded in (
6109 (seq_decoded, tail, seq_encoded),
6110 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6112 self.assertEqual(decoded_tail, tail_junk)
6113 self._assert_expects(decoded, expects)
6114 self.assertEqual(seq, decoded)
6115 self.assertEqual(decoded.encode(), seq_encoded)
6116 self.assertEqual(decoded.tlvlen, len(encoded))
6117 for expect in expects:
6118 if not expect["presented"]:
6119 self.assertNotIn(expect["name"], decoded)
6121 self.assertIn(expect["name"], decoded)
6122 obj = decoded[expect["name"]]
6123 self.assertTrue(obj.decoded)
6124 offset = obj.expl_offset if obj.expled else obj.offset
6125 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6126 self.assertSequenceEqual(
6127 seq_encoded[offset:offset + tlvlen],
6131 evgens = list(seq.decode_evgen(
6132 encoded + decoded_tail,
6133 decode_path=decode_path,
6134 ctx={"bered": True},
6136 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6137 for _decode_path, obj, _ in evgens[:-1]:
6138 self.assertEqual(_decode_path[:-1], decode_path)
6141 _decode_path, obj, tail = evgens[-1]
6142 self.assertEqual(_decode_path, decode_path)
6146 assert_exceeding_data(
6148 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6152 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6153 @given(data_strategy())
6154 def test_symmetric_with_seq(self, d):
6155 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6156 self.assertTrue(seq.ready)
6157 seq_encoded = seq.encode()
6158 seq_decoded, tail = seq.decode(seq_encoded)
6159 self.assertEqual(tail, b"")
6160 self.assertTrue(seq.ready)
6161 self.assertEqual(seq, seq_decoded)
6162 self.assertEqual(seq_decoded.encode(), seq_encoded)
6163 for expect_outer in expect_outers:
6164 if not expect_outer["presented"]:
6165 self.assertNotIn(expect_outer["name"], seq_decoded)
6167 self.assertIn(expect_outer["name"], seq_decoded)
6168 obj = seq_decoded[expect_outer["name"]]
6169 self.assertTrue(obj.decoded)
6170 offset = obj.expl_offset if obj.expled else obj.offset
6171 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6172 self.assertSequenceEqual(
6173 seq_encoded[offset:offset + tlvlen],
6176 self._assert_expects(obj, expect_outer["expects"])
6178 @given(data_strategy())
6179 def test_default_disappears(self, d):
6180 _schema = list(d.draw(dictionaries(
6182 sets(integers(), min_size=2, max_size=2),
6186 class Seq(self.base_klass):
6188 (n, Integer(default=d))
6189 for n, (_, d) in _schema
6192 for name, (value, _) in _schema:
6193 seq[name] = Integer(value)
6194 self.assertEqual(len(seq._value), len(_schema))
6195 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6196 self.assertGreater(len(seq.encode()), len(empty_seq))
6197 for name, (_, default) in _schema:
6198 seq[name] = Integer(default)
6199 self.assertEqual(len(seq._value), 0)
6200 self.assertSequenceEqual(seq.encode(), empty_seq)
6202 @given(data_strategy())
6203 def test_encoded_default_not_accepted(self, d):
6204 _schema = list(d.draw(dictionaries(
6209 tags = [tag_encode(tag) for tag in d.draw(sets(
6210 integers(min_value=1),
6211 min_size=len(_schema),
6212 max_size=len(_schema),
6215 class SeqWithoutDefault(self.base_klass):
6217 (n, Integer(impl=t))
6218 for (n, _), t in zip(_schema, tags)
6220 seq_without_default = SeqWithoutDefault()
6221 for name, value in _schema:
6222 seq_without_default[name] = Integer(value)
6223 seq_encoded = seq_without_default.encode()
6225 class SeqWithDefault(self.base_klass):
6227 (n, Integer(default=v, impl=t))
6228 for (n, v), t in zip(_schema, tags)
6230 seq_with_default = SeqWithDefault()
6231 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6232 seq_with_default.decode(seq_encoded)
6233 for ctx in ({"bered": True}, {"allow_default_values": True}):
6234 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6235 self.assertTrue(seq_decoded.ber_encoded)
6236 self.assertTrue(seq_decoded.bered)
6237 seq_decoded = copy(seq_decoded)
6238 self.assertTrue(seq_decoded.ber_encoded)
6239 self.assertTrue(seq_decoded.bered)
6240 for name, value in _schema:
6241 self.assertEqual(seq_decoded[name], seq_with_default[name])
6242 self.assertEqual(seq_decoded[name], value)
6244 @given(data_strategy())
6245 def test_missing_from_spec(self, d):
6246 names = list(d.draw(sets(text_letters(), min_size=2)))
6247 tags = [tag_encode(tag) for tag in d.draw(sets(
6248 integers(min_value=1),
6249 min_size=len(names),
6250 max_size=len(names),
6252 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6254 class SeqFull(self.base_klass):
6255 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6256 seq_full = SeqFull()
6257 for i, name in enumerate(names):
6258 seq_full[name] = Integer(i)
6259 seq_encoded = seq_full.encode()
6260 altered = names_tags[:-2] + names_tags[-1:]
6262 class SeqMissing(self.base_klass):
6263 schema = [(n, Integer(impl=t)) for n, t in altered]
6264 seq_missing = SeqMissing()
6265 with self.assertRaises(TagMismatch):
6266 seq_missing.decode(seq_encoded)
6268 def test_bered(self):
6269 class Seq(self.base_klass):
6270 schema = (("underlying", Boolean()),)
6271 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6272 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6273 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6274 self.assertFalse(decoded.ber_encoded)
6275 self.assertFalse(decoded.lenindef)
6276 self.assertTrue(decoded.bered)
6277 decoded = copy(decoded)
6278 self.assertFalse(decoded.ber_encoded)
6279 self.assertFalse(decoded.lenindef)
6280 self.assertTrue(decoded.bered)
6282 class Seq(self.base_klass):
6283 schema = (("underlying", OctetString()),)
6285 tag_encode(form=TagFormConstructed, num=4) +
6287 OctetString(b"whatever").encode() +
6290 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6291 with self.assertRaises(DecodeError):
6292 Seq().decode(encoded)
6293 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6294 self.assertFalse(decoded.ber_encoded)
6295 self.assertFalse(decoded.lenindef)
6296 self.assertTrue(decoded.bered)
6297 decoded = copy(decoded)
6298 self.assertFalse(decoded.ber_encoded)
6299 self.assertFalse(decoded.lenindef)
6300 self.assertTrue(decoded.bered)
6303 class TestSequence(SeqMixing, CommonMixin, TestCase):
6304 base_klass = Sequence
6310 def test_remaining(self, value, junk):
6311 class Seq(Sequence):
6313 ("whatever", Integer()),
6315 int_encoded = Integer(value).encode()
6317 Sequence.tag_default,
6318 len_encode(len(int_encoded + junk)),
6321 with assertRaisesRegex(self, DecodeError, "remaining"):
6322 Seq().decode(junked)
6324 @given(sets(text_letters(), min_size=2))
6325 def test_obj_unknown(self, names):
6326 missing = names.pop()
6328 class Seq(Sequence):
6329 schema = [(n, Boolean()) for n in names]
6331 with self.assertRaises(ObjUnknown) as err:
6334 with self.assertRaises(ObjUnknown) as err:
6335 seq[missing] = Boolean()
6338 def test_x690_vector(self):
6339 class Seq(Sequence):
6341 ("name", IA5String()),
6344 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6345 self.assertEqual(seq["name"], "Smith")
6346 self.assertEqual(seq["ok"], True)
6349 class TestSet(SeqMixing, CommonMixin, TestCase):
6352 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6353 @given(data_strategy())
6354 def test_sorted(self, d):
6355 class DummySeq(Sequence):
6356 schema = (("null", Null()),)
6358 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6359 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6360 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6361 tag_nums -= set([dummy_seq_tag_num])
6362 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6363 _schema.append(("seq", DummySeq()))
6366 schema = d.draw(permutations(_schema))
6368 for name, _ in _schema:
6370 seq[name] = OctetString(name.encode("ascii"))
6371 seq["seq"] = DummySeq((("null", Null()),))
6373 seq_encoded = seq.encode()
6374 seq_decoded, _ = seq.decode(seq_encoded)
6375 seq_encoded_expected = []
6376 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6377 if tag_num == dummy_seq_tag_num:
6378 seq_encoded_expected.append(seq["seq"].encode())
6380 seq_encoded_expected.append(seq[str(tag_num)].encode())
6381 self.assertSequenceEqual(
6382 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6383 b"".join(seq_encoded_expected),
6386 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6387 encoded += seq["seq"].encode()
6388 seq_encoded = b"".join((
6390 len_encode(len(encoded)),
6393 with assertRaisesRegex(self, DecodeError, "unordered SET"):
6394 seq.decode(seq_encoded)
6395 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6396 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6397 self.assertTrue(seq_decoded.ber_encoded)
6398 self.assertTrue(seq_decoded.bered)
6399 seq_decoded = copy(seq_decoded)
6400 self.assertTrue(seq_decoded.ber_encoded)
6401 self.assertTrue(seq_decoded.bered)
6403 def test_same_value_twice(self):
6406 ("bool", Boolean()),
6410 encoded = b"".join((
6411 Integer(123).encode(),
6412 Integer(234).encode(),
6413 Boolean(True).encode(),
6415 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6416 with self.assertRaises(TagMismatch):
6417 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6421 def seqof_values_strategy(draw, schema=None, do_expl=False):
6423 schema = draw(sampled_from((Boolean(), Integer())))
6424 bound_min, bound_max = sorted(draw(sets(
6425 integers(min_value=0, max_value=10),
6429 if isinstance(schema, Boolean):
6430 values_generator = booleans().map(Boolean)
6431 elif isinstance(schema, Integer):
6432 values_generator = integers().map(Integer)
6433 values_generator = lists(
6438 values = draw(one_of(none(), values_generator))
6442 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6444 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6445 default = draw(one_of(none(), values_generator))
6446 optional = draw(one_of(none(), booleans()))
6448 draw(integers(min_value=0)),
6449 draw(integers(min_value=0)),
6450 draw(integers(min_value=0)),
6455 (bound_min, bound_max),
6464 class SeqOfMixing(object):
6465 def test_invalid_value_type(self):
6466 with self.assertRaises(InvalidValueType) as err:
6467 self.base_klass(123)
6470 def test_invalid_values_type(self):
6471 class SeqOf(self.base_klass):
6473 with self.assertRaises(InvalidValueType) as err:
6474 SeqOf([Integer(123), Boolean(False), Integer(234)])
6477 def test_schema_required(self):
6478 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6479 self.base_klass.__mro__[1]()
6481 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6482 def test_comparison(self, value1, value2, tag1, tag2):
6483 class SeqOf(self.base_klass):
6485 obj1 = SeqOf([Boolean(value1)])
6486 obj2 = SeqOf([Boolean(value2)])
6487 self.assertEqual(obj1 == obj2, value1 == value2)
6488 self.assertEqual(obj1 != obj2, value1 != value2)
6489 self.assertEqual(obj1 == list(obj2), value1 == value2)
6490 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6491 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6492 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6493 self.assertEqual(obj1 == obj2, tag1 == tag2)
6494 self.assertEqual(obj1 != obj2, tag1 != tag2)
6496 @given(lists(booleans()))
6497 def test_iter(self, values):
6498 class SeqOf(self.base_klass):
6500 obj = SeqOf([Boolean(value) for value in values])
6501 self.assertEqual(len(obj), len(values))
6502 for i, value in enumerate(obj):
6503 self.assertEqual(value, values[i])
6505 @given(data_strategy())
6506 def test_ready(self, d):
6507 ready = [Integer(v) for v in d.draw(lists(
6514 range(d.draw(integers(min_value=1, max_value=5)))
6517 class SeqOf(self.base_klass):
6519 values = d.draw(permutations(ready + non_ready))
6521 for value in values:
6523 self.assertFalse(seqof.ready)
6526 pprint(seqof, big_blobs=True, with_decode_path=True)
6527 with self.assertRaises(ObjNotReady) as err:
6530 for i, value in enumerate(values):
6531 self.assertEqual(seqof[i], value)
6532 if not seqof[i].ready:
6533 seqof[i] = Integer(i)
6534 self.assertTrue(seqof.ready)
6537 pprint(seqof, big_blobs=True, with_decode_path=True)
6539 def test_spec_mismatch(self):
6540 class SeqOf(self.base_klass):
6543 seqof.append(Integer(123))
6544 with self.assertRaises(ValueError):
6545 seqof.append(Boolean(False))
6546 with self.assertRaises(ValueError):
6547 seqof[0] = Boolean(False)
6549 @given(data_strategy())
6550 def test_bounds_satisfied(self, d):
6551 class SeqOf(self.base_klass):
6553 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6554 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6555 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6556 SeqOf(value=value, bounds=(bound_min, bound_max))
6558 @given(data_strategy())
6559 def test_bounds_unsatisfied(self, d):
6560 class SeqOf(self.base_klass):
6562 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6563 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6564 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6565 with self.assertRaises(BoundsError) as err:
6566 SeqOf(value=value, bounds=(bound_min, bound_max))
6568 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6569 SeqOf(bounds=(bound_min, bound_max)).decode(
6570 SeqOf(value).encode()
6573 value = [Boolean(True)] * d.draw(integers(
6574 min_value=bound_max + 1,
6575 max_value=bound_max + 10,
6577 with self.assertRaises(BoundsError) as err:
6578 SeqOf(value=value, bounds=(bound_min, bound_max))
6580 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6581 SeqOf(bounds=(bound_min, bound_max)).decode(
6582 SeqOf(value).encode()
6586 @given(integers(min_value=1, max_value=10))
6587 def test_out_of_bounds(self, bound_max):
6588 class SeqOf(self.base_klass):
6590 bounds = (0, bound_max)
6592 for _ in range(bound_max):
6593 seqof.append(Integer(123))
6594 with self.assertRaises(BoundsError):
6595 seqof.append(Integer(123))
6597 @given(data_strategy())
6598 def test_call(self, d):
6608 ) = d.draw(seqof_values_strategy())
6610 class SeqOf(self.base_klass):
6611 schema = schema_initial
6612 obj_initial = SeqOf(
6613 value=value_initial,
6614 bounds=bounds_initial,
6617 default=default_initial,
6618 optional=optional_initial or False,
6619 _decoded=_decoded_initial,
6630 ) = d.draw(seqof_values_strategy(
6631 schema=schema_initial,
6632 do_expl=impl_initial is None,
6634 if (default is None) and (obj_initial.default is not None):
6637 (bounds is None) and
6638 (value is not None) and
6639 (bounds_initial is not None) and
6640 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6644 (bounds is None) and
6645 (default is not None) and
6646 (bounds_initial is not None) and
6647 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6659 value_expected = default if value is None else value
6661 default_initial if value_expected is None
6664 value_expected = () if value_expected is None else value_expected
6665 self.assertEqual(obj, value_expected)
6666 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6667 self.assertEqual(obj.expl_tag, expl or expl_initial)
6670 default_initial if default is None else default,
6672 if obj.default is None:
6673 optional = optional_initial if optional is None else optional
6674 optional = False if optional is None else optional
6677 self.assertEqual(obj.optional, optional)
6679 (obj._bound_min, obj._bound_max),
6680 bounds or bounds_initial or (0, float("+inf")),
6683 @given(seqof_values_strategy())
6684 def test_copy(self, values):
6685 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6687 class SeqOf(self.base_klass):
6689 register_class(SeqOf)
6696 optional=optional or False,
6699 for copy_func in copy_funcs:
6700 obj_copied = copy_func(obj)
6701 self.assert_copied_basic_fields(obj, obj_copied)
6702 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6703 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6704 self.assertEqual(obj._value, obj_copied._value)
6708 integers(min_value=1).map(tag_encode),
6710 def test_stripped(self, values, tag_impl):
6711 class SeqOf(self.base_klass):
6712 schema = OctetString()
6713 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6714 with self.assertRaises(NotEnoughData):
6715 obj.decode(obj.encode()[:-1])
6719 integers(min_value=1).map(tag_ctxc),
6721 def test_stripped_expl(self, values, tag_expl):
6722 class SeqOf(self.base_klass):
6723 schema = OctetString()
6724 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6725 with self.assertRaises(NotEnoughData):
6726 obj.decode(obj.encode()[:-1])
6729 integers(min_value=31),
6730 integers(min_value=0),
6733 def test_bad_tag(self, tag, offset, decode_path):
6734 with self.assertRaises(DecodeError) as err:
6735 self.base_klass().decode(
6736 tag_encode(tag)[:-1],
6738 decode_path=decode_path,
6741 self.assertEqual(err.exception.offset, offset)
6742 self.assertEqual(err.exception.decode_path, decode_path)
6745 integers(min_value=128),
6746 integers(min_value=0),
6749 def test_bad_len(self, l, offset, decode_path):
6750 with self.assertRaises(DecodeError) as err:
6751 self.base_klass().decode(
6752 self.base_klass.tag_default + len_encode(l)[:-1],
6754 decode_path=decode_path,
6757 self.assertEqual(err.exception.offset, offset)
6758 self.assertEqual(err.exception.decode_path, decode_path)
6760 @given(binary(min_size=1))
6761 def test_tag_mismatch(self, impl):
6762 assume(impl != self.base_klass.tag_default)
6763 with self.assertRaises(TagMismatch):
6764 self.base_klass(impl=impl).decode(self.base_klass().encode())
6766 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6768 seqof_values_strategy(schema=Integer()),
6769 lists(integers().map(Integer)),
6770 integers(min_value=1).map(tag_ctxc),
6771 integers(min_value=0),
6775 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6776 _, _, _, _, _, default, optional, _decoded = values
6778 class SeqOf(self.base_klass):
6788 pprint(obj, big_blobs=True, with_decode_path=True)
6789 self.assertFalse(obj.expled)
6790 obj_encoded = obj.encode()
6791 obj_encoded_cer = encode_cer(obj)
6792 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6793 self.assertSequenceEqual(
6794 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6797 obj_expled = obj(value, expl=tag_expl)
6798 self.assertTrue(obj_expled.expled)
6800 list(obj_expled.pps())
6801 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6802 obj_expled_encoded = obj_expled.encode()
6803 ctx_copied = deepcopy(ctx_dummy)
6804 obj_decoded, tail = obj_expled.decode(
6805 obj_expled_encoded + tail_junk,
6809 self.assertDictEqual(ctx_copied, ctx_dummy)
6811 list(obj_decoded.pps())
6812 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6813 self.assertEqual(tail, tail_junk)
6814 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6815 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6816 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6817 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6819 obj_decoded.expl_llen,
6820 len(len_encode(len(obj_encoded))),
6822 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6823 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6826 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6828 self.assertEqual(obj_decoded.expl_offset, offset)
6829 for obj_inner in obj_decoded:
6830 self.assertIn(obj_inner, obj_decoded)
6831 self.assertSequenceEqual(
6834 obj_inner.offset - offset:
6835 obj_inner.offset + obj_inner.tlvlen - offset
6839 t, _, lv = tag_strip(obj_encoded)
6840 _, _, v = len_decode(lv)
6841 obj_encoded_lenindef = t + LENINDEF + v + EOC
6842 with self.assertRaises(DecodeError):
6843 obj.decode(obj_encoded_lenindef)
6844 obj_decoded_lenindef, tail_lenindef = obj.decode(
6845 obj_encoded_lenindef + tail_junk,
6846 ctx={"bered": True},
6848 self.assertTrue(obj_decoded_lenindef.lenindef)
6849 self.assertTrue(obj_decoded_lenindef.bered)
6850 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6851 self.assertTrue(obj_decoded_lenindef.lenindef)
6852 self.assertTrue(obj_decoded_lenindef.bered)
6853 repr(obj_decoded_lenindef)
6854 list(obj_decoded_lenindef.pps())
6855 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6856 self.assertEqual(tail_lenindef, tail_junk)
6857 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6858 with self.assertRaises(DecodeError):
6859 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6860 with self.assertRaises(DecodeError):
6861 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6863 evgens = list(obj.decode_evgen(
6864 obj_encoded_lenindef + tail_junk,
6865 decode_path=decode_path,
6866 ctx={"bered": True},
6868 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
6869 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
6870 self.assertEqual(_decode_path, decode_path + (str(i),))
6873 _decode_path, obj, tail = evgens[-1]
6874 self.assertEqual(_decode_path, decode_path)
6878 assert_exceeding_data(
6880 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6884 def test_bered(self):
6885 class SeqOf(self.base_klass):
6887 encoded = Boolean(False).encode()
6888 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6889 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6890 with self.assertRaises(DecodeError):
6891 SeqOf().decode(encoded)
6892 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6893 self.assertFalse(decoded.ber_encoded)
6894 self.assertFalse(decoded.lenindef)
6895 self.assertTrue(decoded.bered)
6896 decoded = copy(decoded)
6897 self.assertFalse(decoded.ber_encoded)
6898 self.assertFalse(decoded.lenindef)
6899 self.assertTrue(decoded.bered)
6901 class SeqOf(self.base_klass):
6902 schema = OctetString()
6903 encoded = OctetString(b"whatever").encode()
6905 tag_encode(form=TagFormConstructed, num=4) +
6907 OctetString(b"whatever").encode() +
6910 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6911 with self.assertRaises(DecodeError):
6912 SeqOf().decode(encoded)
6913 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6914 self.assertFalse(decoded.ber_encoded)
6915 self.assertFalse(decoded.lenindef)
6916 self.assertTrue(decoded.bered)
6917 decoded = copy(decoded)
6918 self.assertFalse(decoded.ber_encoded)
6919 self.assertFalse(decoded.lenindef)
6920 self.assertTrue(decoded.bered)
6923 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6924 class SeqOf(SequenceOf):
6928 def _test_symmetric_compare_objs(self, obj1, obj2):
6929 self.assertEqual(obj1, obj2)
6930 self.assertSequenceEqual(list(obj1), list(obj2))
6932 def test_iterator_pickling(self):
6933 class SeqOf(SequenceOf):
6935 register_class(SeqOf)
6938 seqof = seqof(iter(six_xrange(10)))
6939 with assertRaisesRegex(self, ValueError, "iterator"):
6942 def test_iterator_bounds(self):
6943 class SeqOf(SequenceOf):
6948 for i in six_xrange(n):
6951 seqof = SeqOf(gen(n))
6952 self.assertTrue(seqof.ready)
6953 with self.assertRaises(BoundsError):
6955 self.assertFalse(seqof.ready)
6956 seqof = seqof(gen(n))
6957 self.assertTrue(seqof.ready)
6958 with self.assertRaises(BoundsError):
6960 self.assertFalse(seqof.ready)
6962 def test_iterator_twice(self):
6963 class SeqOf(SequenceOf):
6965 bounds = (1, float("+inf"))
6967 for i in six_xrange(10):
6969 seqof = SeqOf(gen())
6970 self.assertTrue(seqof.ready)
6972 self.assertFalse(seqof.ready)
6973 register_class(SeqOf)
6976 def test_non_ready_bound_min(self):
6977 class SeqOf(SequenceOf):
6979 bounds = (1, float("+inf"))
6981 self.assertFalse(seqof.ready)
6984 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6989 def _test_symmetric_compare_objs(self, obj1, obj2):
6990 self.assertSetEqual(
6991 set(int(v) for v in obj1),
6992 set(int(v) for v in obj2),
6995 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6996 @given(data_strategy())
6997 def test_sorted(self, d):
6998 values = [OctetString(v) for v in d.draw(lists(binary()))]
7001 schema = OctetString()
7003 seq_encoded = seq.encode()
7004 seq_decoded, _ = seq.decode(seq_encoded)
7005 self.assertSequenceEqual(
7006 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7007 b"".join(sorted([v.encode() for v in values])),
7010 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7011 @given(data_strategy())
7012 def test_unsorted(self, d):
7013 values = [OctetString(v).encode() for v in d.draw(sets(
7014 binary(min_size=1, max_size=5),
7018 values = d.draw(permutations(values))
7019 assume(values != sorted(values))
7020 encoded = b"".join(values)
7021 seq_encoded = b"".join((
7023 len_encode(len(encoded)),
7028 schema = OctetString()
7030 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
7031 seq.decode(seq_encoded)
7033 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7034 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7035 self.assertTrue(seq_decoded.ber_encoded)
7036 self.assertTrue(seq_decoded.bered)
7037 seq_decoded = copy(seq_decoded)
7038 self.assertTrue(seq_decoded.ber_encoded)
7039 self.assertTrue(seq_decoded.bered)
7040 self.assertSequenceEqual(
7041 [obj.encode() for obj in seq_decoded],
7046 class TestGoMarshalVectors(TestCase):
7048 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7049 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7050 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7051 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7052 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7054 class Seq(Sequence):
7056 ("erste", Integer()),
7057 ("zweite", Integer(optional=True))
7060 seq["erste"] = Integer(64)
7061 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7062 seq["erste"] = Integer(0x123456)
7063 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7064 seq["erste"] = Integer(64)
7065 seq["zweite"] = Integer(65)
7066 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7068 class NestedSeq(Sequence):
7072 seq["erste"] = Integer(127)
7073 seq["zweite"] = None
7074 nested = NestedSeq()
7075 nested["nest"] = seq
7076 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7078 self.assertSequenceEqual(
7079 OctetString(b"\x01\x02\x03").encode(),
7080 hexdec("0403010203"),
7083 class Seq(Sequence):
7085 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7088 seq["erste"] = Integer(64)
7089 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7091 class Seq(Sequence):
7093 ("erste", Integer(expl=tag_ctxc(5))),
7096 seq["erste"] = Integer(64)
7097 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7099 class Seq(Sequence):
7102 impl=tag_encode(0, klass=TagClassContext),
7107 seq["erste"] = Null()
7108 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7110 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7112 self.assertSequenceEqual(
7113 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7114 hexdec("170d3730303130313030303030305a"),
7116 self.assertSequenceEqual(
7117 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7118 hexdec("170d3039313131353232353631365a"),
7120 self.assertSequenceEqual(
7121 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7122 hexdec("180f32313030303430353132303130315a"),
7125 class Seq(Sequence):
7127 ("erste", GeneralizedTime()),
7130 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7131 self.assertSequenceEqual(
7133 hexdec("3011180f32303039313131353232353631365a"),
7136 self.assertSequenceEqual(
7137 BitString((1, b"\x80")).encode(),
7140 self.assertSequenceEqual(
7141 BitString((12, b"\x81\xF0")).encode(),
7142 hexdec("03030481f0"),
7145 self.assertSequenceEqual(
7146 ObjectIdentifier("1.2.3.4").encode(),
7147 hexdec("06032a0304"),
7149 self.assertSequenceEqual(
7150 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7151 hexdec("06092a864888932d010105"),
7153 self.assertSequenceEqual(
7154 ObjectIdentifier("2.100.3").encode(),
7155 hexdec("0603813403"),
7158 self.assertSequenceEqual(
7159 PrintableString("test").encode(),
7160 hexdec("130474657374"),
7162 self.assertSequenceEqual(
7163 PrintableString("x" * 127).encode(),
7164 hexdec("137F" + "78" * 127),
7166 self.assertSequenceEqual(
7167 PrintableString("x" * 128).encode(),
7168 hexdec("138180" + "78" * 128),
7170 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7172 class Seq(Sequence):
7174 ("erste", IA5String()),
7177 seq["erste"] = IA5String("test")
7178 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7180 class Seq(Sequence):
7182 ("erste", PrintableString()),
7185 seq["erste"] = PrintableString("test")
7186 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7187 # Asterisk is actually not allowable
7188 PrintableString._allowable_chars |= set(b"*")
7189 seq["erste"] = PrintableString("test*")
7190 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7191 PrintableString._allowable_chars -= set(b"*")
7193 class Seq(Sequence):
7195 ("erste", Any(optional=True)),
7196 ("zweite", Integer()),
7199 seq["zweite"] = Integer(64)
7200 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7205 seq.append(Integer(10))
7206 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7208 class _SeqOf(SequenceOf):
7209 schema = PrintableString()
7211 class SeqOf(SequenceOf):
7214 _seqof.append(PrintableString("1"))
7216 seqof.append(_seqof)
7217 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7219 class Seq(Sequence):
7221 ("erste", Integer(default=1)),
7224 seq["erste"] = Integer(0)
7225 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7226 seq["erste"] = Integer(1)
7227 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7228 seq["erste"] = Integer(2)
7229 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7232 class TestPP(TestCase):
7233 @given(data_strategy())
7234 def test_oid_printing(self, d):
7236 str(ObjectIdentifier(k)): v * 2
7237 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7239 chosen = d.draw(sampled_from(sorted(oids)))
7240 chosen_id = oids[chosen]
7241 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7242 self.assertNotIn(chosen_id, pp_console_row(pp))
7245 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7249 class TestAutoAddSlots(TestCase):
7251 class Inher(Integer):
7254 with self.assertRaises(AttributeError):
7256 inher.unexistent = "whatever"
7259 class TestOIDDefines(TestCase):
7260 @given(data_strategy())
7261 def runTest(self, d):
7262 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7263 value_name_chosen = d.draw(sampled_from(value_names))
7265 ObjectIdentifier(oid)
7266 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7268 oid_chosen = d.draw(sampled_from(oids))
7269 values = d.draw(lists(
7271 min_size=len(value_names),
7272 max_size=len(value_names),
7274 for definable_class in (Any, OctetString, BitString):
7276 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7277 oid: Integer() for oid in oids[:-1]
7280 for i, value_name in enumerate(value_names):
7281 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7283 class Seq(Sequence):
7286 for value_name, value in zip(value_names, values):
7287 seq[value_name] = definable_class(Integer(value).encode())
7288 seq["type"] = oid_chosen
7289 seq, _ = Seq().decode(seq.encode())
7290 for value_name in value_names:
7291 if value_name == value_name_chosen:
7293 self.assertIsNone(seq[value_name].defined)
7294 if value_name_chosen in oids[:-1]:
7295 self.assertIsNotNone(seq[value_name_chosen].defined)
7296 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7297 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7300 pprint(seq, big_blobs=True, with_decode_path=True)
7303 class TestDefinesByPath(TestCase):
7304 def test_generated(self):
7305 class Seq(Sequence):
7307 ("type", ObjectIdentifier()),
7308 ("value", OctetString(expl=tag_ctxc(123))),
7311 class SeqInner(Sequence):
7313 ("typeInner", ObjectIdentifier()),
7314 ("valueInner", Any()),
7317 class PairValue(SetOf):
7320 class Pair(Sequence):
7322 ("type", ObjectIdentifier()),
7323 ("value", PairValue()),
7326 class Pairs(SequenceOf):
7333 type_octet_stringed,
7335 ObjectIdentifier(oid)
7336 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7338 seq_integered = Seq()
7339 seq_integered["type"] = type_integered
7340 seq_integered["value"] = OctetString(Integer(123).encode())
7341 seq_integered_raw = seq_integered.encode()
7345 (type_octet_stringed, OctetString(b"whatever")),
7346 (type_integered, Integer(123)),
7347 (type_octet_stringed, OctetString(b"whenever")),
7348 (type_integered, Integer(234)),
7350 for t, v in pairs_input:
7353 ("value", PairValue((Any(v),))),
7355 seq_inner = SeqInner()
7356 seq_inner["typeInner"] = type_innered
7357 seq_inner["valueInner"] = Any(pairs)
7358 seq_sequenced = Seq()
7359 seq_sequenced["type"] = type_sequenced
7360 seq_sequenced["value"] = OctetString(seq_inner.encode())
7361 seq_sequenced_raw = seq_sequenced.encode()
7363 list(seq_sequenced.pps())
7364 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7366 defines_by_path = []
7367 ctx_copied = deepcopy(ctx_dummy)
7368 seq_integered, _ = Seq().decode(
7372 self.assertDictEqual(ctx_copied, ctx_dummy)
7373 self.assertIsNone(seq_integered["value"].defined)
7374 defines_by_path.append(
7375 (("type",), ((("value",), {
7376 type_integered: Integer(),
7377 type_sequenced: SeqInner(),
7380 ctx_copied["defines_by_path"] = defines_by_path
7381 seq_integered, _ = Seq().decode(
7385 del ctx_copied["defines_by_path"]
7386 self.assertDictEqual(ctx_copied, ctx_dummy)
7387 self.assertIsNotNone(seq_integered["value"].defined)
7388 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7389 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7390 self.assertTrue(seq_integered_raw[
7391 seq_integered["value"].defined[1].offset:
7392 ].startswith(Integer(123).encode()))
7394 list(seq_integered.pps())
7395 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7397 ctx_copied["defines_by_path"] = defines_by_path
7398 seq_sequenced, _ = Seq().decode(
7402 del ctx_copied["defines_by_path"]
7403 self.assertDictEqual(ctx_copied, ctx_dummy)
7404 self.assertIsNotNone(seq_sequenced["value"].defined)
7405 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7406 seq_inner = seq_sequenced["value"].defined[1]
7407 self.assertIsNone(seq_inner["valueInner"].defined)
7409 list(seq_sequenced.pps())
7410 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7412 defines_by_path.append((
7413 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7414 ((("valueInner",), {type_innered: Pairs()}),),
7416 ctx_copied["defines_by_path"] = defines_by_path
7417 seq_sequenced, _ = Seq().decode(
7421 del ctx_copied["defines_by_path"]
7422 self.assertDictEqual(ctx_copied, ctx_dummy)
7423 self.assertIsNotNone(seq_sequenced["value"].defined)
7424 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7425 seq_inner = seq_sequenced["value"].defined[1]
7426 self.assertIsNotNone(seq_inner["valueInner"].defined)
7427 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7428 pairs = seq_inner["valueInner"].defined[1]
7430 self.assertIsNone(pair["value"][0].defined)
7432 list(seq_sequenced.pps())
7433 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7435 defines_by_path.append((
7438 DecodePathDefBy(type_sequenced),
7440 DecodePathDefBy(type_innered),
7445 type_integered: Integer(),
7446 type_octet_stringed: OctetString(),
7449 ctx_copied["defines_by_path"] = defines_by_path
7450 seq_sequenced, _ = Seq().decode(
7454 del ctx_copied["defines_by_path"]
7455 self.assertDictEqual(ctx_copied, ctx_dummy)
7456 self.assertIsNotNone(seq_sequenced["value"].defined)
7457 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7458 seq_inner = seq_sequenced["value"].defined[1]
7459 self.assertIsNotNone(seq_inner["valueInner"].defined)
7460 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7461 pairs_got = seq_inner["valueInner"].defined[1]
7462 for pair_input, pair_got in zip(pairs_input, pairs_got):
7463 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7464 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7466 list(seq_sequenced.pps())
7467 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7469 @given(oid_strategy(), integers())
7470 def test_simple(self, oid, tgt):
7471 class Inner(Sequence):
7473 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7474 ObjectIdentifier(oid): Integer(),
7478 class Outer(Sequence):
7481 ("tgt", OctetString()),
7485 inner["oid"] = ObjectIdentifier(oid)
7487 outer["inner"] = inner
7488 outer["tgt"] = OctetString(Integer(tgt).encode())
7489 decoded, _ = Outer().decode(outer.encode())
7490 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7492 def test_remaining_data(self):
7493 oid = ObjectIdentifier("1.2.3")
7494 class Seq(Sequence):
7496 ("oid", ObjectIdentifier(defines=((("tgt",), {
7499 ("tgt", OctetString()),
7504 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7506 with assertRaisesRegex(self, DecodeError, "remaining data"):
7507 Seq().decode(seq.encode())
7509 def test_remaining_data_seqof(self):
7510 oid = ObjectIdentifier("1.2.3")
7512 schema = OctetString()
7514 class Seq(Sequence):
7516 ("oid", ObjectIdentifier(defines=((("tgt",), {
7524 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7526 with assertRaisesRegex(self, DecodeError, "remaining data"):
7527 Seq().decode(seq.encode())
7530 class TestAbsDecodePath(TestCase):
7532 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7533 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7535 def test_concat(self, decode_path, rel_path):
7536 dp = abs_decode_path(decode_path, rel_path)
7537 self.assertSequenceEqual(dp, decode_path + rel_path)
7541 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7542 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7544 def test_abs(self, decode_path, rel_path):
7545 self.assertSequenceEqual(
7546 abs_decode_path(decode_path, ("/",) + rel_path),
7551 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7552 integers(min_value=1, max_value=3),
7553 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7555 def test_dots(self, decode_path, number_of_dots, rel_path):
7556 self.assertSequenceEqual(
7557 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7558 decode_path[:-number_of_dots] + rel_path,
7562 class TestStrictDefaultExistence(TestCase):
7563 @given(data_strategy())
7564 def runTest(self, d):
7565 count = d.draw(integers(min_value=1, max_value=10))
7566 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7568 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7569 for i in range(count)
7571 for klass in (Sequence, Set):
7575 for i in range(count):
7576 seq["int%d" % i] = Integer(123)
7578 chosen_choice = "int%d" % chosen
7579 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7580 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7582 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7583 self.assertTrue(decoded.ber_encoded)
7584 self.assertTrue(decoded.bered)
7585 decoded = copy(decoded)
7586 self.assertTrue(decoded.ber_encoded)
7587 self.assertTrue(decoded.bered)
7588 decoded, _ = seq.decode(raw, ctx={"bered": True})
7589 self.assertTrue(decoded.ber_encoded)
7590 self.assertTrue(decoded.bered)
7591 decoded = copy(decoded)
7592 self.assertTrue(decoded.ber_encoded)
7593 self.assertTrue(decoded.bered)
7596 class TestX690PrefixedType(TestCase):
7598 self.assertSequenceEqual(
7599 VisibleString("Jones").encode(),
7600 hexdec("1A054A6F6E6573"),
7604 self.assertSequenceEqual(
7607 impl=tag_encode(3, klass=TagClassApplication),
7609 hexdec("43054A6F6E6573"),
7613 self.assertSequenceEqual(
7617 impl=tag_encode(3, klass=TagClassApplication),
7621 hexdec("A20743054A6F6E6573"),
7625 self.assertSequenceEqual(
7629 impl=tag_encode(3, klass=TagClassApplication),
7631 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7633 hexdec("670743054A6F6E6573"),
7637 self.assertSequenceEqual(
7638 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7639 hexdec("82054A6F6E6573"),
7643 class TestExplOOB(TestCase):
7645 expl = tag_ctxc(123)
7646 raw = Integer(123).encode() + Integer(234).encode()
7647 raw = b"".join((expl, len_encode(len(raw)), raw))
7648 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7649 Integer(expl=expl).decode(raw)
7650 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7653 class TestPickleDifferentVersion(TestCase):
7655 pickled = pickle_dumps(Integer(123), pickle_proto)
7657 version_orig = pyderasn.__version__
7658 pyderasn.__version__ += "different"
7659 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7660 pickle_loads(pickled)
7661 pyderasn.__version__ = version_orig
7662 pickle_loads(pickled)
7665 class TestCERSetOrdering(TestCase):
7666 def test_vectors(self):
7667 """Taken from X.690-201508
7671 ("c", Integer(impl=tag_ctxp(2))),
7672 ("d", Integer(impl=tag_ctxp(4))),
7677 ("g", Integer(impl=tag_ctxp(5))),
7678 ("h", Integer(impl=tag_ctxp(6))),
7683 ("j", Integer(impl=tag_ctxp(0))),
7694 ("a", Integer(impl=tag_ctxp(3))),
7695 ("b", B(expl=tag_ctxc(1))),
7700 ("a", Integer(123)),
7701 ("b", B(("d", Integer(234)))),
7702 ("e", E(("f", F(("g", Integer(345)))))),
7704 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7705 self.assertSequenceEqual(
7706 [i.__class__.__name__ for i in order],
7707 ("E", "B", "Integer"),