2 # PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
3 # Copyright (C) 2017-2022 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 io import BytesIO
24 from operator import attrgetter
25 from os import environ
26 from os import urandom
27 from random import random
28 from string import ascii_letters
29 from string import digits
30 from string import printable
31 from string import whitespace
32 from time import mktime
34 from unittest import TestCase
35 from unittest.mock import patch
37 from dateutil.tz import UTC
38 from hypothesis import assume
39 from hypothesis import given
40 from hypothesis import settings
41 from hypothesis.strategies import binary
42 from hypothesis.strategies import booleans
43 from hypothesis.strategies import composite
44 from hypothesis.strategies import data as data_strategy
45 from hypothesis.strategies import datetimes
46 from hypothesis.strategies import dictionaries
47 from hypothesis.strategies import integers
48 from hypothesis.strategies import just
49 from hypothesis.strategies import lists
50 from hypothesis.strategies import none
51 from hypothesis.strategies import one_of
52 from hypothesis.strategies import permutations
53 from hypothesis.strategies import sampled_from
54 from hypothesis.strategies import sets
55 from hypothesis.strategies import text
56 from hypothesis.strategies import tuples
57 from pickle import dumps as pickle_dumps
58 from pickle import HIGHEST_PROTOCOL as pickle_proto
59 from pickle import loads as pickle_loads
61 from pyderasn import _pp
62 from pyderasn import abs_decode_path
63 from pyderasn import Any
64 from pyderasn import BitString
65 from pyderasn import BMPString
66 from pyderasn import Boolean
67 from pyderasn import BoundsError
68 from pyderasn import Choice
69 from pyderasn import DecodeError
70 from pyderasn import DecodePathDefBy
71 from pyderasn import encode2pass
72 from pyderasn import encode_cer
73 from pyderasn import Enumerated
74 from pyderasn import EOC
75 from pyderasn import EOC_LEN
76 from pyderasn import ExceedingData
77 from pyderasn import GeneralizedTime
78 from pyderasn import GeneralString
79 from pyderasn import GraphicString
80 from pyderasn import hexdec
81 from pyderasn import hexenc
82 from pyderasn import IA5String
83 from pyderasn import Integer
84 from pyderasn import InvalidLength
85 from pyderasn import InvalidOID
86 from pyderasn import InvalidValueType
87 from pyderasn import len_decode
88 from pyderasn import len_encode
89 from pyderasn import LEN_YYMMDDHHMMSSZ
90 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
91 from pyderasn import LEN_YYYYMMDDHHMMSSZ
92 from pyderasn import LENINDEF
93 from pyderasn import LenIndefForm
94 from pyderasn import NotEnoughData
95 from pyderasn import Null
96 from pyderasn import NumericString
97 from pyderasn import ObjectIdentifier
98 from pyderasn import ObjNotReady
99 from pyderasn import ObjUnknown
100 from pyderasn import OctetString
101 from pyderasn import pp_console_row
102 from pyderasn import pprint
103 from pyderasn import PrintableString
104 from pyderasn import Sequence
105 from pyderasn import SequenceOf
106 from pyderasn import Set
107 from pyderasn import SetOf
108 from pyderasn import tag_ctxc
109 from pyderasn import tag_ctxp
110 from pyderasn import tag_decode
111 from pyderasn import tag_encode
112 from pyderasn import tag_strip
113 from pyderasn import TagClassApplication
114 from pyderasn import TagClassContext
115 from pyderasn import TagClassPrivate
116 from pyderasn import TagClassUniversal
117 from pyderasn import TagFormConstructed
118 from pyderasn import TagFormPrimitive
119 from pyderasn import TagMismatch
120 from pyderasn import TeletexString
121 from pyderasn import UniversalString
122 from pyderasn import UTCTime
123 from pyderasn import UTF8String
124 from pyderasn import VideotexString
125 from pyderasn import VisibleString
129 max_examples = environ.get("MAX_EXAMPLES")
130 settings.register_profile("local", settings(
132 **({"max_examples": int(max_examples)} if max_examples else {})
134 settings.load_profile("local")
135 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
137 tag_classes = sampled_from((
143 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
144 decode_path_strat = lists(integers(), max_size=3).map(
145 lambda decode_path: tuple(str(dp) for dp in decode_path)
147 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
150 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
152 self_module = import_module(__name__)
155 def register_class(klass):
156 klassname = klass.__name__ + str(time()).replace(".", "")
157 klass.__name__ = klassname
158 klass.__qualname__ = klassname
159 setattr(self_module, klassname, klass)
162 def assert_exceeding_data(self, call, junk):
165 with self.assertRaisesRegex(ExceedingData, "%d trailing bytes" % len(junk)) as err:
170 class TestHex(TestCase):
172 def test_symmetric(self, data):
173 self.assertEqual(hexdec(hexenc(data)), data)
176 class TestTagCoder(TestCase):
177 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
181 integers(min_value=0, max_value=30),
184 def test_short(self, klass, form, num, junk):
185 raw = tag_encode(klass=klass, form=form, num=num)
186 self.assertEqual(tag_decode(raw), (klass, form, num))
187 self.assertEqual(len(raw), 1)
189 tag_encode(klass=klass, form=form, num=0)[0],
190 raw[0] & (1 << 7 | 1 << 6 | 1 << 5),
192 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
193 self.assertSequenceEqual(stripped.tobytes(), raw)
194 self.assertEqual(tlen, len(raw))
195 self.assertSequenceEqual(tail, junk)
197 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
201 integers(min_value=31),
204 def test_long(self, klass, form, num, junk):
205 raw = tag_encode(klass=klass, form=form, num=num)
206 self.assertEqual(tag_decode(raw), (klass, form, num))
207 self.assertGreater(len(raw), 1)
209 tag_encode(klass=klass, form=form, num=0)[0] | 31,
212 self.assertEqual(raw[-1] & 0x80, 0)
213 self.assertTrue(all(b & 0x80 > 0 for b in raw[1:-1]))
214 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
215 self.assertSequenceEqual(stripped.tobytes(), raw)
216 self.assertEqual(tlen, len(raw))
217 self.assertSequenceEqual(tail, junk)
219 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
220 @given(integers(min_value=31))
221 def test_unfinished_tag(self, num):
222 raw = bytearray(tag_encode(num=num))
223 for i in range(1, len(raw)):
225 with self.assertRaisesRegex(DecodeError, "unfinished tag"):
226 tag_strip(bytes(raw))
228 def test_go_vectors_valid(self):
229 for data, (eklass, etag, elen, eform) in (
230 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
231 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
232 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
233 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
234 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
235 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
236 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
237 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
238 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
239 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
241 tag, _, len_encoded = tag_strip(memoryview(data))
242 klass, form, num = tag_decode(tag)
243 _len, _, tail = len_decode(len_encoded)
244 self.assertSequenceEqual(tail, b"")
245 self.assertEqual(klass, eklass)
246 self.assertEqual(num, etag)
247 self.assertEqual(_len, elen)
248 self.assertEqual(form, eform)
250 def test_go_vectors_invalid(self):
258 with self.assertRaises(DecodeError):
259 _, _, len_encoded = tag_strip(memoryview(data))
260 len_decode(len_encoded)
263 integers(min_value=0, max_value=127),
264 integers(min_value=0, max_value=2),
266 def test_long_instead_of_short(self, l, dummy_num):
267 octets = (b"\x00" * dummy_num) + bytes([l])
268 octets = bytes([(dummy_num + 1) | 0x80]) + octets
269 with self.assertRaises(DecodeError):
272 @given(tag_classes, tag_forms, integers(min_value=31))
273 def test_leading_zero_byte(self, klass, form, num):
274 raw = tag_encode(klass=klass, form=form, num=num)
275 raw = b"".join((raw[:1], b"\x80", raw[1:]))
276 with self.assertRaisesRegex(DecodeError, "leading zero byte"):
279 @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
280 def test_unexpected_long_form(self, klass, form, num):
281 raw = bytes([klass | form | 31, num])
282 with self.assertRaisesRegex(DecodeError, "unexpected long form"):
286 class TestLenCoder(TestCase):
287 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
289 integers(min_value=0, max_value=127),
292 def test_short(self, l, junk):
293 raw = len_encode(l) + junk
294 decoded, llen, tail = len_decode(memoryview(raw))
295 self.assertEqual(decoded, l)
296 self.assertEqual(llen, 1)
297 self.assertEqual(len(raw), 1 + len(junk))
298 self.assertEqual(tail.tobytes(), junk)
300 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
302 integers(min_value=128),
305 def test_long(self, l, junk):
306 raw = len_encode(l) + junk
307 decoded, llen, tail = len_decode(memoryview(raw))
308 self.assertEqual(decoded, l)
309 self.assertEqual((llen - 1) | 0x80, raw[0])
310 self.assertEqual(llen, len(raw) - len(junk))
311 self.assertNotEqual(raw[1], 0)
312 self.assertSequenceEqual(tail.tobytes(), junk)
314 def test_empty(self):
315 with self.assertRaises(NotEnoughData):
318 @given(integers(min_value=128))
319 def test_stripped(self, _len):
320 with self.assertRaises(NotEnoughData):
321 len_decode(len_encode(_len)[:-1])
324 text_printable = text(alphabet=printable, min_size=1)
328 def text_letters(draw):
329 result = draw(text(alphabet=ascii_letters, min_size=1))
333 class CommonMixin(object):
334 def test_tag_default(self):
335 obj = self.base_klass()
336 self.assertEqual(obj.tag, obj.tag_default)
338 def test_simultaneous_impl_expl(self):
339 with self.assertRaises(ValueError):
340 self.base_klass(impl=b"whatever", expl=b"whenever")
342 @given(binary(min_size=1), integers(), integers(), integers())
343 def test_decoded(self, impl, offset, llen, vlen):
344 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
345 self.assertEqual(obj.offset, offset)
346 self.assertEqual(obj.llen, llen)
347 self.assertEqual(obj.vlen, vlen)
348 self.assertEqual(obj.tlen, len(impl))
349 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
351 @given(binary(min_size=1))
352 def test_impl_inherited(self, impl_tag):
353 class Inherited(self.base_klass):
356 self.assertSequenceEqual(obj.impl, impl_tag)
357 self.assertFalse(obj.expled)
359 tag_class, _, tag_num = tag_decode(impl_tag)
360 self.assertEqual(obj.tag_order, (tag_class, tag_num))
362 @given(binary(min_size=1))
363 def test_expl_inherited(self, expl_tag):
364 class Inherited(self.base_klass):
367 self.assertSequenceEqual(obj.expl, expl_tag)
368 self.assertTrue(obj.expled)
370 tag_class, _, tag_num = tag_decode(expl_tag)
371 self.assertEqual(obj.tag_order, (tag_class, tag_num))
373 def assert_copied_basic_fields(self, obj, obj_copied):
374 self.assertEqual(obj, obj_copied)
375 self.assertSequenceEqual(obj.tag, obj_copied.tag)
376 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
377 self.assertEqual(obj.default, obj_copied.default)
378 self.assertEqual(obj.optional, obj_copied.optional)
379 self.assertEqual(obj.offset, obj_copied.offset)
380 self.assertEqual(obj.llen, obj_copied.llen)
381 self.assertEqual(obj.vlen, obj_copied.vlen)
383 self.assertEqual(obj.tag_order, obj_copied.tag_order)
387 def boolean_values_strategy(draw, do_expl=False):
388 value = draw(one_of(none(), booleans()))
392 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
394 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
395 default = draw(one_of(none(), booleans()))
396 optional = draw(one_of(none(), booleans()))
398 draw(integers(min_value=0)),
399 draw(integers(min_value=0)),
400 draw(integers(min_value=0)),
402 return (value, impl, expl, default, optional, _decoded)
405 class BooleanInherited(Boolean):
409 class TestBoolean(CommonMixin, TestCase):
412 def test_invalid_value_type(self):
413 with self.assertRaises(InvalidValueType) as err:
418 def test_optional(self, optional):
419 obj = Boolean(default=Boolean(False), optional=optional)
420 self.assertTrue(obj.optional)
423 def test_ready(self, value):
425 self.assertFalse(obj.ready)
428 pprint(obj, big_blobs=True, with_decode_path=True)
429 with self.assertRaises(ObjNotReady) as err:
431 with self.assertRaises(ObjNotReady) as err:
435 self.assertTrue(obj.ready)
438 pprint(obj, big_blobs=True, with_decode_path=True)
440 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
441 def test_comparison(self, value1, value2, tag1, tag2):
442 for klass in (Boolean, BooleanInherited):
445 self.assertEqual(obj1 == obj2, value1 == value2)
446 self.assertEqual(obj1 != obj2, value1 != value2)
447 self.assertEqual(obj1 == bool(obj2), value1 == value2)
448 obj1 = klass(value1, impl=tag1)
449 obj2 = klass(value1, impl=tag2)
450 self.assertEqual(obj1 == obj2, tag1 == tag2)
451 self.assertEqual(obj1 != obj2, tag1 != tag2)
453 @given(data_strategy())
454 def test_call(self, d):
455 for klass in (Boolean, BooleanInherited):
463 ) = d.draw(boolean_values_strategy())
469 optional_initial or False,
479 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
480 obj = obj_initial(value, impl, expl, default, optional)
482 value_expected = default if value is None else value
484 default_initial if value_expected is None
487 self.assertEqual(obj, value_expected)
488 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
489 self.assertEqual(obj.expl_tag, expl or expl_initial)
492 default_initial if default is None else default,
494 if obj.default is None:
495 optional = optional_initial if optional is None else optional
496 optional = False if optional is None else optional
499 self.assertEqual(obj.optional, optional)
501 @given(boolean_values_strategy())
502 def test_copy(self, values):
503 for klass in (Boolean, BooleanInherited):
505 for copy_func in copy_funcs:
506 obj_copied = copy_func(obj)
507 self.assert_copied_basic_fields(obj, obj_copied)
511 integers(min_value=1).map(tag_encode),
513 def test_stripped(self, value, tag_impl):
514 obj = Boolean(value, impl=tag_impl)
515 with self.assertRaises(NotEnoughData):
516 obj.decode(obj.encode()[:-1])
517 with self.assertRaises(NotEnoughData):
518 obj.decode(encode2pass(obj)[:-1])
522 integers(min_value=1).map(tag_ctxc),
524 def test_stripped_expl(self, value, tag_expl):
525 obj = Boolean(value, expl=tag_expl)
526 with self.assertRaises(NotEnoughData):
527 obj.decode(obj.encode()[:-1])
528 with self.assertRaises(NotEnoughData):
529 obj.decode(encode2pass(obj)[:-1])
532 integers(min_value=31),
533 integers(min_value=0),
536 def test_bad_tag(self, tag, offset, decode_path):
537 with self.assertRaises(DecodeError) as err:
539 tag_encode(tag)[:-1],
541 decode_path=decode_path,
544 self.assertEqual(err.exception.offset, offset)
545 self.assertEqual(err.exception.decode_path, decode_path)
548 integers(min_value=31),
549 integers(min_value=0),
552 def test_bad_expl_tag(self, tag, offset, decode_path):
553 with self.assertRaises(DecodeError) as err:
554 Boolean(expl=Boolean.tag_default).decode(
555 tag_encode(tag)[:-1],
557 decode_path=decode_path,
560 self.assertEqual(err.exception.offset, offset)
561 self.assertEqual(err.exception.decode_path, decode_path)
564 integers(min_value=128),
565 integers(min_value=0),
568 def test_bad_len(self, l, offset, decode_path):
569 with self.assertRaises(DecodeError) as err:
571 Boolean.tag_default + len_encode(l)[:-1],
573 decode_path=decode_path,
576 self.assertEqual(err.exception.offset, offset)
577 self.assertEqual(err.exception.decode_path, decode_path)
580 integers(min_value=128),
581 integers(min_value=0),
584 def test_bad_expl_len(self, l, offset, decode_path):
585 with self.assertRaises(DecodeError) as err:
586 Boolean(expl=Boolean.tag_default).decode(
587 Boolean.tag_default + len_encode(l)[:-1],
589 decode_path=decode_path,
592 self.assertEqual(err.exception.offset, offset)
593 self.assertEqual(err.exception.decode_path, decode_path)
595 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
597 boolean_values_strategy(),
599 integers(min_value=1).map(tag_ctxc),
600 integers(min_value=0),
604 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
605 for klass in (Boolean, BooleanInherited):
606 _, _, _, default, optional, _decoded = values
615 pprint(obj, big_blobs=True, with_decode_path=True)
616 self.assertFalse(obj.expled)
617 obj_encoded = obj.encode()
618 self.assertEqual(encode2pass(obj), obj_encoded)
619 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
620 obj_expled = obj(value, expl=tag_expl)
621 self.assertTrue(obj_expled.expled)
623 list(obj_expled.pps())
624 pprint(obj_expled, big_blobs=True, with_decode_path=True)
625 obj_expled_cer = encode_cer(obj_expled)
626 self.assertNotEqual(obj_expled_cer, obj_encoded)
627 self.assertSequenceEqual(
628 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
631 obj_expled_hex_encoded = obj_expled.hexencode()
632 ctx_copied = deepcopy(ctx_dummy)
633 obj_decoded, tail = obj_expled.hexdecode(
634 obj_expled_hex_encoded + hexenc(tail_junk),
638 self.assertDictEqual(ctx_copied, ctx_dummy)
640 list(obj_decoded.pps())
641 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
642 self.assertEqual(tail, tail_junk)
643 self.assertEqual(obj_decoded, obj_expled)
644 self.assertNotEqual(obj_decoded, obj)
645 self.assertEqual(bool(obj_decoded), bool(obj_expled))
646 self.assertEqual(bool(obj_decoded), bool(obj))
647 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
648 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
649 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
651 obj_decoded.expl_llen,
652 len(len_encode(len(obj_encoded))),
654 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
655 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
658 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
660 self.assertEqual(obj_decoded.expl_offset, offset)
661 assert_exceeding_data(
663 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
667 evgens = list(obj_expled.decode_evgen(
668 hexdec(obj_expled_hex_encoded) + tail_junk,
670 decode_path=decode_path,
673 self.assertEqual(len(evgens), 1)
674 _decode_path, obj, tail = evgens[0]
675 self.assertSequenceEqual(tail, tail_junk)
676 self.assertEqual(_decode_path, decode_path)
677 self.assertEqual(obj, obj_decoded)
678 self.assertEqual(obj.expl_offset, offset)
682 @given(integers(min_value=2, max_value=10))
683 def test_invalid_len(self, l):
684 with self.assertRaises(InvalidLength):
685 Boolean().decode(b"".join((
691 @given(integers(min_value=0 + 1, max_value=255 - 1))
692 def test_ber_value(self, value):
693 with self.assertRaisesRegex(DecodeError, "unacceptable Boolean value"):
694 Boolean().decode(b"".join((
699 encoded = b"".join((Boolean.tag_default, len_encode(1), bytes([value])))
700 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
701 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
702 self.assertTrue(bool(obj))
703 self.assertTrue(obj.ber_encoded)
704 self.assertFalse(obj.lenindef)
705 self.assertTrue(obj.bered)
707 self.assertTrue(obj.ber_encoded)
708 self.assertFalse(obj.lenindef)
709 self.assertTrue(obj.bered)
712 integers(min_value=1).map(tag_ctxc),
713 binary().filter(lambda x: not x.startswith(EOC)),
715 def test_ber_expl_no_eoc(self, expl, junk):
716 encoded = expl + LENINDEF + Boolean(False).encode()
717 with self.assertRaises(LenIndefForm):
718 Boolean(expl=expl).decode(encoded + junk)
719 with self.assertRaisesRegex(DecodeError, "no EOC"):
720 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
721 obj, tail = Boolean(expl=expl).decode(
722 encoded + EOC + junk,
725 self.assertTrue(obj.expl_lenindef)
726 self.assertFalse(obj.lenindef)
727 self.assertFalse(obj.ber_encoded)
728 self.assertTrue(obj.bered)
730 self.assertTrue(obj.expl_lenindef)
731 self.assertFalse(obj.lenindef)
732 self.assertFalse(obj.ber_encoded)
733 self.assertTrue(obj.bered)
734 self.assertSequenceEqual(tail, junk)
737 pprint(obj, big_blobs=True, with_decode_path=True)
740 integers(min_value=1).map(tag_ctxc),
747 def test_ber_expl(self, expl, values):
753 Boolean(value).encode() +
756 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
758 class SeqOf(SequenceOf):
759 schema = Boolean(expl=expl)
760 with self.assertRaises(LenIndefForm):
761 SeqOf().decode(encoded)
762 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
763 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
764 self.assertSequenceEqual(tail, b"")
765 self.assertSequenceEqual([bool(v) for v in seqof], values)
781 len(expl) + 1 + 3 + EOC_LEN,
792 pprint(seqof, big_blobs=True, with_decode_path=True)
796 def integer_values_strategy(draw, do_expl=False):
797 bound_min, value, default, bound_max = sorted(draw(sets(
806 _specs = draw(sets(text_letters()))
809 min_size=len(_specs),
810 max_size=len(_specs),
812 _specs = list(zip(_specs, values))
815 bounds = (bound_min, bound_max)
819 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
821 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
824 optional = draw(one_of(none(), booleans()))
826 draw(integers(min_value=0)),
827 draw(integers(min_value=0)),
828 draw(integers(min_value=0)),
830 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
833 class IntegerInherited(Integer):
837 class TestInteger(CommonMixin, TestCase):
840 def test_invalid_value_type(self):
841 with self.assertRaises(InvalidValueType) as err:
845 @given(sets(text_letters(), min_size=2))
846 def test_unknown_name(self, names_input):
847 missing = names_input.pop()
850 schema = [(n, 123) for n in names_input]
851 with self.assertRaises(ObjUnknown) as err:
855 @given(sets(text_letters(), min_size=2))
856 def test_known_name(self, names_input):
858 schema = [(n, 123) for n in names_input]
859 Int(names_input.pop())
862 def test_optional(self, optional):
863 obj = Integer(default=Integer(0), optional=optional)
864 self.assertTrue(obj.optional)
867 def test_ready(self, value):
869 self.assertFalse(obj.ready)
872 pprint(obj, big_blobs=True, with_decode_path=True)
873 with self.assertRaises(ObjNotReady) as err:
875 with self.assertRaises(ObjNotReady) as err:
879 self.assertTrue(obj.ready)
882 pprint(obj, big_blobs=True, with_decode_path=True)
885 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
886 def test_comparison(self, value1, value2, tag1, tag2):
887 for klass in (Integer, IntegerInherited):
890 self.assertEqual(obj1 == obj2, value1 == value2)
891 self.assertEqual(obj1 != obj2, value1 != value2)
892 self.assertEqual(obj1 == int(obj2), value1 == value2)
893 obj1 = klass(value1, impl=tag1)
894 obj2 = klass(value1, impl=tag2)
895 self.assertEqual(obj1 == obj2, tag1 == tag2)
896 self.assertEqual(obj1 != obj2, tag1 != tag2)
898 @given(lists(integers()))
899 def test_sorted_works(self, values):
900 self.assertSequenceEqual(
901 [int(v) for v in sorted(Integer(v) for v in values)],
905 @given(data_strategy())
906 def test_named(self, d):
907 names_input = list(d.draw(sets(text_letters(), min_size=1)))
908 values_input = list(d.draw(sets(
910 min_size=len(names_input),
911 max_size=len(names_input),
913 chosen_name = d.draw(sampled_from(names_input))
914 names_input = dict(zip(names_input, values_input))
918 _int = Int(chosen_name)
919 self.assertEqual(_int.named, chosen_name)
920 self.assertEqual(int(_int), names_input[chosen_name])
922 @given(integers(), integers(min_value=0), integers(min_value=0))
923 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
924 value = bound_min + value_delta
925 bound_max = value + bound_delta
926 Integer(value=value, bounds=(bound_min, bound_max))
928 @given(sets(integers(), min_size=3, max_size=3))
929 def test_bounds_unsatisfied(self, values):
930 values = sorted(values)
931 with self.assertRaises(BoundsError) as err:
932 Integer(value=values[0], bounds=(values[1], values[2]))
934 with self.assertRaisesRegex(DecodeError, "bounds") as err:
935 Integer(bounds=(values[1], values[2])).decode(
936 Integer(values[0]).encode()
939 with self.assertRaisesRegex(DecodeError, "bounds") as err:
940 Integer(bounds=(values[1], values[2])).decode(
941 encode2pass(Integer(values[0]))
943 with self.assertRaises(BoundsError) as err:
944 Integer(value=values[2], bounds=(values[0], values[1]))
946 with self.assertRaisesRegex(DecodeError, "bounds") as err:
947 Integer(bounds=(values[0], values[1])).decode(
948 Integer(values[2]).encode()
951 with self.assertRaisesRegex(DecodeError, "bounds") as err:
952 Integer(bounds=(values[0], values[1])).decode(
953 encode2pass(Integer(values[2]))
956 @given(data_strategy())
957 def test_call(self, d):
958 for klass in (Integer, IntegerInherited):
968 ) = d.draw(integer_values_strategy())
975 optional_initial or False,
988 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
989 if (default is None) and (obj_initial.default is not None):
993 (value is not None) and
994 (bounds_initial is not None) and
995 not (bounds_initial[0] <= value <= bounds_initial[1])
1000 (default is not None) and
1001 (bounds_initial is not None) and
1002 not (bounds_initial[0] <= default <= bounds_initial[1])
1005 obj = obj_initial(value, bounds, impl, expl, default, optional)
1007 value_expected = default if value is None else value
1009 default_initial if value_expected is None
1012 self.assertEqual(obj, value_expected)
1013 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1014 self.assertEqual(obj.expl_tag, expl or expl_initial)
1017 default_initial if default is None else default,
1019 if obj.default is None:
1020 optional = optional_initial if optional is None else optional
1021 optional = False if optional is None else optional
1024 self.assertEqual(obj.optional, optional)
1026 (obj._bound_min, obj._bound_max),
1027 bounds or bounds_initial or (float("-inf"), float("+inf")),
1031 {} if _specs_initial is None else dict(_specs_initial),
1034 @given(integer_values_strategy())
1035 def test_copy(self, values):
1036 for klass in (Integer, IntegerInherited):
1037 obj = klass(*values)
1038 for copy_func in copy_funcs:
1039 obj_copied = copy_func(obj)
1040 self.assert_copied_basic_fields(obj, obj_copied)
1041 self.assertEqual(obj.specs, obj_copied.specs)
1042 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1043 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1044 self.assertEqual(obj._value, obj_copied._value)
1048 integers(min_value=1).map(tag_encode),
1050 def test_stripped(self, value, tag_impl):
1051 obj = Integer(value, impl=tag_impl)
1052 with self.assertRaises(NotEnoughData):
1053 obj.decode(obj.encode()[:-1])
1057 integers(min_value=1).map(tag_ctxc),
1059 def test_stripped_expl(self, value, tag_expl):
1060 obj = Integer(value, expl=tag_expl)
1061 with self.assertRaises(NotEnoughData):
1062 obj.decode(obj.encode()[:-1])
1064 def test_zero_len(self):
1065 with self.assertRaises(NotEnoughData):
1066 Integer().decode(b"".join((
1067 Integer.tag_default,
1072 integers(min_value=31),
1073 integers(min_value=0),
1076 def test_bad_tag(self, tag, offset, decode_path):
1077 with self.assertRaises(DecodeError) as err:
1079 tag_encode(tag)[:-1],
1081 decode_path=decode_path,
1084 self.assertEqual(err.exception.offset, offset)
1085 self.assertEqual(err.exception.decode_path, decode_path)
1088 integers(min_value=128),
1089 integers(min_value=0),
1092 def test_bad_len(self, l, offset, decode_path):
1093 with self.assertRaises(DecodeError) as err:
1095 Integer.tag_default + len_encode(l)[:-1],
1097 decode_path=decode_path,
1100 self.assertEqual(err.exception.offset, offset)
1101 self.assertEqual(err.exception.decode_path, decode_path)
1104 sets(integers(), min_size=2, max_size=2),
1105 integers(min_value=0),
1108 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1109 value, bound_min = list(sorted(ints))
1112 bounds = (bound_min, bound_min)
1113 with self.assertRaises(DecodeError) as err:
1115 Integer(value).encode(),
1117 decode_path=decode_path,
1120 self.assertEqual(err.exception.offset, offset)
1121 self.assertEqual(err.exception.decode_path, decode_path)
1123 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1125 integer_values_strategy(),
1127 integers(min_value=1).map(tag_ctxc),
1128 integers(min_value=0),
1132 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1133 for klass in (Integer, IntegerInherited):
1134 _, _, _, _, default, optional, _, _decoded = values
1143 pprint(obj, big_blobs=True, with_decode_path=True)
1144 self.assertFalse(obj.expled)
1145 obj_encoded = obj.encode()
1146 self.assertEqual(encode2pass(obj), obj_encoded)
1147 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1148 obj_expled = obj(value, expl=tag_expl)
1149 self.assertTrue(obj_expled.expled)
1151 list(obj_expled.pps())
1152 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1153 obj_expled_encoded = obj_expled.encode()
1154 obj_expled_cer = encode_cer(obj_expled)
1155 self.assertNotEqual(obj_expled_cer, obj_encoded)
1156 self.assertSequenceEqual(
1157 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1160 ctx_copied = deepcopy(ctx_dummy)
1161 obj_decoded, tail = obj_expled.decode(
1162 obj_expled_encoded + tail_junk,
1166 self.assertDictEqual(ctx_copied, ctx_dummy)
1168 list(obj_decoded.pps())
1169 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1170 self.assertEqual(tail, tail_junk)
1171 self.assertEqual(obj_decoded, obj_expled)
1172 self.assertNotEqual(obj_decoded, obj)
1173 self.assertEqual(int(obj_decoded), int(obj_expled))
1174 self.assertEqual(int(obj_decoded), int(obj))
1175 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1176 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1177 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1179 obj_decoded.expl_llen,
1180 len(len_encode(len(obj_encoded))),
1182 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1183 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1186 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1188 self.assertEqual(obj_decoded.expl_offset, offset)
1189 assert_exceeding_data(
1191 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1195 evgens = list(obj_expled.decode_evgen(
1196 obj_expled_encoded + tail_junk,
1198 decode_path=decode_path,
1201 self.assertEqual(len(evgens), 1)
1202 _decode_path, obj, tail = evgens[0]
1203 self.assertSequenceEqual(tail, tail_junk)
1204 self.assertEqual(_decode_path, decode_path)
1205 self.assertEqual(obj, obj_decoded)
1206 self.assertEqual(obj.expl_offset, offset)
1210 def test_go_vectors_valid(self):
1211 for data, expect in ((
1215 (b"\xff\x7f", -129),
1219 (b"\xff\x00", -256),
1223 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1224 (b"\x80\x00\x00\x00", -2147483648),
1227 Integer().decode(b"".join((
1228 Integer.tag_default,
1229 len_encode(len(data)),
1235 def test_go_vectors_invalid(self):
1240 with self.assertRaises(DecodeError):
1241 Integer().decode(b"".join((
1242 Integer.tag_default,
1243 len_encode(len(data)),
1249 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1252 if draw(booleans()):
1253 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1255 integers(min_value=0, max_value=255),
1256 min_size=len(schema),
1257 max_size=len(schema),
1259 schema = list(zip(schema, bits))
1261 def _value(value_required):
1262 if not value_required and draw(booleans()):
1264 generation_choice = 0
1266 generation_choice = draw(sampled_from((1, 2, 3)))
1267 if generation_choice == 1 or draw(booleans()):
1268 return "'%s'B" % "".join(draw(lists(
1269 sampled_from(("0", "1")),
1270 max_size=len(schema),
1272 if generation_choice == 2 or draw(booleans()):
1273 return draw(binary(max_size=len(schema) // 8))
1274 if generation_choice == 3 or draw(booleans()):
1275 if len(schema) == 0:
1277 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1279 value = _value(value_required)
1280 default = _value(value_required=False)
1284 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1286 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1287 optional = draw(one_of(none(), booleans()))
1289 draw(integers(min_value=0)),
1290 draw(integers(min_value=0)),
1291 draw(integers(min_value=0)),
1293 return (schema, value, impl, expl, default, optional, _decoded)
1296 class BitStringInherited(BitString):
1300 class TestBitString(CommonMixin, TestCase):
1301 base_klass = BitString
1303 @given(lists(booleans()))
1304 def test_b_encoding(self, bits):
1305 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1306 self.assertEqual(obj.bit_len, len(bits))
1307 self.assertSequenceEqual(list(obj), bits)
1308 for i, bit in enumerate(bits):
1309 self.assertEqual(obj[i], bit)
1311 @given(lists(booleans()))
1312 def test_out_of_bounds_bits(self, bits):
1313 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1314 for i in range(len(bits), len(bits) * 2):
1315 self.assertFalse(obj[i])
1317 def test_bad_b_encoding(self):
1318 with self.assertRaises(ValueError):
1319 BitString("'010120101'B")
1322 integers(min_value=1, max_value=255),
1323 integers(min_value=1, max_value=255),
1325 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1326 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1327 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1328 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1330 class BS(BitString):
1331 schema = (("whatever", 0),)
1332 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1333 self.assertEqual(obj.bit_len, leading_zeros + 1)
1334 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1336 def test_zero_len(self):
1337 with self.assertRaises(NotEnoughData):
1338 BitString().decode(b"".join((
1339 BitString.tag_default,
1343 def test_invalid_value_type(self):
1344 with self.assertRaises(InvalidValueType) as err:
1347 with self.assertRaises(InvalidValueType) as err:
1351 def test_obj_unknown(self):
1352 with self.assertRaises(ObjUnknown) as err:
1353 BitString(b"whatever")["whenever"]
1356 def test_get_invalid_type(self):
1357 with self.assertRaises(InvalidValueType) as err:
1358 BitString(b"whatever")[(1, 2, 3)]
1361 @given(data_strategy())
1362 def test_unknown_name(self, d):
1363 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1364 missing = _schema.pop()
1366 class BS(BitString):
1367 schema = [(n, i) for i, n in enumerate(_schema)]
1368 with self.assertRaises(ObjUnknown) as err:
1373 def test_optional(self, optional):
1374 obj = BitString(default=BitString(b""), optional=optional)
1375 self.assertTrue(obj.optional)
1378 def test_ready(self, value):
1380 self.assertFalse(obj.ready)
1383 pprint(obj, big_blobs=True, with_decode_path=True)
1384 with self.assertRaises(ObjNotReady) as err:
1387 with self.assertRaises(ObjNotReady) as err:
1389 obj = BitString(value)
1390 self.assertTrue(obj.ready)
1393 pprint(obj, big_blobs=True, with_decode_path=True)
1396 tuples(integers(min_value=0), binary()),
1397 tuples(integers(min_value=0), binary()),
1401 def test_comparison(self, value1, value2, tag1, tag2):
1402 for klass in (BitString, BitStringInherited):
1403 obj1 = klass(value1)
1404 obj2 = klass(value2)
1405 self.assertEqual(obj1 == obj2, value1 == value2)
1406 self.assertEqual(obj1 != obj2, value1 != value2)
1407 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1408 obj1 = klass(value1, impl=tag1)
1409 obj2 = klass(value1, impl=tag2)
1410 self.assertEqual(obj1 == obj2, tag1 == tag2)
1411 self.assertEqual(obj1 != obj2, tag1 != tag2)
1413 @given(data_strategy())
1414 def test_call(self, d):
1415 for klass in (BitString, BitStringInherited):
1424 ) = d.draw(bit_string_values_strategy())
1427 schema = schema_initial
1429 value=value_initial,
1432 default=default_initial,
1433 optional=optional_initial or False,
1434 _decoded=_decoded_initial,
1444 ) = d.draw(bit_string_values_strategy(
1445 schema=schema_initial,
1446 do_expl=impl_initial is None,
1455 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1456 self.assertEqual(obj.expl_tag, expl or expl_initial)
1457 if obj.default is None:
1458 optional = optional_initial if optional is None else optional
1459 optional = False if optional is None else optional
1462 self.assertEqual(obj.optional, optional)
1463 self.assertEqual(obj.specs, obj_initial.specs)
1465 @given(bit_string_values_strategy())
1466 def test_copy(self, values):
1467 for klass in (BitString, BitStringInherited):
1468 _schema, value, impl, expl, default, optional, _decoded = values
1478 optional=optional or False,
1481 for copy_func in copy_funcs:
1482 obj_copied = copy_func(obj)
1483 self.assert_copied_basic_fields(obj, obj_copied)
1484 self.assertEqual(obj.specs, obj_copied.specs)
1485 self.assertEqual(obj._value, obj_copied._value)
1489 integers(min_value=1).map(tag_encode),
1491 def test_stripped(self, value, tag_impl):
1492 obj = BitString(value, impl=tag_impl)
1493 with self.assertRaises(NotEnoughData):
1494 obj.decode(obj.encode()[:-1])
1498 integers(min_value=1).map(tag_ctxc),
1500 def test_stripped_expl(self, value, tag_expl):
1501 obj = BitString(value, expl=tag_expl)
1502 with self.assertRaises(NotEnoughData):
1503 obj.decode(obj.encode()[:-1])
1506 integers(min_value=31),
1507 integers(min_value=0),
1510 def test_bad_tag(self, tag, offset, decode_path):
1511 with self.assertRaises(DecodeError) as err:
1513 tag_encode(tag)[:-1],
1515 decode_path=decode_path,
1518 self.assertEqual(err.exception.offset, offset)
1519 self.assertEqual(err.exception.decode_path, decode_path)
1522 integers(min_value=128),
1523 integers(min_value=0),
1526 def test_bad_len(self, l, offset, decode_path):
1527 with self.assertRaises(DecodeError) as err:
1529 BitString.tag_default + len_encode(l)[:-1],
1531 decode_path=decode_path,
1534 self.assertEqual(err.exception.offset, offset)
1535 self.assertEqual(err.exception.decode_path, decode_path)
1537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1538 @given(data_strategy())
1539 def test_symmetric(self, d):
1548 ) = d.draw(bit_string_values_strategy(value_required=True))
1549 tail_junk = d.draw(binary(max_size=5))
1550 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1551 offset = d.draw(integers(min_value=0))
1552 decode_path = d.draw(decode_path_strat)
1553 for klass in (BitString, BitStringInherited):
1564 pprint(obj, big_blobs=True, with_decode_path=True)
1565 self.assertFalse(obj.expled)
1566 obj_encoded = obj.encode()
1567 self.assertEqual(encode2pass(obj), obj_encoded)
1568 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1569 obj_expled = obj(value, expl=tag_expl)
1570 self.assertTrue(obj_expled.expled)
1572 list(obj_expled.pps())
1573 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1574 obj_expled_encoded = obj_expled.encode()
1575 obj_expled_cer = encode_cer(obj_expled)
1576 self.assertNotEqual(obj_expled_cer, obj_encoded)
1577 self.assertSequenceEqual(
1578 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1581 ctx_copied = deepcopy(ctx_dummy)
1582 obj_decoded, tail = obj_expled.decode(
1583 obj_expled_encoded + tail_junk,
1587 self.assertDictEqual(ctx_copied, ctx_dummy)
1589 list(obj_decoded.pps())
1590 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1591 self.assertEqual(tail, tail_junk)
1592 self.assertEqual(obj_decoded, obj_expled)
1593 self.assertNotEqual(obj_decoded, obj)
1594 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1595 self.assertEqual(bytes(obj_decoded), bytes(obj))
1596 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1597 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1598 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1600 obj_decoded.expl_llen,
1601 len(len_encode(len(obj_encoded))),
1603 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1604 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1607 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1609 self.assertEqual(obj_decoded.expl_offset, offset)
1610 if isinstance(value, tuple):
1611 self.assertSetEqual(set(value), set(obj_decoded.named))
1614 assert_exceeding_data(
1616 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1620 evgens = list(obj_expled.decode_evgen(
1621 obj_expled_encoded + tail_junk,
1623 decode_path=decode_path,
1626 self.assertEqual(len(evgens), 1)
1627 _decode_path, obj, tail = evgens[0]
1628 self.assertSequenceEqual(tail, tail_junk)
1629 self.assertEqual(_decode_path, decode_path)
1630 self.assertEqual(obj.expl_offset, offset)
1634 @given(integers(min_value=1, max_value=255))
1635 def test_bad_zero_value(self, pad_size):
1636 with self.assertRaises(DecodeError):
1637 BitString().decode(b"".join((
1638 BitString.tag_default,
1643 def test_go_vectors_invalid(self):
1649 with self.assertRaises(DecodeError):
1650 BitString().decode(b"".join((
1651 BitString.tag_default,
1656 def test_go_vectors_valid(self):
1657 obj, _ = BitString().decode(b"".join((
1658 BitString.tag_default,
1662 self.assertEqual(bytes(obj), b"")
1663 self.assertEqual(obj.bit_len, 0)
1665 obj, _ = BitString().decode(b"".join((
1666 BitString.tag_default,
1670 self.assertEqual(bytes(obj), b"\x00")
1671 self.assertEqual(obj.bit_len, 1)
1673 obj = BitString((16, b"\x82\x40"))
1674 self.assertTrue(obj[0])
1675 self.assertFalse(obj[1])
1676 self.assertTrue(obj[6])
1677 self.assertTrue(obj[9])
1678 self.assertFalse(obj[17])
1680 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1682 integers(min_value=1, max_value=30),
1685 binary(min_size=1, max_size=5),
1687 binary(min_size=1, max_size=5),
1695 lists(booleans(), min_size=1),
1699 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1700 def chunk_constructed(contents):
1702 tag_encode(form=TagFormConstructed, num=3) +
1704 b"".join(BitString(content).encode() for content in contents) +
1708 chunks_len_expected = []
1709 payload_expected = b""
1710 bit_len_expected = 0
1711 for chunk_input in chunk_inputs:
1712 if isinstance(chunk_input, bytes):
1713 chunks.append(BitString(chunk_input).encode())
1714 payload_expected += chunk_input
1715 bit_len_expected += len(chunk_input) * 8
1716 chunks_len_expected.append(len(chunk_input) + 1)
1718 chunks.append(chunk_constructed(chunk_input))
1719 payload = b"".join(chunk_input)
1720 payload_expected += payload
1721 bit_len_expected += len(payload) * 8
1722 for c in chunk_input:
1723 chunks_len_expected.append(len(c) + 1)
1724 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1725 chunk_last = BitString("'%s'B" % "".join(
1726 "1" if bit else "0" for bit in chunk_last_bits
1728 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1729 payload_expected += bytes(chunk_last)
1730 bit_len_expected += chunk_last.bit_len
1731 encoded_indefinite = (
1732 tag_encode(form=TagFormConstructed, num=impl) +
1735 chunk_last.encode() +
1738 encoded_definite = (
1739 tag_encode(form=TagFormConstructed, num=impl) +
1740 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1744 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
1745 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1746 for lenindef_expected, encoded in (
1747 (True, encoded_indefinite),
1748 (False, encoded_definite),
1750 obj, tail = BitString(impl=tag_encode(impl)).decode(
1752 ctx={"bered": True},
1754 self.assertSequenceEqual(tail, junk)
1755 self.assertEqual(obj.bit_len, bit_len_expected)
1756 self.assertSequenceEqual(bytes(obj), payload_expected)
1757 self.assertTrue(obj.ber_encoded)
1758 self.assertEqual(obj.lenindef, lenindef_expected)
1759 self.assertTrue(obj.bered)
1761 self.assertTrue(obj.ber_encoded)
1762 self.assertEqual(obj.lenindef, lenindef_expected)
1763 self.assertTrue(obj.bered)
1764 self.assertEqual(len(encoded), obj.tlvlen)
1767 pprint(obj, big_blobs=True, with_decode_path=True)
1769 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1771 decode_path=decode_path,
1772 ctx={"bered": True},
1774 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1775 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1776 self.assertGreater(len(dp), len(decode_path))
1777 self.assertEqual(obj.vlen, chunk_len_expected)
1780 integers(min_value=0),
1783 def test_ber_definite_too_short(self, offset, decode_path):
1784 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
1786 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1788 decode_path=decode_path,
1789 ctx={"bered": True},
1791 self.assertEqual(err.exception.decode_path, decode_path)
1792 self.assertEqual(err.exception.offset, offset)
1795 integers(min_value=0),
1798 def test_ber_definite_no_data(self, offset, decode_path):
1799 with self.assertRaisesRegex(DecodeError, "zero length") as err:
1801 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1803 decode_path=decode_path,
1804 ctx={"bered": True},
1806 self.assertEqual(err.exception.decode_path, decode_path)
1807 self.assertEqual(err.exception.offset, offset)
1810 integers(min_value=0),
1812 integers(min_value=1, max_value=3),
1814 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1815 bs = BitString(b"data").encode()
1816 with self.assertRaises(NotEnoughData) as err:
1818 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1820 decode_path=decode_path,
1821 ctx={"bered": True},
1823 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1824 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1827 integers(min_value=0),
1829 integers(min_value=1, max_value=3),
1831 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1832 bs = BitString(b"data").encode()
1833 bs_longer = BitString(b"data-longer").encode()
1834 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
1837 tag_encode(3, form=TagFormConstructed) +
1838 len_encode((chunks + 1) * len(bs)) +
1843 decode_path=decode_path,
1844 ctx={"bered": True},
1846 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1847 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1850 integers(min_value=0),
1853 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1854 with self.assertRaisesRegex(DecodeError, "no chunks") as err:
1856 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1858 decode_path=decode_path,
1859 ctx={"bered": True},
1861 self.assertEqual(err.exception.decode_path, decode_path)
1862 self.assertEqual(err.exception.offset, offset)
1864 @given(data_strategy())
1865 def test_ber_indefinite_not_multiple(self, d):
1866 bs_short = BitString("'A'H").encode()
1867 bs_full = BitString("'AA'H").encode()
1868 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1869 chunks.append(bs_short)
1870 d.draw(permutations(chunks))
1871 chunks.append(bs_short)
1872 offset = d.draw(integers(min_value=0))
1873 decode_path = d.draw(decode_path_strat)
1874 with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
1877 tag_encode(3, form=TagFormConstructed) +
1883 decode_path=decode_path,
1884 ctx={"bered": True},
1887 err.exception.decode_path,
1888 decode_path + (str(chunks.index(bs_short)),),
1891 err.exception.offset,
1892 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1895 def test_x690_vector(self):
1896 vector = BitString("'0A3B5F291CD'H")
1897 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1898 self.assertSequenceEqual(tail, b"")
1899 self.assertEqual(obj, vector)
1900 obj, tail = BitString().decode(
1901 hexdec("23800303000A3B0305045F291CD00000"),
1902 ctx={"bered": True},
1904 self.assertSequenceEqual(tail, b"")
1905 self.assertEqual(obj, vector)
1906 self.assertTrue(obj.ber_encoded)
1907 self.assertTrue(obj.lenindef)
1908 self.assertTrue(obj.bered)
1910 self.assertTrue(obj.ber_encoded)
1911 self.assertTrue(obj.lenindef)
1912 self.assertTrue(obj.bered)
1914 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1915 @given(integers(min_value=1000, max_value=3000))
1916 def test_cer(self, data_len):
1917 data = urandom(data_len)
1918 encoded = encode_cer(BitString(data))
1919 ctx = {"bered": True}
1920 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1921 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1922 evgens_expected = data_len // 999
1923 if evgens_expected * 999 != data_len:
1924 evgens_expected += 1
1925 evgens_expected += 1
1926 self.assertEqual(len(evgens), evgens_expected)
1927 for (_, obj, _) in evgens[:-2]:
1928 self.assertEqual(obj.vlen, 1000)
1929 _, obj, _ = evgens[-2]
1930 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1934 def octet_string_values_strategy(draw, do_expl=False):
1935 bound_min, bound_max = sorted(draw(sets(
1936 integers(min_value=0, max_value=1 << 7),
1940 value = draw(one_of(
1942 binary(min_size=bound_min, max_size=bound_max),
1944 default = draw(one_of(
1946 binary(min_size=bound_min, max_size=bound_max),
1949 if draw(booleans()):
1950 bounds = (bound_min, bound_max)
1954 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1956 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1957 optional = draw(one_of(none(), booleans()))
1959 draw(integers(min_value=0)),
1960 draw(integers(min_value=0)),
1961 draw(integers(min_value=0)),
1963 return (value, bounds, impl, expl, default, optional, _decoded)
1966 class OctetStringInherited(OctetString):
1970 class TestOctetString(CommonMixin, TestCase):
1971 base_klass = OctetString
1973 def test_invalid_value_type(self):
1974 with self.assertRaises(InvalidValueType) as err:
1975 OctetString(str(123))
1979 def test_optional(self, optional):
1980 obj = OctetString(default=OctetString(b""), optional=optional)
1981 self.assertTrue(obj.optional)
1984 def test_ready(self, value):
1986 self.assertFalse(obj.ready)
1989 pprint(obj, big_blobs=True, with_decode_path=True)
1990 with self.assertRaises(ObjNotReady) as err:
1993 with self.assertRaises(ObjNotReady) as err:
1995 obj = OctetString(value)
1996 self.assertTrue(obj.ready)
1999 pprint(obj, big_blobs=True, with_decode_path=True)
2001 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
2002 def test_comparison(self, value1, value2, tag1, tag2):
2003 for klass in (OctetString, OctetStringInherited):
2004 obj1 = klass(value1)
2005 obj2 = klass(value2)
2006 self.assertEqual(obj1 == obj2, value1 == value2)
2007 self.assertEqual(obj1 != obj2, value1 != value2)
2008 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2009 obj1 = klass(value1, impl=tag1)
2010 obj2 = klass(value1, impl=tag2)
2011 self.assertEqual(obj1 == obj2, tag1 == tag2)
2012 self.assertEqual(obj1 != obj2, tag1 != tag2)
2014 @given(lists(binary()))
2015 def test_sorted_works(self, values):
2016 self.assertSequenceEqual(
2017 [bytes(v) for v in sorted(OctetString(v) for v in values)],
2021 @given(data_strategy())
2022 def test_bounds_satisfied(self, d):
2023 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2024 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2025 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
2026 OctetString(value=value, bounds=(bound_min, bound_max))
2028 @given(data_strategy())
2029 def test_bounds_unsatisfied(self, d):
2030 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2031 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2032 value = d.draw(binary(max_size=bound_min - 1))
2033 with self.assertRaises(BoundsError) as err:
2034 OctetString(value=value, bounds=(bound_min, bound_max))
2036 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2037 OctetString(bounds=(bound_min, bound_max)).decode(
2038 OctetString(value).encode()
2041 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2042 OctetString(bounds=(bound_min, bound_max)).decode(
2043 encode2pass(OctetString(value))
2045 value = d.draw(binary(min_size=bound_max + 1))
2046 with self.assertRaises(BoundsError) as err:
2047 OctetString(value=value, bounds=(bound_min, bound_max))
2049 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2050 OctetString(bounds=(bound_min, bound_max)).decode(
2051 OctetString(value).encode()
2054 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2055 OctetString(bounds=(bound_min, bound_max)).decode(
2056 encode2pass(OctetString(value))
2059 @given(data_strategy())
2060 def test_call(self, d):
2061 for klass in (OctetString, OctetStringInherited):
2070 ) = d.draw(octet_string_values_strategy())
2071 obj_initial = klass(
2077 optional_initial or False,
2088 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2089 if (default is None) and (obj_initial.default is not None):
2092 (bounds is None) and
2093 (value is not None) and
2094 (bounds_initial is not None) and
2095 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2099 (bounds is None) and
2100 (default is not None) and
2101 (bounds_initial is not None) and
2102 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2105 obj = obj_initial(value, bounds, impl, expl, default, optional)
2107 value_expected = default if value is None else value
2109 default_initial if value_expected is None
2112 self.assertEqual(obj, value_expected)
2113 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2114 self.assertEqual(obj.expl_tag, expl or expl_initial)
2117 default_initial if default is None else default,
2119 if obj.default is None:
2120 optional = optional_initial if optional is None else optional
2121 optional = False if optional is None else optional
2124 self.assertEqual(obj.optional, optional)
2126 (obj._bound_min, obj._bound_max),
2127 bounds or bounds_initial or (0, float("+inf")),
2130 @given(octet_string_values_strategy())
2131 def test_copy(self, values):
2132 for klass in (OctetString, OctetStringInherited):
2133 obj = klass(*values)
2134 for copy_func in copy_funcs:
2135 obj_copied = copy_func(obj)
2136 self.assert_copied_basic_fields(obj, obj_copied)
2137 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2138 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2139 self.assertEqual(obj._value, obj_copied._value)
2143 integers(min_value=1).map(tag_encode),
2145 def test_stripped(self, value, tag_impl):
2146 obj = OctetString(value, impl=tag_impl)
2147 with self.assertRaises(NotEnoughData):
2148 obj.decode(obj.encode()[:-1])
2152 integers(min_value=1).map(tag_ctxc),
2154 def test_stripped_expl(self, value, tag_expl):
2155 obj = OctetString(value, expl=tag_expl)
2156 with self.assertRaises(NotEnoughData):
2157 obj.decode(obj.encode()[:-1])
2160 integers(min_value=31),
2161 integers(min_value=0),
2164 def test_bad_tag(self, tag, offset, decode_path):
2165 with self.assertRaises(DecodeError) as err:
2166 OctetString().decode(
2167 tag_encode(tag)[:-1],
2169 decode_path=decode_path,
2172 self.assertEqual(err.exception.offset, offset)
2173 self.assertEqual(err.exception.decode_path, decode_path)
2176 integers(min_value=128),
2177 integers(min_value=0),
2180 def test_bad_len(self, l, offset, decode_path):
2181 with self.assertRaises(DecodeError) as err:
2182 OctetString().decode(
2183 OctetString.tag_default + len_encode(l)[:-1],
2185 decode_path=decode_path,
2188 self.assertEqual(err.exception.offset, offset)
2189 self.assertEqual(err.exception.decode_path, decode_path)
2192 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2193 integers(min_value=0),
2196 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2197 value, bound_min = list(sorted(ints))
2199 class String(OctetString):
2200 bounds = (bound_min, bound_min)
2201 with self.assertRaises(DecodeError) as err:
2203 OctetString(b"\x00" * value).encode(),
2205 decode_path=decode_path,
2208 self.assertEqual(err.exception.offset, offset)
2209 self.assertEqual(err.exception.decode_path, decode_path)
2211 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2213 octet_string_values_strategy(),
2215 integers(min_value=1).map(tag_ctxc),
2216 integers(min_value=0),
2231 for klass in (OctetString, OctetStringInherited):
2232 _, _, _, _, default, optional, _decoded = values
2241 pprint(obj, big_blobs=True, with_decode_path=True)
2242 self.assertFalse(obj.expled)
2243 obj_encoded = obj.encode()
2244 self.assertEqual(encode2pass(obj), obj_encoded)
2245 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2246 obj_expled = obj(value, expl=tag_expl)
2247 self.assertTrue(obj_expled.expled)
2249 list(obj_expled.pps())
2250 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2251 obj_expled_encoded = obj_expled.encode()
2252 obj_expled_cer = encode_cer(obj_expled)
2253 self.assertNotEqual(obj_expled_cer, obj_encoded)
2254 self.assertSequenceEqual(
2255 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2258 ctx_dummy["keep_memoryview"] = keep_memoryview
2259 ctx_copied = deepcopy(ctx_dummy)
2260 obj_decoded, tail = obj_expled.decode(
2261 obj_expled_encoded + tail_junk,
2265 self.assertDictEqual(ctx_copied, ctx_dummy)
2267 list(obj_decoded.pps())
2268 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2269 self.assertEqual(tail, tail_junk)
2270 self.assertEqual(obj_decoded, obj_expled)
2271 self.assertNotEqual(obj_decoded, obj)
2272 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2273 self.assertEqual(bytes(obj_decoded), bytes(obj))
2274 self.assertIsInstance(
2276 memoryview if keep_memoryview else bytes,
2278 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2279 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2280 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2282 obj_decoded.expl_llen,
2283 len(len_encode(len(obj_encoded))),
2285 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2286 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2289 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2291 self.assertEqual(obj_decoded.expl_offset, offset)
2292 assert_exceeding_data(
2294 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2298 evgens = list(obj_expled.decode_evgen(
2299 obj_expled_encoded + tail_junk,
2301 decode_path=decode_path,
2304 self.assertEqual(len(evgens), 1)
2305 _decode_path, obj, tail = evgens[0]
2306 self.assertSequenceEqual(tail, tail_junk)
2307 self.assertEqual(_decode_path, decode_path)
2308 self.assertEqual(obj.expl_offset, offset)
2312 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2314 integers(min_value=1, max_value=30),
2317 binary(min_size=1, max_size=5),
2319 binary(min_size=1, max_size=5),
2330 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2331 def chunk_constructed(contents):
2333 tag_encode(form=TagFormConstructed, num=4) +
2335 b"".join(OctetString(content).encode() for content in contents) +
2339 chunks_len_expected = []
2340 payload_expected = b""
2341 for chunk_input in chunk_inputs:
2342 if isinstance(chunk_input, bytes):
2343 chunks.append(OctetString(chunk_input).encode())
2344 payload_expected += chunk_input
2345 chunks_len_expected.append(len(chunk_input))
2347 chunks.append(chunk_constructed(chunk_input))
2348 payload = b"".join(chunk_input)
2349 payload_expected += payload
2350 for c in chunk_input:
2351 chunks_len_expected.append(len(c))
2352 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2353 encoded_indefinite = (
2354 tag_encode(form=TagFormConstructed, num=impl) +
2359 encoded_definite = (
2360 tag_encode(form=TagFormConstructed, num=impl) +
2361 len_encode(len(b"".join(chunks))) +
2364 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
2365 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2366 for lenindef_expected, encoded in (
2367 (True, encoded_indefinite),
2368 (False, encoded_definite),
2370 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2372 ctx={"bered": True},
2374 self.assertSequenceEqual(tail, junk)
2375 self.assertSequenceEqual(bytes(obj), payload_expected)
2376 self.assertTrue(obj.ber_encoded)
2377 self.assertEqual(obj.lenindef, lenindef_expected)
2378 self.assertTrue(obj.bered)
2380 self.assertTrue(obj.ber_encoded)
2381 self.assertEqual(obj.lenindef, lenindef_expected)
2382 self.assertTrue(obj.bered)
2383 self.assertEqual(len(encoded), obj.tlvlen)
2386 pprint(obj, big_blobs=True, with_decode_path=True)
2388 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2390 decode_path=decode_path,
2391 ctx={"bered": True},
2393 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2394 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2395 self.assertGreater(len(dp), len(decode_path))
2396 self.assertEqual(obj.vlen, chunk_len_expected)
2399 integers(min_value=0),
2402 def test_ber_definite_too_short(self, offset, decode_path):
2403 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
2404 OctetString().decode(
2405 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2407 decode_path=decode_path,
2408 ctx={"bered": True},
2410 self.assertEqual(err.exception.decode_path, decode_path)
2411 self.assertEqual(err.exception.offset, offset)
2414 integers(min_value=0),
2416 integers(min_value=1, max_value=3),
2418 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2419 bs = OctetString(b"data").encode()
2420 with self.assertRaises(NotEnoughData) as err:
2421 OctetString().decode(
2422 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2424 decode_path=decode_path,
2425 ctx={"bered": True},
2427 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2428 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2431 integers(min_value=0),
2433 integers(min_value=1, max_value=3),
2435 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2436 bs = OctetString(b"data").encode()
2437 bs_longer = OctetString(b"data-longer").encode()
2438 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
2439 OctetString().decode(
2441 tag_encode(4, form=TagFormConstructed) +
2442 len_encode((chunks + 1) * len(bs)) +
2447 decode_path=decode_path,
2448 ctx={"bered": True},
2450 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2451 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2453 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2454 @given(integers(min_value=1001, max_value=3000))
2455 def test_cer(self, data_len):
2456 data = urandom(data_len)
2457 encoded = encode_cer(OctetString(data))
2458 ctx = {"bered": True}
2459 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2460 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2461 evgens_expected = data_len // 1000
2462 if evgens_expected * 1000 != data_len:
2463 evgens_expected += 1
2464 evgens_expected += 1
2465 self.assertEqual(len(evgens), evgens_expected)
2466 for (_, obj, _) in evgens[:-2]:
2467 self.assertEqual(obj.vlen, 1000)
2468 _, obj, _ = evgens[-2]
2469 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2473 def null_values_strategy(draw, do_expl=False):
2477 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2479 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2480 optional = draw(one_of(none(), booleans()))
2482 draw(integers(min_value=0)),
2483 draw(integers(min_value=0)),
2484 draw(integers(min_value=0)),
2486 return (impl, expl, optional, _decoded)
2489 class NullInherited(Null):
2493 class TestNull(CommonMixin, TestCase):
2496 def test_ready(self):
2498 self.assertTrue(obj.ready)
2501 pprint(obj, big_blobs=True, with_decode_path=True)
2503 @given(binary(min_size=1), binary(min_size=1))
2504 def test_comparison(self, tag1, tag2):
2505 for klass in (Null, NullInherited):
2506 obj1 = klass(impl=tag1)
2507 obj2 = klass(impl=tag2)
2508 self.assertEqual(obj1 == obj2, tag1 == tag2)
2509 self.assertEqual(obj1 != obj2, tag1 != tag2)
2510 self.assertNotEqual(obj1, tag2)
2512 @given(data_strategy())
2513 def test_call(self, d):
2514 for klass in (Null, NullInherited):
2520 ) = d.draw(null_values_strategy())
2521 obj_initial = klass(
2524 optional=optional_initial or False,
2525 _decoded=_decoded_initial,
2532 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2533 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2534 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2535 self.assertEqual(obj.expl_tag, expl or expl_initial)
2536 optional = optional_initial if optional is None else optional
2537 optional = False if optional is None else optional
2538 self.assertEqual(obj.optional, optional)
2540 @given(null_values_strategy())
2541 def test_copy(self, values):
2542 for klass in (Null, NullInherited):
2543 impl, expl, optional, _decoded = values
2547 optional=optional or False,
2550 for copy_func in copy_funcs:
2551 obj_copied = copy_func(obj)
2552 self.assert_copied_basic_fields(obj, obj_copied)
2554 @given(integers(min_value=1).map(tag_encode))
2555 def test_stripped(self, tag_impl):
2556 obj = Null(impl=tag_impl)
2557 with self.assertRaises(NotEnoughData):
2558 obj.decode(obj.encode()[:-1])
2560 @given(integers(min_value=1).map(tag_ctxc))
2561 def test_stripped_expl(self, tag_expl):
2562 obj = Null(expl=tag_expl)
2563 with self.assertRaises(NotEnoughData):
2564 obj.decode(obj.encode()[:-1])
2567 integers(min_value=31),
2568 integers(min_value=0),
2571 def test_bad_tag(self, tag, offset, decode_path):
2572 with self.assertRaises(DecodeError) as err:
2574 tag_encode(tag)[:-1],
2576 decode_path=decode_path,
2579 self.assertEqual(err.exception.offset, offset)
2580 self.assertEqual(err.exception.decode_path, decode_path)
2583 integers(min_value=128),
2584 integers(min_value=0),
2587 def test_bad_len(self, l, offset, decode_path):
2588 with self.assertRaises(DecodeError) as err:
2590 Null.tag_default + len_encode(l)[:-1],
2592 decode_path=decode_path,
2595 self.assertEqual(err.exception.offset, offset)
2596 self.assertEqual(err.exception.decode_path, decode_path)
2598 @given(binary(min_size=1))
2599 def test_tag_mismatch(self, impl):
2600 assume(impl != Null.tag_default)
2601 with self.assertRaises(TagMismatch):
2602 Null(impl=impl).decode(Null().encode())
2605 null_values_strategy(),
2606 integers(min_value=1).map(tag_ctxc),
2607 integers(min_value=0),
2611 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2612 for klass in (Null, NullInherited):
2613 _, _, optional, _decoded = values
2614 obj = klass(optional=optional, _decoded=_decoded)
2617 pprint(obj, big_blobs=True, with_decode_path=True)
2618 self.assertFalse(obj.expled)
2619 obj_encoded = obj.encode()
2620 self.assertEqual(encode2pass(obj), obj_encoded)
2621 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2622 obj_expled = obj(expl=tag_expl)
2623 self.assertTrue(obj_expled.expled)
2625 list(obj_expled.pps())
2626 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2627 obj_expled_encoded = obj_expled.encode()
2628 obj_expled_cer = encode_cer(obj_expled)
2629 self.assertNotEqual(obj_expled_cer, obj_encoded)
2630 self.assertSequenceEqual(
2631 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2634 ctx_copied = deepcopy(ctx_dummy)
2635 obj_decoded, tail = obj_expled.decode(
2636 obj_expled_encoded + tail_junk,
2640 self.assertDictEqual(ctx_copied, ctx_dummy)
2642 list(obj_decoded.pps())
2643 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2644 self.assertEqual(tail, tail_junk)
2645 self.assertEqual(obj_decoded, obj_expled)
2646 self.assertNotEqual(obj_decoded, obj)
2647 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2648 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2649 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2651 obj_decoded.expl_llen,
2652 len(len_encode(len(obj_encoded))),
2654 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2655 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2658 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2660 self.assertEqual(obj_decoded.expl_offset, offset)
2661 assert_exceeding_data(
2663 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2667 evgens = list(obj_expled.decode_evgen(
2668 obj_expled_encoded + tail_junk,
2670 decode_path=decode_path,
2673 self.assertEqual(len(evgens), 1)
2674 _decode_path, obj, tail = evgens[0]
2675 self.assertSequenceEqual(tail, tail_junk)
2676 self.assertEqual(_decode_path, decode_path)
2677 self.assertEqual(obj, obj_decoded)
2678 self.assertEqual(obj.expl_offset, offset)
2682 @given(integers(min_value=1))
2683 def test_invalid_len(self, l):
2684 with self.assertRaises(InvalidLength):
2685 Null().decode(b"".join((
2692 def oid_strategy(draw):
2693 first_arc = draw(integers(min_value=0, max_value=2))
2695 if first_arc in (0, 1):
2696 second_arc = draw(integers(min_value=0, max_value=39))
2698 second_arc = draw(integers(min_value=0, max_value=1 << 63))
2699 other_arcs = draw(lists(integers(min_value=0, max_value=1 << 63)))
2700 return tuple([first_arc, second_arc] + other_arcs)
2704 def oid_values_strategy(draw, do_expl=False):
2705 value = draw(one_of(none(), oid_strategy()))
2709 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2711 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2712 default = draw(one_of(none(), oid_strategy()))
2713 optional = draw(one_of(none(), booleans()))
2715 draw(integers(min_value=0)),
2716 draw(integers(min_value=0)),
2717 draw(integers(min_value=0)),
2719 return (value, impl, expl, default, optional, _decoded)
2722 class ObjectIdentifierInherited(ObjectIdentifier):
2726 class TestObjectIdentifier(CommonMixin, TestCase):
2727 base_klass = ObjectIdentifier
2729 def test_invalid_value_type(self):
2730 with self.assertRaises(InvalidValueType) as err:
2731 ObjectIdentifier(123)
2735 def test_optional(self, optional):
2736 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2737 self.assertTrue(obj.optional)
2739 @given(oid_strategy())
2740 def test_ready(self, value):
2741 obj = ObjectIdentifier()
2742 self.assertFalse(obj.ready)
2745 pprint(obj, big_blobs=True, with_decode_path=True)
2746 with self.assertRaises(ObjNotReady) as err:
2749 with self.assertRaises(ObjNotReady) as err:
2751 obj = ObjectIdentifier(value)
2752 self.assertTrue(obj.ready)
2753 self.assertFalse(obj.ber_encoded)
2756 pprint(obj, big_blobs=True, with_decode_path=True)
2759 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2760 def test_comparison(self, value1, value2, tag1, tag2):
2761 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2762 obj1 = klass(value1)
2763 obj2 = klass(value2)
2764 self.assertEqual(obj1 == obj2, value1 == value2)
2765 self.assertEqual(obj1 != obj2, value1 != value2)
2766 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2767 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2768 obj1 = klass(value1, impl=tag1)
2769 obj2 = klass(value1, impl=tag2)
2770 self.assertEqual(obj1 == obj2, tag1 == tag2)
2771 self.assertEqual(obj1 != obj2, tag1 != tag2)
2773 @given(lists(oid_strategy()))
2774 def test_sorted_works(self, values):
2775 self.assertSequenceEqual(
2776 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2780 @given(data_strategy())
2781 def test_call(self, d):
2782 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2790 ) = d.draw(oid_values_strategy())
2791 obj_initial = klass(
2792 value=value_initial,
2795 default=default_initial,
2796 optional=optional_initial or False,
2797 _decoded=_decoded_initial,
2806 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2815 value_expected = default if value is None else value
2817 default_initial if value_expected is None
2820 self.assertEqual(obj, value_expected)
2821 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2822 self.assertEqual(obj.expl_tag, expl or expl_initial)
2825 default_initial if default is None else default,
2827 if obj.default is None:
2828 optional = optional_initial if optional is None else optional
2829 optional = False if optional is None else optional
2832 self.assertEqual(obj.optional, optional)
2834 @given(oid_values_strategy())
2835 def test_copy(self, values):
2836 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2853 for copy_func in copy_funcs:
2854 obj_copied = copy_func(obj)
2855 self.assert_copied_basic_fields(obj, obj_copied)
2856 self.assertEqual(obj._value, obj_copied._value)
2858 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2861 integers(min_value=1).map(tag_encode),
2863 def test_stripped(self, value, tag_impl):
2864 obj = ObjectIdentifier(value, impl=tag_impl)
2865 with self.assertRaises(NotEnoughData):
2866 obj.decode(obj.encode()[:-1])
2870 integers(min_value=1).map(tag_ctxc),
2872 def test_stripped_expl(self, value, tag_expl):
2873 obj = ObjectIdentifier(value, expl=tag_expl)
2874 with self.assertRaises(NotEnoughData):
2875 obj.decode(obj.encode()[:-1])
2878 integers(min_value=31),
2879 integers(min_value=0),
2882 def test_bad_tag(self, tag, offset, decode_path):
2883 with self.assertRaises(DecodeError) as err:
2884 ObjectIdentifier().decode(
2885 tag_encode(tag)[:-1],
2887 decode_path=decode_path,
2890 self.assertEqual(err.exception.offset, offset)
2891 self.assertEqual(err.exception.decode_path, decode_path)
2894 integers(min_value=128),
2895 integers(min_value=0),
2898 def test_bad_len(self, l, offset, decode_path):
2899 with self.assertRaises(DecodeError) as err:
2900 ObjectIdentifier().decode(
2901 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2903 decode_path=decode_path,
2906 self.assertEqual(err.exception.offset, offset)
2907 self.assertEqual(err.exception.decode_path, decode_path)
2909 def test_zero_oid(self):
2910 with self.assertRaises(NotEnoughData):
2911 ObjectIdentifier().decode(
2912 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2915 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2916 @given(oid_strategy())
2917 def test_unfinished_oid(self, value):
2918 assume(list(value)[-1] > 255)
2919 obj_encoded = ObjectIdentifier(value).encode()
2920 obj, _ = ObjectIdentifier().decode(obj_encoded)
2921 data = obj_encoded[obj.tlen + obj.llen:-1]
2923 ObjectIdentifier.tag_default,
2924 len_encode(len(data)),
2927 with self.assertRaisesRegex(DecodeError, "unfinished OID"):
2930 @given(integers(min_value=0, max_value=1 << 63))
2931 def test_invalid_short(self, value):
2932 with self.assertRaises(InvalidOID):
2933 ObjectIdentifier((value,))
2934 with self.assertRaises(InvalidOID):
2935 ObjectIdentifier("%d" % value)
2938 integers(min_value=3, max_value=1 << 63),
2939 integers(min_value=0, max_value=1 << 63),
2941 def test_invalid_first_arc(self, first_arc, second_arc):
2942 with self.assertRaises(InvalidOID):
2943 ObjectIdentifier((first_arc, second_arc))
2944 with self.assertRaises(InvalidOID):
2945 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2948 integers(min_value=0, max_value=1),
2949 integers(min_value=40, max_value=1 << 63),
2951 def test_invalid_second_arc(self, first_arc, second_arc):
2952 with self.assertRaises(InvalidOID):
2953 ObjectIdentifier((first_arc, second_arc))
2954 with self.assertRaises(InvalidOID):
2955 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2957 @given(text(alphabet=ascii_letters + ".", min_size=1))
2958 def test_junk(self, oid):
2959 with self.assertRaises(InvalidOID):
2960 ObjectIdentifier(oid)
2962 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2963 @given(oid_strategy())
2964 def test_validness(self, oid):
2965 obj = ObjectIdentifier(oid)
2966 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2969 pprint(obj, big_blobs=True, with_decode_path=True)
2971 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2973 oid_values_strategy(),
2975 integers(min_value=1).map(tag_ctxc),
2976 integers(min_value=0),
2980 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2981 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2982 _, _, _, default, optional, _decoded = values
2991 pprint(obj, big_blobs=True, with_decode_path=True)
2992 self.assertFalse(obj.expled)
2993 obj_encoded = obj.encode()
2994 self.assertEqual(encode2pass(obj), obj_encoded)
2995 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2996 obj_expled = obj(value, expl=tag_expl)
2997 self.assertTrue(obj_expled.expled)
2999 list(obj_expled.pps())
3000 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3001 obj_expled_encoded = obj_expled.encode()
3002 obj_expled_cer = encode_cer(obj_expled)
3003 self.assertNotEqual(obj_expled_cer, obj_encoded)
3004 self.assertSequenceEqual(
3005 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
3008 ctx_copied = deepcopy(ctx_dummy)
3009 obj_decoded, tail = obj_expled.decode(
3010 obj_expled_encoded + tail_junk,
3014 self.assertDictEqual(ctx_copied, ctx_dummy)
3016 list(obj_decoded.pps())
3017 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3018 self.assertEqual(tail, tail_junk)
3019 self.assertEqual(obj_decoded, obj_expled)
3020 self.assertNotEqual(obj_decoded, obj)
3021 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
3022 self.assertEqual(tuple(obj_decoded), tuple(obj))
3023 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3024 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3025 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3027 obj_decoded.expl_llen,
3028 len(len_encode(len(obj_encoded))),
3030 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3031 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3034 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3036 self.assertEqual(obj_decoded.expl_offset, offset)
3037 assert_exceeding_data(
3039 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3043 evgens = list(obj_expled.decode_evgen(
3044 obj_expled_encoded + tail_junk,
3046 decode_path=decode_path,
3049 self.assertEqual(len(evgens), 1)
3050 _decode_path, obj, tail = evgens[0]
3051 self.assertSequenceEqual(tail, tail_junk)
3052 self.assertEqual(_decode_path, decode_path)
3053 self.assertEqual(obj, obj_decoded)
3054 self.assertEqual(obj.expl_offset, offset)
3059 oid_strategy().map(ObjectIdentifier),
3060 oid_strategy().map(ObjectIdentifier),
3062 def test_add(self, oid1, oid2):
3063 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3064 for oid_to_add in (oid2, tuple(oid2)):
3065 self.assertEqual(oid1 + oid_to_add, oid_expect)
3066 with self.assertRaises(InvalidValueType):
3069 def test_go_vectors_valid(self):
3070 for data, expect in (
3072 (b"\x55\x02", (2, 5, 2)),
3073 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3074 (b"\x81\x34\x03", (2, 100, 3)),
3077 ObjectIdentifier().decode(b"".join((
3078 ObjectIdentifier.tag_default,
3079 len_encode(len(data)),
3085 def test_go_vectors_invalid(self):
3086 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3087 with self.assertRaises(DecodeError):
3088 ObjectIdentifier().decode(b"".join((
3089 Integer.tag_default,
3090 len_encode(len(data)),
3094 def test_go_non_minimal_encoding(self):
3095 with self.assertRaises(DecodeError):
3096 ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
3098 def test_x690_vector(self):
3100 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3101 ObjectIdentifier((2, 999, 3)),
3104 def test_nonnormalized_first_arc(self):
3106 ObjectIdentifier.tag_default +
3109 ObjectIdentifier((1, 0)).encode()[-1:]
3111 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3112 self.assertTrue(obj.ber_encoded)
3113 self.assertTrue(obj.bered)
3115 self.assertTrue(obj.ber_encoded)
3116 self.assertTrue(obj.bered)
3117 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3118 ObjectIdentifier().decode(tampered)
3120 @given(data_strategy())
3121 def test_negative_arcs(self, d):
3122 oid = list(d.draw(oid_strategy()))
3125 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3127 if oid[idx - 1] == 0:
3129 with self.assertRaises(InvalidOID):
3130 ObjectIdentifier(tuple(oid))
3131 with self.assertRaises(InvalidOID):
3132 ObjectIdentifier(".".join(str(i) for i in oid))
3134 @given(data_strategy())
3135 def test_plused_arcs(self, d):
3136 oid = [str(arc) for arc in d.draw(oid_strategy())]
3137 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3138 oid[idx - 1] = "+" + oid[idx - 1]
3139 with self.assertRaises(InvalidOID):
3140 ObjectIdentifier(".".join(str(i) for i in oid))
3142 @given(data_strategy())
3143 def test_nonnormalized_arcs(self, d):
3144 arcs = d.draw(lists(
3145 integers(min_value=0, max_value=100),
3149 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3150 _, _, lv = tag_strip(dered)
3151 _, _, v = len_decode(lv)
3152 v_no_first_arc = v[1:]
3153 idx_for_tamper = d.draw(integers(
3155 max_value=len(v_no_first_arc) - 1,
3157 tampered = list(bytearray(v_no_first_arc))
3158 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3159 tampered.insert(idx_for_tamper, 0x80)
3160 tampered = bytes(bytearray(tampered))
3162 ObjectIdentifier.tag_default +
3163 len_encode(len(tampered)) +
3166 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3167 self.assertTrue(obj.ber_encoded)
3168 self.assertTrue(obj.bered)
3170 self.assertTrue(obj.ber_encoded)
3171 self.assertTrue(obj.bered)
3172 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3173 ObjectIdentifier().decode(tampered)
3177 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3179 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3180 values = list(draw(sets(
3182 min_size=len(schema),
3183 max_size=len(schema),
3185 schema = list(zip(schema, values))
3186 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3190 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3192 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3193 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3194 optional = draw(one_of(none(), booleans()))
3196 draw(integers(min_value=0)),
3197 draw(integers(min_value=0)),
3198 draw(integers(min_value=0)),
3200 return (schema, value, impl, expl, default, optional, _decoded)
3203 class TestEnumerated(CommonMixin, TestCase):
3204 class EWhatever(Enumerated):
3205 schema = (("whatever", 0),)
3207 base_klass = EWhatever
3209 def test_schema_required(self):
3210 with self.assertRaisesRegex(ValueError, "schema must be specified"):
3213 def test_invalid_value_type(self):
3214 with self.assertRaises(InvalidValueType) as err:
3215 self.base_klass((1, 2))
3218 @given(sets(text_letters(), min_size=2))
3219 def test_unknown_name(self, schema_input):
3220 missing = schema_input.pop()
3222 class E(Enumerated):
3223 schema = [(n, 123) for n in schema_input]
3224 with self.assertRaises(ObjUnknown) as err:
3229 sets(text_letters(), min_size=2),
3230 sets(integers(), min_size=2),
3232 def test_unknown_value(self, schema_input, values_input):
3234 missing_value = values_input.pop()
3235 _input = list(zip(schema_input, values_input))
3237 class E(Enumerated):
3239 with self.assertRaises(DecodeError) as err:
3244 def test_optional(self, optional):
3245 obj = self.base_klass(default="whatever", optional=optional)
3246 self.assertTrue(obj.optional)
3248 def test_ready(self):
3249 obj = self.base_klass()
3250 self.assertFalse(obj.ready)
3253 pprint(obj, big_blobs=True, with_decode_path=True)
3254 with self.assertRaises(ObjNotReady) as err:
3257 obj = self.base_klass("whatever")
3258 self.assertTrue(obj.ready)
3261 pprint(obj, big_blobs=True, with_decode_path=True)
3263 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3264 def test_comparison(self, value1, value2, tag1, tag2):
3265 class E(Enumerated):
3267 ("whatever0", value1),
3268 ("whatever1", value2),
3271 class EInherited(E):
3273 for klass in (E, EInherited):
3274 obj1 = klass(value1)
3275 obj2 = klass(value2)
3276 self.assertEqual(obj1 == obj2, value1 == value2)
3277 self.assertEqual(obj1 != obj2, value1 != value2)
3278 self.assertEqual(obj1 == int(obj2), value1 == value2)
3279 obj1 = klass(value1, impl=tag1)
3280 obj2 = klass(value1, impl=tag2)
3281 self.assertEqual(obj1 == obj2, tag1 == tag2)
3282 self.assertEqual(obj1 != obj2, tag1 != tag2)
3284 @given(data_strategy())
3285 def test_call(self, d):
3294 ) = d.draw(enumerated_values_strategy())
3296 class E(Enumerated):
3297 schema = schema_initial
3299 value=value_initial,
3302 default=default_initial,
3303 optional=optional_initial or False,
3304 _decoded=_decoded_initial,
3314 ) = d.draw(enumerated_values_strategy(
3315 schema=schema_initial,
3316 do_expl=impl_initial is None,
3326 value_expected = default if value is None else value
3328 default_initial if value_expected is None
3333 dict(schema_initial).get(value_expected, value_expected),
3335 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3336 self.assertEqual(obj.expl_tag, expl or expl_initial)
3339 default_initial if default is None else default,
3341 if obj.default is None:
3342 optional = optional_initial if optional is None else optional
3343 optional = False if optional is None else optional
3346 self.assertEqual(obj.optional, optional)
3347 self.assertEqual(obj.specs, dict(schema_initial))
3349 @given(enumerated_values_strategy())
3350 def test_copy(self, values):
3351 schema_input, value, impl, expl, default, optional, _decoded = values
3353 class E(Enumerated):
3354 schema = schema_input
3364 for copy_func in copy_funcs:
3365 obj_copied = copy_func(obj)
3366 self.assert_copied_basic_fields(obj, obj_copied)
3367 self.assertEqual(obj.specs, obj_copied.specs)
3369 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3370 @given(data_strategy())
3371 def test_symmetric(self, d):
3372 schema_input, _, _, _, default, optional, _decoded = d.draw(
3373 enumerated_values_strategy(),
3375 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3376 offset = d.draw(integers(min_value=0))
3377 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3378 tail_junk = d.draw(binary(max_size=5))
3379 decode_path = d.draw(decode_path_strat)
3381 class E(Enumerated):
3382 schema = schema_input
3391 pprint(obj, big_blobs=True, with_decode_path=True)
3392 self.assertFalse(obj.expled)
3393 obj_encoded = obj.encode()
3394 self.assertEqual(encode2pass(obj), obj_encoded)
3395 obj_expled = obj(value, expl=tag_expl)
3396 self.assertTrue(obj_expled.expled)
3398 list(obj_expled.pps())
3399 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3400 obj_expled_encoded = obj_expled.encode()
3401 ctx_copied = deepcopy(ctx_dummy)
3402 obj_decoded, tail = obj_expled.decode(
3403 obj_expled_encoded + tail_junk,
3407 self.assertDictEqual(ctx_copied, ctx_dummy)
3409 list(obj_decoded.pps())
3410 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3411 self.assertEqual(tail, tail_junk)
3412 self.assertEqual(obj_decoded, obj_expled)
3413 self.assertNotEqual(obj_decoded, obj)
3414 self.assertEqual(int(obj_decoded), int(obj_expled))
3415 self.assertEqual(int(obj_decoded), int(obj))
3416 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3417 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3418 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3420 obj_decoded.expl_llen,
3421 len(len_encode(len(obj_encoded))),
3423 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3424 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3427 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3429 self.assertEqual(obj_decoded.expl_offset, offset)
3430 assert_exceeding_data(
3432 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3436 evgens = list(obj_expled.decode_evgen(
3437 obj_expled_encoded + tail_junk,
3439 decode_path=decode_path,
3442 self.assertEqual(len(evgens), 1)
3443 _decode_path, obj, tail = evgens[0]
3444 self.assertSequenceEqual(tail, tail_junk)
3445 self.assertEqual(_decode_path, decode_path)
3446 self.assertEqual(obj, obj_decoded)
3447 self.assertEqual(obj.expl_offset, offset)
3453 def string_values_strategy(draw, alphabet, do_expl=False):
3454 bound_min, bound_max = sorted(draw(sets(
3455 integers(min_value=0, max_value=1 << 7),
3459 value = draw(one_of(
3461 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3463 default = draw(one_of(
3465 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3468 if draw(booleans()):
3469 bounds = (bound_min, bound_max)
3473 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3475 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3476 optional = draw(one_of(none(), booleans()))
3478 draw(integers(min_value=0)),
3479 draw(integers(min_value=0)),
3480 draw(integers(min_value=0)),
3482 return (value, bounds, impl, expl, default, optional, _decoded)
3485 class StringMixin(object):
3486 def test_invalid_value_type(self):
3487 with self.assertRaises(InvalidValueType) as err:
3488 self.base_klass((1, 2))
3491 def text_alphabet(self):
3492 return "".join(chr(c) for c in range(256))
3495 def test_optional(self, optional):
3496 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3497 self.assertTrue(obj.optional)
3499 @given(data_strategy())
3500 def test_ready(self, d):
3501 obj = self.base_klass()
3502 self.assertFalse(obj.ready)
3505 pprint(obj, big_blobs=True, with_decode_path=True)
3507 with self.assertRaises(ObjNotReady) as err:
3510 with self.assertRaises(ObjNotReady) as err:
3512 value = d.draw(text(alphabet=self.text_alphabet()))
3513 obj = self.base_klass(value)
3514 self.assertTrue(obj.ready)
3517 pprint(obj, big_blobs=True, with_decode_path=True)
3520 @given(data_strategy())
3521 def test_comparison(self, d):
3522 value1 = d.draw(text(alphabet=self.text_alphabet()))
3523 value2 = d.draw(text(alphabet=self.text_alphabet()))
3524 tag1 = d.draw(binary(min_size=1))
3525 tag2 = d.draw(binary(min_size=1))
3526 obj1 = self.base_klass(value1)
3527 obj2 = self.base_klass(value2)
3528 self.assertEqual(obj1 == obj2, value1 == value2)
3529 self.assertEqual(obj1 != obj2, value1 != value2)
3530 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3531 self.assertEqual(obj1 == str(obj2), value1 == value2)
3532 obj1 = self.base_klass(value1, impl=tag1)
3533 obj2 = self.base_klass(value1, impl=tag2)
3534 self.assertEqual(obj1 == obj2, tag1 == tag2)
3535 self.assertEqual(obj1 != obj2, tag1 != tag2)
3537 @given(data_strategy())
3538 def test_bounds_satisfied(self, d):
3539 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3540 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3541 value = d.draw(text(
3542 alphabet=self.text_alphabet(),
3546 self.base_klass(value=value, bounds=(bound_min, bound_max))
3548 @given(data_strategy())
3549 def test_bounds_unsatisfied(self, d):
3550 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3551 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3552 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3553 with self.assertRaises(BoundsError) as err:
3554 self.base_klass(value=value, bounds=(bound_min, bound_max))
3556 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3557 self.base_klass(bounds=(bound_min, bound_max)).decode(
3558 self.base_klass(value).encode()
3561 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3562 self.base_klass(bounds=(bound_min, bound_max)).decode(
3563 encode2pass(self.base_klass(value))
3565 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3566 with self.assertRaises(BoundsError) as err:
3567 self.base_klass(value=value, bounds=(bound_min, bound_max))
3569 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3570 self.base_klass(bounds=(bound_min, bound_max)).decode(
3571 self.base_klass(value).encode()
3574 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3575 self.base_klass(bounds=(bound_min, bound_max)).decode(
3576 encode2pass(self.base_klass(value))
3579 @given(data_strategy())
3580 def test_call(self, d):
3589 ) = d.draw(string_values_strategy(self.text_alphabet()))
3590 obj_initial = self.base_klass(
3596 optional_initial or False,
3607 ) = d.draw(string_values_strategy(
3608 self.text_alphabet(),
3609 do_expl=impl_initial is None,
3611 if (default is None) and (obj_initial.default is not None):
3614 (bounds is None) and
3615 (value is not None) and
3616 (bounds_initial is not None) and
3617 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3621 (bounds is None) and
3622 (default is not None) and
3623 (bounds_initial is not None) and
3624 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3627 obj = obj_initial(value, bounds, impl, expl, default, optional)
3629 value_expected = default if value is None else value
3631 default_initial if value_expected is None
3634 self.assertEqual(obj, value_expected)
3635 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3636 self.assertEqual(obj.expl_tag, expl or expl_initial)
3639 default_initial if default is None else default,
3641 if obj.default is None:
3642 optional = optional_initial if optional is None else optional
3643 optional = False if optional is None else optional
3646 self.assertEqual(obj.optional, optional)
3648 (obj._bound_min, obj._bound_max),
3649 bounds or bounds_initial or (0, float("+inf")),
3652 @given(data_strategy())
3653 def test_copy(self, d):
3654 values = d.draw(string_values_strategy(self.text_alphabet()))
3655 obj = self.base_klass(*values)
3656 for copy_func in copy_funcs:
3657 obj_copied = copy_func(obj)
3658 self.assert_copied_basic_fields(obj, obj_copied)
3659 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3660 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3661 self.assertEqual(obj._value, obj_copied._value)
3663 @given(data_strategy())
3664 def test_stripped(self, d):
3665 value = d.draw(text(alphabet=self.text_alphabet()))
3666 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3667 obj = self.base_klass(value, impl=tag_impl)
3668 with self.assertRaises(NotEnoughData):
3669 obj.decode(obj.encode()[:-1])
3671 @given(data_strategy())
3672 def test_stripped_expl(self, d):
3673 value = d.draw(text(alphabet=self.text_alphabet()))
3674 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3675 obj = self.base_klass(value, expl=tag_expl)
3676 with self.assertRaises(NotEnoughData):
3677 obj.decode(obj.encode()[:-1])
3680 integers(min_value=31),
3681 integers(min_value=0),
3684 def test_bad_tag(self, tag, offset, decode_path):
3685 with self.assertRaises(DecodeError) as err:
3686 self.base_klass().decode(
3687 tag_encode(tag)[:-1],
3689 decode_path=decode_path,
3692 self.assertEqual(err.exception.offset, offset)
3693 self.assertEqual(err.exception.decode_path, decode_path)
3696 integers(min_value=128),
3697 integers(min_value=0),
3700 def test_bad_len(self, l, offset, decode_path):
3701 with self.assertRaises(DecodeError) as err:
3702 self.base_klass().decode(
3703 self.base_klass.tag_default + len_encode(l)[:-1],
3705 decode_path=decode_path,
3708 self.assertEqual(err.exception.offset, offset)
3709 self.assertEqual(err.exception.decode_path, decode_path)
3712 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3713 integers(min_value=0),
3716 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3717 value, bound_min = list(sorted(ints))
3719 class String(self.base_klass):
3720 # Multiply this value by four, to satisfy UTF-32 bounds
3721 # (4 bytes per character) validation
3722 bounds = (bound_min * 4, bound_min * 4)
3723 with self.assertRaises(DecodeError) as err:
3725 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3727 decode_path=decode_path,
3730 self.assertEqual(err.exception.offset, offset)
3731 self.assertEqual(err.exception.decode_path, decode_path)
3733 @given(data_strategy())
3734 def test_symmetric(self, d):
3735 values = d.draw(string_values_strategy(self.text_alphabet()))
3736 value = d.draw(text(alphabet=self.text_alphabet()))
3737 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3738 offset = d.draw(integers(min_value=0))
3739 tail_junk = d.draw(binary(max_size=5))
3740 decode_path = d.draw(decode_path_strat)
3741 _, _, _, _, default, optional, _decoded = values
3742 obj = self.base_klass(
3750 pprint(obj, big_blobs=True, with_decode_path=True)
3751 self.assertFalse(obj.expled)
3752 obj_encoded = obj.encode()
3753 self.assertEqual(encode2pass(obj), obj_encoded)
3754 obj_expled = obj(value, expl=tag_expl)
3755 self.assertTrue(obj_expled.expled)
3757 list(obj_expled.pps())
3758 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3759 obj_expled_encoded = obj_expled.encode()
3760 ctx_copied = deepcopy(ctx_dummy)
3761 obj_decoded, tail = obj_expled.decode(
3762 obj_expled_encoded + tail_junk,
3766 self.assertDictEqual(ctx_copied, ctx_dummy)
3768 list(obj_decoded.pps())
3769 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3770 self.assertEqual(tail, tail_junk)
3771 self.assertEqual(obj_decoded, obj_expled)
3772 self.assertNotEqual(obj_decoded, obj)
3773 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3774 self.assertEqual(bytes(obj_decoded), bytes(obj))
3775 self.assertEqual(str(obj_decoded), str(obj_expled))
3776 self.assertEqual(str(obj_decoded), str(obj))
3777 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3778 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3779 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3781 obj_decoded.expl_llen,
3782 len(len_encode(len(obj_encoded))),
3784 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3785 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3788 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3790 self.assertEqual(obj_decoded.expl_offset, offset)
3791 assert_exceeding_data(
3793 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3797 evgens = list(obj_expled.decode_evgen(
3798 obj_expled_encoded + tail_junk,
3800 decode_path=decode_path,
3803 self.assertEqual(len(evgens), 1)
3804 _decode_path, obj, tail = evgens[0]
3805 self.assertSequenceEqual(tail, tail_junk)
3806 self.assertEqual(_decode_path, decode_path)
3807 if not getattr(self, "evgen_mode_skip_value", True):
3808 self.assertEqual(obj, obj_decoded)
3809 self.assertEqual(obj.expl_offset, offset)
3814 cyrillic_letters = text(
3815 alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
3821 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3822 base_klass = UTF8String
3824 @given(cyrillic_letters)
3825 def test_byte_per_primitive(self, chars):
3827 char_raw = char.encode("utf-8")
3828 encoded = b"".join((
3829 self.base_klass().tag_constructed,
3831 OctetString(char_raw[:1]).encode(),
3832 OctetString(char_raw[1:2]).encode(),
3836 self.base_klass().decod(encoded, ctx={"bered": True}),
3841 class UnicodeDecodeErrorMixin(object):
3842 @given(cyrillic_letters)
3843 def test_unicode_decode_error(self, cyrillic_text):
3844 with self.assertRaises(DecodeError):
3845 self.base_klass(cyrillic_text)
3848 class TestNumericString(StringMixin, CommonMixin, TestCase):
3849 base_klass = NumericString
3851 def text_alphabet(self):
3854 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3855 def test_non_numeric(self, non_numeric_text):
3856 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3857 self.base_klass(non_numeric_text)
3860 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3861 integers(min_value=0),
3864 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3865 value, bound_min = list(sorted(ints))
3867 class String(self.base_klass):
3868 bounds = (bound_min, bound_min)
3869 with self.assertRaises(DecodeError) as err:
3871 self.base_klass(b"1" * value).encode(),
3873 decode_path=decode_path,
3876 self.assertEqual(err.exception.offset, offset)
3877 self.assertEqual(err.exception.decode_path, decode_path)
3879 def test_byte_per_primitive(self):
3880 encoded = b"".join((
3881 self.base_klass().tag_constructed,
3883 OctetString(b"1").encode(),
3884 OctetString(b"2").encode(),
3888 self.base_klass().decod(encoded, ctx={"bered": True}),
3893 class TestPrintableString(
3894 UnicodeDecodeErrorMixin,
3899 base_klass = PrintableString
3901 def text_alphabet(self):
3902 return ascii_letters + digits + " '()+,-./:=?"
3904 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3905 def test_non_printable(self, non_printable_text):
3906 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3907 self.base_klass(non_printable_text)
3910 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3911 integers(min_value=0),
3914 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3915 value, bound_min = list(sorted(ints))
3917 class String(self.base_klass):
3918 bounds = (bound_min, bound_min)
3919 with self.assertRaises(DecodeError) as err:
3921 self.base_klass(b"1" * value).encode(),
3923 decode_path=decode_path,
3926 self.assertEqual(err.exception.offset, offset)
3927 self.assertEqual(err.exception.decode_path, decode_path)
3929 def test_allowable_invalid_chars(self):
3931 ("*", {"allow_asterisk": True}),
3932 ("&", {"allow_ampersand": True}),
3933 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3936 obj = self.base_klass(s)
3937 for prop in kwargs.keys():
3938 self.assertFalse(getattr(obj, prop))
3940 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3942 self.base_klass(s, **kwargs)
3943 klass = self.base_klass(**kwargs)
3945 for prop in kwargs.keys():
3946 self.assertTrue(getattr(obj, prop))
3949 for prop in kwargs.keys():
3950 self.assertTrue(getattr(obj, prop))
3953 class TestTeletexString(
3954 UnicodeDecodeErrorMixin,
3959 base_klass = TeletexString
3962 class TestVideotexString(
3963 UnicodeDecodeErrorMixin,
3968 base_klass = VideotexString
3971 class TestIA5String(
3972 UnicodeDecodeErrorMixin,
3977 base_klass = IA5String
3979 def text_alphabet(self):
3980 return "".join(chr(c) for c in range(128))
3982 @given(integers(min_value=128, max_value=255))
3983 def test_alphabet_bad(self, code):
3984 with self.assertRaises(DecodeError):
3985 self.base_klass().decod(
3986 self.base_klass.tag_default +
3988 bytes(bytearray([code])),
3992 class TestGraphicString(
3993 UnicodeDecodeErrorMixin,
3998 base_klass = GraphicString
4001 class TestVisibleString(
4002 UnicodeDecodeErrorMixin,
4007 base_klass = VisibleString
4009 def text_alphabet(self):
4010 return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
4012 def test_x690_vector(self):
4013 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
4014 self.assertSequenceEqual(tail, b"")
4015 self.assertEqual(str(obj), "Jones")
4016 self.assertFalse(obj.ber_encoded)
4017 self.assertFalse(obj.lenindef)
4018 self.assertFalse(obj.bered)
4020 obj, tail = VisibleString().decode(
4021 hexdec("3A0904034A6F6E04026573"),
4022 ctx={"bered": True},
4024 self.assertSequenceEqual(tail, b"")
4025 self.assertEqual(str(obj), "Jones")
4026 self.assertTrue(obj.ber_encoded)
4027 self.assertFalse(obj.lenindef)
4028 self.assertTrue(obj.bered)
4030 self.assertTrue(obj.ber_encoded)
4031 self.assertFalse(obj.lenindef)
4032 self.assertTrue(obj.bered)
4034 obj, tail = VisibleString().decode(
4035 hexdec("3A8004034A6F6E040265730000"),
4036 ctx={"bered": True},
4038 self.assertSequenceEqual(tail, b"")
4039 self.assertEqual(str(obj), "Jones")
4040 self.assertTrue(obj.ber_encoded)
4041 self.assertTrue(obj.lenindef)
4042 self.assertTrue(obj.bered)
4044 self.assertTrue(obj.ber_encoded)
4045 self.assertTrue(obj.lenindef)
4046 self.assertTrue(obj.bered)
4049 integers(min_value=0, max_value=ord(" ") - 1),
4050 integers(min_value=ord("~") + 1, max_value=255),
4052 def test_alphabet_bad(self, code):
4053 with self.assertRaises(DecodeError):
4054 self.base_klass().decod(
4055 self.base_klass.tag_default +
4057 bytes(bytearray([code])),
4061 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
4062 integers(min_value=0),
4065 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
4066 value, bound_min = list(sorted(ints))
4068 class String(self.base_klass):
4069 bounds = (bound_min, bound_min)
4070 with self.assertRaises(DecodeError) as err:
4072 self.base_klass(b"1" * value).encode(),
4074 decode_path=decode_path,
4077 self.assertEqual(err.exception.offset, offset)
4078 self.assertEqual(err.exception.decode_path, decode_path)
4081 class TestGeneralString(
4082 UnicodeDecodeErrorMixin,
4087 base_klass = GeneralString
4090 class TestUniversalString(StringMixin, CommonMixin, TestCase):
4091 base_klass = UniversalString
4094 class TestBMPString(StringMixin, CommonMixin, TestCase):
4095 base_klass = BMPString
4099 def generalized_time_values_strategy(
4107 if draw(booleans()):
4108 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4110 value = value.replace(microsecond=0)
4112 if draw(booleans()):
4113 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4115 default = default.replace(microsecond=0)
4119 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4121 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4122 optional = draw(one_of(none(), booleans()))
4124 draw(integers(min_value=0)),
4125 draw(integers(min_value=0)),
4126 draw(integers(min_value=0)),
4128 return (value, impl, expl, default, optional, _decoded)
4131 class TimeMixin(object):
4132 def test_invalid_value_type(self):
4133 with self.assertRaises(InvalidValueType) as err:
4134 self.base_klass(datetime.now().timetuple())
4137 @given(data_strategy())
4138 def test_optional(self, d):
4139 default = d.draw(datetimes(
4140 min_value=self.min_datetime,
4141 max_value=self.max_datetime,
4143 optional = d.draw(booleans())
4144 obj = self.base_klass(default=default, optional=optional)
4145 self.assertTrue(obj.optional)
4147 @given(data_strategy())
4148 def test_ready(self, d):
4149 obj = self.base_klass()
4150 self.assertFalse(obj.ready)
4153 pprint(obj, big_blobs=True, with_decode_path=True)
4154 with self.assertRaises(ObjNotReady) as err:
4157 with self.assertRaises(ObjNotReady) as err:
4159 value = d.draw(datetimes(
4160 min_value=self.min_datetime,
4161 max_value=self.max_datetime,
4163 obj = self.base_klass(value)
4164 self.assertTrue(obj.ready)
4167 pprint(obj, big_blobs=True, with_decode_path=True)
4169 @given(data_strategy())
4170 def test_comparison(self, d):
4171 value1 = d.draw(datetimes(
4172 min_value=self.min_datetime,
4173 max_value=self.max_datetime,
4175 value2 = d.draw(datetimes(
4176 min_value=self.min_datetime,
4177 max_value=self.max_datetime,
4179 tag1 = d.draw(binary(min_size=1))
4180 tag2 = d.draw(binary(min_size=1))
4182 value1 = value1.replace(microsecond=0)
4183 value2 = value2.replace(microsecond=0)
4184 obj1 = self.base_klass(value1)
4185 obj2 = self.base_klass(value2)
4186 self.assertEqual(obj1 == obj2, value1 == value2)
4187 self.assertEqual(obj1 != obj2, value1 != value2)
4188 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4189 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4190 obj1 = self.base_klass(value1, impl=tag1)
4191 obj2 = self.base_klass(value1, impl=tag2)
4192 self.assertEqual(obj1 == obj2, tag1 == tag2)
4193 self.assertEqual(obj1 != obj2, tag1 != tag2)
4195 @given(data_strategy())
4196 def test_call(self, d):
4204 ) = d.draw(generalized_time_values_strategy(
4205 min_datetime=self.min_datetime,
4206 max_datetime=self.max_datetime,
4207 omit_ms=self.omit_ms,
4209 obj_initial = self.base_klass(
4210 value=value_initial,
4213 default=default_initial,
4214 optional=optional_initial or False,
4215 _decoded=_decoded_initial,
4224 ) = d.draw(generalized_time_values_strategy(
4225 min_datetime=self.min_datetime,
4226 max_datetime=self.max_datetime,
4227 omit_ms=self.omit_ms,
4228 do_expl=impl_initial is None,
4238 value_expected = default if value is None else value
4240 default_initial if value_expected is None
4243 self.assertEqual(obj, value_expected)
4244 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4245 self.assertEqual(obj.expl_tag, expl or expl_initial)
4248 default_initial if default is None else default,
4250 if obj.default is None:
4251 optional = optional_initial if optional is None else optional
4252 optional = False if optional is None else optional
4255 self.assertEqual(obj.optional, optional)
4257 @given(data_strategy())
4258 def test_copy(self, d):
4259 values = d.draw(generalized_time_values_strategy(
4260 min_datetime=self.min_datetime,
4261 max_datetime=self.max_datetime,
4263 obj = self.base_klass(*values)
4264 for copy_func in copy_funcs:
4265 obj_copied = copy_func(obj)
4266 self.assert_copied_basic_fields(obj, obj_copied)
4267 self.assertEqual(obj._value, obj_copied._value)
4269 @given(data_strategy())
4270 def test_stripped(self, d):
4271 value = d.draw(datetimes(
4272 min_value=self.min_datetime,
4273 max_value=self.max_datetime,
4275 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4276 obj = self.base_klass(value, impl=tag_impl)
4277 with self.assertRaises(NotEnoughData):
4278 obj.decode(obj.encode()[:-1])
4280 @given(data_strategy())
4281 def test_stripped_expl(self, d):
4282 value = d.draw(datetimes(
4283 min_value=self.min_datetime,
4284 max_value=self.max_datetime,
4286 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4287 obj = self.base_klass(value, expl=tag_expl)
4288 with self.assertRaises(NotEnoughData):
4289 obj.decode(obj.encode()[:-1])
4291 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4292 @given(data_strategy())
4293 def test_symmetric(self, d):
4294 values = d.draw(generalized_time_values_strategy(
4295 min_datetime=self.min_datetime,
4296 max_datetime=self.max_datetime,
4298 value = d.draw(datetimes(
4299 min_value=self.min_datetime,
4300 max_value=self.max_datetime,
4302 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4303 offset = d.draw(integers(min_value=0))
4304 tail_junk = d.draw(binary(max_size=5))
4305 _, _, _, default, optional, _decoded = values
4306 obj = self.base_klass(
4314 pprint(obj, big_blobs=True, with_decode_path=True)
4315 self.assertFalse(obj.expled)
4316 obj_encoded = obj.encode()
4317 self.assertEqual(encode2pass(obj), obj_encoded)
4318 self.additional_symmetric_check(value, obj_encoded)
4319 obj_expled = obj(value, expl=tag_expl)
4320 self.assertTrue(obj_expled.expled)
4322 list(obj_expled.pps())
4323 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4324 obj_expled_encoded = obj_expled.encode()
4325 ctx_copied = deepcopy(ctx_dummy)
4326 obj_decoded, tail = obj_expled.decode(
4327 obj_expled_encoded + tail_junk,
4331 self.assertDictEqual(ctx_copied, ctx_dummy)
4333 list(obj_decoded.pps())
4334 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4335 self.assertEqual(tail, tail_junk)
4336 self.assertEqual(obj_decoded, obj_expled)
4337 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4338 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4339 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4340 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4341 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4343 obj_decoded.expl_llen,
4344 len(len_encode(len(obj_encoded))),
4346 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4347 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4350 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4352 self.assertEqual(obj_decoded.expl_offset, offset)
4353 assert_exceeding_data(
4355 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4360 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4361 base_klass = GeneralizedTime
4363 min_datetime = datetime(1900, 1, 1)
4364 max_datetime = datetime(9999, 12, 31)
4365 evgen_mode_skip_value = False
4367 def additional_symmetric_check(self, value, obj_encoded):
4368 if value.microsecond > 0:
4369 self.assertFalse(obj_encoded.endswith(b"0Z"))
4371 def test_repr_not_ready(self):
4372 str(GeneralizedTime())
4373 repr(GeneralizedTime())
4375 def test_x690_vector_valid(self):
4379 b"19920722132100.3Z",
4381 GeneralizedTime(data)
4383 def test_x690_vector_invalid(self):
4386 b"19920622123421.0Z",
4387 b"19920722132100.30Z",
4389 with self.assertRaises(DecodeError) as err:
4390 GeneralizedTime(data)
4393 def test_go_vectors_invalid(self):
4405 b"-20100102030410Z",
4406 b"2010-0102030410Z",
4407 b"2010-0002030410Z",
4408 b"201001-02030410Z",
4409 b"20100102-030410Z",
4410 b"2010010203-0410Z",
4411 b"201001020304-10Z",
4412 # These ones are INVALID in *DER*, but accepted
4413 # by Go's encoding/asn1
4414 b"20100102030405+0607",
4415 b"20100102030405-0607",
4417 with self.assertRaises(DecodeError) as err:
4418 GeneralizedTime(data)
4421 def test_go_vectors_valid(self):
4423 GeneralizedTime(b"20100102030405Z").todatetime(),
4424 datetime(2010, 1, 2, 3, 4, 5, 0),
4427 def test_go_vectors_valid_ber(self):
4429 b"20100102030405+0607",
4430 b"20100102030405-0607",
4432 GeneralizedTime(data, ctx={"bered": True})
4434 def test_utc_offsets(self):
4435 """Some know equal UTC offsets
4438 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4442 "200101011130-0700",
4443 "200101011500-03:30",
4446 self.assertEqual(dts[0], dts[1])
4447 self.assertEqual(dts[0], dts[2])
4448 self.assertEqual(dts[0], dts[3])
4450 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4451 @given(data_strategy())
4452 def test_valid_ber(self, d):
4453 year = d.draw(integers(min_value=2, max_value=9999))
4454 month = d.draw(integers(min_value=1, max_value=12))
4455 day = d.draw(integers(min_value=1, max_value=28))
4456 hours = d.draw(integers(min_value=0, max_value=23))
4457 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4458 dt = datetime(year, month, day, hours)
4459 fractions_sign = d.draw(sampled_from(" ,."))
4461 if fractions_sign != " ":
4462 fractions = random()
4463 if d.draw(booleans()):
4464 minutes = d.draw(integers(min_value=0, max_value=59))
4465 data += "%02d" % minutes
4466 dt += timedelta(seconds=60 * minutes)
4467 if d.draw(booleans()):
4468 seconds = d.draw(integers(min_value=0, max_value=59))
4469 data += "%02d" % seconds
4470 dt += timedelta(seconds=seconds)
4471 if fractions is not None:
4472 dt += timedelta(microseconds=10**6 * fractions)
4473 elif fractions is not None:
4474 dt += timedelta(seconds=60 * fractions)
4475 elif fractions is not None:
4476 dt += timedelta(seconds=3600 * fractions)
4477 if fractions is not None:
4478 data += fractions_sign + str(fractions)[2:]
4479 if d.draw(booleans()):
4481 elif d.draw(booleans()):
4482 offset_hour = d.draw(integers(min_value=0, max_value=13))
4484 if d.draw(booleans()):
4489 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4490 data += "%02d" % offset_hour
4491 minutes_separator = d.draw(sampled_from((None, "", ":")))
4492 if minutes_separator is not None:
4493 offset_minute = d.draw(integers(min_value=0, max_value=59))
4494 dt -= timedelta(seconds=sign * 60 * offset_minute)
4495 data += "%s%02d" % (minutes_separator, offset_minute)
4496 data = data.encode("ascii")
4497 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4499 GeneralizedTime().decod(data_der)
4504 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4507 mktime(obj.todatetime().timetuple()),
4508 mktime(dt.timetuple()),
4512 obj.todatetime().timestamp()
4516 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4517 self.assertEqual(obj.ber_encoded, not dered)
4518 self.assertEqual(obj.bered, not dered)
4519 self.assertEqual(obj.ber_raw, None if dered else data)
4520 self.assertEqual(obj.encode() == data_der, dered)
4525 def test_invalid_ber(self):
4527 # "00010203040506.07",
4528 "-0010203040506.07",
4529 "0001-203040506.07",
4530 "000102-3040506.07",
4531 "00010203-40506.07",
4532 "0001020304-506.07",
4533 "000102030405-6.07",
4534 "00010203040506.-7",
4535 "+0010203040506.07",
4536 "0001+203040506.07",
4537 "000102+3040506.07",
4538 "00010203+40506.07",
4539 "0001020304+506.07",
4540 "000102030405+6.07",
4541 "00010203040506.+7",
4542 " 0010203040506.07",
4543 "0001 203040506.07",
4544 "000102 3040506.07",
4545 "00010203 40506.07",
4546 "0001020304 506.07",
4547 "000102030405 6.07",
4548 "00010203040506. 7",
4549 "001 0203040506.07",
4550 "00012 03040506.07",
4551 "0001023 040506.07",
4552 "000102034 0506.07",
4553 "00010203045 06.07",
4554 "0001020304056 .07",
4555 "00010203040506.7 ",
4635 "00010203040506.07+15",
4636 "00010203040506.07-15",
4637 "00010203040506.07+14:60",
4638 "00010203040506.07+1460",
4639 "00010203040506.07-1460",
4640 "00010203040506.07+00:60",
4641 "00010203040506.07-00:60",
4643 "00010203040506+15",
4644 "00010203040506-15",
4645 "00010203040506+14:60",
4646 "00010203040506+1460",
4647 "00010203040506-1460",
4648 "00010203040506+00:60",
4649 "00010203040506-00:60",
4658 with self.assertRaises(DecodeError):
4659 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4660 data = data.replace(".", ",")
4661 with self.assertRaises(DecodeError):
4662 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4666 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4667 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4669 binary(min_size=1, max_size=1),
4671 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4672 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4675 def test_junk(self, part0, part1, part2):
4676 junk = part0 + part1 + part2
4677 assume(not (set(junk) <= set(digits.encode("ascii"))))
4678 with self.assertRaises(DecodeError):
4679 GeneralizedTime().decode(
4680 GeneralizedTime.tag_default +
4681 len_encode(len(junk)) +
4687 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4688 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4690 binary(min_size=1, max_size=1),
4692 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4693 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4696 def test_junk_dm(self, part0, part1, part2):
4697 junk = part0 + part1 + part2
4698 assume(not (set(junk) <= set(digits.encode("ascii"))))
4699 with self.assertRaises(DecodeError):
4700 GeneralizedTime().decode(
4701 GeneralizedTime.tag_default +
4702 len_encode(len(junk)) +
4706 def test_ns_fractions(self):
4707 GeneralizedTime(b"20010101000000.000001Z")
4708 with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
4709 GeneralizedTime(b"20010101000000.0000001Z")
4711 def test_non_pure_integers(self):
4713 # b"20000102030405Z,
4720 b"20000102030405.+6Z",
4721 b"20000102030405.-6Z",
4728 b"20000102030405._6Z",
4729 b"20000102030405.6_Z",
4736 b"20000102030405. 6Z",
4743 b"20000102030405.6 Z",
4745 with self.assertRaises(DecodeError):
4746 GeneralizedTime(data)
4748 def test_aware(self):
4749 with self.assertRaisesRegex(ValueError, "only naive"):
4750 GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
4753 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4754 base_klass = UTCTime
4756 min_datetime = datetime(2000, 1, 1)
4757 max_datetime = datetime(2049, 12, 31)
4758 evgen_mode_skip_value = False
4760 def additional_symmetric_check(self, value, obj_encoded):
4763 def test_repr_not_ready(self):
4764 str(GeneralizedTime())
4767 def test_x690_vector_valid(self):
4775 def test_x690_vector_invalid(self):
4780 with self.assertRaises(DecodeError) as err:
4784 def test_go_vectors_invalid(self):
4810 # These ones are INVALID in *DER*, but accepted
4811 # by Go's encoding/asn1
4812 b"910506164540-0700",
4813 b"910506164540+0730",
4817 with self.assertRaises(DecodeError) as err:
4821 def test_go_vectors_valid(self):
4823 UTCTime(b"910506234540Z").todatetime(),
4824 datetime(1991, 5, 6, 23, 45, 40, 0),
4827 def test_non_pure_integers(self):
4856 with self.assertRaises(DecodeError):
4859 def test_x680_vector_valid_ber(self):
4861 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4862 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4863 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4864 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4866 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4867 obj = UTCTime().decod(data_der, ctx={"bered": True})
4868 self.assertEqual(obj, dt)
4869 self.assertEqual(obj.todatetime(), dt)
4870 self.assertTrue(obj.ber_encoded)
4871 self.assertTrue(obj.bered)
4872 self.assertEqual(obj.ber_raw, data)
4873 self.assertNotEqual(obj.encode(), data_der)
4876 def test_go_vectors_valid_ber(self):
4878 b"910506164540-0700",
4879 b"910506164540+0730",
4883 data = UTCTime.tag_default + len_encode(len(data)) + data
4884 obj = UTCTime().decod(data, ctx={"bered": True})
4885 self.assertTrue(obj.ber_encoded)
4886 self.assertTrue(obj.bered)
4887 self.assertNotEqual(obj.encode(), data)
4890 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4891 @given(data_strategy())
4892 def test_valid_ber(self, d):
4893 year = d.draw(integers(min_value=0, max_value=99))
4894 month = d.draw(integers(min_value=1, max_value=12))
4895 day = d.draw(integers(min_value=1, max_value=28))
4896 hours = d.draw(integers(min_value=0, max_value=23))
4897 minute = d.draw(integers(min_value=0, max_value=59))
4898 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4900 year + (2000 if year < 50 else 1900),
4907 if d.draw(booleans()):
4909 seconds = d.draw(integers(min_value=0, max_value=59))
4910 data += "%02d" % seconds
4911 dt += timedelta(seconds=seconds)
4912 if d.draw(booleans()):
4916 offset_hour = d.draw(integers(min_value=0, max_value=13))
4917 offset_minute = d.draw(integers(min_value=0, max_value=59))
4918 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4919 if d.draw(booleans()):
4925 data += "%02d%02d" % (offset_hour, offset_minute)
4926 data = data.encode("ascii")
4927 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4928 obj = UTCTime().decod(data_der, ctx={"bered": True})
4929 self.assertEqual(obj, dt)
4930 self.assertEqual(obj.todatetime(), dt)
4931 self.assertEqual(obj.ber_encoded, not dered)
4932 self.assertEqual(obj.bered, not dered)
4933 self.assertEqual(obj.ber_raw, None if dered else data)
4934 self.assertEqual(obj.encode() == data_der, dered)
4939 def test_invalid_ber(self):
4980 b"0001020304+0000Z",
4989 with self.assertRaises(DecodeError):
4990 UTCTime(data, ctx={"bered": True})
4991 data = data[:8] + data[8+2:]
4992 with self.assertRaises(DecodeError):
4993 UTCTime(data, ctx={"bered": True})
5038 b"000102030405+000",
5039 b"000102030405+000Z",
5040 b"000102030405+0000Z",
5041 b"000102030405+-101",
5042 b"000102030405+01-1",
5043 b"000102030405+0060",
5044 b"000102030405+1401",
5045 b"500101000002+0003",
5047 with self.assertRaises(DecodeError):
5048 UTCTime(data, ctx={"bered": True})
5050 @given(integers(min_value=0, max_value=49))
5051 def test_pre50(self, year):
5053 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5057 @given(integers(min_value=50, max_value=99))
5058 def test_post50(self, year):
5060 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5066 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5067 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5069 binary(min_size=1, max_size=1),
5071 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5072 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5075 def test_junk(self, part0, part1, part2):
5076 junk = part0 + part1 + part2
5077 assume(not (set(junk) <= set(digits.encode("ascii"))))
5078 with self.assertRaises(DecodeError):
5080 UTCTime.tag_default +
5081 len_encode(len(junk)) +
5085 def test_aware(self):
5086 with self.assertRaisesRegex(ValueError, "only naive"):
5087 UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
5089 def test_raises_if_no_dateutil(self):
5090 with patch("pyderasn.tzUTC", new="missing"):
5091 with self.assertRaisesRegex(NotImplementedError, "dateutil"):
5092 UTCTime(datetime.now()).totzdatetime()
5094 def test_tzinfo_gives_datetime_with_tzutc_tzinfo(self):
5095 self.assertEqual(UTCTime(datetime.now()).totzdatetime().tzinfo, UTC)
5099 def tlv_value_strategy(draw):
5100 tag_num = draw(integers(min_value=1))
5101 data = draw(binary())
5102 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
5106 def any_values_strategy(draw, do_expl=False):
5107 value = draw(one_of(none(), tlv_value_strategy()))
5110 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5111 optional = draw(one_of(none(), booleans()))
5113 draw(integers(min_value=0)),
5114 draw(integers(min_value=0)),
5115 draw(integers(min_value=0)),
5117 return (value, expl, optional, _decoded)
5120 class AnyInherited(Any):
5124 class TestAny(CommonMixin, TestCase):
5127 def test_invalid_value_type(self):
5128 with self.assertRaises(InvalidValueType) as err:
5133 def test_optional(self, optional):
5134 obj = Any(optional=optional)
5135 self.assertEqual(obj.optional, optional)
5137 @given(tlv_value_strategy())
5138 def test_ready(self, value):
5140 self.assertFalse(obj.ready)
5143 pprint(obj, big_blobs=True, with_decode_path=True)
5144 with self.assertRaises(ObjNotReady) as err:
5147 with self.assertRaises(ObjNotReady) as err:
5150 self.assertTrue(obj.ready)
5153 pprint(obj, big_blobs=True, with_decode_path=True)
5156 def test_basic(self, value):
5157 integer_encoded = Integer(value).encode()
5159 Any(integer_encoded),
5160 Any(Integer(value)),
5161 Any(Any(Integer(value))),
5163 self.assertSequenceEqual(bytes(obj), integer_encoded)
5165 obj.decode(obj.encode())[0].vlen,
5166 len(integer_encoded),
5170 pprint(obj, big_blobs=True, with_decode_path=True)
5171 self.assertSequenceEqual(obj.encode(), integer_encoded)
5173 @given(tlv_value_strategy(), tlv_value_strategy())
5174 def test_comparison(self, value1, value2):
5175 for klass in (Any, AnyInherited):
5176 obj1 = klass(value1)
5177 obj2 = klass(value2)
5178 self.assertEqual(obj1 == obj2, value1 == value2)
5179 self.assertEqual(obj1 != obj2, value1 != value2)
5180 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5182 @given(data_strategy())
5183 def test_call(self, d):
5184 for klass in (Any, AnyInherited):
5190 ) = d.draw(any_values_strategy())
5191 obj_initial = klass(
5194 optional_initial or False,
5202 ) = d.draw(any_values_strategy(do_expl=True))
5203 obj = obj_initial(value, expl, optional)
5205 value_expected = None if value is None else value
5206 self.assertEqual(obj, value_expected)
5207 self.assertEqual(obj.expl_tag, expl or expl_initial)
5208 if obj.default is None:
5209 optional = optional_initial if optional is None else optional
5210 optional = False if optional is None else optional
5211 self.assertEqual(obj.optional, optional)
5213 def test_simultaneous_impl_expl(self):
5214 # override it, as Any does not have implicit tag
5217 def test_decoded(self):
5218 # override it, as Any does not have implicit tag
5221 @given(any_values_strategy())
5222 def test_copy(self, values):
5223 for klass in (Any, AnyInherited):
5224 obj = klass(*values)
5225 for copy_func in copy_funcs:
5226 obj_copied = copy_func(obj)
5227 self.assert_copied_basic_fields(obj, obj_copied)
5228 self.assertEqual(obj._value, obj_copied._value)
5230 @given(binary().map(OctetString))
5231 def test_stripped(self, value):
5233 with self.assertRaises(NotEnoughData):
5234 obj.decode(obj.encode()[:-1])
5237 tlv_value_strategy(),
5238 integers(min_value=1).map(tag_ctxc),
5240 def test_stripped_expl(self, value, tag_expl):
5241 obj = Any(value, expl=tag_expl)
5242 with self.assertRaises(NotEnoughData):
5243 obj.decode(obj.encode()[:-1])
5246 integers(min_value=31),
5247 integers(min_value=0),
5250 def test_bad_tag(self, tag, offset, decode_path):
5251 with self.assertRaises(DecodeError) as err:
5253 tag_encode(tag)[:-1],
5255 decode_path=decode_path,
5258 self.assertEqual(err.exception.offset, offset)
5259 self.assertEqual(err.exception.decode_path, decode_path)
5262 integers(min_value=128),
5263 integers(min_value=0),
5266 def test_bad_len(self, l, offset, decode_path):
5267 with self.assertRaises(DecodeError) as err:
5269 Any.tag_default + len_encode(l)[:-1],
5271 decode_path=decode_path,
5274 self.assertEqual(err.exception.offset, offset)
5275 self.assertEqual(err.exception.decode_path, decode_path)
5277 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5279 any_values_strategy(),
5280 integers().map(lambda x: Integer(x).encode()),
5281 integers(min_value=1).map(tag_ctxc),
5282 integers(min_value=0),
5297 for klass in (Any, AnyInherited):
5298 _, _, optional, _decoded = values
5299 obj = klass(value=value, optional=optional, _decoded=_decoded)
5302 pprint(obj, big_blobs=True, with_decode_path=True)
5303 self.assertFalse(obj.expled)
5304 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5305 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5306 obj_encoded = obj.encode()
5307 self.assertEqual(encode2pass(obj), obj_encoded)
5308 obj_expled = obj(value, expl=tag_expl)
5309 self.assertTrue(obj_expled.expled)
5310 tag_class, _, tag_num = tag_decode(tag_expl)
5311 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5313 list(obj_expled.pps())
5314 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5315 obj_expled_encoded = obj_expled.encode()
5316 ctx_dummy["keep_memoryview"] = keep_memoryview
5317 ctx_copied = deepcopy(ctx_dummy)
5318 obj_decoded, tail = obj_expled.decode(
5319 obj_expled_encoded + tail_junk,
5323 self.assertDictEqual(ctx_copied, ctx_dummy)
5325 list(obj_decoded.pps())
5326 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5327 self.assertEqual(tail, tail_junk)
5328 self.assertEqual(obj_decoded, obj_expled)
5329 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5330 self.assertEqual(bytes(obj_decoded), bytes(obj))
5331 self.assertIsInstance(
5333 memoryview if keep_memoryview else bytes,
5335 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5336 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5337 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5339 obj_decoded.expl_llen,
5340 len(len_encode(len(obj_encoded))),
5342 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5343 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5346 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5348 self.assertEqual(obj_decoded.expl_offset, offset)
5349 self.assertEqual(obj_decoded.tlen, 0)
5350 self.assertEqual(obj_decoded.llen, 0)
5351 self.assertEqual(obj_decoded.vlen, len(value))
5352 assert_exceeding_data(
5354 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5358 evgens = list(obj_expled.decode_evgen(
5359 obj_expled_encoded + tail_junk,
5361 decode_path=decode_path,
5364 self.assertEqual(len(evgens), 1)
5365 _decode_path, obj, tail = evgens[0]
5366 self.assertSequenceEqual(tail, tail_junk)
5367 self.assertEqual(_decode_path, decode_path)
5368 self.assertEqual(obj.expl_offset, offset)
5373 integers(min_value=1).map(tag_ctxc),
5374 integers(min_value=0, max_value=3),
5375 integers(min_value=0),
5379 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5380 chunk = Boolean(False, expl=expl).encode()
5382 OctetString.tag_default +
5384 b"".join([chunk] * chunks) +
5387 with self.assertRaises(LenIndefForm):
5391 decode_path=decode_path,
5393 obj, tail = Any().decode(
5396 decode_path=decode_path,
5397 ctx={"bered": True},
5399 self.assertSequenceEqual(tail, junk)
5400 self.assertEqual(obj.offset, offset)
5401 self.assertEqual(obj.tlvlen, len(encoded))
5402 self.assertTrue(obj.lenindef)
5403 self.assertFalse(obj.ber_encoded)
5404 self.assertTrue(obj.bered)
5406 self.assertTrue(obj.lenindef)
5407 self.assertFalse(obj.ber_encoded)
5408 self.assertTrue(obj.bered)
5411 pprint(obj, big_blobs=True, with_decode_path=True)
5412 with self.assertRaises(NotEnoughData) as err:
5416 decode_path=decode_path,
5417 ctx={"bered": True},
5419 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5420 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5422 class SeqOf(SequenceOf):
5423 schema = Boolean(expl=expl)
5425 class Seq(Sequence):
5427 ("type", ObjectIdentifier(defines=((("value",), {
5428 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5433 ("type", ObjectIdentifier("1.2.3")),
5434 ("value", Any(encoded)),
5436 seq_encoded = seq.encode()
5437 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5438 self.assertIsNotNone(seq_decoded["value"].defined)
5440 list(seq_decoded.pps())
5441 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5442 self.assertTrue(seq_decoded.bered)
5443 self.assertFalse(seq_decoded["type"].bered)
5444 self.assertTrue(seq_decoded["value"].bered)
5446 chunk = chunk[:-1] + b"\x01"
5447 chunks = b"".join([chunk] * (chunks + 1))
5448 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5450 ("type", ObjectIdentifier("1.2.3")),
5451 ("value", Any(encoded)),
5453 seq_encoded = seq.encode()
5454 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5455 self.assertIsNotNone(seq_decoded["value"].defined)
5457 list(seq_decoded.pps())
5458 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5459 self.assertTrue(seq_decoded.bered)
5460 self.assertFalse(seq_decoded["type"].bered)
5461 self.assertTrue(seq_decoded["value"].bered)
5465 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5467 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5468 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5470 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5471 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5473 min_size=len(names),
5474 max_size=len(names),
5477 (name, Integer(**tag_kwargs))
5478 for name, tag_kwargs in zip(names, tags)
5481 if value_required or draw(booleans()):
5482 value = draw(tuples(
5483 sampled_from([name for name, _ in schema]),
5484 integers().map(Integer),
5488 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5489 default = draw(one_of(
5491 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5493 optional = draw(one_of(none(), booleans()))
5495 draw(integers(min_value=0)),
5496 draw(integers(min_value=0)),
5497 draw(integers(min_value=0)),
5499 return (schema, value, expl, default, optional, _decoded)
5502 class ChoiceInherited(Choice):
5506 class TestChoice(CommonMixin, TestCase):
5508 schema = (("whatever", Boolean()),)
5511 def test_schema_required(self):
5512 with self.assertRaisesRegex(ValueError, "schema must be specified"):
5515 def test_impl_forbidden(self):
5516 with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
5517 Choice(impl=b"whatever")
5519 def test_invalid_value_type(self):
5520 with self.assertRaises(InvalidValueType) as err:
5521 self.base_klass(123)
5523 with self.assertRaises(ObjUnknown) as err:
5524 self.base_klass(("whenever", Boolean(False)))
5526 with self.assertRaises(InvalidValueType) as err:
5527 self.base_klass(("whatever", Integer(123)))
5531 def test_optional(self, optional):
5532 obj = self.base_klass(
5533 default=self.base_klass(("whatever", Boolean(False))),
5536 self.assertTrue(obj.optional)
5539 def test_ready(self, value):
5540 obj = self.base_klass()
5541 self.assertFalse(obj.ready)
5544 pprint(obj, big_blobs=True, with_decode_path=True)
5545 self.assertIsNone(obj["whatever"])
5546 with self.assertRaises(ObjNotReady) as err:
5549 with self.assertRaises(ObjNotReady) as err:
5551 obj["whatever"] = Boolean()
5552 self.assertFalse(obj.ready)
5555 pprint(obj, big_blobs=True, with_decode_path=True)
5556 obj["whatever"] = Boolean(value)
5557 self.assertTrue(obj.ready)
5560 pprint(obj, big_blobs=True, with_decode_path=True)
5562 @given(booleans(), booleans())
5563 def test_comparison(self, value1, value2):
5564 class WahlInherited(self.base_klass):
5566 for klass in (self.base_klass, WahlInherited):
5567 obj1 = klass(("whatever", Boolean(value1)))
5568 obj2 = klass(("whatever", Boolean(value2)))
5569 self.assertEqual(obj1 == obj2, value1 == value2)
5570 self.assertEqual(obj1 != obj2, value1 != value2)
5571 self.assertEqual(obj1 == obj2._value, value1 == value2)
5572 self.assertFalse(obj1 == obj2._value[1])
5574 @given(data_strategy())
5575 def test_call(self, d):
5576 for klass in (Choice, ChoiceInherited):
5584 ) = d.draw(choice_values_strategy())
5587 schema = schema_initial
5589 value=value_initial,
5591 default=default_initial,
5592 optional=optional_initial or False,
5593 _decoded=_decoded_initial,
5602 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5603 obj = obj_initial(value, expl, default, optional)
5605 value_expected = default if value is None else value
5607 default_initial if value_expected is None
5610 self.assertEqual(obj.choice, value_expected[0])
5611 self.assertEqual(obj.value, int(value_expected[1]))
5612 self.assertEqual(obj.expl_tag, expl or expl_initial)
5613 default_expect = default_initial if default is None else default
5614 if default_expect is not None:
5615 self.assertEqual(obj.default.choice, default_expect[0])
5616 self.assertEqual(obj.default.value, int(default_expect[1]))
5617 if obj.default is None:
5618 optional = optional_initial if optional is None else optional
5619 optional = False if optional is None else optional
5622 self.assertEqual(obj.optional, optional)
5623 self.assertEqual(obj.specs, obj_initial.specs)
5625 def test_simultaneous_impl_expl(self):
5626 # override it, as Any does not have implicit tag
5629 def test_decoded(self):
5630 # override it, as Any does not have implicit tag
5633 @given(choice_values_strategy())
5634 def test_copy(self, values):
5635 _schema, value, expl, default, optional, _decoded = values
5637 class Wahl(self.base_klass):
5639 register_class(Wahl)
5644 optional=optional or False,
5647 for copy_func in copy_funcs:
5648 obj_copied = copy_func(obj)
5649 self.assertIsNone(obj.tag)
5650 self.assertIsNone(obj_copied.tag)
5651 # hack for assert_copied_basic_fields
5652 obj.tag = "whatever"
5653 obj_copied.tag = "whatever"
5654 self.assert_copied_basic_fields(obj, obj_copied)
5656 self.assertEqual(obj._value, obj_copied._value)
5657 self.assertEqual(obj.specs, obj_copied.specs)
5660 def test_stripped(self, value):
5661 obj = self.base_klass(("whatever", Boolean(value)))
5662 with self.assertRaises(NotEnoughData):
5663 obj.decode(obj.encode()[:-1])
5667 integers(min_value=1).map(tag_ctxc),
5669 def test_stripped_expl(self, value, tag_expl):
5670 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5671 with self.assertRaises(NotEnoughData):
5672 obj.decode(obj.encode()[:-1])
5674 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5675 @given(data_strategy())
5676 def test_symmetric(self, d):
5677 _schema, value, _, default, optional, _decoded = d.draw(
5678 choice_values_strategy(value_required=True)
5680 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5681 offset = d.draw(integers(min_value=0))
5682 tail_junk = d.draw(binary(max_size=5))
5683 decode_path = d.draw(decode_path_strat)
5685 class Wahl(self.base_klass):
5695 pprint(obj, big_blobs=True, with_decode_path=True)
5696 self.assertFalse(obj.expled)
5697 self.assertEqual(obj.tag_order, obj.value.tag_order)
5698 obj_encoded = obj.encode()
5699 self.assertEqual(encode2pass(obj), obj_encoded)
5700 obj_expled = obj(value, expl=tag_expl)
5701 self.assertTrue(obj_expled.expled)
5702 tag_class, _, tag_num = tag_decode(tag_expl)
5703 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5705 list(obj_expled.pps())
5706 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5707 obj_expled_encoded = obj_expled.encode()
5708 ctx_copied = deepcopy(ctx_dummy)
5709 obj_decoded, tail = obj_expled.decode(
5710 obj_expled_encoded + tail_junk,
5714 self.assertDictEqual(ctx_copied, ctx_dummy)
5716 list(obj_decoded.pps())
5717 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5718 self.assertEqual(tail, tail_junk)
5719 self.assertEqual(obj_decoded, obj_expled)
5720 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5721 self.assertEqual(obj_decoded.value, obj_expled.value)
5722 self.assertEqual(obj_decoded.choice, obj.choice)
5723 self.assertEqual(obj_decoded.value, obj.value)
5724 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5725 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5726 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5728 obj_decoded.expl_llen,
5729 len(len_encode(len(obj_encoded))),
5731 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5732 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5735 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5737 self.assertEqual(obj_decoded.expl_offset, offset)
5738 self.assertSequenceEqual(
5740 obj_decoded.value.fulloffset - offset:
5741 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5745 assert_exceeding_data(
5747 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5751 evgens = list(obj_expled.decode_evgen(
5752 obj_expled_encoded + tail_junk,
5754 decode_path=decode_path,
5757 self.assertEqual(len(evgens), 2)
5758 _decode_path, obj, tail = evgens[0]
5759 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5760 _decode_path, obj, tail = evgens[1]
5761 self.assertSequenceEqual(tail, tail_junk)
5762 self.assertEqual(_decode_path, decode_path)
5763 self.assertEqual(obj.expl_offset, offset)
5768 def test_set_get(self, value):
5771 ("erste", Boolean()),
5772 ("zweite", Integer()),
5775 with self.assertRaises(ObjUnknown) as err:
5776 obj["whatever"] = "whenever"
5777 with self.assertRaises(InvalidValueType) as err:
5778 obj["zweite"] = Boolean(False)
5779 obj["zweite"] = Integer(value)
5781 with self.assertRaises(ObjUnknown) as err:
5784 self.assertIsNone(obj["erste"])
5785 self.assertEqual(obj["zweite"], Integer(value))
5787 def test_tag_mismatch(self):
5790 ("erste", Boolean()),
5792 int_encoded = Integer(123).encode()
5793 bool_encoded = Boolean(False).encode()
5795 obj.decode(bool_encoded)
5796 with self.assertRaises(TagMismatch):
5797 obj.decode(int_encoded)
5799 def test_tag_mismatch_underlying(self):
5800 class SeqOfBoolean(SequenceOf):
5803 class SeqOfInteger(SequenceOf):
5808 ("erste", SeqOfBoolean()),
5811 int_encoded = SeqOfInteger((Integer(123),)).encode()
5812 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5814 obj.decode(bool_encoded)
5815 with self.assertRaises(TagMismatch) as err:
5816 obj.decode(int_encoded)
5817 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5821 def seq_values_strategy(draw, seq_klass, do_expl=False):
5823 if draw(booleans()):
5825 value._value = draw(dictionaries(
5828 booleans().map(Boolean),
5829 integers().map(Integer),
5833 if draw(booleans()):
5834 schema = list(draw(dictionaries(
5837 booleans().map(Boolean),
5838 integers().map(Integer),
5844 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5846 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5848 if draw(booleans()):
5849 default = seq_klass()
5850 default._value = draw(dictionaries(
5853 booleans().map(Boolean),
5854 integers().map(Integer),
5857 optional = draw(one_of(none(), booleans()))
5859 draw(integers(min_value=0)),
5860 draw(integers(min_value=0)),
5861 draw(integers(min_value=0)),
5863 return (value, schema, impl, expl, default, optional, _decoded)
5867 def sequence_strategy(draw, seq_klass):
5868 inputs = draw(lists(
5870 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5871 tuples(just(Integer), integers(), one_of(none(), integers())),
5876 integers(min_value=1),
5877 min_size=len(inputs),
5878 max_size=len(inputs),
5881 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5882 for tag, expled in zip(tags, draw(lists(
5884 min_size=len(inputs),
5885 max_size=len(inputs),
5889 for i, optional in enumerate(draw(lists(
5890 sampled_from(("required", "optional", "empty")),
5891 min_size=len(inputs),
5892 max_size=len(inputs),
5894 if optional in ("optional", "empty"):
5895 inits[i]["optional"] = True
5896 if optional == "empty":
5898 empties = set(empties)
5899 names = list(draw(sets(
5901 min_size=len(inputs),
5902 max_size=len(inputs),
5905 for i, (klass, value, default) in enumerate(inputs):
5906 schema.append((names[i], klass(default=default, **inits[i])))
5907 seq_name = draw(text_letters())
5908 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5911 for i, (klass, value, default) in enumerate(inputs):
5918 "default_value": None if spec.default is None else default,
5922 expect["optional"] = True
5924 expect["presented"] = True
5925 expect["value"] = value
5927 expect["optional"] = True
5928 if default is not None and default == value:
5929 expect["presented"] = False
5930 seq[name] = klass(value)
5931 expects.append(expect)
5936 def sequences_strategy(draw, seq_klass):
5937 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5939 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5940 for tag, expled in zip(tags, draw(lists(
5947 i for i, is_default in enumerate(draw(lists(
5953 names = list(draw(sets(
5958 seq_expectses = draw(lists(
5959 sequence_strategy(seq_klass=seq_klass),
5963 seqs = [seq for seq, _ in seq_expectses]
5965 for i, (name, seq) in enumerate(zip(names, seqs)):
5968 seq(default=(seq if i in defaulted else None), **inits[i]),
5970 seq_name = draw(text_letters())
5971 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5974 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5977 "expects": expects_inner,
5980 seq_outer[name] = seq_inner
5981 if seq_outer.specs[name].default is None:
5982 expect["presented"] = True
5983 expect_outers.append(expect)
5984 return seq_outer, expect_outers
5987 class SeqMixin(object):
5988 def test_invalid_value_type(self):
5989 with self.assertRaises(InvalidValueType) as err:
5990 self.base_klass(123)
5993 def test_invalid_value_type_set(self):
5994 class Seq(self.base_klass):
5995 schema = (("whatever", Boolean()),)
5997 with self.assertRaises(InvalidValueType) as err:
5998 seq["whatever"] = Integer(123)
6002 def test_optional(self, optional):
6003 obj = self.base_klass(default=self.base_klass(), optional=optional)
6004 self.assertTrue(obj.optional)
6006 @given(data_strategy())
6007 def test_ready(self, d):
6009 str(i): v for i, v in enumerate(d.draw(lists(
6016 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
6023 for name in d.draw(permutations(
6024 list(ready.keys()) + list(non_ready.keys()),
6026 schema_input.append((name, Boolean()))
6028 class Seq(self.base_klass):
6029 schema = tuple(schema_input)
6031 for name in ready.keys():
6033 seq[name] = Boolean()
6034 self.assertFalse(seq.ready)
6037 pprint(seq, big_blobs=True, with_decode_path=True)
6038 for name, value in ready.items():
6039 seq[name] = Boolean(value)
6040 self.assertFalse(seq.ready)
6043 pprint(seq, big_blobs=True, with_decode_path=True)
6044 with self.assertRaises(ObjNotReady) as err:
6047 with self.assertRaises(ObjNotReady) as err:
6049 for name, value in non_ready.items():
6050 seq[name] = Boolean(value)
6051 self.assertTrue(seq.ready)
6054 pprint(seq, big_blobs=True, with_decode_path=True)
6056 @given(data_strategy())
6057 def test_call(self, d):
6058 class SeqInherited(self.base_klass):
6060 for klass in (self.base_klass, SeqInherited):
6069 ) = d.draw(seq_values_strategy(seq_klass=klass))
6070 obj_initial = klass(
6076 optional_initial or False,
6087 ) = d.draw(seq_values_strategy(
6089 do_expl=impl_initial is None,
6091 obj = obj_initial(value, impl, expl, default, optional)
6092 value_expected = default if value is None else value
6094 default_initial if value_expected is None
6097 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
6098 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6099 self.assertEqual(obj.expl_tag, expl or expl_initial)
6101 {} if obj.default is None else obj.default._value,
6102 getattr(default_initial if default is None else default, "_value", {}),
6104 if obj.default is None:
6105 optional = optional_initial if optional is None else optional
6106 optional = False if optional is None else optional
6109 self.assertEqual(list(obj.specs.items()), schema_initial or [])
6110 self.assertEqual(obj.optional, optional)
6112 @given(data_strategy())
6113 def test_copy(self, d):
6114 class SeqInherited(self.base_klass):
6116 register_class(SeqInherited)
6117 for klass in (self.base_klass, SeqInherited):
6118 values = d.draw(seq_values_strategy(seq_klass=klass))
6119 obj = klass(*values)
6120 for copy_func in copy_funcs:
6121 obj_copied = copy_func(obj)
6122 self.assert_copied_basic_fields(obj, obj_copied)
6123 self.assertEqual(obj.specs, obj_copied.specs)
6124 self.assertEqual(obj._value, obj_copied._value)
6126 @given(data_strategy())
6127 def test_stripped(self, d):
6128 value = d.draw(integers())
6129 tag_impl = tag_encode(d.draw(integers(min_value=1)))
6131 class Seq(self.base_klass):
6133 schema = (("whatever", Integer()),)
6135 seq["whatever"] = Integer(value)
6136 with self.assertRaises(NotEnoughData):
6137 seq.decode(seq.encode()[:-1])
6139 @given(data_strategy())
6140 def test_stripped_expl(self, d):
6141 value = d.draw(integers())
6142 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
6144 class Seq(self.base_klass):
6146 schema = (("whatever", Integer()),)
6148 seq["whatever"] = Integer(value)
6149 with self.assertRaises(NotEnoughData):
6150 seq.decode(seq.encode()[:-1])
6152 @given(integers(min_value=3), binary(min_size=2))
6153 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
6154 junk = tag_encode(junk_tag_num) + junk
6156 _, _, len_encoded = tag_strip(memoryview(junk))
6157 len_decode(len_encoded)
6163 class Seq(self.base_klass):
6165 ("whatever", Integer()),
6167 ("whenever", Integer()),
6170 seq["whatever"] = Integer(123)
6171 seq["junk"] = Any(junk)
6172 seq["whenever"] = Integer(123)
6173 with self.assertRaises(DecodeError):
6174 seq.decode(seq.encode())
6177 integers(min_value=31),
6178 integers(min_value=0),
6181 def test_bad_tag(self, tag, offset, decode_path):
6182 with self.assertRaises(DecodeError) as err:
6183 self.base_klass().decode(
6184 tag_encode(tag)[:-1],
6186 decode_path=decode_path,
6189 self.assertEqual(err.exception.offset, offset)
6190 self.assertEqual(err.exception.decode_path, decode_path)
6193 integers(min_value=128),
6194 integers(min_value=0),
6197 def test_bad_len(self, l, offset, decode_path):
6198 with self.assertRaises(DecodeError) as err:
6199 self.base_klass().decode(
6200 self.base_klass.tag_default + len_encode(l)[:-1],
6202 decode_path=decode_path,
6205 self.assertEqual(err.exception.offset, offset)
6206 self.assertEqual(err.exception.decode_path, decode_path)
6208 def _assert_expects(self, seq, expects):
6209 for expect in expects:
6211 seq.specs[expect["name"]].optional,
6214 if expect["default_value"] is not None:
6216 seq.specs[expect["name"]].default,
6217 expect["default_value"],
6219 if expect["presented"]:
6220 self.assertIn(expect["name"], seq)
6221 self.assertEqual(seq[expect["name"]], expect["value"])
6223 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6224 @given(data_strategy())
6225 def test_symmetric(self, d):
6226 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6227 tail_junk = d.draw(binary(max_size=5))
6228 decode_path = d.draw(decode_path_strat)
6229 self.assertTrue(seq.ready)
6230 self.assertFalse(seq.decoded)
6231 self._assert_expects(seq, expects)
6234 pprint(seq, big_blobs=True, with_decode_path=True)
6235 self.assertTrue(seq.ready)
6236 seq_encoded = seq.encode()
6237 self.assertEqual(encode2pass(seq), seq_encoded)
6238 seq_encoded_cer = encode_cer(seq)
6239 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6240 self.assertSequenceEqual(
6241 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6244 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6245 self.assertFalse(seq_decoded.lenindef)
6246 self.assertFalse(seq_decoded.ber_encoded)
6247 self.assertFalse(seq_decoded.bered)
6249 t, _, lv = tag_strip(seq_encoded)
6250 _, _, v = len_decode(lv)
6251 seq_encoded_lenindef = t + LENINDEF + v + EOC
6252 with self.assertRaises(DecodeError):
6253 seq.decode(seq_encoded_lenindef)
6254 ctx_copied = deepcopy(ctx_dummy)
6255 ctx_copied["bered"] = True
6256 seq_decoded_lenindef, tail_lenindef = seq.decode(
6257 seq_encoded_lenindef + tail_junk,
6260 del ctx_copied["bered"]
6261 self.assertDictEqual(ctx_copied, ctx_dummy)
6262 self.assertTrue(seq_decoded_lenindef.lenindef)
6263 self.assertTrue(seq_decoded_lenindef.bered)
6264 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6265 self.assertTrue(seq_decoded_lenindef.lenindef)
6266 self.assertTrue(seq_decoded_lenindef.bered)
6267 with self.assertRaises(DecodeError):
6268 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6269 with self.assertRaises(DecodeError):
6270 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6271 repr(seq_decoded_lenindef)
6272 list(seq_decoded_lenindef.pps())
6273 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6274 self.assertTrue(seq_decoded_lenindef.ready)
6276 for decoded, decoded_tail, encoded in (
6277 (seq_decoded, tail, seq_encoded),
6278 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6280 self.assertEqual(decoded_tail, tail_junk)
6281 self._assert_expects(decoded, expects)
6282 self.assertEqual(seq, decoded)
6283 self.assertEqual(decoded.encode(), seq_encoded)
6284 self.assertEqual(decoded.tlvlen, len(encoded))
6285 for expect in expects:
6286 if not expect["presented"]:
6287 self.assertNotIn(expect["name"], decoded)
6289 self.assertIn(expect["name"], decoded)
6290 obj = decoded[expect["name"]]
6291 self.assertTrue(obj.decoded)
6292 offset = obj.expl_offset if obj.expled else obj.offset
6293 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6294 self.assertSequenceEqual(
6295 seq_encoded[offset:offset + tlvlen],
6299 evgens = list(seq.decode_evgen(
6300 encoded + decoded_tail,
6301 decode_path=decode_path,
6302 ctx={"bered": True},
6304 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6305 for _decode_path, obj, _ in evgens[:-1]:
6306 self.assertEqual(_decode_path[:-1], decode_path)
6309 _decode_path, obj, tail = evgens[-1]
6310 self.assertEqual(_decode_path, decode_path)
6314 assert_exceeding_data(
6316 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6320 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6321 @given(data_strategy())
6322 def test_symmetric_with_seq(self, d):
6323 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6324 self.assertTrue(seq.ready)
6325 seq_encoded = seq.encode()
6326 self.assertEqual(encode2pass(seq), seq_encoded)
6327 seq_decoded, tail = seq.decode(seq_encoded)
6328 self.assertEqual(tail, b"")
6329 self.assertTrue(seq.ready)
6330 self.assertEqual(seq, seq_decoded)
6331 self.assertEqual(seq_decoded.encode(), seq_encoded)
6332 for expect_outer in expect_outers:
6333 if not expect_outer["presented"]:
6334 self.assertNotIn(expect_outer["name"], seq_decoded)
6336 self.assertIn(expect_outer["name"], seq_decoded)
6337 obj = seq_decoded[expect_outer["name"]]
6338 self.assertTrue(obj.decoded)
6339 offset = obj.expl_offset if obj.expled else obj.offset
6340 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6341 self.assertSequenceEqual(
6342 seq_encoded[offset:offset + tlvlen],
6345 self._assert_expects(obj, expect_outer["expects"])
6347 @given(data_strategy())
6348 def test_default_disappears(self, d):
6349 _schema = list(d.draw(dictionaries(
6351 sets(integers(), min_size=2, max_size=2),
6355 class Seq(self.base_klass):
6357 (n, Integer(default=d))
6358 for n, (_, d) in _schema
6361 for name, (value, _) in _schema:
6362 seq[name] = Integer(value)
6363 self.assertEqual(len(seq._value), len(_schema))
6364 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6365 self.assertGreater(len(seq.encode()), len(empty_seq))
6366 for name, (_, default) in _schema:
6367 seq[name] = Integer(default)
6368 self.assertEqual(len(seq._value), 0)
6369 self.assertSequenceEqual(seq.encode(), empty_seq)
6371 @given(data_strategy())
6372 def test_encoded_default_not_accepted(self, d):
6373 _schema = list(d.draw(dictionaries(
6378 tags = [tag_encode(tag) for tag in d.draw(sets(
6379 integers(min_value=1),
6380 min_size=len(_schema),
6381 max_size=len(_schema),
6385 schema = (("int", Integer()),)
6387 class SeqWithoutDefault(self.base_klass):
6390 for (n, _), t in zip(_schema, tags)
6392 seq_without_default = SeqWithoutDefault()
6393 for name, value in _schema:
6394 seq_without_default[name] = Wahl(("int", Integer(value)))
6395 seq_encoded = seq_without_default.encode()
6396 seq_without_default.decode(seq_encoded)
6398 len(list(seq_without_default.decode_evgen(seq_encoded))),
6399 len(_schema) * 2 + 1,
6402 class SeqWithDefault(self.base_klass):
6404 (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
6405 for (n, v), t in zip(_schema, tags)
6407 seq_with_default = SeqWithDefault()
6408 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6409 seq_with_default.decode(seq_encoded)
6410 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6411 list(seq_with_default.decode_evgen(seq_encoded))
6412 for ctx in ({"bered": True}, {"allow_default_values": True}):
6413 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6414 self.assertTrue(seq_decoded.ber_encoded)
6415 self.assertTrue(seq_decoded.bered)
6416 seq_decoded = copy(seq_decoded)
6417 self.assertTrue(seq_decoded.ber_encoded)
6418 self.assertTrue(seq_decoded.bered)
6419 for name, value in _schema:
6420 self.assertEqual(seq_decoded[name], seq_with_default[name])
6421 self.assertEqual(seq_decoded[name].value, value)
6423 len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
6427 seq_without_default = SeqWithoutDefault()
6428 for name, value in _schema:
6429 seq_without_default[name] = Wahl(("int", Integer(value + 1)))
6430 seq_encoded = seq_without_default.encode()
6431 seq_with_default.decode(seq_encoded)
6433 len(list(seq_with_default.decode_evgen(seq_encoded))),
6437 @given(data_strategy())
6438 def test_missing_from_spec(self, d):
6439 names = list(d.draw(sets(text_letters(), min_size=2)))
6440 tags = [tag_encode(tag) for tag in d.draw(sets(
6441 integers(min_value=1),
6442 min_size=len(names),
6443 max_size=len(names),
6445 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6447 class SeqFull(self.base_klass):
6448 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6449 seq_full = SeqFull()
6450 for i, name in enumerate(names):
6451 seq_full[name] = Integer(i)
6452 seq_encoded = seq_full.encode()
6453 altered = names_tags[:-2] + names_tags[-1:]
6455 class SeqMissing(self.base_klass):
6456 schema = [(n, Integer(impl=t)) for n, t in altered]
6457 seq_missing = SeqMissing()
6458 with self.assertRaises(TagMismatch):
6459 seq_missing.decode(seq_encoded)
6460 with self.assertRaises(TagMismatch):
6461 list(seq_missing.decode_evgen(seq_encoded))
6463 def test_bered(self):
6464 class Seq(self.base_klass):
6465 schema = (("underlying", Boolean()),)
6466 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6467 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6468 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6469 self.assertFalse(decoded.ber_encoded)
6470 self.assertFalse(decoded.lenindef)
6471 self.assertTrue(decoded.bered)
6472 decoded = copy(decoded)
6473 self.assertFalse(decoded.ber_encoded)
6474 self.assertFalse(decoded.lenindef)
6475 self.assertTrue(decoded.bered)
6477 class Seq(self.base_klass):
6478 schema = (("underlying", OctetString()),)
6480 tag_encode(form=TagFormConstructed, num=4) +
6482 OctetString(b"whatever").encode() +
6485 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6486 with self.assertRaises(DecodeError):
6487 Seq().decode(encoded)
6488 with self.assertRaises(DecodeError):
6489 list(Seq().decode_evgen(encoded))
6490 list(Seq().decode_evgen(encoded, ctx={"bered": True}))
6491 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6492 self.assertFalse(decoded.ber_encoded)
6493 self.assertFalse(decoded.lenindef)
6494 self.assertTrue(decoded.bered)
6495 decoded = copy(decoded)
6496 self.assertFalse(decoded.ber_encoded)
6497 self.assertFalse(decoded.lenindef)
6498 self.assertTrue(decoded.bered)
6501 class TestSequence(SeqMixin, CommonMixin, TestCase):
6502 base_klass = Sequence
6508 def test_remaining(self, value, junk):
6509 class Seq(Sequence):
6511 ("whatever", Integer()),
6513 int_encoded = Integer(value).encode()
6515 Sequence.tag_default,
6516 len_encode(len(int_encoded + junk)),
6519 with self.assertRaisesRegex(DecodeError, "remaining"):
6520 Seq().decode(junked)
6522 @given(sets(text_letters(), min_size=2))
6523 def test_obj_unknown(self, names):
6524 missing = names.pop()
6526 class Seq(Sequence):
6527 schema = [(n, Boolean()) for n in names]
6529 with self.assertRaises(ObjUnknown) as err:
6532 with self.assertRaises(ObjUnknown) as err:
6533 seq[missing] = Boolean()
6536 def test_x690_vector(self):
6537 class Seq(Sequence):
6539 ("name", IA5String()),
6542 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6543 self.assertEqual(seq["name"], "Smith")
6544 self.assertEqual(seq["ok"], True)
6547 class TestSet(SeqMixin, CommonMixin, TestCase):
6550 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6551 @given(data_strategy())
6552 def test_sorted(self, d):
6553 class DummySeq(Sequence):
6554 schema = (("null", Null()),)
6556 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6557 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6558 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6559 tag_nums -= set([dummy_seq_tag_num])
6560 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6561 _schema.append(("seq", DummySeq()))
6564 schema = d.draw(permutations(_schema))
6566 for name, _ in _schema:
6568 seq[name] = OctetString(name.encode("ascii"))
6569 seq["seq"] = DummySeq((("null", Null()),))
6571 seq_encoded = seq.encode()
6572 seq_decoded, _ = seq.decode(seq_encoded)
6573 seq_encoded_expected = []
6574 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6575 if tag_num == dummy_seq_tag_num:
6576 seq_encoded_expected.append(seq["seq"].encode())
6578 seq_encoded_expected.append(seq[str(tag_num)].encode())
6579 self.assertSequenceEqual(
6580 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6581 b"".join(seq_encoded_expected),
6584 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6585 encoded += seq["seq"].encode()
6586 seq_encoded = b"".join((
6588 len_encode(len(encoded)),
6591 with self.assertRaisesRegex(DecodeError, "unordered SET"):
6592 seq.decode(seq_encoded)
6593 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6594 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6595 self.assertTrue(seq_decoded.ber_encoded)
6596 self.assertTrue(seq_decoded.bered)
6597 seq_decoded = copy(seq_decoded)
6598 self.assertTrue(seq_decoded.ber_encoded)
6599 self.assertTrue(seq_decoded.bered)
6601 def test_same_value_twice(self):
6604 ("bool", Boolean()),
6608 encoded = b"".join((
6609 Integer(123).encode(),
6610 Integer(234).encode(),
6611 Boolean(True).encode(),
6613 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6614 with self.assertRaises(TagMismatch):
6615 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6619 def seqof_values_strategy(draw, schema=None, do_expl=False):
6621 schema = draw(sampled_from((Boolean(), Integer())))
6622 bound_min, bound_max = sorted(draw(sets(
6623 integers(min_value=0, max_value=10),
6627 if isinstance(schema, Boolean):
6628 values_generator = booleans().map(Boolean)
6629 elif isinstance(schema, Integer):
6630 values_generator = integers().map(Integer)
6631 values_generator = lists(
6636 values = draw(one_of(none(), values_generator))
6640 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6642 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6643 default = draw(one_of(none(), values_generator))
6644 optional = draw(one_of(none(), booleans()))
6646 draw(integers(min_value=0)),
6647 draw(integers(min_value=0)),
6648 draw(integers(min_value=0)),
6653 (bound_min, bound_max),
6662 class SeqOfMixin(object):
6663 def test_invalid_value_type(self):
6664 with self.assertRaises(InvalidValueType) as err:
6665 self.base_klass(123)
6668 def test_invalid_values_type(self):
6669 class SeqOf(self.base_klass):
6671 with self.assertRaises(InvalidValueType) as err:
6672 SeqOf([Integer(123), Boolean(False), Integer(234)])
6675 def test_schema_required(self):
6676 with self.assertRaisesRegex(ValueError, "schema must be specified"):
6677 self.base_klass.__mro__[1]()
6679 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6680 def test_comparison(self, value1, value2, tag1, tag2):
6681 class SeqOf(self.base_klass):
6683 obj1 = SeqOf([Boolean(value1)])
6684 obj2 = SeqOf([Boolean(value2)])
6685 self.assertEqual(obj1 == obj2, value1 == value2)
6686 self.assertEqual(obj1 != obj2, value1 != value2)
6687 self.assertEqual(obj1 == list(obj2), value1 == value2)
6688 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6689 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6690 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6691 self.assertEqual(obj1 == obj2, tag1 == tag2)
6692 self.assertEqual(obj1 != obj2, tag1 != tag2)
6694 @given(lists(booleans()))
6695 def test_iter(self, values):
6696 class SeqOf(self.base_klass):
6698 obj = SeqOf([Boolean(value) for value in values])
6699 self.assertEqual(len(obj), len(values))
6700 for i, value in enumerate(obj):
6701 self.assertEqual(value, values[i])
6703 @given(data_strategy())
6704 def test_ready(self, d):
6705 ready = [Integer(v) for v in d.draw(lists(
6712 range(d.draw(integers(min_value=1, max_value=5)))
6715 class SeqOf(self.base_klass):
6717 values = d.draw(permutations(ready + non_ready))
6719 for value in values:
6721 self.assertFalse(seqof.ready)
6724 pprint(seqof, big_blobs=True, with_decode_path=True)
6725 with self.assertRaises(ObjNotReady) as err:
6728 with self.assertRaises(ObjNotReady) as err:
6730 for i, value in enumerate(values):
6731 self.assertEqual(seqof[i], value)
6732 if not seqof[i].ready:
6733 seqof[i] = Integer(i)
6734 self.assertTrue(seqof.ready)
6737 pprint(seqof, big_blobs=True, with_decode_path=True)
6739 def test_spec_mismatch(self):
6740 class SeqOf(self.base_klass):
6743 seqof.append(Integer(123))
6744 with self.assertRaises(ValueError):
6745 seqof.append(Boolean(False))
6746 with self.assertRaises(ValueError):
6747 seqof[0] = Boolean(False)
6749 @given(data_strategy())
6750 def test_bounds_satisfied(self, d):
6751 class SeqOf(self.base_klass):
6753 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6754 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6755 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6756 SeqOf(value=value, bounds=(bound_min, bound_max))
6758 @given(data_strategy())
6759 def test_bounds_unsatisfied(self, d):
6760 class SeqOf(self.base_klass):
6762 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6763 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6764 value = [Boolean(False)] * d.draw(integers(min_value=0, max_value=bound_min - 1))
6765 with self.assertRaises(BoundsError) as err:
6766 SeqOf(value=value, bounds=(bound_min, bound_max))
6768 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6769 SeqOf(bounds=(bound_min, bound_max)).decode(
6770 SeqOf(value).encode()
6773 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6774 SeqOf(bounds=(bound_min, bound_max)).decode(
6775 encode2pass(SeqOf(value))
6777 value = [Boolean(True)] * d.draw(integers(
6778 min_value=bound_max + 1,
6779 max_value=bound_max + 10,
6781 with self.assertRaises(BoundsError) as err:
6782 SeqOf(value=value, bounds=(bound_min, bound_max))
6784 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6785 SeqOf(bounds=(bound_min, bound_max)).decode(
6786 SeqOf(value).encode()
6789 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6790 SeqOf(bounds=(bound_min, bound_max)).decode(
6791 encode2pass(SeqOf(value))
6794 @given(integers(min_value=1, max_value=10))
6795 def test_out_of_bounds(self, bound_max):
6796 class SeqOf(self.base_klass):
6798 bounds = (0, bound_max)
6800 for _ in range(bound_max):
6801 seqof.append(Integer(123))
6802 with self.assertRaises(BoundsError):
6803 seqof.append(Integer(123))
6805 @given(data_strategy())
6806 def test_call(self, d):
6816 ) = d.draw(seqof_values_strategy())
6818 class SeqOf(self.base_klass):
6819 schema = schema_initial
6820 obj_initial = SeqOf(
6821 value=value_initial,
6822 bounds=bounds_initial,
6825 default=default_initial,
6826 optional=optional_initial or False,
6827 _decoded=_decoded_initial,
6838 ) = d.draw(seqof_values_strategy(
6839 schema=schema_initial,
6840 do_expl=impl_initial is None,
6842 if (default is None) and (obj_initial.default is not None):
6845 (bounds is None) and
6846 (value is not None) and
6847 (bounds_initial is not None) and
6848 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6852 (bounds is None) and
6853 (default is not None) and
6854 (bounds_initial is not None) and
6855 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6867 value_expected = default if value is None else value
6869 default_initial if value_expected is None
6872 value_expected = () if value_expected is None else value_expected
6873 self.assertEqual(obj, value_expected)
6874 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6875 self.assertEqual(obj.expl_tag, expl or expl_initial)
6878 default_initial if default is None else default,
6880 if obj.default is None:
6881 optional = optional_initial if optional is None else optional
6882 optional = False if optional is None else optional
6885 self.assertEqual(obj.optional, optional)
6887 (obj._bound_min, obj._bound_max),
6888 bounds or bounds_initial or (0, float("+inf")),
6891 @given(seqof_values_strategy())
6892 def test_copy(self, values):
6893 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6895 class SeqOf(self.base_klass):
6897 register_class(SeqOf)
6904 optional=optional or False,
6907 for copy_func in copy_funcs:
6908 obj_copied = copy_func(obj)
6909 self.assert_copied_basic_fields(obj, obj_copied)
6910 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6911 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6912 self.assertEqual(obj._value, obj_copied._value)
6916 integers(min_value=1).map(tag_encode),
6918 def test_stripped(self, values, tag_impl):
6919 class SeqOf(self.base_klass):
6920 schema = OctetString()
6921 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6922 with self.assertRaises(NotEnoughData):
6923 obj.decode(obj.encode()[:-1])
6927 integers(min_value=1).map(tag_ctxc),
6929 def test_stripped_expl(self, values, tag_expl):
6930 class SeqOf(self.base_klass):
6931 schema = OctetString()
6932 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6933 with self.assertRaises(NotEnoughData):
6934 obj.decode(obj.encode()[:-1])
6937 integers(min_value=31),
6938 integers(min_value=0),
6941 def test_bad_tag(self, tag, offset, decode_path):
6942 with self.assertRaises(DecodeError) as err:
6943 self.base_klass().decode(
6944 tag_encode(tag)[:-1],
6946 decode_path=decode_path,
6949 self.assertEqual(err.exception.offset, offset)
6950 self.assertEqual(err.exception.decode_path, decode_path)
6953 integers(min_value=128),
6954 integers(min_value=0),
6957 def test_bad_len(self, l, offset, decode_path):
6958 with self.assertRaises(DecodeError) as err:
6959 self.base_klass().decode(
6960 self.base_klass.tag_default + len_encode(l)[:-1],
6962 decode_path=decode_path,
6965 self.assertEqual(err.exception.offset, offset)
6966 self.assertEqual(err.exception.decode_path, decode_path)
6968 @given(binary(min_size=1))
6969 def test_tag_mismatch(self, impl):
6970 assume(impl != self.base_klass.tag_default)
6971 with self.assertRaises(TagMismatch):
6972 self.base_klass(impl=impl).decode(self.base_klass().encode())
6974 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6976 seqof_values_strategy(schema=Integer()),
6977 lists(integers().map(Integer)),
6978 integers(min_value=1).map(tag_ctxc),
6979 integers(min_value=0),
6983 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6984 _, _, _, _, _, default, optional, _decoded = values
6986 class SeqOf(self.base_klass):
6996 pprint(obj, big_blobs=True, with_decode_path=True)
6997 self.assertFalse(obj.expled)
6998 obj_encoded = obj.encode()
6999 self.assertEqual(encode2pass(obj), obj_encoded)
7000 obj_encoded_cer = encode_cer(obj)
7001 self.assertNotEqual(obj_encoded_cer, obj_encoded)
7002 self.assertSequenceEqual(
7003 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
7006 obj_expled = obj(value, expl=tag_expl)
7007 self.assertTrue(obj_expled.expled)
7009 list(obj_expled.pps())
7010 pprint(obj_expled, big_blobs=True, with_decode_path=True)
7011 obj_expled_encoded = obj_expled.encode()
7012 ctx_copied = deepcopy(ctx_dummy)
7013 obj_decoded, tail = obj_expled.decode(
7014 obj_expled_encoded + tail_junk,
7018 self.assertDictEqual(ctx_copied, ctx_dummy)
7020 list(obj_decoded.pps())
7021 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
7022 self.assertEqual(tail, tail_junk)
7023 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
7024 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
7025 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
7026 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
7028 obj_decoded.expl_llen,
7029 len(len_encode(len(obj_encoded))),
7031 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
7032 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
7035 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
7037 self.assertEqual(obj_decoded.expl_offset, offset)
7038 for obj_inner in obj_decoded:
7039 self.assertIn(obj_inner, obj_decoded)
7040 self.assertSequenceEqual(
7043 obj_inner.offset - offset:
7044 obj_inner.offset + obj_inner.tlvlen - offset
7048 t, _, lv = tag_strip(obj_encoded)
7049 _, _, v = len_decode(lv)
7050 obj_encoded_lenindef = t + LENINDEF + v + EOC
7051 with self.assertRaises(DecodeError):
7052 obj.decode(obj_encoded_lenindef)
7053 obj_decoded_lenindef, tail_lenindef = obj.decode(
7054 obj_encoded_lenindef + tail_junk,
7055 ctx={"bered": True},
7057 self.assertTrue(obj_decoded_lenindef.lenindef)
7058 self.assertTrue(obj_decoded_lenindef.bered)
7059 obj_decoded_lenindef = copy(obj_decoded_lenindef)
7060 self.assertTrue(obj_decoded_lenindef.lenindef)
7061 self.assertTrue(obj_decoded_lenindef.bered)
7062 repr(obj_decoded_lenindef)
7063 list(obj_decoded_lenindef.pps())
7064 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
7065 self.assertEqual(tail_lenindef, tail_junk)
7066 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
7067 with self.assertRaises(DecodeError):
7068 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
7069 with self.assertRaises(DecodeError):
7070 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
7072 evgens = list(obj.decode_evgen(
7073 obj_encoded_lenindef + tail_junk,
7074 decode_path=decode_path,
7075 ctx={"bered": True},
7077 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
7078 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
7079 self.assertEqual(_decode_path, decode_path + (str(i),))
7082 _decode_path, obj, tail = evgens[-1]
7083 self.assertEqual(_decode_path, decode_path)
7087 assert_exceeding_data(
7089 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
7093 def test_bered(self):
7094 class SeqOf(self.base_klass):
7096 encoded = Boolean(False).encode()
7097 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
7098 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7099 with self.assertRaises(DecodeError):
7100 SeqOf().decode(encoded)
7101 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7102 self.assertFalse(decoded.ber_encoded)
7103 self.assertFalse(decoded.lenindef)
7104 self.assertTrue(decoded.bered)
7105 decoded = copy(decoded)
7106 self.assertFalse(decoded.ber_encoded)
7107 self.assertFalse(decoded.lenindef)
7108 self.assertTrue(decoded.bered)
7110 class SeqOf(self.base_klass):
7111 schema = OctetString()
7112 encoded = OctetString(b"whatever").encode()
7114 tag_encode(form=TagFormConstructed, num=4) +
7116 OctetString(b"whatever").encode() +
7119 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7120 with self.assertRaises(DecodeError):
7121 SeqOf().decode(encoded)
7122 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7123 self.assertFalse(decoded.ber_encoded)
7124 self.assertFalse(decoded.lenindef)
7125 self.assertTrue(decoded.bered)
7126 decoded = copy(decoded)
7127 self.assertFalse(decoded.ber_encoded)
7128 self.assertFalse(decoded.lenindef)
7129 self.assertTrue(decoded.bered)
7132 class TestSequenceOf(SeqOfMixin, CommonMixin, TestCase):
7133 class SeqOf(SequenceOf):
7137 def _test_symmetric_compare_objs(self, obj1, obj2):
7138 self.assertEqual(obj1, obj2)
7139 self.assertSequenceEqual(list(obj1), list(obj2))
7141 def test_iterator_pickling(self):
7142 class SeqOf(SequenceOf):
7144 register_class(SeqOf)
7147 seqof = seqof(iter(range(10)))
7148 with self.assertRaisesRegex(ValueError, "iterator"):
7151 def test_iterator_bounds(self):
7152 class SeqOf(SequenceOf):
7161 seqof = SeqOf(gen(n))
7162 self.assertTrue(seqof.ready)
7163 with self.assertRaises(BoundsError):
7165 self.assertFalse(seqof.ready)
7166 seqof = seqof(gen(n))
7167 self.assertTrue(seqof.ready)
7168 with self.assertRaises(BoundsError):
7170 self.assertFalse(seqof.ready)
7172 def test_iterator_twice(self):
7173 class SeqOf(SequenceOf):
7175 bounds = (1, float("+inf"))
7180 seqof = SeqOf(gen())
7181 self.assertTrue(seqof.ready)
7183 self.assertFalse(seqof.ready)
7184 register_class(SeqOf)
7187 def test_iterator_2pass(self):
7188 class SeqOf(SequenceOf):
7190 bounds = (1, float("+inf"))
7195 seqof = SeqOf(gen())
7196 self.assertTrue(seqof.ready)
7197 _, state = seqof.encode1st()
7198 self.assertFalse(seqof.ready)
7199 seqof = seqof(gen())
7200 self.assertTrue(seqof.ready)
7202 seqof.encode2nd(buf.write, iter(state))
7203 self.assertSequenceEqual(
7204 [int(i) for i in seqof.decod(buf.getvalue())],
7208 def test_non_ready_bound_min(self):
7209 class SeqOf(SequenceOf):
7211 bounds = (1, float("+inf"))
7213 self.assertFalse(seqof.ready)
7216 class TestSetOf(SeqOfMixin, CommonMixin, TestCase):
7221 def _test_symmetric_compare_objs(self, obj1, obj2):
7222 self.assertSetEqual(
7223 set(int(v) for v in obj1),
7224 set(int(v) for v in obj2),
7227 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7228 @given(data_strategy())
7229 def test_sorted(self, d):
7230 values = [OctetString(v) for v in d.draw(lists(binary()))]
7233 schema = OctetString()
7235 seq_encoded = seq.encode()
7236 seq_decoded, _ = seq.decode(seq_encoded)
7237 self.assertSequenceEqual(
7238 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7239 b"".join(sorted([v.encode() for v in values])),
7242 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7243 @given(data_strategy())
7244 def test_unsorted(self, d):
7245 values = [OctetString(v).encode() for v in d.draw(sets(
7246 binary(min_size=1, max_size=5),
7250 values = d.draw(permutations(values))
7251 assume(values != sorted(values))
7252 encoded = b"".join(values)
7253 seq_encoded = b"".join((
7255 len_encode(len(encoded)),
7260 schema = OctetString()
7262 with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
7263 seq.decode(seq_encoded)
7265 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7266 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7267 self.assertTrue(seq_decoded.ber_encoded)
7268 self.assertTrue(seq_decoded.bered)
7269 seq_decoded = copy(seq_decoded)
7270 self.assertTrue(seq_decoded.ber_encoded)
7271 self.assertTrue(seq_decoded.bered)
7272 self.assertSequenceEqual(
7273 [obj.encode() for obj in seq_decoded],
7278 class TestGoMarshalVectors(TestCase):
7280 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7281 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7282 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7283 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7284 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7286 class Seq(Sequence):
7288 ("erste", Integer()),
7289 ("zweite", Integer(optional=True))
7292 seq["erste"] = Integer(64)
7293 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7294 seq["erste"] = Integer(0x123456)
7295 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7296 seq["erste"] = Integer(64)
7297 seq["zweite"] = Integer(65)
7298 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7300 class NestedSeq(Sequence):
7304 seq["erste"] = Integer(127)
7305 seq["zweite"] = None
7306 nested = NestedSeq()
7307 nested["nest"] = seq
7308 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7310 self.assertSequenceEqual(
7311 OctetString(b"\x01\x02\x03").encode(),
7312 hexdec("0403010203"),
7315 class Seq(Sequence):
7317 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7320 seq["erste"] = Integer(64)
7321 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7323 class Seq(Sequence):
7325 ("erste", Integer(expl=tag_ctxc(5))),
7328 seq["erste"] = Integer(64)
7329 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7331 class Seq(Sequence):
7334 impl=tag_encode(0, klass=TagClassContext),
7339 seq["erste"] = Null()
7340 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7342 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7344 self.assertSequenceEqual(
7345 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7346 hexdec("170d3730303130313030303030305a"),
7348 self.assertSequenceEqual(
7349 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7350 hexdec("170d3039313131353232353631365a"),
7352 self.assertSequenceEqual(
7353 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7354 hexdec("180f32313030303430353132303130315a"),
7357 class Seq(Sequence):
7359 ("erste", GeneralizedTime()),
7362 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7363 self.assertSequenceEqual(
7365 hexdec("3011180f32303039313131353232353631365a"),
7368 self.assertSequenceEqual(
7369 BitString((1, b"\x80")).encode(),
7372 self.assertSequenceEqual(
7373 BitString((12, b"\x81\xF0")).encode(),
7374 hexdec("03030481f0"),
7377 self.assertSequenceEqual(
7378 ObjectIdentifier("1.2.3.4").encode(),
7379 hexdec("06032a0304"),
7381 self.assertSequenceEqual(
7382 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7383 hexdec("06092a864888932d010105"),
7385 self.assertSequenceEqual(
7386 ObjectIdentifier("2.100.3").encode(),
7387 hexdec("0603813403"),
7390 self.assertSequenceEqual(
7391 PrintableString("test").encode(),
7392 hexdec("130474657374"),
7394 self.assertSequenceEqual(
7395 PrintableString("x" * 127).encode(),
7396 hexdec("137F" + "78" * 127),
7398 self.assertSequenceEqual(
7399 PrintableString("x" * 128).encode(),
7400 hexdec("138180" + "78" * 128),
7402 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7404 class Seq(Sequence):
7406 ("erste", IA5String()),
7409 seq["erste"] = IA5String("test")
7410 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7412 class Seq(Sequence):
7414 ("erste", PrintableString()),
7417 seq["erste"] = PrintableString("test")
7418 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7419 # Asterisk is actually not allowable
7420 pyderasn.PRINTABLE_ALLOWABLE_CHARS |= set(b"*")
7421 seq["erste"] = PrintableString("test*")
7422 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7423 pyderasn.PRINTABLE_ALLOWABLE_CHARS -= set(b"*")
7425 class Seq(Sequence):
7427 ("erste", Any(optional=True)),
7428 ("zweite", Integer()),
7431 seq["zweite"] = Integer(64)
7432 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7437 seq.append(Integer(10))
7438 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7440 class _SeqOf(SequenceOf):
7441 schema = PrintableString()
7443 class SeqOf(SequenceOf):
7446 _seqof.append(PrintableString("1"))
7448 seqof.append(_seqof)
7449 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7451 class Seq(Sequence):
7453 ("erste", Integer(default=1)),
7456 seq["erste"] = Integer(0)
7457 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7458 seq["erste"] = Integer(1)
7459 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7460 seq["erste"] = Integer(2)
7461 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7464 class TestPP(TestCase):
7465 @given(data_strategy())
7466 def test_oid_printing(self, d):
7468 str(ObjectIdentifier(k)): v * 2
7469 for k, v in d.draw(dictionaries(
7475 chosen = d.draw(sampled_from(sorted(oids)))
7476 chosen_id = oids[chosen]
7477 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7478 self.assertNotIn(chosen_id, pp_console_row(pp))
7481 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7485 class TestAutoAddSlots(TestCase):
7487 class Inher(Integer):
7490 with self.assertRaises(AttributeError):
7492 inher.unexistent = "whatever"
7495 class TestOIDDefines(TestCase):
7496 @given(data_strategy())
7497 def runTest(self, d):
7498 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7499 value_name_chosen = d.draw(sampled_from(value_names))
7501 ObjectIdentifier(oid)
7502 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7504 oid_chosen = d.draw(sampled_from(oids))
7505 values = d.draw(lists(
7507 min_size=len(value_names),
7508 max_size=len(value_names),
7510 for definable_class in (Any, OctetString, BitString):
7512 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7513 oid: Integer() for oid in oids[:-1]
7516 for i, value_name in enumerate(value_names):
7517 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7519 class Seq(Sequence):
7522 for value_name, value in zip(value_names, values):
7523 seq[value_name] = definable_class(Integer(value).encode())
7524 seq["type"] = oid_chosen
7525 seq, _ = Seq().decode(seq.encode())
7526 for value_name in value_names:
7527 if value_name == value_name_chosen:
7529 self.assertIsNone(seq[value_name].defined)
7530 if value_name_chosen in oids[:-1]:
7531 self.assertIsNotNone(seq[value_name_chosen].defined)
7532 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7533 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7536 pprint(seq, big_blobs=True, with_decode_path=True)
7539 class TestDefinesByPath(TestCase):
7540 def test_generated(self):
7541 class Seq(Sequence):
7543 ("type", ObjectIdentifier()),
7544 ("value", OctetString(expl=tag_ctxc(123))),
7547 class SeqInner(Sequence):
7549 ("typeInner", ObjectIdentifier()),
7550 ("valueInner", Any()),
7553 class PairValue(SetOf):
7556 class Pair(Sequence):
7558 ("type", ObjectIdentifier()),
7559 ("value", PairValue()),
7562 class Pairs(SequenceOf):
7569 type_octet_stringed,
7571 ObjectIdentifier(oid)
7572 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7574 seq_integered = Seq()
7575 seq_integered["type"] = type_integered
7576 seq_integered["value"] = OctetString(Integer(123).encode())
7577 seq_integered_raw = seq_integered.encode()
7581 (type_octet_stringed, OctetString(b"whatever")),
7582 (type_integered, Integer(123)),
7583 (type_octet_stringed, OctetString(b"whenever")),
7584 (type_integered, Integer(234)),
7586 for t, v in pairs_input:
7589 ("value", PairValue((Any(v),))),
7591 seq_inner = SeqInner()
7592 seq_inner["typeInner"] = type_innered
7593 seq_inner["valueInner"] = Any(pairs)
7594 seq_sequenced = Seq()
7595 seq_sequenced["type"] = type_sequenced
7596 seq_sequenced["value"] = OctetString(seq_inner.encode())
7597 seq_sequenced_raw = seq_sequenced.encode()
7599 list(seq_sequenced.pps())
7600 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7602 defines_by_path = []
7603 ctx_copied = deepcopy(ctx_dummy)
7604 seq_integered, _ = Seq().decode(
7608 self.assertDictEqual(ctx_copied, ctx_dummy)
7609 self.assertIsNone(seq_integered["value"].defined)
7610 defines_by_path.append(
7611 (("type",), ((("value",), {
7612 type_integered: Integer(),
7613 type_sequenced: SeqInner(),
7616 ctx_copied["defines_by_path"] = defines_by_path
7617 seq_integered, _ = Seq().decode(
7621 del ctx_copied["defines_by_path"]
7622 self.assertDictEqual(ctx_copied, ctx_dummy)
7623 self.assertIsNotNone(seq_integered["value"].defined)
7624 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7625 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7626 self.assertTrue(seq_integered_raw[
7627 seq_integered["value"].defined[1].offset:
7628 ].startswith(Integer(123).encode()))
7630 list(seq_integered.pps())
7631 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7633 ctx_copied["defines_by_path"] = defines_by_path
7634 seq_sequenced, _ = Seq().decode(
7638 del ctx_copied["defines_by_path"]
7639 self.assertDictEqual(ctx_copied, ctx_dummy)
7640 self.assertIsNotNone(seq_sequenced["value"].defined)
7641 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7642 seq_inner = seq_sequenced["value"].defined[1]
7643 self.assertIsNone(seq_inner["valueInner"].defined)
7645 list(seq_sequenced.pps())
7646 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7648 defines_by_path.append((
7649 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7650 ((("valueInner",), {type_innered: Pairs()}),),
7652 ctx_copied["defines_by_path"] = defines_by_path
7653 seq_sequenced, _ = Seq().decode(
7657 del ctx_copied["defines_by_path"]
7658 self.assertDictEqual(ctx_copied, ctx_dummy)
7659 self.assertIsNotNone(seq_sequenced["value"].defined)
7660 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7661 seq_inner = seq_sequenced["value"].defined[1]
7662 self.assertIsNotNone(seq_inner["valueInner"].defined)
7663 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7664 pairs = seq_inner["valueInner"].defined[1]
7666 self.assertIsNone(pair["value"][0].defined)
7668 list(seq_sequenced.pps())
7669 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7671 defines_by_path.append((
7674 DecodePathDefBy(type_sequenced),
7676 DecodePathDefBy(type_innered),
7681 type_integered: Integer(),
7682 type_octet_stringed: OctetString(),
7685 ctx_copied["defines_by_path"] = defines_by_path
7686 seq_sequenced, _ = Seq().decode(
7690 del ctx_copied["defines_by_path"]
7691 self.assertDictEqual(ctx_copied, ctx_dummy)
7692 self.assertIsNotNone(seq_sequenced["value"].defined)
7693 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7694 seq_inner = seq_sequenced["value"].defined[1]
7695 self.assertIsNotNone(seq_inner["valueInner"].defined)
7696 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7697 pairs_got = seq_inner["valueInner"].defined[1]
7698 for pair_input, pair_got in zip(pairs_input, pairs_got):
7699 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7700 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7702 list(seq_sequenced.pps())
7703 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7705 @given(oid_strategy(), integers())
7706 def test_simple(self, oid, tgt):
7707 class Inner(Sequence):
7709 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7710 ObjectIdentifier(oid): Integer(),
7714 class Outer(Sequence):
7717 ("tgt", OctetString()),
7721 inner["oid"] = ObjectIdentifier(oid)
7723 outer["inner"] = inner
7724 outer["tgt"] = OctetString(Integer(tgt).encode())
7725 decoded, _ = Outer().decode(outer.encode())
7726 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7728 def test_remaining_data(self):
7729 oid = ObjectIdentifier("1.2.3")
7731 class Seq(Sequence):
7733 ("oid", ObjectIdentifier(defines=((("tgt",), {
7736 ("tgt", OctetString()),
7741 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7743 with self.assertRaisesRegex(DecodeError, "remaining data"):
7744 Seq().decode(seq.encode())
7746 def test_remaining_data_seqof(self):
7747 oid = ObjectIdentifier("1.2.3")
7750 schema = OctetString()
7752 class Seq(Sequence):
7754 ("oid", ObjectIdentifier(defines=((("tgt",), {
7762 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7764 with self.assertRaisesRegex(DecodeError, "remaining data"):
7765 Seq().decode(seq.encode())
7768 class TestAbsDecodePath(TestCase):
7770 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7771 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7773 def test_concat(self, decode_path, rel_path):
7774 dp = abs_decode_path(decode_path, rel_path)
7775 self.assertSequenceEqual(dp, decode_path + rel_path)
7779 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7780 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7782 def test_abs(self, decode_path, rel_path):
7783 self.assertSequenceEqual(
7784 abs_decode_path(decode_path, ("/",) + rel_path),
7789 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7790 integers(min_value=1, max_value=3),
7791 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7793 def test_dots(self, decode_path, number_of_dots, rel_path):
7794 self.assertSequenceEqual(
7795 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7796 decode_path[:-number_of_dots] + rel_path,
7800 class TestStrictDefaultExistence(TestCase):
7801 @given(data_strategy())
7802 def runTest(self, d):
7803 count = d.draw(integers(min_value=1, max_value=10))
7804 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7806 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7807 for i in range(count)
7809 for klass in (Sequence, Set):
7813 for i in range(count):
7814 seq["int%d" % i] = Integer(123)
7816 chosen_choice = "int%d" % chosen
7817 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7818 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
7820 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7821 self.assertTrue(decoded.ber_encoded)
7822 self.assertTrue(decoded.bered)
7823 decoded = copy(decoded)
7824 self.assertTrue(decoded.ber_encoded)
7825 self.assertTrue(decoded.bered)
7826 decoded, _ = seq.decode(raw, ctx={"bered": True})
7827 self.assertTrue(decoded.ber_encoded)
7828 self.assertTrue(decoded.bered)
7829 decoded = copy(decoded)
7830 self.assertTrue(decoded.ber_encoded)
7831 self.assertTrue(decoded.bered)
7834 class TestX690PrefixedType(TestCase):
7836 self.assertSequenceEqual(
7837 VisibleString("Jones").encode(),
7838 hexdec("1A054A6F6E6573"),
7842 self.assertSequenceEqual(
7845 impl=tag_encode(3, klass=TagClassApplication),
7847 hexdec("43054A6F6E6573"),
7851 self.assertSequenceEqual(
7855 impl=tag_encode(3, klass=TagClassApplication),
7859 hexdec("A20743054A6F6E6573"),
7863 self.assertSequenceEqual(
7867 impl=tag_encode(3, klass=TagClassApplication),
7869 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7871 hexdec("670743054A6F6E6573"),
7875 self.assertSequenceEqual(
7876 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7877 hexdec("82054A6F6E6573"),
7881 class TestExplOOB(TestCase):
7883 expl = tag_ctxc(123)
7884 raw = Integer(123).encode() + Integer(234).encode()
7885 raw = b"".join((expl, len_encode(len(raw)), raw))
7886 with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
7887 Integer(expl=expl).decode(raw)
7888 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7891 class TestPickleDifferentVersion(TestCase):
7893 pickled = pickle_dumps(Integer(123), pickle_proto)
7895 version_orig = pyderasn.__version__
7896 pyderasn.__version__ += "different"
7897 with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
7898 pickle_loads(pickled)
7899 pyderasn.__version__ = version_orig
7900 pickle_loads(pickled)
7903 class TestCERSetOrdering(TestCase):
7904 def test_vectors(self):
7905 """Taken from X.690-201508
7909 ("c", Integer(impl=tag_ctxp(2))),
7910 ("d", Integer(impl=tag_ctxp(4))),
7915 ("g", Integer(impl=tag_ctxp(5))),
7916 ("h", Integer(impl=tag_ctxp(6))),
7921 ("j", Integer(impl=tag_ctxp(0))),
7932 ("a", Integer(impl=tag_ctxp(3))),
7933 ("b", B(expl=tag_ctxc(1))),
7938 ("a", Integer(123)),
7939 ("b", B(("d", Integer(234)))),
7940 ("e", E(("f", F(("g", Integer(345)))))),
7942 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7943 self.assertSequenceEqual(
7944 [i.__class__.__name__ for i in order],
7945 ("E", "B", "Integer"),