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 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1277 value = _value(value_required)
1278 default = _value(value_required=False)
1282 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1284 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1285 optional = draw(one_of(none(), booleans()))
1287 draw(integers(min_value=0)),
1288 draw(integers(min_value=0)),
1289 draw(integers(min_value=0)),
1291 return (schema, value, impl, expl, default, optional, _decoded)
1294 class BitStringInherited(BitString):
1298 class TestBitString(CommonMixin, TestCase):
1299 base_klass = BitString
1301 @given(lists(booleans()))
1302 def test_b_encoding(self, bits):
1303 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1304 self.assertEqual(obj.bit_len, len(bits))
1305 self.assertSequenceEqual(list(obj), bits)
1306 for i, bit in enumerate(bits):
1307 self.assertEqual(obj[i], bit)
1309 @given(lists(booleans()))
1310 def test_out_of_bounds_bits(self, bits):
1311 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1312 for i in range(len(bits), len(bits) * 2):
1313 self.assertFalse(obj[i])
1315 def test_bad_b_encoding(self):
1316 with self.assertRaises(ValueError):
1317 BitString("'010120101'B")
1320 integers(min_value=1, max_value=255),
1321 integers(min_value=1, max_value=255),
1323 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1324 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1325 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1326 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1328 class BS(BitString):
1329 schema = (("whatever", 0),)
1330 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1331 self.assertEqual(obj.bit_len, leading_zeros + 1)
1332 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1334 def test_zero_len(self):
1335 with self.assertRaises(NotEnoughData):
1336 BitString().decode(b"".join((
1337 BitString.tag_default,
1341 def test_invalid_value_type(self):
1342 with self.assertRaises(InvalidValueType) as err:
1345 with self.assertRaises(InvalidValueType) as err:
1349 def test_obj_unknown(self):
1350 with self.assertRaises(ObjUnknown) as err:
1351 BitString(b"whatever")["whenever"]
1354 def test_get_invalid_type(self):
1355 with self.assertRaises(InvalidValueType) as err:
1356 BitString(b"whatever")[(1, 2, 3)]
1359 @given(data_strategy())
1360 def test_unknown_name(self, d):
1361 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1362 missing = _schema.pop()
1364 class BS(BitString):
1365 schema = [(n, i) for i, n in enumerate(_schema)]
1366 with self.assertRaises(ObjUnknown) as err:
1371 def test_optional(self, optional):
1372 obj = BitString(default=BitString(b""), optional=optional)
1373 self.assertTrue(obj.optional)
1376 def test_ready(self, value):
1378 self.assertFalse(obj.ready)
1381 pprint(obj, big_blobs=True, with_decode_path=True)
1382 with self.assertRaises(ObjNotReady) as err:
1385 with self.assertRaises(ObjNotReady) as err:
1387 obj = BitString(value)
1388 self.assertTrue(obj.ready)
1391 pprint(obj, big_blobs=True, with_decode_path=True)
1394 tuples(integers(min_value=0), binary()),
1395 tuples(integers(min_value=0), binary()),
1399 def test_comparison(self, value1, value2, tag1, tag2):
1400 for klass in (BitString, BitStringInherited):
1401 obj1 = klass(value1)
1402 obj2 = klass(value2)
1403 self.assertEqual(obj1 == obj2, value1 == value2)
1404 self.assertEqual(obj1 != obj2, value1 != value2)
1405 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1406 obj1 = klass(value1, impl=tag1)
1407 obj2 = klass(value1, impl=tag2)
1408 self.assertEqual(obj1 == obj2, tag1 == tag2)
1409 self.assertEqual(obj1 != obj2, tag1 != tag2)
1411 @given(data_strategy())
1412 def test_call(self, d):
1413 for klass in (BitString, BitStringInherited):
1422 ) = d.draw(bit_string_values_strategy())
1425 schema = schema_initial
1427 value=value_initial,
1430 default=default_initial,
1431 optional=optional_initial or False,
1432 _decoded=_decoded_initial,
1442 ) = d.draw(bit_string_values_strategy(
1443 schema=schema_initial,
1444 do_expl=impl_initial is None,
1453 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1454 self.assertEqual(obj.expl_tag, expl or expl_initial)
1455 if obj.default is None:
1456 optional = optional_initial if optional is None else optional
1457 optional = False if optional is None else optional
1460 self.assertEqual(obj.optional, optional)
1461 self.assertEqual(obj.specs, obj_initial.specs)
1463 @given(bit_string_values_strategy())
1464 def test_copy(self, values):
1465 for klass in (BitString, BitStringInherited):
1466 _schema, value, impl, expl, default, optional, _decoded = values
1476 optional=optional or False,
1479 for copy_func in copy_funcs:
1480 obj_copied = copy_func(obj)
1481 self.assert_copied_basic_fields(obj, obj_copied)
1482 self.assertEqual(obj.specs, obj_copied.specs)
1483 self.assertEqual(obj._value, obj_copied._value)
1487 integers(min_value=1).map(tag_encode),
1489 def test_stripped(self, value, tag_impl):
1490 obj = BitString(value, impl=tag_impl)
1491 with self.assertRaises(NotEnoughData):
1492 obj.decode(obj.encode()[:-1])
1496 integers(min_value=1).map(tag_ctxc),
1498 def test_stripped_expl(self, value, tag_expl):
1499 obj = BitString(value, expl=tag_expl)
1500 with self.assertRaises(NotEnoughData):
1501 obj.decode(obj.encode()[:-1])
1504 integers(min_value=31),
1505 integers(min_value=0),
1508 def test_bad_tag(self, tag, offset, decode_path):
1509 with self.assertRaises(DecodeError) as err:
1511 tag_encode(tag)[:-1],
1513 decode_path=decode_path,
1516 self.assertEqual(err.exception.offset, offset)
1517 self.assertEqual(err.exception.decode_path, decode_path)
1520 integers(min_value=128),
1521 integers(min_value=0),
1524 def test_bad_len(self, l, offset, decode_path):
1525 with self.assertRaises(DecodeError) as err:
1527 BitString.tag_default + len_encode(l)[:-1],
1529 decode_path=decode_path,
1532 self.assertEqual(err.exception.offset, offset)
1533 self.assertEqual(err.exception.decode_path, decode_path)
1535 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1536 @given(data_strategy())
1537 def test_symmetric(self, d):
1546 ) = d.draw(bit_string_values_strategy(value_required=True))
1547 tail_junk = d.draw(binary(max_size=5))
1548 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1549 offset = d.draw(integers(min_value=0))
1550 decode_path = d.draw(decode_path_strat)
1551 for klass in (BitString, BitStringInherited):
1562 pprint(obj, big_blobs=True, with_decode_path=True)
1563 self.assertFalse(obj.expled)
1564 obj_encoded = obj.encode()
1565 self.assertEqual(encode2pass(obj), obj_encoded)
1566 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1567 obj_expled = obj(value, expl=tag_expl)
1568 self.assertTrue(obj_expled.expled)
1570 list(obj_expled.pps())
1571 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1572 obj_expled_encoded = obj_expled.encode()
1573 obj_expled_cer = encode_cer(obj_expled)
1574 self.assertNotEqual(obj_expled_cer, obj_encoded)
1575 self.assertSequenceEqual(
1576 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1579 ctx_copied = deepcopy(ctx_dummy)
1580 obj_decoded, tail = obj_expled.decode(
1581 obj_expled_encoded + tail_junk,
1585 self.assertDictEqual(ctx_copied, ctx_dummy)
1587 list(obj_decoded.pps())
1588 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1589 self.assertEqual(tail, tail_junk)
1590 self.assertEqual(obj_decoded, obj_expled)
1591 self.assertNotEqual(obj_decoded, obj)
1592 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1593 self.assertEqual(bytes(obj_decoded), bytes(obj))
1594 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1595 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1596 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1598 obj_decoded.expl_llen,
1599 len(len_encode(len(obj_encoded))),
1601 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1602 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1605 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1607 self.assertEqual(obj_decoded.expl_offset, offset)
1608 if isinstance(value, tuple):
1609 self.assertSetEqual(set(value), set(obj_decoded.named))
1612 assert_exceeding_data(
1614 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1618 evgens = list(obj_expled.decode_evgen(
1619 obj_expled_encoded + tail_junk,
1621 decode_path=decode_path,
1624 self.assertEqual(len(evgens), 1)
1625 _decode_path, obj, tail = evgens[0]
1626 self.assertSequenceEqual(tail, tail_junk)
1627 self.assertEqual(_decode_path, decode_path)
1628 self.assertEqual(obj.expl_offset, offset)
1632 @given(integers(min_value=1, max_value=255))
1633 def test_bad_zero_value(self, pad_size):
1634 with self.assertRaises(DecodeError):
1635 BitString().decode(b"".join((
1636 BitString.tag_default,
1641 def test_go_vectors_invalid(self):
1647 with self.assertRaises(DecodeError):
1648 BitString().decode(b"".join((
1649 BitString.tag_default,
1654 def test_go_vectors_valid(self):
1655 obj, _ = BitString().decode(b"".join((
1656 BitString.tag_default,
1660 self.assertEqual(bytes(obj), b"")
1661 self.assertEqual(obj.bit_len, 0)
1663 obj, _ = BitString().decode(b"".join((
1664 BitString.tag_default,
1668 self.assertEqual(bytes(obj), b"\x00")
1669 self.assertEqual(obj.bit_len, 1)
1671 obj = BitString((16, b"\x82\x40"))
1672 self.assertTrue(obj[0])
1673 self.assertFalse(obj[1])
1674 self.assertTrue(obj[6])
1675 self.assertTrue(obj[9])
1676 self.assertFalse(obj[17])
1678 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1680 integers(min_value=1, max_value=30),
1683 binary(min_size=1, max_size=5),
1685 binary(min_size=1, max_size=5),
1693 lists(booleans(), min_size=1),
1697 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1698 def chunk_constructed(contents):
1700 tag_encode(form=TagFormConstructed, num=3) +
1702 b"".join(BitString(content).encode() for content in contents) +
1706 chunks_len_expected = []
1707 payload_expected = b""
1708 bit_len_expected = 0
1709 for chunk_input in chunk_inputs:
1710 if isinstance(chunk_input, bytes):
1711 chunks.append(BitString(chunk_input).encode())
1712 payload_expected += chunk_input
1713 bit_len_expected += len(chunk_input) * 8
1714 chunks_len_expected.append(len(chunk_input) + 1)
1716 chunks.append(chunk_constructed(chunk_input))
1717 payload = b"".join(chunk_input)
1718 payload_expected += payload
1719 bit_len_expected += len(payload) * 8
1720 for c in chunk_input:
1721 chunks_len_expected.append(len(c) + 1)
1722 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1723 chunk_last = BitString("'%s'B" % "".join(
1724 "1" if bit else "0" for bit in chunk_last_bits
1726 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1727 payload_expected += bytes(chunk_last)
1728 bit_len_expected += chunk_last.bit_len
1729 encoded_indefinite = (
1730 tag_encode(form=TagFormConstructed, num=impl) +
1733 chunk_last.encode() +
1736 encoded_definite = (
1737 tag_encode(form=TagFormConstructed, num=impl) +
1738 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1742 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
1743 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1744 for lenindef_expected, encoded in (
1745 (True, encoded_indefinite),
1746 (False, encoded_definite),
1748 obj, tail = BitString(impl=tag_encode(impl)).decode(
1750 ctx={"bered": True},
1752 self.assertSequenceEqual(tail, junk)
1753 self.assertEqual(obj.bit_len, bit_len_expected)
1754 self.assertSequenceEqual(bytes(obj), payload_expected)
1755 self.assertTrue(obj.ber_encoded)
1756 self.assertEqual(obj.lenindef, lenindef_expected)
1757 self.assertTrue(obj.bered)
1759 self.assertTrue(obj.ber_encoded)
1760 self.assertEqual(obj.lenindef, lenindef_expected)
1761 self.assertTrue(obj.bered)
1762 self.assertEqual(len(encoded), obj.tlvlen)
1765 pprint(obj, big_blobs=True, with_decode_path=True)
1767 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1769 decode_path=decode_path,
1770 ctx={"bered": True},
1772 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1773 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1774 self.assertGreater(len(dp), len(decode_path))
1775 self.assertEqual(obj.vlen, chunk_len_expected)
1778 integers(min_value=0),
1781 def test_ber_definite_too_short(self, offset, decode_path):
1782 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
1784 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1786 decode_path=decode_path,
1787 ctx={"bered": True},
1789 self.assertEqual(err.exception.decode_path, decode_path)
1790 self.assertEqual(err.exception.offset, offset)
1793 integers(min_value=0),
1796 def test_ber_definite_no_data(self, offset, decode_path):
1797 with self.assertRaisesRegex(DecodeError, "zero length") as err:
1799 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1801 decode_path=decode_path,
1802 ctx={"bered": True},
1804 self.assertEqual(err.exception.decode_path, decode_path)
1805 self.assertEqual(err.exception.offset, offset)
1808 integers(min_value=0),
1810 integers(min_value=1, max_value=3),
1812 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1813 bs = BitString(b"data").encode()
1814 with self.assertRaises(NotEnoughData) as err:
1816 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1818 decode_path=decode_path,
1819 ctx={"bered": True},
1821 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1822 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1825 integers(min_value=0),
1827 integers(min_value=1, max_value=3),
1829 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1830 bs = BitString(b"data").encode()
1831 bs_longer = BitString(b"data-longer").encode()
1832 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
1835 tag_encode(3, form=TagFormConstructed) +
1836 len_encode((chunks + 1) * len(bs)) +
1841 decode_path=decode_path,
1842 ctx={"bered": True},
1844 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1845 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1848 integers(min_value=0),
1851 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1852 with self.assertRaisesRegex(DecodeError, "no chunks") as err:
1854 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1856 decode_path=decode_path,
1857 ctx={"bered": True},
1859 self.assertEqual(err.exception.decode_path, decode_path)
1860 self.assertEqual(err.exception.offset, offset)
1862 @given(data_strategy())
1863 def test_ber_indefinite_not_multiple(self, d):
1864 bs_short = BitString("'A'H").encode()
1865 bs_full = BitString("'AA'H").encode()
1866 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1867 chunks.append(bs_short)
1868 d.draw(permutations(chunks))
1869 chunks.append(bs_short)
1870 offset = d.draw(integers(min_value=0))
1871 decode_path = d.draw(decode_path_strat)
1872 with self.assertRaisesRegex(DecodeError, "multiple of 8 bits") as err:
1875 tag_encode(3, form=TagFormConstructed) +
1881 decode_path=decode_path,
1882 ctx={"bered": True},
1885 err.exception.decode_path,
1886 decode_path + (str(chunks.index(bs_short)),),
1889 err.exception.offset,
1890 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1893 def test_x690_vector(self):
1894 vector = BitString("'0A3B5F291CD'H")
1895 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1896 self.assertSequenceEqual(tail, b"")
1897 self.assertEqual(obj, vector)
1898 obj, tail = BitString().decode(
1899 hexdec("23800303000A3B0305045F291CD00000"),
1900 ctx={"bered": True},
1902 self.assertSequenceEqual(tail, b"")
1903 self.assertEqual(obj, vector)
1904 self.assertTrue(obj.ber_encoded)
1905 self.assertTrue(obj.lenindef)
1906 self.assertTrue(obj.bered)
1908 self.assertTrue(obj.ber_encoded)
1909 self.assertTrue(obj.lenindef)
1910 self.assertTrue(obj.bered)
1912 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1913 @given(integers(min_value=1000, max_value=3000))
1914 def test_cer(self, data_len):
1915 data = urandom(data_len)
1916 encoded = encode_cer(BitString(data))
1917 ctx = {"bered": True}
1918 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1919 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1920 evgens_expected = data_len // 999
1921 if evgens_expected * 999 != data_len:
1922 evgens_expected += 1
1923 evgens_expected += 1
1924 self.assertEqual(len(evgens), evgens_expected)
1925 for (_, obj, _) in evgens[:-2]:
1926 self.assertEqual(obj.vlen, 1000)
1927 _, obj, _ = evgens[-2]
1928 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1932 def octet_string_values_strategy(draw, do_expl=False):
1933 bound_min, bound_max = sorted(draw(sets(
1934 integers(min_value=0, max_value=1 << 7),
1938 value = draw(one_of(
1940 binary(min_size=bound_min, max_size=bound_max),
1942 default = draw(one_of(
1944 binary(min_size=bound_min, max_size=bound_max),
1947 if draw(booleans()):
1948 bounds = (bound_min, bound_max)
1952 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1954 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1955 optional = draw(one_of(none(), booleans()))
1957 draw(integers(min_value=0)),
1958 draw(integers(min_value=0)),
1959 draw(integers(min_value=0)),
1961 return (value, bounds, impl, expl, default, optional, _decoded)
1964 class OctetStringInherited(OctetString):
1968 class TestOctetString(CommonMixin, TestCase):
1969 base_klass = OctetString
1971 def test_invalid_value_type(self):
1972 with self.assertRaises(InvalidValueType) as err:
1973 OctetString(str(123))
1977 def test_optional(self, optional):
1978 obj = OctetString(default=OctetString(b""), optional=optional)
1979 self.assertTrue(obj.optional)
1982 def test_ready(self, value):
1984 self.assertFalse(obj.ready)
1987 pprint(obj, big_blobs=True, with_decode_path=True)
1988 with self.assertRaises(ObjNotReady) as err:
1991 with self.assertRaises(ObjNotReady) as err:
1993 obj = OctetString(value)
1994 self.assertTrue(obj.ready)
1997 pprint(obj, big_blobs=True, with_decode_path=True)
1999 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
2000 def test_comparison(self, value1, value2, tag1, tag2):
2001 for klass in (OctetString, OctetStringInherited):
2002 obj1 = klass(value1)
2003 obj2 = klass(value2)
2004 self.assertEqual(obj1 == obj2, value1 == value2)
2005 self.assertEqual(obj1 != obj2, value1 != value2)
2006 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2007 obj1 = klass(value1, impl=tag1)
2008 obj2 = klass(value1, impl=tag2)
2009 self.assertEqual(obj1 == obj2, tag1 == tag2)
2010 self.assertEqual(obj1 != obj2, tag1 != tag2)
2012 @given(lists(binary()))
2013 def test_sorted_works(self, values):
2014 self.assertSequenceEqual(
2015 [bytes(v) for v in sorted(OctetString(v) for v in values)],
2019 @given(data_strategy())
2020 def test_bounds_satisfied(self, d):
2021 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2022 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2023 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
2024 OctetString(value=value, bounds=(bound_min, bound_max))
2026 @given(data_strategy())
2027 def test_bounds_unsatisfied(self, d):
2028 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2029 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2030 value = d.draw(binary(max_size=bound_min - 1))
2031 with self.assertRaises(BoundsError) as err:
2032 OctetString(value=value, bounds=(bound_min, bound_max))
2034 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2035 OctetString(bounds=(bound_min, bound_max)).decode(
2036 OctetString(value).encode()
2039 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2040 OctetString(bounds=(bound_min, bound_max)).decode(
2041 encode2pass(OctetString(value))
2043 value = d.draw(binary(min_size=bound_max + 1))
2044 with self.assertRaises(BoundsError) as err:
2045 OctetString(value=value, bounds=(bound_min, bound_max))
2047 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2048 OctetString(bounds=(bound_min, bound_max)).decode(
2049 OctetString(value).encode()
2052 with self.assertRaisesRegex(DecodeError, "bounds") as err:
2053 OctetString(bounds=(bound_min, bound_max)).decode(
2054 encode2pass(OctetString(value))
2057 @given(data_strategy())
2058 def test_call(self, d):
2059 for klass in (OctetString, OctetStringInherited):
2068 ) = d.draw(octet_string_values_strategy())
2069 obj_initial = klass(
2075 optional_initial or False,
2086 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2087 if (default is None) and (obj_initial.default is not None):
2090 (bounds is None) and
2091 (value is not None) and
2092 (bounds_initial is not None) and
2093 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2097 (bounds is None) and
2098 (default is not None) and
2099 (bounds_initial is not None) and
2100 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2103 obj = obj_initial(value, bounds, impl, expl, default, optional)
2105 value_expected = default if value is None else value
2107 default_initial if value_expected is None
2110 self.assertEqual(obj, value_expected)
2111 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2112 self.assertEqual(obj.expl_tag, expl or expl_initial)
2115 default_initial if default is None else default,
2117 if obj.default is None:
2118 optional = optional_initial if optional is None else optional
2119 optional = False if optional is None else optional
2122 self.assertEqual(obj.optional, optional)
2124 (obj._bound_min, obj._bound_max),
2125 bounds or bounds_initial or (0, float("+inf")),
2128 @given(octet_string_values_strategy())
2129 def test_copy(self, values):
2130 for klass in (OctetString, OctetStringInherited):
2131 obj = klass(*values)
2132 for copy_func in copy_funcs:
2133 obj_copied = copy_func(obj)
2134 self.assert_copied_basic_fields(obj, obj_copied)
2135 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2136 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2137 self.assertEqual(obj._value, obj_copied._value)
2141 integers(min_value=1).map(tag_encode),
2143 def test_stripped(self, value, tag_impl):
2144 obj = OctetString(value, impl=tag_impl)
2145 with self.assertRaises(NotEnoughData):
2146 obj.decode(obj.encode()[:-1])
2150 integers(min_value=1).map(tag_ctxc),
2152 def test_stripped_expl(self, value, tag_expl):
2153 obj = OctetString(value, expl=tag_expl)
2154 with self.assertRaises(NotEnoughData):
2155 obj.decode(obj.encode()[:-1])
2158 integers(min_value=31),
2159 integers(min_value=0),
2162 def test_bad_tag(self, tag, offset, decode_path):
2163 with self.assertRaises(DecodeError) as err:
2164 OctetString().decode(
2165 tag_encode(tag)[:-1],
2167 decode_path=decode_path,
2170 self.assertEqual(err.exception.offset, offset)
2171 self.assertEqual(err.exception.decode_path, decode_path)
2174 integers(min_value=128),
2175 integers(min_value=0),
2178 def test_bad_len(self, l, offset, decode_path):
2179 with self.assertRaises(DecodeError) as err:
2180 OctetString().decode(
2181 OctetString.tag_default + len_encode(l)[:-1],
2183 decode_path=decode_path,
2186 self.assertEqual(err.exception.offset, offset)
2187 self.assertEqual(err.exception.decode_path, decode_path)
2190 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2191 integers(min_value=0),
2194 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2195 value, bound_min = list(sorted(ints))
2197 class String(OctetString):
2198 bounds = (bound_min, bound_min)
2199 with self.assertRaises(DecodeError) as err:
2201 OctetString(b"\x00" * value).encode(),
2203 decode_path=decode_path,
2206 self.assertEqual(err.exception.offset, offset)
2207 self.assertEqual(err.exception.decode_path, decode_path)
2209 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2211 octet_string_values_strategy(),
2213 integers(min_value=1).map(tag_ctxc),
2214 integers(min_value=0),
2218 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2219 for klass in (OctetString, OctetStringInherited):
2220 _, _, _, _, default, optional, _decoded = values
2229 pprint(obj, big_blobs=True, with_decode_path=True)
2230 self.assertFalse(obj.expled)
2231 obj_encoded = obj.encode()
2232 self.assertEqual(encode2pass(obj), obj_encoded)
2233 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2234 obj_expled = obj(value, expl=tag_expl)
2235 self.assertTrue(obj_expled.expled)
2237 list(obj_expled.pps())
2238 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2239 obj_expled_encoded = obj_expled.encode()
2240 obj_expled_cer = encode_cer(obj_expled)
2241 self.assertNotEqual(obj_expled_cer, obj_encoded)
2242 self.assertSequenceEqual(
2243 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2246 ctx_copied = deepcopy(ctx_dummy)
2247 obj_decoded, tail = obj_expled.decode(
2248 obj_expled_encoded + tail_junk,
2252 self.assertDictEqual(ctx_copied, ctx_dummy)
2254 list(obj_decoded.pps())
2255 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2256 self.assertEqual(tail, tail_junk)
2257 self.assertEqual(obj_decoded, obj_expled)
2258 self.assertNotEqual(obj_decoded, obj)
2259 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2260 self.assertEqual(bytes(obj_decoded), bytes(obj))
2261 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2262 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2263 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2265 obj_decoded.expl_llen,
2266 len(len_encode(len(obj_encoded))),
2268 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2269 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2272 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2274 self.assertEqual(obj_decoded.expl_offset, offset)
2275 assert_exceeding_data(
2277 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2281 evgens = list(obj_expled.decode_evgen(
2282 obj_expled_encoded + tail_junk,
2284 decode_path=decode_path,
2287 self.assertEqual(len(evgens), 1)
2288 _decode_path, obj, tail = evgens[0]
2289 self.assertSequenceEqual(tail, tail_junk)
2290 self.assertEqual(_decode_path, decode_path)
2291 self.assertEqual(obj.expl_offset, offset)
2295 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2297 integers(min_value=1, max_value=30),
2300 binary(min_size=1, max_size=5),
2302 binary(min_size=1, max_size=5),
2313 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2314 def chunk_constructed(contents):
2316 tag_encode(form=TagFormConstructed, num=4) +
2318 b"".join(OctetString(content).encode() for content in contents) +
2322 chunks_len_expected = []
2323 payload_expected = b""
2324 for chunk_input in chunk_inputs:
2325 if isinstance(chunk_input, bytes):
2326 chunks.append(OctetString(chunk_input).encode())
2327 payload_expected += chunk_input
2328 chunks_len_expected.append(len(chunk_input))
2330 chunks.append(chunk_constructed(chunk_input))
2331 payload = b"".join(chunk_input)
2332 payload_expected += payload
2333 for c in chunk_input:
2334 chunks_len_expected.append(len(c))
2335 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2336 encoded_indefinite = (
2337 tag_encode(form=TagFormConstructed, num=impl) +
2342 encoded_definite = (
2343 tag_encode(form=TagFormConstructed, num=impl) +
2344 len_encode(len(b"".join(chunks))) +
2347 with self.assertRaisesRegex(DecodeError, "unallowed BER"):
2348 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2349 for lenindef_expected, encoded in (
2350 (True, encoded_indefinite),
2351 (False, encoded_definite),
2353 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2355 ctx={"bered": True},
2357 self.assertSequenceEqual(tail, junk)
2358 self.assertSequenceEqual(bytes(obj), payload_expected)
2359 self.assertTrue(obj.ber_encoded)
2360 self.assertEqual(obj.lenindef, lenindef_expected)
2361 self.assertTrue(obj.bered)
2363 self.assertTrue(obj.ber_encoded)
2364 self.assertEqual(obj.lenindef, lenindef_expected)
2365 self.assertTrue(obj.bered)
2366 self.assertEqual(len(encoded), obj.tlvlen)
2369 pprint(obj, big_blobs=True, with_decode_path=True)
2371 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2373 decode_path=decode_path,
2374 ctx={"bered": True},
2376 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2377 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2378 self.assertGreater(len(dp), len(decode_path))
2379 self.assertEqual(obj.vlen, chunk_len_expected)
2382 integers(min_value=0),
2385 def test_ber_definite_too_short(self, offset, decode_path):
2386 with self.assertRaisesRegex(DecodeError, "longer than data") as err:
2387 OctetString().decode(
2388 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2390 decode_path=decode_path,
2391 ctx={"bered": True},
2393 self.assertEqual(err.exception.decode_path, decode_path)
2394 self.assertEqual(err.exception.offset, offset)
2397 integers(min_value=0),
2399 integers(min_value=1, max_value=3),
2401 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2402 bs = OctetString(b"data").encode()
2403 with self.assertRaises(NotEnoughData) as err:
2404 OctetString().decode(
2405 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2407 decode_path=decode_path,
2408 ctx={"bered": True},
2410 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2411 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2414 integers(min_value=0),
2416 integers(min_value=1, max_value=3),
2418 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2419 bs = OctetString(b"data").encode()
2420 bs_longer = OctetString(b"data-longer").encode()
2421 with self.assertRaisesRegex(DecodeError, "chunk out of bounds") as err:
2422 OctetString().decode(
2424 tag_encode(4, form=TagFormConstructed) +
2425 len_encode((chunks + 1) * len(bs)) +
2430 decode_path=decode_path,
2431 ctx={"bered": True},
2433 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2434 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2436 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2437 @given(integers(min_value=1001, max_value=3000))
2438 def test_cer(self, data_len):
2439 data = urandom(data_len)
2440 encoded = encode_cer(OctetString(data))
2441 ctx = {"bered": True}
2442 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2443 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2444 evgens_expected = data_len // 1000
2445 if evgens_expected * 1000 != data_len:
2446 evgens_expected += 1
2447 evgens_expected += 1
2448 self.assertEqual(len(evgens), evgens_expected)
2449 for (_, obj, _) in evgens[:-2]:
2450 self.assertEqual(obj.vlen, 1000)
2451 _, obj, _ = evgens[-2]
2452 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2456 def null_values_strategy(draw, do_expl=False):
2460 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2462 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2463 optional = draw(one_of(none(), booleans()))
2465 draw(integers(min_value=0)),
2466 draw(integers(min_value=0)),
2467 draw(integers(min_value=0)),
2469 return (impl, expl, optional, _decoded)
2472 class NullInherited(Null):
2476 class TestNull(CommonMixin, TestCase):
2479 def test_ready(self):
2481 self.assertTrue(obj.ready)
2484 pprint(obj, big_blobs=True, with_decode_path=True)
2486 @given(binary(min_size=1), binary(min_size=1))
2487 def test_comparison(self, tag1, tag2):
2488 for klass in (Null, NullInherited):
2489 obj1 = klass(impl=tag1)
2490 obj2 = klass(impl=tag2)
2491 self.assertEqual(obj1 == obj2, tag1 == tag2)
2492 self.assertEqual(obj1 != obj2, tag1 != tag2)
2493 self.assertNotEqual(obj1, tag2)
2495 @given(data_strategy())
2496 def test_call(self, d):
2497 for klass in (Null, NullInherited):
2503 ) = d.draw(null_values_strategy())
2504 obj_initial = klass(
2507 optional=optional_initial or False,
2508 _decoded=_decoded_initial,
2515 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2516 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2517 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2518 self.assertEqual(obj.expl_tag, expl or expl_initial)
2519 optional = optional_initial if optional is None else optional
2520 optional = False if optional is None else optional
2521 self.assertEqual(obj.optional, optional)
2523 @given(null_values_strategy())
2524 def test_copy(self, values):
2525 for klass in (Null, NullInherited):
2526 impl, expl, optional, _decoded = values
2530 optional=optional or False,
2533 for copy_func in copy_funcs:
2534 obj_copied = copy_func(obj)
2535 self.assert_copied_basic_fields(obj, obj_copied)
2537 @given(integers(min_value=1).map(tag_encode))
2538 def test_stripped(self, tag_impl):
2539 obj = Null(impl=tag_impl)
2540 with self.assertRaises(NotEnoughData):
2541 obj.decode(obj.encode()[:-1])
2543 @given(integers(min_value=1).map(tag_ctxc))
2544 def test_stripped_expl(self, tag_expl):
2545 obj = Null(expl=tag_expl)
2546 with self.assertRaises(NotEnoughData):
2547 obj.decode(obj.encode()[:-1])
2550 integers(min_value=31),
2551 integers(min_value=0),
2554 def test_bad_tag(self, tag, offset, decode_path):
2555 with self.assertRaises(DecodeError) as err:
2557 tag_encode(tag)[:-1],
2559 decode_path=decode_path,
2562 self.assertEqual(err.exception.offset, offset)
2563 self.assertEqual(err.exception.decode_path, decode_path)
2566 integers(min_value=128),
2567 integers(min_value=0),
2570 def test_bad_len(self, l, offset, decode_path):
2571 with self.assertRaises(DecodeError) as err:
2573 Null.tag_default + len_encode(l)[:-1],
2575 decode_path=decode_path,
2578 self.assertEqual(err.exception.offset, offset)
2579 self.assertEqual(err.exception.decode_path, decode_path)
2581 @given(binary(min_size=1))
2582 def test_tag_mismatch(self, impl):
2583 assume(impl != Null.tag_default)
2584 with self.assertRaises(TagMismatch):
2585 Null(impl=impl).decode(Null().encode())
2588 null_values_strategy(),
2589 integers(min_value=1).map(tag_ctxc),
2590 integers(min_value=0),
2594 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2595 for klass in (Null, NullInherited):
2596 _, _, optional, _decoded = values
2597 obj = klass(optional=optional, _decoded=_decoded)
2600 pprint(obj, big_blobs=True, with_decode_path=True)
2601 self.assertFalse(obj.expled)
2602 obj_encoded = obj.encode()
2603 self.assertEqual(encode2pass(obj), obj_encoded)
2604 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2605 obj_expled = obj(expl=tag_expl)
2606 self.assertTrue(obj_expled.expled)
2608 list(obj_expled.pps())
2609 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2610 obj_expled_encoded = obj_expled.encode()
2611 obj_expled_cer = encode_cer(obj_expled)
2612 self.assertNotEqual(obj_expled_cer, obj_encoded)
2613 self.assertSequenceEqual(
2614 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2617 ctx_copied = deepcopy(ctx_dummy)
2618 obj_decoded, tail = obj_expled.decode(
2619 obj_expled_encoded + tail_junk,
2623 self.assertDictEqual(ctx_copied, ctx_dummy)
2625 list(obj_decoded.pps())
2626 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2627 self.assertEqual(tail, tail_junk)
2628 self.assertEqual(obj_decoded, obj_expled)
2629 self.assertNotEqual(obj_decoded, obj)
2630 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2631 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2632 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2634 obj_decoded.expl_llen,
2635 len(len_encode(len(obj_encoded))),
2637 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2638 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2641 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2643 self.assertEqual(obj_decoded.expl_offset, offset)
2644 assert_exceeding_data(
2646 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2650 evgens = list(obj_expled.decode_evgen(
2651 obj_expled_encoded + tail_junk,
2653 decode_path=decode_path,
2656 self.assertEqual(len(evgens), 1)
2657 _decode_path, obj, tail = evgens[0]
2658 self.assertSequenceEqual(tail, tail_junk)
2659 self.assertEqual(_decode_path, decode_path)
2660 self.assertEqual(obj, obj_decoded)
2661 self.assertEqual(obj.expl_offset, offset)
2665 @given(integers(min_value=1))
2666 def test_invalid_len(self, l):
2667 with self.assertRaises(InvalidLength):
2668 Null().decode(b"".join((
2675 def oid_strategy(draw):
2676 first_arc = draw(integers(min_value=0, max_value=2))
2678 if first_arc in (0, 1):
2679 second_arc = draw(integers(min_value=0, max_value=39))
2681 second_arc = draw(integers(min_value=0))
2682 other_arcs = draw(lists(integers(min_value=0)))
2683 return tuple([first_arc, second_arc] + other_arcs)
2687 def oid_values_strategy(draw, do_expl=False):
2688 value = draw(one_of(none(), oid_strategy()))
2692 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2694 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2695 default = draw(one_of(none(), oid_strategy()))
2696 optional = draw(one_of(none(), booleans()))
2698 draw(integers(min_value=0)),
2699 draw(integers(min_value=0)),
2700 draw(integers(min_value=0)),
2702 return (value, impl, expl, default, optional, _decoded)
2705 class ObjectIdentifierInherited(ObjectIdentifier):
2709 class TestObjectIdentifier(CommonMixin, TestCase):
2710 base_klass = ObjectIdentifier
2712 def test_invalid_value_type(self):
2713 with self.assertRaises(InvalidValueType) as err:
2714 ObjectIdentifier(123)
2718 def test_optional(self, optional):
2719 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2720 self.assertTrue(obj.optional)
2722 @given(oid_strategy())
2723 def test_ready(self, value):
2724 obj = ObjectIdentifier()
2725 self.assertFalse(obj.ready)
2728 pprint(obj, big_blobs=True, with_decode_path=True)
2729 with self.assertRaises(ObjNotReady) as err:
2732 with self.assertRaises(ObjNotReady) as err:
2734 obj = ObjectIdentifier(value)
2735 self.assertTrue(obj.ready)
2736 self.assertFalse(obj.ber_encoded)
2739 pprint(obj, big_blobs=True, with_decode_path=True)
2742 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2743 def test_comparison(self, value1, value2, tag1, tag2):
2744 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2745 obj1 = klass(value1)
2746 obj2 = klass(value2)
2747 self.assertEqual(obj1 == obj2, value1 == value2)
2748 self.assertEqual(obj1 != obj2, value1 != value2)
2749 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2750 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2751 obj1 = klass(value1, impl=tag1)
2752 obj2 = klass(value1, impl=tag2)
2753 self.assertEqual(obj1 == obj2, tag1 == tag2)
2754 self.assertEqual(obj1 != obj2, tag1 != tag2)
2756 @given(lists(oid_strategy()))
2757 def test_sorted_works(self, values):
2758 self.assertSequenceEqual(
2759 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2763 @given(data_strategy())
2764 def test_call(self, d):
2765 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2773 ) = d.draw(oid_values_strategy())
2774 obj_initial = klass(
2775 value=value_initial,
2778 default=default_initial,
2779 optional=optional_initial or False,
2780 _decoded=_decoded_initial,
2789 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2798 value_expected = default if value is None else value
2800 default_initial if value_expected is None
2803 self.assertEqual(obj, value_expected)
2804 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2805 self.assertEqual(obj.expl_tag, expl or expl_initial)
2808 default_initial if default is None else default,
2810 if obj.default is None:
2811 optional = optional_initial if optional is None else optional
2812 optional = False if optional is None else optional
2815 self.assertEqual(obj.optional, optional)
2817 @given(oid_values_strategy())
2818 def test_copy(self, values):
2819 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2836 for copy_func in copy_funcs:
2837 obj_copied = copy_func(obj)
2838 self.assert_copied_basic_fields(obj, obj_copied)
2839 self.assertEqual(obj._value, obj_copied._value)
2841 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2844 integers(min_value=1).map(tag_encode),
2846 def test_stripped(self, value, tag_impl):
2847 obj = ObjectIdentifier(value, impl=tag_impl)
2848 with self.assertRaises(NotEnoughData):
2849 obj.decode(obj.encode()[:-1])
2853 integers(min_value=1).map(tag_ctxc),
2855 def test_stripped_expl(self, value, tag_expl):
2856 obj = ObjectIdentifier(value, expl=tag_expl)
2857 with self.assertRaises(NotEnoughData):
2858 obj.decode(obj.encode()[:-1])
2861 integers(min_value=31),
2862 integers(min_value=0),
2865 def test_bad_tag(self, tag, offset, decode_path):
2866 with self.assertRaises(DecodeError) as err:
2867 ObjectIdentifier().decode(
2868 tag_encode(tag)[:-1],
2870 decode_path=decode_path,
2873 self.assertEqual(err.exception.offset, offset)
2874 self.assertEqual(err.exception.decode_path, decode_path)
2877 integers(min_value=128),
2878 integers(min_value=0),
2881 def test_bad_len(self, l, offset, decode_path):
2882 with self.assertRaises(DecodeError) as err:
2883 ObjectIdentifier().decode(
2884 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2886 decode_path=decode_path,
2889 self.assertEqual(err.exception.offset, offset)
2890 self.assertEqual(err.exception.decode_path, decode_path)
2892 def test_zero_oid(self):
2893 with self.assertRaises(NotEnoughData):
2894 ObjectIdentifier().decode(
2895 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2898 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2899 @given(oid_strategy())
2900 def test_unfinished_oid(self, value):
2901 assume(list(value)[-1] > 255)
2902 obj_encoded = ObjectIdentifier(value).encode()
2903 obj, _ = ObjectIdentifier().decode(obj_encoded)
2904 data = obj_encoded[obj.tlen + obj.llen:-1]
2906 ObjectIdentifier.tag_default,
2907 len_encode(len(data)),
2910 with self.assertRaisesRegex(DecodeError, "unfinished OID"):
2913 @given(integers(min_value=0))
2914 def test_invalid_short(self, value):
2915 with self.assertRaises(InvalidOID):
2916 ObjectIdentifier((value,))
2917 with self.assertRaises(InvalidOID):
2918 ObjectIdentifier("%d" % value)
2920 @given(integers(min_value=3), integers(min_value=0))
2921 def test_invalid_first_arc(self, first_arc, second_arc):
2922 with self.assertRaises(InvalidOID):
2923 ObjectIdentifier((first_arc, second_arc))
2924 with self.assertRaises(InvalidOID):
2925 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2927 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2928 def test_invalid_second_arc(self, first_arc, second_arc):
2929 with self.assertRaises(InvalidOID):
2930 ObjectIdentifier((first_arc, second_arc))
2931 with self.assertRaises(InvalidOID):
2932 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2934 @given(text(alphabet=ascii_letters + ".", min_size=1))
2935 def test_junk(self, oid):
2936 with self.assertRaises(InvalidOID):
2937 ObjectIdentifier(oid)
2939 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2940 @given(oid_strategy())
2941 def test_validness(self, oid):
2942 obj = ObjectIdentifier(oid)
2943 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2946 pprint(obj, big_blobs=True, with_decode_path=True)
2948 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2950 oid_values_strategy(),
2952 integers(min_value=1).map(tag_ctxc),
2953 integers(min_value=0),
2957 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2958 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2959 _, _, _, default, optional, _decoded = values
2968 pprint(obj, big_blobs=True, with_decode_path=True)
2969 self.assertFalse(obj.expled)
2970 obj_encoded = obj.encode()
2971 self.assertEqual(encode2pass(obj), obj_encoded)
2972 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2973 obj_expled = obj(value, expl=tag_expl)
2974 self.assertTrue(obj_expled.expled)
2976 list(obj_expled.pps())
2977 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2978 obj_expled_encoded = obj_expled.encode()
2979 obj_expled_cer = encode_cer(obj_expled)
2980 self.assertNotEqual(obj_expled_cer, obj_encoded)
2981 self.assertSequenceEqual(
2982 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2985 ctx_copied = deepcopy(ctx_dummy)
2986 obj_decoded, tail = obj_expled.decode(
2987 obj_expled_encoded + tail_junk,
2991 self.assertDictEqual(ctx_copied, ctx_dummy)
2993 list(obj_decoded.pps())
2994 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2995 self.assertEqual(tail, tail_junk)
2996 self.assertEqual(obj_decoded, obj_expled)
2997 self.assertNotEqual(obj_decoded, obj)
2998 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2999 self.assertEqual(tuple(obj_decoded), tuple(obj))
3000 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3001 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3002 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3004 obj_decoded.expl_llen,
3005 len(len_encode(len(obj_encoded))),
3007 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3008 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3011 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3013 self.assertEqual(obj_decoded.expl_offset, offset)
3014 assert_exceeding_data(
3016 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3020 evgens = list(obj_expled.decode_evgen(
3021 obj_expled_encoded + tail_junk,
3023 decode_path=decode_path,
3026 self.assertEqual(len(evgens), 1)
3027 _decode_path, obj, tail = evgens[0]
3028 self.assertSequenceEqual(tail, tail_junk)
3029 self.assertEqual(_decode_path, decode_path)
3030 self.assertEqual(obj, obj_decoded)
3031 self.assertEqual(obj.expl_offset, offset)
3036 oid_strategy().map(ObjectIdentifier),
3037 oid_strategy().map(ObjectIdentifier),
3039 def test_add(self, oid1, oid2):
3040 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3041 for oid_to_add in (oid2, tuple(oid2)):
3042 self.assertEqual(oid1 + oid_to_add, oid_expect)
3043 with self.assertRaises(InvalidValueType):
3046 def test_go_vectors_valid(self):
3047 for data, expect in (
3049 (b"\x55\x02", (2, 5, 2)),
3050 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3051 (b"\x81\x34\x03", (2, 100, 3)),
3054 ObjectIdentifier().decode(b"".join((
3055 ObjectIdentifier.tag_default,
3056 len_encode(len(data)),
3062 def test_go_vectors_invalid(self):
3063 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3064 with self.assertRaises(DecodeError):
3065 ObjectIdentifier().decode(b"".join((
3066 Integer.tag_default,
3067 len_encode(len(data)),
3071 def test_go_non_minimal_encoding(self):
3072 with self.assertRaises(DecodeError):
3073 ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
3075 def test_x690_vector(self):
3077 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3078 ObjectIdentifier((2, 999, 3)),
3081 def test_nonnormalized_first_arc(self):
3083 ObjectIdentifier.tag_default +
3086 ObjectIdentifier((1, 0)).encode()[-1:]
3088 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3089 self.assertTrue(obj.ber_encoded)
3090 self.assertTrue(obj.bered)
3092 self.assertTrue(obj.ber_encoded)
3093 self.assertTrue(obj.bered)
3094 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3095 ObjectIdentifier().decode(tampered)
3097 @given(data_strategy())
3098 def test_negative_arcs(self, d):
3099 oid = list(d.draw(oid_strategy()))
3102 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3104 if oid[idx - 1] == 0:
3106 with self.assertRaises(InvalidOID):
3107 ObjectIdentifier(tuple(oid))
3108 with self.assertRaises(InvalidOID):
3109 ObjectIdentifier(".".join(str(i) for i in oid))
3111 @given(data_strategy())
3112 def test_plused_arcs(self, d):
3113 oid = [str(arc) for arc in d.draw(oid_strategy())]
3114 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3115 oid[idx - 1] = "+" + oid[idx - 1]
3116 with self.assertRaises(InvalidOID):
3117 ObjectIdentifier(".".join(str(i) for i in oid))
3119 @given(data_strategy())
3120 def test_nonnormalized_arcs(self, d):
3121 arcs = d.draw(lists(
3122 integers(min_value=0, max_value=100),
3126 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3127 _, _, lv = tag_strip(dered)
3128 _, _, v = len_decode(lv)
3129 v_no_first_arc = v[1:]
3130 idx_for_tamper = d.draw(integers(
3132 max_value=len(v_no_first_arc) - 1,
3134 tampered = list(bytearray(v_no_first_arc))
3135 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3136 tampered.insert(idx_for_tamper, 0x80)
3137 tampered = bytes(bytearray(tampered))
3139 ObjectIdentifier.tag_default +
3140 len_encode(len(tampered)) +
3143 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3144 self.assertTrue(obj.ber_encoded)
3145 self.assertTrue(obj.bered)
3147 self.assertTrue(obj.ber_encoded)
3148 self.assertTrue(obj.bered)
3149 with self.assertRaisesRegex(DecodeError, "non normalized arc encoding"):
3150 ObjectIdentifier().decode(tampered)
3154 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3156 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3157 values = list(draw(sets(
3159 min_size=len(schema),
3160 max_size=len(schema),
3162 schema = list(zip(schema, values))
3163 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3167 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3169 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3170 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3171 optional = draw(one_of(none(), booleans()))
3173 draw(integers(min_value=0)),
3174 draw(integers(min_value=0)),
3175 draw(integers(min_value=0)),
3177 return (schema, value, impl, expl, default, optional, _decoded)
3180 class TestEnumerated(CommonMixin, TestCase):
3181 class EWhatever(Enumerated):
3182 schema = (("whatever", 0),)
3184 base_klass = EWhatever
3186 def test_schema_required(self):
3187 with self.assertRaisesRegex(ValueError, "schema must be specified"):
3190 def test_invalid_value_type(self):
3191 with self.assertRaises(InvalidValueType) as err:
3192 self.base_klass((1, 2))
3195 @given(sets(text_letters(), min_size=2))
3196 def test_unknown_name(self, schema_input):
3197 missing = schema_input.pop()
3199 class E(Enumerated):
3200 schema = [(n, 123) for n in schema_input]
3201 with self.assertRaises(ObjUnknown) as err:
3206 sets(text_letters(), min_size=2),
3207 sets(integers(), min_size=2),
3209 def test_unknown_value(self, schema_input, values_input):
3211 missing_value = values_input.pop()
3212 _input = list(zip(schema_input, values_input))
3214 class E(Enumerated):
3216 with self.assertRaises(DecodeError) as err:
3221 def test_optional(self, optional):
3222 obj = self.base_klass(default="whatever", optional=optional)
3223 self.assertTrue(obj.optional)
3225 def test_ready(self):
3226 obj = self.base_klass()
3227 self.assertFalse(obj.ready)
3230 pprint(obj, big_blobs=True, with_decode_path=True)
3231 with self.assertRaises(ObjNotReady) as err:
3234 obj = self.base_klass("whatever")
3235 self.assertTrue(obj.ready)
3238 pprint(obj, big_blobs=True, with_decode_path=True)
3240 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3241 def test_comparison(self, value1, value2, tag1, tag2):
3242 class E(Enumerated):
3244 ("whatever0", value1),
3245 ("whatever1", value2),
3248 class EInherited(E):
3250 for klass in (E, EInherited):
3251 obj1 = klass(value1)
3252 obj2 = klass(value2)
3253 self.assertEqual(obj1 == obj2, value1 == value2)
3254 self.assertEqual(obj1 != obj2, value1 != value2)
3255 self.assertEqual(obj1 == int(obj2), value1 == value2)
3256 obj1 = klass(value1, impl=tag1)
3257 obj2 = klass(value1, impl=tag2)
3258 self.assertEqual(obj1 == obj2, tag1 == tag2)
3259 self.assertEqual(obj1 != obj2, tag1 != tag2)
3261 @given(data_strategy())
3262 def test_call(self, d):
3271 ) = d.draw(enumerated_values_strategy())
3273 class E(Enumerated):
3274 schema = schema_initial
3276 value=value_initial,
3279 default=default_initial,
3280 optional=optional_initial or False,
3281 _decoded=_decoded_initial,
3291 ) = d.draw(enumerated_values_strategy(
3292 schema=schema_initial,
3293 do_expl=impl_initial is None,
3303 value_expected = default if value is None else value
3305 default_initial if value_expected is None
3310 dict(schema_initial).get(value_expected, value_expected),
3312 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3313 self.assertEqual(obj.expl_tag, expl or expl_initial)
3316 default_initial if default is None else default,
3318 if obj.default is None:
3319 optional = optional_initial if optional is None else optional
3320 optional = False if optional is None else optional
3323 self.assertEqual(obj.optional, optional)
3324 self.assertEqual(obj.specs, dict(schema_initial))
3326 @given(enumerated_values_strategy())
3327 def test_copy(self, values):
3328 schema_input, value, impl, expl, default, optional, _decoded = values
3330 class E(Enumerated):
3331 schema = schema_input
3341 for copy_func in copy_funcs:
3342 obj_copied = copy_func(obj)
3343 self.assert_copied_basic_fields(obj, obj_copied)
3344 self.assertEqual(obj.specs, obj_copied.specs)
3346 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3347 @given(data_strategy())
3348 def test_symmetric(self, d):
3349 schema_input, _, _, _, default, optional, _decoded = d.draw(
3350 enumerated_values_strategy(),
3352 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3353 offset = d.draw(integers(min_value=0))
3354 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3355 tail_junk = d.draw(binary(max_size=5))
3356 decode_path = d.draw(decode_path_strat)
3358 class E(Enumerated):
3359 schema = schema_input
3368 pprint(obj, big_blobs=True, with_decode_path=True)
3369 self.assertFalse(obj.expled)
3370 obj_encoded = obj.encode()
3371 self.assertEqual(encode2pass(obj), obj_encoded)
3372 obj_expled = obj(value, expl=tag_expl)
3373 self.assertTrue(obj_expled.expled)
3375 list(obj_expled.pps())
3376 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3377 obj_expled_encoded = obj_expled.encode()
3378 ctx_copied = deepcopy(ctx_dummy)
3379 obj_decoded, tail = obj_expled.decode(
3380 obj_expled_encoded + tail_junk,
3384 self.assertDictEqual(ctx_copied, ctx_dummy)
3386 list(obj_decoded.pps())
3387 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3388 self.assertEqual(tail, tail_junk)
3389 self.assertEqual(obj_decoded, obj_expled)
3390 self.assertNotEqual(obj_decoded, obj)
3391 self.assertEqual(int(obj_decoded), int(obj_expled))
3392 self.assertEqual(int(obj_decoded), int(obj))
3393 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3394 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3395 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3397 obj_decoded.expl_llen,
3398 len(len_encode(len(obj_encoded))),
3400 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3401 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3404 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3406 self.assertEqual(obj_decoded.expl_offset, offset)
3407 assert_exceeding_data(
3409 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3413 evgens = list(obj_expled.decode_evgen(
3414 obj_expled_encoded + tail_junk,
3416 decode_path=decode_path,
3419 self.assertEqual(len(evgens), 1)
3420 _decode_path, obj, tail = evgens[0]
3421 self.assertSequenceEqual(tail, tail_junk)
3422 self.assertEqual(_decode_path, decode_path)
3423 self.assertEqual(obj, obj_decoded)
3424 self.assertEqual(obj.expl_offset, offset)
3430 def string_values_strategy(draw, alphabet, do_expl=False):
3431 bound_min, bound_max = sorted(draw(sets(
3432 integers(min_value=0, max_value=1 << 7),
3436 value = draw(one_of(
3438 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3440 default = draw(one_of(
3442 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3445 if draw(booleans()):
3446 bounds = (bound_min, bound_max)
3450 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3452 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3453 optional = draw(one_of(none(), booleans()))
3455 draw(integers(min_value=0)),
3456 draw(integers(min_value=0)),
3457 draw(integers(min_value=0)),
3459 return (value, bounds, impl, expl, default, optional, _decoded)
3462 class StringMixin(object):
3463 def test_invalid_value_type(self):
3464 with self.assertRaises(InvalidValueType) as err:
3465 self.base_klass((1, 2))
3468 def text_alphabet(self):
3469 return "".join(chr(c) for c in range(256))
3472 def test_optional(self, optional):
3473 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3474 self.assertTrue(obj.optional)
3476 @given(data_strategy())
3477 def test_ready(self, d):
3478 obj = self.base_klass()
3479 self.assertFalse(obj.ready)
3482 pprint(obj, big_blobs=True, with_decode_path=True)
3484 with self.assertRaises(ObjNotReady) as err:
3487 with self.assertRaises(ObjNotReady) as err:
3489 value = d.draw(text(alphabet=self.text_alphabet()))
3490 obj = self.base_klass(value)
3491 self.assertTrue(obj.ready)
3494 pprint(obj, big_blobs=True, with_decode_path=True)
3497 @given(data_strategy())
3498 def test_comparison(self, d):
3499 value1 = d.draw(text(alphabet=self.text_alphabet()))
3500 value2 = d.draw(text(alphabet=self.text_alphabet()))
3501 tag1 = d.draw(binary(min_size=1))
3502 tag2 = d.draw(binary(min_size=1))
3503 obj1 = self.base_klass(value1)
3504 obj2 = self.base_klass(value2)
3505 self.assertEqual(obj1 == obj2, value1 == value2)
3506 self.assertEqual(obj1 != obj2, value1 != value2)
3507 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3508 self.assertEqual(obj1 == str(obj2), value1 == value2)
3509 obj1 = self.base_klass(value1, impl=tag1)
3510 obj2 = self.base_klass(value1, impl=tag2)
3511 self.assertEqual(obj1 == obj2, tag1 == tag2)
3512 self.assertEqual(obj1 != obj2, tag1 != tag2)
3514 @given(data_strategy())
3515 def test_bounds_satisfied(self, d):
3516 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3517 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3518 value = d.draw(text(
3519 alphabet=self.text_alphabet(),
3523 self.base_klass(value=value, bounds=(bound_min, bound_max))
3525 @given(data_strategy())
3526 def test_bounds_unsatisfied(self, d):
3527 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3528 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3529 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3530 with self.assertRaises(BoundsError) as err:
3531 self.base_klass(value=value, bounds=(bound_min, bound_max))
3533 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3534 self.base_klass(bounds=(bound_min, bound_max)).decode(
3535 self.base_klass(value).encode()
3538 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3539 self.base_klass(bounds=(bound_min, bound_max)).decode(
3540 encode2pass(self.base_klass(value))
3542 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3543 with self.assertRaises(BoundsError) as err:
3544 self.base_klass(value=value, bounds=(bound_min, bound_max))
3546 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3547 self.base_klass(bounds=(bound_min, bound_max)).decode(
3548 self.base_klass(value).encode()
3551 with self.assertRaisesRegex(DecodeError, "bounds") as err:
3552 self.base_klass(bounds=(bound_min, bound_max)).decode(
3553 encode2pass(self.base_klass(value))
3556 @given(data_strategy())
3557 def test_call(self, d):
3566 ) = d.draw(string_values_strategy(self.text_alphabet()))
3567 obj_initial = self.base_klass(
3573 optional_initial or False,
3584 ) = d.draw(string_values_strategy(
3585 self.text_alphabet(),
3586 do_expl=impl_initial is None,
3588 if (default is None) and (obj_initial.default is not None):
3591 (bounds is None) and
3592 (value is not None) and
3593 (bounds_initial is not None) and
3594 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3598 (bounds is None) and
3599 (default is not None) and
3600 (bounds_initial is not None) and
3601 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3604 obj = obj_initial(value, bounds, impl, expl, default, optional)
3606 value_expected = default if value is None else value
3608 default_initial if value_expected is None
3611 self.assertEqual(obj, value_expected)
3612 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3613 self.assertEqual(obj.expl_tag, expl or expl_initial)
3616 default_initial if default is None else default,
3618 if obj.default is None:
3619 optional = optional_initial if optional is None else optional
3620 optional = False if optional is None else optional
3623 self.assertEqual(obj.optional, optional)
3625 (obj._bound_min, obj._bound_max),
3626 bounds or bounds_initial or (0, float("+inf")),
3629 @given(data_strategy())
3630 def test_copy(self, d):
3631 values = d.draw(string_values_strategy(self.text_alphabet()))
3632 obj = self.base_klass(*values)
3633 for copy_func in copy_funcs:
3634 obj_copied = copy_func(obj)
3635 self.assert_copied_basic_fields(obj, obj_copied)
3636 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3637 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3638 self.assertEqual(obj._value, obj_copied._value)
3640 @given(data_strategy())
3641 def test_stripped(self, d):
3642 value = d.draw(text(alphabet=self.text_alphabet()))
3643 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3644 obj = self.base_klass(value, impl=tag_impl)
3645 with self.assertRaises(NotEnoughData):
3646 obj.decode(obj.encode()[:-1])
3648 @given(data_strategy())
3649 def test_stripped_expl(self, d):
3650 value = d.draw(text(alphabet=self.text_alphabet()))
3651 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3652 obj = self.base_klass(value, expl=tag_expl)
3653 with self.assertRaises(NotEnoughData):
3654 obj.decode(obj.encode()[:-1])
3657 integers(min_value=31),
3658 integers(min_value=0),
3661 def test_bad_tag(self, tag, offset, decode_path):
3662 with self.assertRaises(DecodeError) as err:
3663 self.base_klass().decode(
3664 tag_encode(tag)[:-1],
3666 decode_path=decode_path,
3669 self.assertEqual(err.exception.offset, offset)
3670 self.assertEqual(err.exception.decode_path, decode_path)
3673 integers(min_value=128),
3674 integers(min_value=0),
3677 def test_bad_len(self, l, offset, decode_path):
3678 with self.assertRaises(DecodeError) as err:
3679 self.base_klass().decode(
3680 self.base_klass.tag_default + len_encode(l)[:-1],
3682 decode_path=decode_path,
3685 self.assertEqual(err.exception.offset, offset)
3686 self.assertEqual(err.exception.decode_path, decode_path)
3689 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3690 integers(min_value=0),
3693 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3694 value, bound_min = list(sorted(ints))
3696 class String(self.base_klass):
3697 # Multiply this value by four, to satisfy UTF-32 bounds
3698 # (4 bytes per character) validation
3699 bounds = (bound_min * 4, bound_min * 4)
3700 with self.assertRaises(DecodeError) as err:
3702 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3704 decode_path=decode_path,
3707 self.assertEqual(err.exception.offset, offset)
3708 self.assertEqual(err.exception.decode_path, decode_path)
3710 @given(data_strategy())
3711 def test_symmetric(self, d):
3712 values = d.draw(string_values_strategy(self.text_alphabet()))
3713 value = d.draw(text(alphabet=self.text_alphabet()))
3714 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3715 offset = d.draw(integers(min_value=0))
3716 tail_junk = d.draw(binary(max_size=5))
3717 decode_path = d.draw(decode_path_strat)
3718 _, _, _, _, default, optional, _decoded = values
3719 obj = self.base_klass(
3727 pprint(obj, big_blobs=True, with_decode_path=True)
3728 self.assertFalse(obj.expled)
3729 obj_encoded = obj.encode()
3730 self.assertEqual(encode2pass(obj), obj_encoded)
3731 obj_expled = obj(value, expl=tag_expl)
3732 self.assertTrue(obj_expled.expled)
3734 list(obj_expled.pps())
3735 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3736 obj_expled_encoded = obj_expled.encode()
3737 ctx_copied = deepcopy(ctx_dummy)
3738 obj_decoded, tail = obj_expled.decode(
3739 obj_expled_encoded + tail_junk,
3743 self.assertDictEqual(ctx_copied, ctx_dummy)
3745 list(obj_decoded.pps())
3746 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3747 self.assertEqual(tail, tail_junk)
3748 self.assertEqual(obj_decoded, obj_expled)
3749 self.assertNotEqual(obj_decoded, obj)
3750 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3751 self.assertEqual(bytes(obj_decoded), bytes(obj))
3752 self.assertEqual(str(obj_decoded), str(obj_expled))
3753 self.assertEqual(str(obj_decoded), str(obj))
3754 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3755 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3756 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3758 obj_decoded.expl_llen,
3759 len(len_encode(len(obj_encoded))),
3761 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3762 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3765 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3767 self.assertEqual(obj_decoded.expl_offset, offset)
3768 assert_exceeding_data(
3770 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3774 evgens = list(obj_expled.decode_evgen(
3775 obj_expled_encoded + tail_junk,
3777 decode_path=decode_path,
3780 self.assertEqual(len(evgens), 1)
3781 _decode_path, obj, tail = evgens[0]
3782 self.assertSequenceEqual(tail, tail_junk)
3783 self.assertEqual(_decode_path, decode_path)
3784 if not getattr(self, "evgen_mode_skip_value", True):
3785 self.assertEqual(obj, obj_decoded)
3786 self.assertEqual(obj.expl_offset, offset)
3791 cyrillic_letters = text(
3792 alphabet="".join(chr(i) for i in list(range(0x0410, 0x044f + 1))),
3798 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3799 base_klass = UTF8String
3801 @given(cyrillic_letters)
3802 def test_byte_per_primitive(self, chars):
3804 char_raw = char.encode("utf-8")
3805 encoded = b"".join((
3806 self.base_klass().tag_constructed,
3808 OctetString(char_raw[:1]).encode(),
3809 OctetString(char_raw[1:2]).encode(),
3813 self.base_klass().decod(encoded, ctx={"bered": True}),
3818 class UnicodeDecodeErrorMixin(object):
3819 @given(cyrillic_letters)
3820 def test_unicode_decode_error(self, cyrillic_text):
3821 with self.assertRaises(DecodeError):
3822 self.base_klass(cyrillic_text)
3825 class TestNumericString(StringMixin, CommonMixin, TestCase):
3826 base_klass = NumericString
3828 def text_alphabet(self):
3831 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3832 def test_non_numeric(self, non_numeric_text):
3833 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3834 self.base_klass(non_numeric_text)
3837 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3838 integers(min_value=0),
3841 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3842 value, bound_min = list(sorted(ints))
3844 class String(self.base_klass):
3845 bounds = (bound_min, bound_min)
3846 with self.assertRaises(DecodeError) as err:
3848 self.base_klass(b"1" * value).encode(),
3850 decode_path=decode_path,
3853 self.assertEqual(err.exception.offset, offset)
3854 self.assertEqual(err.exception.decode_path, decode_path)
3856 def test_byte_per_primitive(self):
3857 encoded = b"".join((
3858 self.base_klass().tag_constructed,
3860 OctetString(b"1").encode(),
3861 OctetString(b"2").encode(),
3865 self.base_klass().decod(encoded, ctx={"bered": True}),
3870 class TestPrintableString(
3871 UnicodeDecodeErrorMixin,
3876 base_klass = PrintableString
3878 def text_alphabet(self):
3879 return ascii_letters + digits + " '()+,-./:=?"
3881 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3882 def test_non_printable(self, non_printable_text):
3883 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3884 self.base_klass(non_printable_text)
3887 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3888 integers(min_value=0),
3891 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3892 value, bound_min = list(sorted(ints))
3894 class String(self.base_klass):
3895 bounds = (bound_min, bound_min)
3896 with self.assertRaises(DecodeError) as err:
3898 self.base_klass(b"1" * value).encode(),
3900 decode_path=decode_path,
3903 self.assertEqual(err.exception.offset, offset)
3904 self.assertEqual(err.exception.decode_path, decode_path)
3906 def test_allowable_invalid_chars(self):
3908 ("*", {"allow_asterisk": True}),
3909 ("&", {"allow_ampersand": True}),
3910 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3913 obj = self.base_klass(s)
3914 for prop in kwargs.keys():
3915 self.assertFalse(getattr(obj, prop))
3917 with self.assertRaisesRegex(DecodeError, "alphabet value"):
3919 self.base_klass(s, **kwargs)
3920 klass = self.base_klass(**kwargs)
3922 for prop in kwargs.keys():
3923 self.assertTrue(getattr(obj, prop))
3926 for prop in kwargs.keys():
3927 self.assertTrue(getattr(obj, prop))
3930 class TestTeletexString(
3931 UnicodeDecodeErrorMixin,
3936 base_klass = TeletexString
3939 class TestVideotexString(
3940 UnicodeDecodeErrorMixin,
3945 base_klass = VideotexString
3948 class TestIA5String(
3949 UnicodeDecodeErrorMixin,
3954 base_klass = IA5String
3956 def text_alphabet(self):
3957 return "".join(chr(c) for c in range(128))
3959 @given(integers(min_value=128, max_value=255))
3960 def test_alphabet_bad(self, code):
3961 with self.assertRaises(DecodeError):
3962 self.base_klass().decod(
3963 self.base_klass.tag_default +
3965 bytes(bytearray([code])),
3969 class TestGraphicString(
3970 UnicodeDecodeErrorMixin,
3975 base_klass = GraphicString
3978 class TestVisibleString(
3979 UnicodeDecodeErrorMixin,
3984 base_klass = VisibleString
3986 def text_alphabet(self):
3987 return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
3989 def test_x690_vector(self):
3990 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3991 self.assertSequenceEqual(tail, b"")
3992 self.assertEqual(str(obj), "Jones")
3993 self.assertFalse(obj.ber_encoded)
3994 self.assertFalse(obj.lenindef)
3995 self.assertFalse(obj.bered)
3997 obj, tail = VisibleString().decode(
3998 hexdec("3A0904034A6F6E04026573"),
3999 ctx={"bered": True},
4001 self.assertSequenceEqual(tail, b"")
4002 self.assertEqual(str(obj), "Jones")
4003 self.assertTrue(obj.ber_encoded)
4004 self.assertFalse(obj.lenindef)
4005 self.assertTrue(obj.bered)
4007 self.assertTrue(obj.ber_encoded)
4008 self.assertFalse(obj.lenindef)
4009 self.assertTrue(obj.bered)
4011 obj, tail = VisibleString().decode(
4012 hexdec("3A8004034A6F6E040265730000"),
4013 ctx={"bered": True},
4015 self.assertSequenceEqual(tail, b"")
4016 self.assertEqual(str(obj), "Jones")
4017 self.assertTrue(obj.ber_encoded)
4018 self.assertTrue(obj.lenindef)
4019 self.assertTrue(obj.bered)
4021 self.assertTrue(obj.ber_encoded)
4022 self.assertTrue(obj.lenindef)
4023 self.assertTrue(obj.bered)
4026 integers(min_value=0, max_value=ord(" ") - 1),
4027 integers(min_value=ord("~") + 1, max_value=255),
4029 def test_alphabet_bad(self, code):
4030 with self.assertRaises(DecodeError):
4031 self.base_klass().decod(
4032 self.base_klass.tag_default +
4034 bytes(bytearray([code])),
4038 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
4039 integers(min_value=0),
4042 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
4043 value, bound_min = list(sorted(ints))
4045 class String(self.base_klass):
4046 bounds = (bound_min, bound_min)
4047 with self.assertRaises(DecodeError) as err:
4049 self.base_klass(b"1" * value).encode(),
4051 decode_path=decode_path,
4054 self.assertEqual(err.exception.offset, offset)
4055 self.assertEqual(err.exception.decode_path, decode_path)
4058 class TestGeneralString(
4059 UnicodeDecodeErrorMixin,
4064 base_klass = GeneralString
4067 class TestUniversalString(StringMixin, CommonMixin, TestCase):
4068 base_klass = UniversalString
4071 class TestBMPString(StringMixin, CommonMixin, TestCase):
4072 base_klass = BMPString
4076 def generalized_time_values_strategy(
4084 if draw(booleans()):
4085 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4087 value = value.replace(microsecond=0)
4089 if draw(booleans()):
4090 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
4092 default = default.replace(microsecond=0)
4096 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4098 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4099 optional = draw(one_of(none(), booleans()))
4101 draw(integers(min_value=0)),
4102 draw(integers(min_value=0)),
4103 draw(integers(min_value=0)),
4105 return (value, impl, expl, default, optional, _decoded)
4108 class TimeMixin(object):
4109 def test_invalid_value_type(self):
4110 with self.assertRaises(InvalidValueType) as err:
4111 self.base_klass(datetime.now().timetuple())
4114 @given(data_strategy())
4115 def test_optional(self, d):
4116 default = d.draw(datetimes(
4117 min_value=self.min_datetime,
4118 max_value=self.max_datetime,
4120 optional = d.draw(booleans())
4121 obj = self.base_klass(default=default, optional=optional)
4122 self.assertTrue(obj.optional)
4124 @given(data_strategy())
4125 def test_ready(self, d):
4126 obj = self.base_klass()
4127 self.assertFalse(obj.ready)
4130 pprint(obj, big_blobs=True, with_decode_path=True)
4131 with self.assertRaises(ObjNotReady) as err:
4134 with self.assertRaises(ObjNotReady) as err:
4136 value = d.draw(datetimes(
4137 min_value=self.min_datetime,
4138 max_value=self.max_datetime,
4140 obj = self.base_klass(value)
4141 self.assertTrue(obj.ready)
4144 pprint(obj, big_blobs=True, with_decode_path=True)
4146 @given(data_strategy())
4147 def test_comparison(self, d):
4148 value1 = d.draw(datetimes(
4149 min_value=self.min_datetime,
4150 max_value=self.max_datetime,
4152 value2 = d.draw(datetimes(
4153 min_value=self.min_datetime,
4154 max_value=self.max_datetime,
4156 tag1 = d.draw(binary(min_size=1))
4157 tag2 = d.draw(binary(min_size=1))
4159 value1 = value1.replace(microsecond=0)
4160 value2 = value2.replace(microsecond=0)
4161 obj1 = self.base_klass(value1)
4162 obj2 = self.base_klass(value2)
4163 self.assertEqual(obj1 == obj2, value1 == value2)
4164 self.assertEqual(obj1 != obj2, value1 != value2)
4165 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4166 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4167 obj1 = self.base_klass(value1, impl=tag1)
4168 obj2 = self.base_klass(value1, impl=tag2)
4169 self.assertEqual(obj1 == obj2, tag1 == tag2)
4170 self.assertEqual(obj1 != obj2, tag1 != tag2)
4172 @given(data_strategy())
4173 def test_call(self, d):
4181 ) = d.draw(generalized_time_values_strategy(
4182 min_datetime=self.min_datetime,
4183 max_datetime=self.max_datetime,
4184 omit_ms=self.omit_ms,
4186 obj_initial = self.base_klass(
4187 value=value_initial,
4190 default=default_initial,
4191 optional=optional_initial or False,
4192 _decoded=_decoded_initial,
4201 ) = d.draw(generalized_time_values_strategy(
4202 min_datetime=self.min_datetime,
4203 max_datetime=self.max_datetime,
4204 omit_ms=self.omit_ms,
4205 do_expl=impl_initial is None,
4215 value_expected = default if value is None else value
4217 default_initial if value_expected is None
4220 self.assertEqual(obj, value_expected)
4221 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4222 self.assertEqual(obj.expl_tag, expl or expl_initial)
4225 default_initial if default is None else default,
4227 if obj.default is None:
4228 optional = optional_initial if optional is None else optional
4229 optional = False if optional is None else optional
4232 self.assertEqual(obj.optional, optional)
4234 @given(data_strategy())
4235 def test_copy(self, d):
4236 values = d.draw(generalized_time_values_strategy(
4237 min_datetime=self.min_datetime,
4238 max_datetime=self.max_datetime,
4240 obj = self.base_klass(*values)
4241 for copy_func in copy_funcs:
4242 obj_copied = copy_func(obj)
4243 self.assert_copied_basic_fields(obj, obj_copied)
4244 self.assertEqual(obj._value, obj_copied._value)
4246 @given(data_strategy())
4247 def test_stripped(self, d):
4248 value = d.draw(datetimes(
4249 min_value=self.min_datetime,
4250 max_value=self.max_datetime,
4252 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4253 obj = self.base_klass(value, impl=tag_impl)
4254 with self.assertRaises(NotEnoughData):
4255 obj.decode(obj.encode()[:-1])
4257 @given(data_strategy())
4258 def test_stripped_expl(self, d):
4259 value = d.draw(datetimes(
4260 min_value=self.min_datetime,
4261 max_value=self.max_datetime,
4263 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4264 obj = self.base_klass(value, expl=tag_expl)
4265 with self.assertRaises(NotEnoughData):
4266 obj.decode(obj.encode()[:-1])
4268 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4269 @given(data_strategy())
4270 def test_symmetric(self, d):
4271 values = d.draw(generalized_time_values_strategy(
4272 min_datetime=self.min_datetime,
4273 max_datetime=self.max_datetime,
4275 value = d.draw(datetimes(
4276 min_value=self.min_datetime,
4277 max_value=self.max_datetime,
4279 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4280 offset = d.draw(integers(min_value=0))
4281 tail_junk = d.draw(binary(max_size=5))
4282 _, _, _, default, optional, _decoded = values
4283 obj = self.base_klass(
4291 pprint(obj, big_blobs=True, with_decode_path=True)
4292 self.assertFalse(obj.expled)
4293 obj_encoded = obj.encode()
4294 self.assertEqual(encode2pass(obj), obj_encoded)
4295 self.additional_symmetric_check(value, obj_encoded)
4296 obj_expled = obj(value, expl=tag_expl)
4297 self.assertTrue(obj_expled.expled)
4299 list(obj_expled.pps())
4300 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4301 obj_expled_encoded = obj_expled.encode()
4302 ctx_copied = deepcopy(ctx_dummy)
4303 obj_decoded, tail = obj_expled.decode(
4304 obj_expled_encoded + tail_junk,
4308 self.assertDictEqual(ctx_copied, ctx_dummy)
4310 list(obj_decoded.pps())
4311 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4312 self.assertEqual(tail, tail_junk)
4313 self.assertEqual(obj_decoded, obj_expled)
4314 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4315 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4316 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4317 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4318 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4320 obj_decoded.expl_llen,
4321 len(len_encode(len(obj_encoded))),
4323 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4324 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4327 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4329 self.assertEqual(obj_decoded.expl_offset, offset)
4330 assert_exceeding_data(
4332 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4337 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4338 base_klass = GeneralizedTime
4340 min_datetime = datetime(1900, 1, 1)
4341 max_datetime = datetime(9999, 12, 31)
4342 evgen_mode_skip_value = False
4344 def additional_symmetric_check(self, value, obj_encoded):
4345 if value.microsecond > 0:
4346 self.assertFalse(obj_encoded.endswith(b"0Z"))
4348 def test_repr_not_ready(self):
4349 str(GeneralizedTime())
4350 repr(GeneralizedTime())
4352 def test_x690_vector_valid(self):
4356 b"19920722132100.3Z",
4358 GeneralizedTime(data)
4360 def test_x690_vector_invalid(self):
4363 b"19920622123421.0Z",
4364 b"19920722132100.30Z",
4366 with self.assertRaises(DecodeError) as err:
4367 GeneralizedTime(data)
4370 def test_go_vectors_invalid(self):
4382 b"-20100102030410Z",
4383 b"2010-0102030410Z",
4384 b"2010-0002030410Z",
4385 b"201001-02030410Z",
4386 b"20100102-030410Z",
4387 b"2010010203-0410Z",
4388 b"201001020304-10Z",
4389 # These ones are INVALID in *DER*, but accepted
4390 # by Go's encoding/asn1
4391 b"20100102030405+0607",
4392 b"20100102030405-0607",
4394 with self.assertRaises(DecodeError) as err:
4395 GeneralizedTime(data)
4398 def test_go_vectors_valid(self):
4400 GeneralizedTime(b"20100102030405Z").todatetime(),
4401 datetime(2010, 1, 2, 3, 4, 5, 0),
4404 def test_go_vectors_valid_ber(self):
4406 b"20100102030405+0607",
4407 b"20100102030405-0607",
4409 GeneralizedTime(data, ctx={"bered": True})
4411 def test_utc_offsets(self):
4412 """Some know equal UTC offsets
4415 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4419 "200101011130-0700",
4420 "200101011500-03:30",
4423 self.assertEqual(dts[0], dts[1])
4424 self.assertEqual(dts[0], dts[2])
4425 self.assertEqual(dts[0], dts[3])
4427 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4428 @given(data_strategy())
4429 def test_valid_ber(self, d):
4430 year = d.draw(integers(min_value=2, max_value=9999))
4431 month = d.draw(integers(min_value=1, max_value=12))
4432 day = d.draw(integers(min_value=1, max_value=28))
4433 hours = d.draw(integers(min_value=0, max_value=23))
4434 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4435 dt = datetime(year, month, day, hours)
4436 fractions_sign = d.draw(sampled_from(" ,."))
4438 if fractions_sign != " ":
4439 fractions = random()
4440 if d.draw(booleans()):
4441 minutes = d.draw(integers(min_value=0, max_value=59))
4442 data += "%02d" % minutes
4443 dt += timedelta(seconds=60 * minutes)
4444 if d.draw(booleans()):
4445 seconds = d.draw(integers(min_value=0, max_value=59))
4446 data += "%02d" % seconds
4447 dt += timedelta(seconds=seconds)
4448 if fractions is not None:
4449 dt += timedelta(microseconds=10**6 * fractions)
4450 elif fractions is not None:
4451 dt += timedelta(seconds=60 * fractions)
4452 elif fractions is not None:
4453 dt += timedelta(seconds=3600 * fractions)
4454 if fractions is not None:
4455 data += fractions_sign + str(fractions)[2:]
4456 if d.draw(booleans()):
4458 elif d.draw(booleans()):
4459 offset_hour = d.draw(integers(min_value=0, max_value=13))
4461 if d.draw(booleans()):
4466 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4467 data += "%02d" % offset_hour
4468 minutes_separator = d.draw(sampled_from((None, "", ":")))
4469 if minutes_separator is not None:
4470 offset_minute = d.draw(integers(min_value=0, max_value=59))
4471 dt -= timedelta(seconds=sign * 60 * offset_minute)
4472 data += "%s%02d" % (minutes_separator, offset_minute)
4473 data = data.encode("ascii")
4474 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4476 GeneralizedTime().decod(data_der)
4481 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4484 mktime(obj.todatetime().timetuple()),
4485 mktime(dt.timetuple()),
4489 obj.todatetime().timestamp()
4493 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4494 self.assertEqual(obj.ber_encoded, not dered)
4495 self.assertEqual(obj.bered, not dered)
4496 self.assertEqual(obj.ber_raw, None if dered else data)
4497 self.assertEqual(obj.encode() == data_der, dered)
4502 def test_invalid_ber(self):
4504 # "00010203040506.07",
4505 "-0010203040506.07",
4506 "0001-203040506.07",
4507 "000102-3040506.07",
4508 "00010203-40506.07",
4509 "0001020304-506.07",
4510 "000102030405-6.07",
4511 "00010203040506.-7",
4512 "+0010203040506.07",
4513 "0001+203040506.07",
4514 "000102+3040506.07",
4515 "00010203+40506.07",
4516 "0001020304+506.07",
4517 "000102030405+6.07",
4518 "00010203040506.+7",
4519 " 0010203040506.07",
4520 "0001 203040506.07",
4521 "000102 3040506.07",
4522 "00010203 40506.07",
4523 "0001020304 506.07",
4524 "000102030405 6.07",
4525 "00010203040506. 7",
4526 "001 0203040506.07",
4527 "00012 03040506.07",
4528 "0001023 040506.07",
4529 "000102034 0506.07",
4530 "00010203045 06.07",
4531 "0001020304056 .07",
4532 "00010203040506.7 ",
4612 "00010203040506.07+15",
4613 "00010203040506.07-15",
4614 "00010203040506.07+14:60",
4615 "00010203040506.07+1460",
4616 "00010203040506.07-1460",
4617 "00010203040506.07+00:60",
4618 "00010203040506.07-00:60",
4620 "00010203040506+15",
4621 "00010203040506-15",
4622 "00010203040506+14:60",
4623 "00010203040506+1460",
4624 "00010203040506-1460",
4625 "00010203040506+00:60",
4626 "00010203040506-00:60",
4635 with self.assertRaises(DecodeError):
4636 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4637 data = data.replace(".", ",")
4638 with self.assertRaises(DecodeError):
4639 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4643 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4644 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4646 binary(min_size=1, max_size=1),
4648 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4649 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4652 def test_junk(self, part0, part1, part2):
4653 junk = part0 + part1 + part2
4654 assume(not (set(junk) <= set(digits.encode("ascii"))))
4655 with self.assertRaises(DecodeError):
4656 GeneralizedTime().decode(
4657 GeneralizedTime.tag_default +
4658 len_encode(len(junk)) +
4664 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4665 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4667 binary(min_size=1, max_size=1),
4669 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4670 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4673 def test_junk_dm(self, part0, part1, part2):
4674 junk = part0 + part1 + part2
4675 assume(not (set(junk) <= set(digits.encode("ascii"))))
4676 with self.assertRaises(DecodeError):
4677 GeneralizedTime().decode(
4678 GeneralizedTime.tag_default +
4679 len_encode(len(junk)) +
4683 def test_ns_fractions(self):
4684 GeneralizedTime(b"20010101000000.000001Z")
4685 with self.assertRaisesRegex(DecodeError, "only microsecond fractions"):
4686 GeneralizedTime(b"20010101000000.0000001Z")
4688 def test_non_pure_integers(self):
4690 # b"20000102030405Z,
4697 b"20000102030405.+6Z",
4698 b"20000102030405.-6Z",
4705 b"20000102030405._6Z",
4706 b"20000102030405.6_Z",
4713 b"20000102030405. 6Z",
4720 b"20000102030405.6 Z",
4722 with self.assertRaises(DecodeError):
4723 GeneralizedTime(data)
4725 def test_aware(self):
4726 with self.assertRaisesRegex(ValueError, "only naive"):
4727 GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
4730 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4731 base_klass = UTCTime
4733 min_datetime = datetime(2000, 1, 1)
4734 max_datetime = datetime(2049, 12, 31)
4735 evgen_mode_skip_value = False
4737 def additional_symmetric_check(self, value, obj_encoded):
4740 def test_repr_not_ready(self):
4741 str(GeneralizedTime())
4744 def test_x690_vector_valid(self):
4752 def test_x690_vector_invalid(self):
4757 with self.assertRaises(DecodeError) as err:
4761 def test_go_vectors_invalid(self):
4787 # These ones are INVALID in *DER*, but accepted
4788 # by Go's encoding/asn1
4789 b"910506164540-0700",
4790 b"910506164540+0730",
4794 with self.assertRaises(DecodeError) as err:
4798 def test_go_vectors_valid(self):
4800 UTCTime(b"910506234540Z").todatetime(),
4801 datetime(1991, 5, 6, 23, 45, 40, 0),
4804 def test_non_pure_integers(self):
4833 with self.assertRaises(DecodeError):
4836 def test_x680_vector_valid_ber(self):
4838 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4839 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4840 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4841 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4843 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4844 obj = UTCTime().decod(data_der, ctx={"bered": True})
4845 self.assertEqual(obj, dt)
4846 self.assertEqual(obj.todatetime(), dt)
4847 self.assertTrue(obj.ber_encoded)
4848 self.assertTrue(obj.bered)
4849 self.assertEqual(obj.ber_raw, data)
4850 self.assertNotEqual(obj.encode(), data_der)
4853 def test_go_vectors_valid_ber(self):
4855 b"910506164540-0700",
4856 b"910506164540+0730",
4860 data = UTCTime.tag_default + len_encode(len(data)) + data
4861 obj = UTCTime().decod(data, ctx={"bered": True})
4862 self.assertTrue(obj.ber_encoded)
4863 self.assertTrue(obj.bered)
4864 self.assertNotEqual(obj.encode(), data)
4867 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4868 @given(data_strategy())
4869 def test_valid_ber(self, d):
4870 year = d.draw(integers(min_value=0, max_value=99))
4871 month = d.draw(integers(min_value=1, max_value=12))
4872 day = d.draw(integers(min_value=1, max_value=28))
4873 hours = d.draw(integers(min_value=0, max_value=23))
4874 minute = d.draw(integers(min_value=0, max_value=59))
4875 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4877 year + (2000 if year < 50 else 1900),
4884 if d.draw(booleans()):
4886 seconds = d.draw(integers(min_value=0, max_value=59))
4887 data += "%02d" % seconds
4888 dt += timedelta(seconds=seconds)
4889 if d.draw(booleans()):
4893 offset_hour = d.draw(integers(min_value=0, max_value=13))
4894 offset_minute = d.draw(integers(min_value=0, max_value=59))
4895 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4896 if d.draw(booleans()):
4902 data += "%02d%02d" % (offset_hour, offset_minute)
4903 data = data.encode("ascii")
4904 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4905 obj = UTCTime().decod(data_der, ctx={"bered": True})
4906 self.assertEqual(obj, dt)
4907 self.assertEqual(obj.todatetime(), dt)
4908 self.assertEqual(obj.ber_encoded, not dered)
4909 self.assertEqual(obj.bered, not dered)
4910 self.assertEqual(obj.ber_raw, None if dered else data)
4911 self.assertEqual(obj.encode() == data_der, dered)
4916 def test_invalid_ber(self):
4957 b"0001020304+0000Z",
4966 with self.assertRaises(DecodeError):
4967 UTCTime(data, ctx={"bered": True})
4968 data = data[:8] + data[8+2:]
4969 with self.assertRaises(DecodeError):
4970 UTCTime(data, ctx={"bered": True})
5015 b"000102030405+000",
5016 b"000102030405+000Z",
5017 b"000102030405+0000Z",
5018 b"000102030405+-101",
5019 b"000102030405+01-1",
5020 b"000102030405+0060",
5021 b"000102030405+1401",
5022 b"500101000002+0003",
5024 with self.assertRaises(DecodeError):
5025 UTCTime(data, ctx={"bered": True})
5027 @given(integers(min_value=0, max_value=49))
5028 def test_pre50(self, year):
5030 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5034 @given(integers(min_value=50, max_value=99))
5035 def test_post50(self, year):
5037 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
5043 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5044 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5046 binary(min_size=1, max_size=1),
5048 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5049 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
5052 def test_junk(self, part0, part1, part2):
5053 junk = part0 + part1 + part2
5054 assume(not (set(junk) <= set(digits.encode("ascii"))))
5055 with self.assertRaises(DecodeError):
5057 UTCTime.tag_default +
5058 len_encode(len(junk)) +
5062 def test_aware(self):
5063 with self.assertRaisesRegex(ValueError, "only naive"):
5064 UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
5066 def test_raises_if_no_dateutil(self):
5067 with patch("pyderasn.tzUTC", new="missing"):
5068 with self.assertRaisesRegex(NotImplementedError, "dateutil"):
5069 UTCTime(datetime.now()).totzdatetime()
5071 def test_tzinfo_gives_datetime_with_tzutc_tzinfo(self):
5072 self.assertEqual(UTCTime(datetime.now()).totzdatetime().tzinfo, UTC)
5076 def tlv_value_strategy(draw):
5077 tag_num = draw(integers(min_value=1))
5078 data = draw(binary())
5079 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
5083 def any_values_strategy(draw, do_expl=False):
5084 value = draw(one_of(none(), tlv_value_strategy()))
5087 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5088 optional = draw(one_of(none(), booleans()))
5090 draw(integers(min_value=0)),
5091 draw(integers(min_value=0)),
5092 draw(integers(min_value=0)),
5094 return (value, expl, optional, _decoded)
5097 class AnyInherited(Any):
5101 class TestAny(CommonMixin, TestCase):
5104 def test_invalid_value_type(self):
5105 with self.assertRaises(InvalidValueType) as err:
5110 def test_optional(self, optional):
5111 obj = Any(optional=optional)
5112 self.assertEqual(obj.optional, optional)
5114 @given(tlv_value_strategy())
5115 def test_ready(self, value):
5117 self.assertFalse(obj.ready)
5120 pprint(obj, big_blobs=True, with_decode_path=True)
5121 with self.assertRaises(ObjNotReady) as err:
5124 with self.assertRaises(ObjNotReady) as err:
5127 self.assertTrue(obj.ready)
5130 pprint(obj, big_blobs=True, with_decode_path=True)
5133 def test_basic(self, value):
5134 integer_encoded = Integer(value).encode()
5136 Any(integer_encoded),
5137 Any(Integer(value)),
5138 Any(Any(Integer(value))),
5140 self.assertSequenceEqual(bytes(obj), integer_encoded)
5142 obj.decode(obj.encode())[0].vlen,
5143 len(integer_encoded),
5147 pprint(obj, big_blobs=True, with_decode_path=True)
5148 self.assertSequenceEqual(obj.encode(), integer_encoded)
5150 @given(tlv_value_strategy(), tlv_value_strategy())
5151 def test_comparison(self, value1, value2):
5152 for klass in (Any, AnyInherited):
5153 obj1 = klass(value1)
5154 obj2 = klass(value2)
5155 self.assertEqual(obj1 == obj2, value1 == value2)
5156 self.assertEqual(obj1 != obj2, value1 != value2)
5157 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5159 @given(data_strategy())
5160 def test_call(self, d):
5161 for klass in (Any, AnyInherited):
5167 ) = d.draw(any_values_strategy())
5168 obj_initial = klass(
5171 optional_initial or False,
5179 ) = d.draw(any_values_strategy(do_expl=True))
5180 obj = obj_initial(value, expl, optional)
5182 value_expected = None if value is None else value
5183 self.assertEqual(obj, value_expected)
5184 self.assertEqual(obj.expl_tag, expl or expl_initial)
5185 if obj.default is None:
5186 optional = optional_initial if optional is None else optional
5187 optional = False if optional is None else optional
5188 self.assertEqual(obj.optional, optional)
5190 def test_simultaneous_impl_expl(self):
5191 # override it, as Any does not have implicit tag
5194 def test_decoded(self):
5195 # override it, as Any does not have implicit tag
5198 @given(any_values_strategy())
5199 def test_copy(self, values):
5200 for klass in (Any, AnyInherited):
5201 obj = klass(*values)
5202 for copy_func in copy_funcs:
5203 obj_copied = copy_func(obj)
5204 self.assert_copied_basic_fields(obj, obj_copied)
5205 self.assertEqual(obj._value, obj_copied._value)
5207 @given(binary().map(OctetString))
5208 def test_stripped(self, value):
5210 with self.assertRaises(NotEnoughData):
5211 obj.decode(obj.encode()[:-1])
5214 tlv_value_strategy(),
5215 integers(min_value=1).map(tag_ctxc),
5217 def test_stripped_expl(self, value, tag_expl):
5218 obj = Any(value, expl=tag_expl)
5219 with self.assertRaises(NotEnoughData):
5220 obj.decode(obj.encode()[:-1])
5223 integers(min_value=31),
5224 integers(min_value=0),
5227 def test_bad_tag(self, tag, offset, decode_path):
5228 with self.assertRaises(DecodeError) as err:
5230 tag_encode(tag)[:-1],
5232 decode_path=decode_path,
5235 self.assertEqual(err.exception.offset, offset)
5236 self.assertEqual(err.exception.decode_path, decode_path)
5239 integers(min_value=128),
5240 integers(min_value=0),
5243 def test_bad_len(self, l, offset, decode_path):
5244 with self.assertRaises(DecodeError) as err:
5246 Any.tag_default + len_encode(l)[:-1],
5248 decode_path=decode_path,
5251 self.assertEqual(err.exception.offset, offset)
5252 self.assertEqual(err.exception.decode_path, decode_path)
5254 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5256 any_values_strategy(),
5257 integers().map(lambda x: Integer(x).encode()),
5258 integers(min_value=1).map(tag_ctxc),
5259 integers(min_value=0),
5263 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5264 for klass in (Any, AnyInherited):
5265 _, _, optional, _decoded = values
5266 obj = klass(value=value, optional=optional, _decoded=_decoded)
5269 pprint(obj, big_blobs=True, with_decode_path=True)
5270 self.assertFalse(obj.expled)
5271 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5272 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5273 obj_encoded = obj.encode()
5274 self.assertEqual(encode2pass(obj), obj_encoded)
5275 obj_expled = obj(value, expl=tag_expl)
5276 self.assertTrue(obj_expled.expled)
5277 tag_class, _, tag_num = tag_decode(tag_expl)
5278 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5280 list(obj_expled.pps())
5281 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5282 obj_expled_encoded = obj_expled.encode()
5283 ctx_copied = deepcopy(ctx_dummy)
5284 obj_decoded, tail = obj_expled.decode(
5285 obj_expled_encoded + tail_junk,
5289 self.assertDictEqual(ctx_copied, ctx_dummy)
5291 list(obj_decoded.pps())
5292 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5293 self.assertEqual(tail, tail_junk)
5294 self.assertEqual(obj_decoded, obj_expled)
5295 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5296 self.assertEqual(bytes(obj_decoded), bytes(obj))
5297 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5298 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5299 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5301 obj_decoded.expl_llen,
5302 len(len_encode(len(obj_encoded))),
5304 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5305 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5308 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5310 self.assertEqual(obj_decoded.expl_offset, offset)
5311 self.assertEqual(obj_decoded.tlen, 0)
5312 self.assertEqual(obj_decoded.llen, 0)
5313 self.assertEqual(obj_decoded.vlen, len(value))
5314 assert_exceeding_data(
5316 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5320 evgens = list(obj_expled.decode_evgen(
5321 obj_expled_encoded + tail_junk,
5323 decode_path=decode_path,
5326 self.assertEqual(len(evgens), 1)
5327 _decode_path, obj, tail = evgens[0]
5328 self.assertSequenceEqual(tail, tail_junk)
5329 self.assertEqual(_decode_path, decode_path)
5330 self.assertEqual(obj.expl_offset, offset)
5335 integers(min_value=1).map(tag_ctxc),
5336 integers(min_value=0, max_value=3),
5337 integers(min_value=0),
5341 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5342 chunk = Boolean(False, expl=expl).encode()
5344 OctetString.tag_default +
5346 b"".join([chunk] * chunks) +
5349 with self.assertRaises(LenIndefForm):
5353 decode_path=decode_path,
5355 obj, tail = Any().decode(
5358 decode_path=decode_path,
5359 ctx={"bered": True},
5361 self.assertSequenceEqual(tail, junk)
5362 self.assertEqual(obj.offset, offset)
5363 self.assertEqual(obj.tlvlen, len(encoded))
5364 self.assertTrue(obj.lenindef)
5365 self.assertFalse(obj.ber_encoded)
5366 self.assertTrue(obj.bered)
5368 self.assertTrue(obj.lenindef)
5369 self.assertFalse(obj.ber_encoded)
5370 self.assertTrue(obj.bered)
5373 pprint(obj, big_blobs=True, with_decode_path=True)
5374 with self.assertRaises(NotEnoughData) as err:
5378 decode_path=decode_path,
5379 ctx={"bered": True},
5381 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5382 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5384 class SeqOf(SequenceOf):
5385 schema = Boolean(expl=expl)
5387 class Seq(Sequence):
5389 ("type", ObjectIdentifier(defines=((("value",), {
5390 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5395 ("type", ObjectIdentifier("1.2.3")),
5396 ("value", Any(encoded)),
5398 seq_encoded = seq.encode()
5399 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5400 self.assertIsNotNone(seq_decoded["value"].defined)
5402 list(seq_decoded.pps())
5403 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5404 self.assertTrue(seq_decoded.bered)
5405 self.assertFalse(seq_decoded["type"].bered)
5406 self.assertTrue(seq_decoded["value"].bered)
5408 chunk = chunk[:-1] + b"\x01"
5409 chunks = b"".join([chunk] * (chunks + 1))
5410 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5412 ("type", ObjectIdentifier("1.2.3")),
5413 ("value", Any(encoded)),
5415 seq_encoded = seq.encode()
5416 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5417 self.assertIsNotNone(seq_decoded["value"].defined)
5419 list(seq_decoded.pps())
5420 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5421 self.assertTrue(seq_decoded.bered)
5422 self.assertFalse(seq_decoded["type"].bered)
5423 self.assertTrue(seq_decoded["value"].bered)
5427 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5429 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5430 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5432 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5433 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5435 min_size=len(names),
5436 max_size=len(names),
5439 (name, Integer(**tag_kwargs))
5440 for name, tag_kwargs in zip(names, tags)
5443 if value_required or draw(booleans()):
5444 value = draw(tuples(
5445 sampled_from([name for name, _ in schema]),
5446 integers().map(Integer),
5450 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5451 default = draw(one_of(
5453 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5455 optional = draw(one_of(none(), booleans()))
5457 draw(integers(min_value=0)),
5458 draw(integers(min_value=0)),
5459 draw(integers(min_value=0)),
5461 return (schema, value, expl, default, optional, _decoded)
5464 class ChoiceInherited(Choice):
5468 class TestChoice(CommonMixin, TestCase):
5470 schema = (("whatever", Boolean()),)
5473 def test_schema_required(self):
5474 with self.assertRaisesRegex(ValueError, "schema must be specified"):
5477 def test_impl_forbidden(self):
5478 with self.assertRaisesRegex(ValueError, "no implicit tag allowed"):
5479 Choice(impl=b"whatever")
5481 def test_invalid_value_type(self):
5482 with self.assertRaises(InvalidValueType) as err:
5483 self.base_klass(123)
5485 with self.assertRaises(ObjUnknown) as err:
5486 self.base_klass(("whenever", Boolean(False)))
5488 with self.assertRaises(InvalidValueType) as err:
5489 self.base_klass(("whatever", Integer(123)))
5493 def test_optional(self, optional):
5494 obj = self.base_klass(
5495 default=self.base_klass(("whatever", Boolean(False))),
5498 self.assertTrue(obj.optional)
5501 def test_ready(self, value):
5502 obj = self.base_klass()
5503 self.assertFalse(obj.ready)
5506 pprint(obj, big_blobs=True, with_decode_path=True)
5507 self.assertIsNone(obj["whatever"])
5508 with self.assertRaises(ObjNotReady) as err:
5511 with self.assertRaises(ObjNotReady) as err:
5513 obj["whatever"] = Boolean()
5514 self.assertFalse(obj.ready)
5517 pprint(obj, big_blobs=True, with_decode_path=True)
5518 obj["whatever"] = Boolean(value)
5519 self.assertTrue(obj.ready)
5522 pprint(obj, big_blobs=True, with_decode_path=True)
5524 @given(booleans(), booleans())
5525 def test_comparison(self, value1, value2):
5526 class WahlInherited(self.base_klass):
5528 for klass in (self.base_klass, WahlInherited):
5529 obj1 = klass(("whatever", Boolean(value1)))
5530 obj2 = klass(("whatever", Boolean(value2)))
5531 self.assertEqual(obj1 == obj2, value1 == value2)
5532 self.assertEqual(obj1 != obj2, value1 != value2)
5533 self.assertEqual(obj1 == obj2._value, value1 == value2)
5534 self.assertFalse(obj1 == obj2._value[1])
5536 @given(data_strategy())
5537 def test_call(self, d):
5538 for klass in (Choice, ChoiceInherited):
5546 ) = d.draw(choice_values_strategy())
5549 schema = schema_initial
5551 value=value_initial,
5553 default=default_initial,
5554 optional=optional_initial or False,
5555 _decoded=_decoded_initial,
5564 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5565 obj = obj_initial(value, expl, default, optional)
5567 value_expected = default if value is None else value
5569 default_initial if value_expected is None
5572 self.assertEqual(obj.choice, value_expected[0])
5573 self.assertEqual(obj.value, int(value_expected[1]))
5574 self.assertEqual(obj.expl_tag, expl or expl_initial)
5575 default_expect = default_initial if default is None else default
5576 if default_expect is not None:
5577 self.assertEqual(obj.default.choice, default_expect[0])
5578 self.assertEqual(obj.default.value, int(default_expect[1]))
5579 if obj.default is None:
5580 optional = optional_initial if optional is None else optional
5581 optional = False if optional is None else optional
5584 self.assertEqual(obj.optional, optional)
5585 self.assertEqual(obj.specs, obj_initial.specs)
5587 def test_simultaneous_impl_expl(self):
5588 # override it, as Any does not have implicit tag
5591 def test_decoded(self):
5592 # override it, as Any does not have implicit tag
5595 @given(choice_values_strategy())
5596 def test_copy(self, values):
5597 _schema, value, expl, default, optional, _decoded = values
5599 class Wahl(self.base_klass):
5601 register_class(Wahl)
5606 optional=optional or False,
5609 for copy_func in copy_funcs:
5610 obj_copied = copy_func(obj)
5611 self.assertIsNone(obj.tag)
5612 self.assertIsNone(obj_copied.tag)
5613 # hack for assert_copied_basic_fields
5614 obj.tag = "whatever"
5615 obj_copied.tag = "whatever"
5616 self.assert_copied_basic_fields(obj, obj_copied)
5618 self.assertEqual(obj._value, obj_copied._value)
5619 self.assertEqual(obj.specs, obj_copied.specs)
5622 def test_stripped(self, value):
5623 obj = self.base_klass(("whatever", Boolean(value)))
5624 with self.assertRaises(NotEnoughData):
5625 obj.decode(obj.encode()[:-1])
5629 integers(min_value=1).map(tag_ctxc),
5631 def test_stripped_expl(self, value, tag_expl):
5632 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5633 with self.assertRaises(NotEnoughData):
5634 obj.decode(obj.encode()[:-1])
5636 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5637 @given(data_strategy())
5638 def test_symmetric(self, d):
5639 _schema, value, _, default, optional, _decoded = d.draw(
5640 choice_values_strategy(value_required=True)
5642 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5643 offset = d.draw(integers(min_value=0))
5644 tail_junk = d.draw(binary(max_size=5))
5645 decode_path = d.draw(decode_path_strat)
5647 class Wahl(self.base_klass):
5657 pprint(obj, big_blobs=True, with_decode_path=True)
5658 self.assertFalse(obj.expled)
5659 self.assertEqual(obj.tag_order, obj.value.tag_order)
5660 obj_encoded = obj.encode()
5661 self.assertEqual(encode2pass(obj), obj_encoded)
5662 obj_expled = obj(value, expl=tag_expl)
5663 self.assertTrue(obj_expled.expled)
5664 tag_class, _, tag_num = tag_decode(tag_expl)
5665 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5667 list(obj_expled.pps())
5668 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5669 obj_expled_encoded = obj_expled.encode()
5670 ctx_copied = deepcopy(ctx_dummy)
5671 obj_decoded, tail = obj_expled.decode(
5672 obj_expled_encoded + tail_junk,
5676 self.assertDictEqual(ctx_copied, ctx_dummy)
5678 list(obj_decoded.pps())
5679 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5680 self.assertEqual(tail, tail_junk)
5681 self.assertEqual(obj_decoded, obj_expled)
5682 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5683 self.assertEqual(obj_decoded.value, obj_expled.value)
5684 self.assertEqual(obj_decoded.choice, obj.choice)
5685 self.assertEqual(obj_decoded.value, obj.value)
5686 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5687 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5688 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5690 obj_decoded.expl_llen,
5691 len(len_encode(len(obj_encoded))),
5693 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5694 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5697 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5699 self.assertEqual(obj_decoded.expl_offset, offset)
5700 self.assertSequenceEqual(
5702 obj_decoded.value.fulloffset - offset:
5703 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5707 assert_exceeding_data(
5709 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5713 evgens = list(obj_expled.decode_evgen(
5714 obj_expled_encoded + tail_junk,
5716 decode_path=decode_path,
5719 self.assertEqual(len(evgens), 2)
5720 _decode_path, obj, tail = evgens[0]
5721 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5722 _decode_path, obj, tail = evgens[1]
5723 self.assertSequenceEqual(tail, tail_junk)
5724 self.assertEqual(_decode_path, decode_path)
5725 self.assertEqual(obj.expl_offset, offset)
5730 def test_set_get(self, value):
5733 ("erste", Boolean()),
5734 ("zweite", Integer()),
5737 with self.assertRaises(ObjUnknown) as err:
5738 obj["whatever"] = "whenever"
5739 with self.assertRaises(InvalidValueType) as err:
5740 obj["zweite"] = Boolean(False)
5741 obj["zweite"] = Integer(value)
5743 with self.assertRaises(ObjUnknown) as err:
5746 self.assertIsNone(obj["erste"])
5747 self.assertEqual(obj["zweite"], Integer(value))
5749 def test_tag_mismatch(self):
5752 ("erste", Boolean()),
5754 int_encoded = Integer(123).encode()
5755 bool_encoded = Boolean(False).encode()
5757 obj.decode(bool_encoded)
5758 with self.assertRaises(TagMismatch):
5759 obj.decode(int_encoded)
5761 def test_tag_mismatch_underlying(self):
5762 class SeqOfBoolean(SequenceOf):
5765 class SeqOfInteger(SequenceOf):
5770 ("erste", SeqOfBoolean()),
5773 int_encoded = SeqOfInteger((Integer(123),)).encode()
5774 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5776 obj.decode(bool_encoded)
5777 with self.assertRaises(TagMismatch) as err:
5778 obj.decode(int_encoded)
5779 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5783 def seq_values_strategy(draw, seq_klass, do_expl=False):
5785 if draw(booleans()):
5787 value._value = draw(dictionaries(
5790 booleans().map(Boolean),
5791 integers().map(Integer),
5795 if draw(booleans()):
5796 schema = list(draw(dictionaries(
5799 booleans().map(Boolean),
5800 integers().map(Integer),
5806 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5808 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5810 if draw(booleans()):
5811 default = seq_klass()
5812 default._value = draw(dictionaries(
5815 booleans().map(Boolean),
5816 integers().map(Integer),
5819 optional = draw(one_of(none(), booleans()))
5821 draw(integers(min_value=0)),
5822 draw(integers(min_value=0)),
5823 draw(integers(min_value=0)),
5825 return (value, schema, impl, expl, default, optional, _decoded)
5829 def sequence_strategy(draw, seq_klass):
5830 inputs = draw(lists(
5832 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5833 tuples(just(Integer), integers(), one_of(none(), integers())),
5838 integers(min_value=1),
5839 min_size=len(inputs),
5840 max_size=len(inputs),
5843 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5844 for tag, expled in zip(tags, draw(lists(
5846 min_size=len(inputs),
5847 max_size=len(inputs),
5851 for i, optional in enumerate(draw(lists(
5852 sampled_from(("required", "optional", "empty")),
5853 min_size=len(inputs),
5854 max_size=len(inputs),
5856 if optional in ("optional", "empty"):
5857 inits[i]["optional"] = True
5858 if optional == "empty":
5860 empties = set(empties)
5861 names = list(draw(sets(
5863 min_size=len(inputs),
5864 max_size=len(inputs),
5867 for i, (klass, value, default) in enumerate(inputs):
5868 schema.append((names[i], klass(default=default, **inits[i])))
5869 seq_name = draw(text_letters())
5870 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5873 for i, (klass, value, default) in enumerate(inputs):
5880 "default_value": None if spec.default is None else default,
5884 expect["optional"] = True
5886 expect["presented"] = True
5887 expect["value"] = value
5889 expect["optional"] = True
5890 if default is not None and default == value:
5891 expect["presented"] = False
5892 seq[name] = klass(value)
5893 expects.append(expect)
5898 def sequences_strategy(draw, seq_klass):
5899 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5901 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5902 for tag, expled in zip(tags, draw(lists(
5909 i for i, is_default in enumerate(draw(lists(
5915 names = list(draw(sets(
5920 seq_expectses = draw(lists(
5921 sequence_strategy(seq_klass=seq_klass),
5925 seqs = [seq for seq, _ in seq_expectses]
5927 for i, (name, seq) in enumerate(zip(names, seqs)):
5930 seq(default=(seq if i in defaulted else None), **inits[i]),
5932 seq_name = draw(text_letters())
5933 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5936 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5939 "expects": expects_inner,
5942 seq_outer[name] = seq_inner
5943 if seq_outer.specs[name].default is None:
5944 expect["presented"] = True
5945 expect_outers.append(expect)
5946 return seq_outer, expect_outers
5949 class SeqMixin(object):
5950 def test_invalid_value_type(self):
5951 with self.assertRaises(InvalidValueType) as err:
5952 self.base_klass(123)
5955 def test_invalid_value_type_set(self):
5956 class Seq(self.base_klass):
5957 schema = (("whatever", Boolean()),)
5959 with self.assertRaises(InvalidValueType) as err:
5960 seq["whatever"] = Integer(123)
5964 def test_optional(self, optional):
5965 obj = self.base_klass(default=self.base_klass(), optional=optional)
5966 self.assertTrue(obj.optional)
5968 @given(data_strategy())
5969 def test_ready(self, d):
5971 str(i): v for i, v in enumerate(d.draw(lists(
5978 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5985 for name in d.draw(permutations(
5986 list(ready.keys()) + list(non_ready.keys()),
5988 schema_input.append((name, Boolean()))
5990 class Seq(self.base_klass):
5991 schema = tuple(schema_input)
5993 for name in ready.keys():
5995 seq[name] = Boolean()
5996 self.assertFalse(seq.ready)
5999 pprint(seq, big_blobs=True, with_decode_path=True)
6000 for name, value in ready.items():
6001 seq[name] = Boolean(value)
6002 self.assertFalse(seq.ready)
6005 pprint(seq, big_blobs=True, with_decode_path=True)
6006 with self.assertRaises(ObjNotReady) as err:
6009 with self.assertRaises(ObjNotReady) as err:
6011 for name, value in non_ready.items():
6012 seq[name] = Boolean(value)
6013 self.assertTrue(seq.ready)
6016 pprint(seq, big_blobs=True, with_decode_path=True)
6018 @given(data_strategy())
6019 def test_call(self, d):
6020 class SeqInherited(self.base_klass):
6022 for klass in (self.base_klass, SeqInherited):
6031 ) = d.draw(seq_values_strategy(seq_klass=klass))
6032 obj_initial = klass(
6038 optional_initial or False,
6049 ) = d.draw(seq_values_strategy(
6051 do_expl=impl_initial is None,
6053 obj = obj_initial(value, impl, expl, default, optional)
6054 value_expected = default if value is None else value
6056 default_initial if value_expected is None
6059 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
6060 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6061 self.assertEqual(obj.expl_tag, expl or expl_initial)
6063 {} if obj.default is None else obj.default._value,
6064 getattr(default_initial if default is None else default, "_value", {}),
6066 if obj.default is None:
6067 optional = optional_initial if optional is None else optional
6068 optional = False if optional is None else optional
6071 self.assertEqual(list(obj.specs.items()), schema_initial or [])
6072 self.assertEqual(obj.optional, optional)
6074 @given(data_strategy())
6075 def test_copy(self, d):
6076 class SeqInherited(self.base_klass):
6078 register_class(SeqInherited)
6079 for klass in (self.base_klass, SeqInherited):
6080 values = d.draw(seq_values_strategy(seq_klass=klass))
6081 obj = klass(*values)
6082 for copy_func in copy_funcs:
6083 obj_copied = copy_func(obj)
6084 self.assert_copied_basic_fields(obj, obj_copied)
6085 self.assertEqual(obj.specs, obj_copied.specs)
6086 self.assertEqual(obj._value, obj_copied._value)
6088 @given(data_strategy())
6089 def test_stripped(self, d):
6090 value = d.draw(integers())
6091 tag_impl = tag_encode(d.draw(integers(min_value=1)))
6093 class Seq(self.base_klass):
6095 schema = (("whatever", Integer()),)
6097 seq["whatever"] = Integer(value)
6098 with self.assertRaises(NotEnoughData):
6099 seq.decode(seq.encode()[:-1])
6101 @given(data_strategy())
6102 def test_stripped_expl(self, d):
6103 value = d.draw(integers())
6104 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
6106 class Seq(self.base_klass):
6108 schema = (("whatever", Integer()),)
6110 seq["whatever"] = Integer(value)
6111 with self.assertRaises(NotEnoughData):
6112 seq.decode(seq.encode()[:-1])
6114 @given(integers(min_value=3), binary(min_size=2))
6115 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
6116 junk = tag_encode(junk_tag_num) + junk
6118 _, _, len_encoded = tag_strip(memoryview(junk))
6119 len_decode(len_encoded)
6125 class Seq(self.base_klass):
6127 ("whatever", Integer()),
6129 ("whenever", Integer()),
6132 seq["whatever"] = Integer(123)
6133 seq["junk"] = Any(junk)
6134 seq["whenever"] = Integer(123)
6135 with self.assertRaises(DecodeError):
6136 seq.decode(seq.encode())
6139 integers(min_value=31),
6140 integers(min_value=0),
6143 def test_bad_tag(self, tag, offset, decode_path):
6144 with self.assertRaises(DecodeError) as err:
6145 self.base_klass().decode(
6146 tag_encode(tag)[:-1],
6148 decode_path=decode_path,
6151 self.assertEqual(err.exception.offset, offset)
6152 self.assertEqual(err.exception.decode_path, decode_path)
6155 integers(min_value=128),
6156 integers(min_value=0),
6159 def test_bad_len(self, l, offset, decode_path):
6160 with self.assertRaises(DecodeError) as err:
6161 self.base_klass().decode(
6162 self.base_klass.tag_default + len_encode(l)[:-1],
6164 decode_path=decode_path,
6167 self.assertEqual(err.exception.offset, offset)
6168 self.assertEqual(err.exception.decode_path, decode_path)
6170 def _assert_expects(self, seq, expects):
6171 for expect in expects:
6173 seq.specs[expect["name"]].optional,
6176 if expect["default_value"] is not None:
6178 seq.specs[expect["name"]].default,
6179 expect["default_value"],
6181 if expect["presented"]:
6182 self.assertIn(expect["name"], seq)
6183 self.assertEqual(seq[expect["name"]], expect["value"])
6185 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6186 @given(data_strategy())
6187 def test_symmetric(self, d):
6188 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6189 tail_junk = d.draw(binary(max_size=5))
6190 decode_path = d.draw(decode_path_strat)
6191 self.assertTrue(seq.ready)
6192 self.assertFalse(seq.decoded)
6193 self._assert_expects(seq, expects)
6196 pprint(seq, big_blobs=True, with_decode_path=True)
6197 self.assertTrue(seq.ready)
6198 seq_encoded = seq.encode()
6199 self.assertEqual(encode2pass(seq), seq_encoded)
6200 seq_encoded_cer = encode_cer(seq)
6201 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6202 self.assertSequenceEqual(
6203 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6206 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6207 self.assertFalse(seq_decoded.lenindef)
6208 self.assertFalse(seq_decoded.ber_encoded)
6209 self.assertFalse(seq_decoded.bered)
6211 t, _, lv = tag_strip(seq_encoded)
6212 _, _, v = len_decode(lv)
6213 seq_encoded_lenindef = t + LENINDEF + v + EOC
6214 with self.assertRaises(DecodeError):
6215 seq.decode(seq_encoded_lenindef)
6216 ctx_copied = deepcopy(ctx_dummy)
6217 ctx_copied["bered"] = True
6218 seq_decoded_lenindef, tail_lenindef = seq.decode(
6219 seq_encoded_lenindef + tail_junk,
6222 del ctx_copied["bered"]
6223 self.assertDictEqual(ctx_copied, ctx_dummy)
6224 self.assertTrue(seq_decoded_lenindef.lenindef)
6225 self.assertTrue(seq_decoded_lenindef.bered)
6226 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6227 self.assertTrue(seq_decoded_lenindef.lenindef)
6228 self.assertTrue(seq_decoded_lenindef.bered)
6229 with self.assertRaises(DecodeError):
6230 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6231 with self.assertRaises(DecodeError):
6232 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6233 repr(seq_decoded_lenindef)
6234 list(seq_decoded_lenindef.pps())
6235 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6236 self.assertTrue(seq_decoded_lenindef.ready)
6238 for decoded, decoded_tail, encoded in (
6239 (seq_decoded, tail, seq_encoded),
6240 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6242 self.assertEqual(decoded_tail, tail_junk)
6243 self._assert_expects(decoded, expects)
6244 self.assertEqual(seq, decoded)
6245 self.assertEqual(decoded.encode(), seq_encoded)
6246 self.assertEqual(decoded.tlvlen, len(encoded))
6247 for expect in expects:
6248 if not expect["presented"]:
6249 self.assertNotIn(expect["name"], decoded)
6251 self.assertIn(expect["name"], decoded)
6252 obj = decoded[expect["name"]]
6253 self.assertTrue(obj.decoded)
6254 offset = obj.expl_offset if obj.expled else obj.offset
6255 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6256 self.assertSequenceEqual(
6257 seq_encoded[offset:offset + tlvlen],
6261 evgens = list(seq.decode_evgen(
6262 encoded + decoded_tail,
6263 decode_path=decode_path,
6264 ctx={"bered": True},
6266 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6267 for _decode_path, obj, _ in evgens[:-1]:
6268 self.assertEqual(_decode_path[:-1], decode_path)
6271 _decode_path, obj, tail = evgens[-1]
6272 self.assertEqual(_decode_path, decode_path)
6276 assert_exceeding_data(
6278 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6282 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6283 @given(data_strategy())
6284 def test_symmetric_with_seq(self, d):
6285 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6286 self.assertTrue(seq.ready)
6287 seq_encoded = seq.encode()
6288 self.assertEqual(encode2pass(seq), seq_encoded)
6289 seq_decoded, tail = seq.decode(seq_encoded)
6290 self.assertEqual(tail, b"")
6291 self.assertTrue(seq.ready)
6292 self.assertEqual(seq, seq_decoded)
6293 self.assertEqual(seq_decoded.encode(), seq_encoded)
6294 for expect_outer in expect_outers:
6295 if not expect_outer["presented"]:
6296 self.assertNotIn(expect_outer["name"], seq_decoded)
6298 self.assertIn(expect_outer["name"], seq_decoded)
6299 obj = seq_decoded[expect_outer["name"]]
6300 self.assertTrue(obj.decoded)
6301 offset = obj.expl_offset if obj.expled else obj.offset
6302 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6303 self.assertSequenceEqual(
6304 seq_encoded[offset:offset + tlvlen],
6307 self._assert_expects(obj, expect_outer["expects"])
6309 @given(data_strategy())
6310 def test_default_disappears(self, d):
6311 _schema = list(d.draw(dictionaries(
6313 sets(integers(), min_size=2, max_size=2),
6317 class Seq(self.base_klass):
6319 (n, Integer(default=d))
6320 for n, (_, d) in _schema
6323 for name, (value, _) in _schema:
6324 seq[name] = Integer(value)
6325 self.assertEqual(len(seq._value), len(_schema))
6326 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6327 self.assertGreater(len(seq.encode()), len(empty_seq))
6328 for name, (_, default) in _schema:
6329 seq[name] = Integer(default)
6330 self.assertEqual(len(seq._value), 0)
6331 self.assertSequenceEqual(seq.encode(), empty_seq)
6333 @given(data_strategy())
6334 def test_encoded_default_not_accepted(self, d):
6335 _schema = list(d.draw(dictionaries(
6340 tags = [tag_encode(tag) for tag in d.draw(sets(
6341 integers(min_value=1),
6342 min_size=len(_schema),
6343 max_size=len(_schema),
6347 schema = (("int", Integer()),)
6349 class SeqWithoutDefault(self.base_klass):
6352 for (n, _), t in zip(_schema, tags)
6354 seq_without_default = SeqWithoutDefault()
6355 for name, value in _schema:
6356 seq_without_default[name] = Wahl(("int", Integer(value)))
6357 seq_encoded = seq_without_default.encode()
6358 seq_without_default.decode(seq_encoded)
6360 len(list(seq_without_default.decode_evgen(seq_encoded))),
6361 len(_schema) * 2 + 1,
6364 class SeqWithDefault(self.base_klass):
6366 (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
6367 for (n, v), t in zip(_schema, tags)
6369 seq_with_default = SeqWithDefault()
6370 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6371 seq_with_default.decode(seq_encoded)
6372 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
6373 list(seq_with_default.decode_evgen(seq_encoded))
6374 for ctx in ({"bered": True}, {"allow_default_values": True}):
6375 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6376 self.assertTrue(seq_decoded.ber_encoded)
6377 self.assertTrue(seq_decoded.bered)
6378 seq_decoded = copy(seq_decoded)
6379 self.assertTrue(seq_decoded.ber_encoded)
6380 self.assertTrue(seq_decoded.bered)
6381 for name, value in _schema:
6382 self.assertEqual(seq_decoded[name], seq_with_default[name])
6383 self.assertEqual(seq_decoded[name].value, value)
6385 len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
6389 seq_without_default = SeqWithoutDefault()
6390 for name, value in _schema:
6391 seq_without_default[name] = Wahl(("int", Integer(value + 1)))
6392 seq_encoded = seq_without_default.encode()
6393 seq_with_default.decode(seq_encoded)
6395 len(list(seq_with_default.decode_evgen(seq_encoded))),
6399 @given(data_strategy())
6400 def test_missing_from_spec(self, d):
6401 names = list(d.draw(sets(text_letters(), min_size=2)))
6402 tags = [tag_encode(tag) for tag in d.draw(sets(
6403 integers(min_value=1),
6404 min_size=len(names),
6405 max_size=len(names),
6407 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6409 class SeqFull(self.base_klass):
6410 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6411 seq_full = SeqFull()
6412 for i, name in enumerate(names):
6413 seq_full[name] = Integer(i)
6414 seq_encoded = seq_full.encode()
6415 altered = names_tags[:-2] + names_tags[-1:]
6417 class SeqMissing(self.base_klass):
6418 schema = [(n, Integer(impl=t)) for n, t in altered]
6419 seq_missing = SeqMissing()
6420 with self.assertRaises(TagMismatch):
6421 seq_missing.decode(seq_encoded)
6422 with self.assertRaises(TagMismatch):
6423 list(seq_missing.decode_evgen(seq_encoded))
6425 def test_bered(self):
6426 class Seq(self.base_klass):
6427 schema = (("underlying", Boolean()),)
6428 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6429 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6430 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6431 self.assertFalse(decoded.ber_encoded)
6432 self.assertFalse(decoded.lenindef)
6433 self.assertTrue(decoded.bered)
6434 decoded = copy(decoded)
6435 self.assertFalse(decoded.ber_encoded)
6436 self.assertFalse(decoded.lenindef)
6437 self.assertTrue(decoded.bered)
6439 class Seq(self.base_klass):
6440 schema = (("underlying", OctetString()),)
6442 tag_encode(form=TagFormConstructed, num=4) +
6444 OctetString(b"whatever").encode() +
6447 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6448 with self.assertRaises(DecodeError):
6449 Seq().decode(encoded)
6450 with self.assertRaises(DecodeError):
6451 list(Seq().decode_evgen(encoded))
6452 list(Seq().decode_evgen(encoded, ctx={"bered": True}))
6453 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6454 self.assertFalse(decoded.ber_encoded)
6455 self.assertFalse(decoded.lenindef)
6456 self.assertTrue(decoded.bered)
6457 decoded = copy(decoded)
6458 self.assertFalse(decoded.ber_encoded)
6459 self.assertFalse(decoded.lenindef)
6460 self.assertTrue(decoded.bered)
6463 class TestSequence(SeqMixin, CommonMixin, TestCase):
6464 base_klass = Sequence
6470 def test_remaining(self, value, junk):
6471 class Seq(Sequence):
6473 ("whatever", Integer()),
6475 int_encoded = Integer(value).encode()
6477 Sequence.tag_default,
6478 len_encode(len(int_encoded + junk)),
6481 with self.assertRaisesRegex(DecodeError, "remaining"):
6482 Seq().decode(junked)
6484 @given(sets(text_letters(), min_size=2))
6485 def test_obj_unknown(self, names):
6486 missing = names.pop()
6488 class Seq(Sequence):
6489 schema = [(n, Boolean()) for n in names]
6491 with self.assertRaises(ObjUnknown) as err:
6494 with self.assertRaises(ObjUnknown) as err:
6495 seq[missing] = Boolean()
6498 def test_x690_vector(self):
6499 class Seq(Sequence):
6501 ("name", IA5String()),
6504 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6505 self.assertEqual(seq["name"], "Smith")
6506 self.assertEqual(seq["ok"], True)
6509 class TestSet(SeqMixin, CommonMixin, TestCase):
6512 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6513 @given(data_strategy())
6514 def test_sorted(self, d):
6515 class DummySeq(Sequence):
6516 schema = (("null", Null()),)
6518 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6519 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6520 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6521 tag_nums -= set([dummy_seq_tag_num])
6522 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6523 _schema.append(("seq", DummySeq()))
6526 schema = d.draw(permutations(_schema))
6528 for name, _ in _schema:
6530 seq[name] = OctetString(name.encode("ascii"))
6531 seq["seq"] = DummySeq((("null", Null()),))
6533 seq_encoded = seq.encode()
6534 seq_decoded, _ = seq.decode(seq_encoded)
6535 seq_encoded_expected = []
6536 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6537 if tag_num == dummy_seq_tag_num:
6538 seq_encoded_expected.append(seq["seq"].encode())
6540 seq_encoded_expected.append(seq[str(tag_num)].encode())
6541 self.assertSequenceEqual(
6542 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6543 b"".join(seq_encoded_expected),
6546 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6547 encoded += seq["seq"].encode()
6548 seq_encoded = b"".join((
6550 len_encode(len(encoded)),
6553 with self.assertRaisesRegex(DecodeError, "unordered SET"):
6554 seq.decode(seq_encoded)
6555 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6556 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6557 self.assertTrue(seq_decoded.ber_encoded)
6558 self.assertTrue(seq_decoded.bered)
6559 seq_decoded = copy(seq_decoded)
6560 self.assertTrue(seq_decoded.ber_encoded)
6561 self.assertTrue(seq_decoded.bered)
6563 def test_same_value_twice(self):
6566 ("bool", Boolean()),
6570 encoded = b"".join((
6571 Integer(123).encode(),
6572 Integer(234).encode(),
6573 Boolean(True).encode(),
6575 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6576 with self.assertRaises(TagMismatch):
6577 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6581 def seqof_values_strategy(draw, schema=None, do_expl=False):
6583 schema = draw(sampled_from((Boolean(), Integer())))
6584 bound_min, bound_max = sorted(draw(sets(
6585 integers(min_value=0, max_value=10),
6589 if isinstance(schema, Boolean):
6590 values_generator = booleans().map(Boolean)
6591 elif isinstance(schema, Integer):
6592 values_generator = integers().map(Integer)
6593 values_generator = lists(
6598 values = draw(one_of(none(), values_generator))
6602 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6604 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6605 default = draw(one_of(none(), values_generator))
6606 optional = draw(one_of(none(), booleans()))
6608 draw(integers(min_value=0)),
6609 draw(integers(min_value=0)),
6610 draw(integers(min_value=0)),
6615 (bound_min, bound_max),
6624 class SeqOfMixin(object):
6625 def test_invalid_value_type(self):
6626 with self.assertRaises(InvalidValueType) as err:
6627 self.base_klass(123)
6630 def test_invalid_values_type(self):
6631 class SeqOf(self.base_klass):
6633 with self.assertRaises(InvalidValueType) as err:
6634 SeqOf([Integer(123), Boolean(False), Integer(234)])
6637 def test_schema_required(self):
6638 with self.assertRaisesRegex(ValueError, "schema must be specified"):
6639 self.base_klass.__mro__[1]()
6641 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6642 def test_comparison(self, value1, value2, tag1, tag2):
6643 class SeqOf(self.base_klass):
6645 obj1 = SeqOf([Boolean(value1)])
6646 obj2 = SeqOf([Boolean(value2)])
6647 self.assertEqual(obj1 == obj2, value1 == value2)
6648 self.assertEqual(obj1 != obj2, value1 != value2)
6649 self.assertEqual(obj1 == list(obj2), value1 == value2)
6650 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6651 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6652 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6653 self.assertEqual(obj1 == obj2, tag1 == tag2)
6654 self.assertEqual(obj1 != obj2, tag1 != tag2)
6656 @given(lists(booleans()))
6657 def test_iter(self, values):
6658 class SeqOf(self.base_klass):
6660 obj = SeqOf([Boolean(value) for value in values])
6661 self.assertEqual(len(obj), len(values))
6662 for i, value in enumerate(obj):
6663 self.assertEqual(value, values[i])
6665 @given(data_strategy())
6666 def test_ready(self, d):
6667 ready = [Integer(v) for v in d.draw(lists(
6674 range(d.draw(integers(min_value=1, max_value=5)))
6677 class SeqOf(self.base_klass):
6679 values = d.draw(permutations(ready + non_ready))
6681 for value in values:
6683 self.assertFalse(seqof.ready)
6686 pprint(seqof, big_blobs=True, with_decode_path=True)
6687 with self.assertRaises(ObjNotReady) as err:
6690 with self.assertRaises(ObjNotReady) as err:
6692 for i, value in enumerate(values):
6693 self.assertEqual(seqof[i], value)
6694 if not seqof[i].ready:
6695 seqof[i] = Integer(i)
6696 self.assertTrue(seqof.ready)
6699 pprint(seqof, big_blobs=True, with_decode_path=True)
6701 def test_spec_mismatch(self):
6702 class SeqOf(self.base_klass):
6705 seqof.append(Integer(123))
6706 with self.assertRaises(ValueError):
6707 seqof.append(Boolean(False))
6708 with self.assertRaises(ValueError):
6709 seqof[0] = Boolean(False)
6711 @given(data_strategy())
6712 def test_bounds_satisfied(self, d):
6713 class SeqOf(self.base_klass):
6715 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6716 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6717 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6718 SeqOf(value=value, bounds=(bound_min, bound_max))
6720 @given(data_strategy())
6721 def test_bounds_unsatisfied(self, d):
6722 class SeqOf(self.base_klass):
6724 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6725 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6726 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6727 with self.assertRaises(BoundsError) as err:
6728 SeqOf(value=value, bounds=(bound_min, bound_max))
6730 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6731 SeqOf(bounds=(bound_min, bound_max)).decode(
6732 SeqOf(value).encode()
6735 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6736 SeqOf(bounds=(bound_min, bound_max)).decode(
6737 encode2pass(SeqOf(value))
6739 value = [Boolean(True)] * d.draw(integers(
6740 min_value=bound_max + 1,
6741 max_value=bound_max + 10,
6743 with self.assertRaises(BoundsError) as err:
6744 SeqOf(value=value, bounds=(bound_min, bound_max))
6746 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6747 SeqOf(bounds=(bound_min, bound_max)).decode(
6748 SeqOf(value).encode()
6751 with self.assertRaisesRegex(DecodeError, "bounds") as err:
6752 SeqOf(bounds=(bound_min, bound_max)).decode(
6753 encode2pass(SeqOf(value))
6756 @given(integers(min_value=1, max_value=10))
6757 def test_out_of_bounds(self, bound_max):
6758 class SeqOf(self.base_klass):
6760 bounds = (0, bound_max)
6762 for _ in range(bound_max):
6763 seqof.append(Integer(123))
6764 with self.assertRaises(BoundsError):
6765 seqof.append(Integer(123))
6767 @given(data_strategy())
6768 def test_call(self, d):
6778 ) = d.draw(seqof_values_strategy())
6780 class SeqOf(self.base_klass):
6781 schema = schema_initial
6782 obj_initial = SeqOf(
6783 value=value_initial,
6784 bounds=bounds_initial,
6787 default=default_initial,
6788 optional=optional_initial or False,
6789 _decoded=_decoded_initial,
6800 ) = d.draw(seqof_values_strategy(
6801 schema=schema_initial,
6802 do_expl=impl_initial is None,
6804 if (default is None) and (obj_initial.default is not None):
6807 (bounds is None) and
6808 (value is not None) and
6809 (bounds_initial is not None) and
6810 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6814 (bounds is None) and
6815 (default is not None) and
6816 (bounds_initial is not None) and
6817 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6829 value_expected = default if value is None else value
6831 default_initial if value_expected is None
6834 value_expected = () if value_expected is None else value_expected
6835 self.assertEqual(obj, value_expected)
6836 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6837 self.assertEqual(obj.expl_tag, expl or expl_initial)
6840 default_initial if default is None else default,
6842 if obj.default is None:
6843 optional = optional_initial if optional is None else optional
6844 optional = False if optional is None else optional
6847 self.assertEqual(obj.optional, optional)
6849 (obj._bound_min, obj._bound_max),
6850 bounds or bounds_initial or (0, float("+inf")),
6853 @given(seqof_values_strategy())
6854 def test_copy(self, values):
6855 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6857 class SeqOf(self.base_klass):
6859 register_class(SeqOf)
6866 optional=optional or False,
6869 for copy_func in copy_funcs:
6870 obj_copied = copy_func(obj)
6871 self.assert_copied_basic_fields(obj, obj_copied)
6872 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6873 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6874 self.assertEqual(obj._value, obj_copied._value)
6878 integers(min_value=1).map(tag_encode),
6880 def test_stripped(self, values, tag_impl):
6881 class SeqOf(self.base_klass):
6882 schema = OctetString()
6883 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6884 with self.assertRaises(NotEnoughData):
6885 obj.decode(obj.encode()[:-1])
6889 integers(min_value=1).map(tag_ctxc),
6891 def test_stripped_expl(self, values, tag_expl):
6892 class SeqOf(self.base_klass):
6893 schema = OctetString()
6894 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6895 with self.assertRaises(NotEnoughData):
6896 obj.decode(obj.encode()[:-1])
6899 integers(min_value=31),
6900 integers(min_value=0),
6903 def test_bad_tag(self, tag, offset, decode_path):
6904 with self.assertRaises(DecodeError) as err:
6905 self.base_klass().decode(
6906 tag_encode(tag)[:-1],
6908 decode_path=decode_path,
6911 self.assertEqual(err.exception.offset, offset)
6912 self.assertEqual(err.exception.decode_path, decode_path)
6915 integers(min_value=128),
6916 integers(min_value=0),
6919 def test_bad_len(self, l, offset, decode_path):
6920 with self.assertRaises(DecodeError) as err:
6921 self.base_klass().decode(
6922 self.base_klass.tag_default + len_encode(l)[:-1],
6924 decode_path=decode_path,
6927 self.assertEqual(err.exception.offset, offset)
6928 self.assertEqual(err.exception.decode_path, decode_path)
6930 @given(binary(min_size=1))
6931 def test_tag_mismatch(self, impl):
6932 assume(impl != self.base_klass.tag_default)
6933 with self.assertRaises(TagMismatch):
6934 self.base_klass(impl=impl).decode(self.base_klass().encode())
6936 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6938 seqof_values_strategy(schema=Integer()),
6939 lists(integers().map(Integer)),
6940 integers(min_value=1).map(tag_ctxc),
6941 integers(min_value=0),
6945 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6946 _, _, _, _, _, default, optional, _decoded = values
6948 class SeqOf(self.base_klass):
6958 pprint(obj, big_blobs=True, with_decode_path=True)
6959 self.assertFalse(obj.expled)
6960 obj_encoded = obj.encode()
6961 self.assertEqual(encode2pass(obj), obj_encoded)
6962 obj_encoded_cer = encode_cer(obj)
6963 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6964 self.assertSequenceEqual(
6965 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6968 obj_expled = obj(value, expl=tag_expl)
6969 self.assertTrue(obj_expled.expled)
6971 list(obj_expled.pps())
6972 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6973 obj_expled_encoded = obj_expled.encode()
6974 ctx_copied = deepcopy(ctx_dummy)
6975 obj_decoded, tail = obj_expled.decode(
6976 obj_expled_encoded + tail_junk,
6980 self.assertDictEqual(ctx_copied, ctx_dummy)
6982 list(obj_decoded.pps())
6983 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6984 self.assertEqual(tail, tail_junk)
6985 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6986 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6987 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6988 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6990 obj_decoded.expl_llen,
6991 len(len_encode(len(obj_encoded))),
6993 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6994 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6997 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6999 self.assertEqual(obj_decoded.expl_offset, offset)
7000 for obj_inner in obj_decoded:
7001 self.assertIn(obj_inner, obj_decoded)
7002 self.assertSequenceEqual(
7005 obj_inner.offset - offset:
7006 obj_inner.offset + obj_inner.tlvlen - offset
7010 t, _, lv = tag_strip(obj_encoded)
7011 _, _, v = len_decode(lv)
7012 obj_encoded_lenindef = t + LENINDEF + v + EOC
7013 with self.assertRaises(DecodeError):
7014 obj.decode(obj_encoded_lenindef)
7015 obj_decoded_lenindef, tail_lenindef = obj.decode(
7016 obj_encoded_lenindef + tail_junk,
7017 ctx={"bered": True},
7019 self.assertTrue(obj_decoded_lenindef.lenindef)
7020 self.assertTrue(obj_decoded_lenindef.bered)
7021 obj_decoded_lenindef = copy(obj_decoded_lenindef)
7022 self.assertTrue(obj_decoded_lenindef.lenindef)
7023 self.assertTrue(obj_decoded_lenindef.bered)
7024 repr(obj_decoded_lenindef)
7025 list(obj_decoded_lenindef.pps())
7026 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
7027 self.assertEqual(tail_lenindef, tail_junk)
7028 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
7029 with self.assertRaises(DecodeError):
7030 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
7031 with self.assertRaises(DecodeError):
7032 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
7034 evgens = list(obj.decode_evgen(
7035 obj_encoded_lenindef + tail_junk,
7036 decode_path=decode_path,
7037 ctx={"bered": True},
7039 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
7040 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
7041 self.assertEqual(_decode_path, decode_path + (str(i),))
7044 _decode_path, obj, tail = evgens[-1]
7045 self.assertEqual(_decode_path, decode_path)
7049 assert_exceeding_data(
7051 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
7055 def test_bered(self):
7056 class SeqOf(self.base_klass):
7058 encoded = Boolean(False).encode()
7059 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
7060 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7061 with self.assertRaises(DecodeError):
7062 SeqOf().decode(encoded)
7063 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7064 self.assertFalse(decoded.ber_encoded)
7065 self.assertFalse(decoded.lenindef)
7066 self.assertTrue(decoded.bered)
7067 decoded = copy(decoded)
7068 self.assertFalse(decoded.ber_encoded)
7069 self.assertFalse(decoded.lenindef)
7070 self.assertTrue(decoded.bered)
7072 class SeqOf(self.base_klass):
7073 schema = OctetString()
7074 encoded = OctetString(b"whatever").encode()
7076 tag_encode(form=TagFormConstructed, num=4) +
7078 OctetString(b"whatever").encode() +
7081 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
7082 with self.assertRaises(DecodeError):
7083 SeqOf().decode(encoded)
7084 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
7085 self.assertFalse(decoded.ber_encoded)
7086 self.assertFalse(decoded.lenindef)
7087 self.assertTrue(decoded.bered)
7088 decoded = copy(decoded)
7089 self.assertFalse(decoded.ber_encoded)
7090 self.assertFalse(decoded.lenindef)
7091 self.assertTrue(decoded.bered)
7094 class TestSequenceOf(SeqOfMixin, CommonMixin, TestCase):
7095 class SeqOf(SequenceOf):
7099 def _test_symmetric_compare_objs(self, obj1, obj2):
7100 self.assertEqual(obj1, obj2)
7101 self.assertSequenceEqual(list(obj1), list(obj2))
7103 def test_iterator_pickling(self):
7104 class SeqOf(SequenceOf):
7106 register_class(SeqOf)
7109 seqof = seqof(iter(range(10)))
7110 with self.assertRaisesRegex(ValueError, "iterator"):
7113 def test_iterator_bounds(self):
7114 class SeqOf(SequenceOf):
7123 seqof = SeqOf(gen(n))
7124 self.assertTrue(seqof.ready)
7125 with self.assertRaises(BoundsError):
7127 self.assertFalse(seqof.ready)
7128 seqof = seqof(gen(n))
7129 self.assertTrue(seqof.ready)
7130 with self.assertRaises(BoundsError):
7132 self.assertFalse(seqof.ready)
7134 def test_iterator_twice(self):
7135 class SeqOf(SequenceOf):
7137 bounds = (1, float("+inf"))
7142 seqof = SeqOf(gen())
7143 self.assertTrue(seqof.ready)
7145 self.assertFalse(seqof.ready)
7146 register_class(SeqOf)
7149 def test_iterator_2pass(self):
7150 class SeqOf(SequenceOf):
7152 bounds = (1, float("+inf"))
7157 seqof = SeqOf(gen())
7158 self.assertTrue(seqof.ready)
7159 _, state = seqof.encode1st()
7160 self.assertFalse(seqof.ready)
7161 seqof = seqof(gen())
7162 self.assertTrue(seqof.ready)
7164 seqof.encode2nd(buf.write, iter(state))
7165 self.assertSequenceEqual(
7166 [int(i) for i in seqof.decod(buf.getvalue())],
7170 def test_non_ready_bound_min(self):
7171 class SeqOf(SequenceOf):
7173 bounds = (1, float("+inf"))
7175 self.assertFalse(seqof.ready)
7178 class TestSetOf(SeqOfMixin, CommonMixin, TestCase):
7183 def _test_symmetric_compare_objs(self, obj1, obj2):
7184 self.assertSetEqual(
7185 set(int(v) for v in obj1),
7186 set(int(v) for v in obj2),
7189 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7190 @given(data_strategy())
7191 def test_sorted(self, d):
7192 values = [OctetString(v) for v in d.draw(lists(binary()))]
7195 schema = OctetString()
7197 seq_encoded = seq.encode()
7198 seq_decoded, _ = seq.decode(seq_encoded)
7199 self.assertSequenceEqual(
7200 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
7201 b"".join(sorted([v.encode() for v in values])),
7204 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
7205 @given(data_strategy())
7206 def test_unsorted(self, d):
7207 values = [OctetString(v).encode() for v in d.draw(sets(
7208 binary(min_size=1, max_size=5),
7212 values = d.draw(permutations(values))
7213 assume(values != sorted(values))
7214 encoded = b"".join(values)
7215 seq_encoded = b"".join((
7217 len_encode(len(encoded)),
7222 schema = OctetString()
7224 with self.assertRaisesRegex(DecodeError, "unordered SET OF"):
7225 seq.decode(seq_encoded)
7227 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
7228 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
7229 self.assertTrue(seq_decoded.ber_encoded)
7230 self.assertTrue(seq_decoded.bered)
7231 seq_decoded = copy(seq_decoded)
7232 self.assertTrue(seq_decoded.ber_encoded)
7233 self.assertTrue(seq_decoded.bered)
7234 self.assertSequenceEqual(
7235 [obj.encode() for obj in seq_decoded],
7240 class TestGoMarshalVectors(TestCase):
7242 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
7243 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
7244 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
7245 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
7246 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
7248 class Seq(Sequence):
7250 ("erste", Integer()),
7251 ("zweite", Integer(optional=True))
7254 seq["erste"] = Integer(64)
7255 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7256 seq["erste"] = Integer(0x123456)
7257 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
7258 seq["erste"] = Integer(64)
7259 seq["zweite"] = Integer(65)
7260 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
7262 class NestedSeq(Sequence):
7266 seq["erste"] = Integer(127)
7267 seq["zweite"] = None
7268 nested = NestedSeq()
7269 nested["nest"] = seq
7270 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
7272 self.assertSequenceEqual(
7273 OctetString(b"\x01\x02\x03").encode(),
7274 hexdec("0403010203"),
7277 class Seq(Sequence):
7279 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7282 seq["erste"] = Integer(64)
7283 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7285 class Seq(Sequence):
7287 ("erste", Integer(expl=tag_ctxc(5))),
7290 seq["erste"] = Integer(64)
7291 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7293 class Seq(Sequence):
7296 impl=tag_encode(0, klass=TagClassContext),
7301 seq["erste"] = Null()
7302 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7304 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7306 self.assertSequenceEqual(
7307 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7308 hexdec("170d3730303130313030303030305a"),
7310 self.assertSequenceEqual(
7311 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7312 hexdec("170d3039313131353232353631365a"),
7314 self.assertSequenceEqual(
7315 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7316 hexdec("180f32313030303430353132303130315a"),
7319 class Seq(Sequence):
7321 ("erste", GeneralizedTime()),
7324 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7325 self.assertSequenceEqual(
7327 hexdec("3011180f32303039313131353232353631365a"),
7330 self.assertSequenceEqual(
7331 BitString((1, b"\x80")).encode(),
7334 self.assertSequenceEqual(
7335 BitString((12, b"\x81\xF0")).encode(),
7336 hexdec("03030481f0"),
7339 self.assertSequenceEqual(
7340 ObjectIdentifier("1.2.3.4").encode(),
7341 hexdec("06032a0304"),
7343 self.assertSequenceEqual(
7344 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7345 hexdec("06092a864888932d010105"),
7347 self.assertSequenceEqual(
7348 ObjectIdentifier("2.100.3").encode(),
7349 hexdec("0603813403"),
7352 self.assertSequenceEqual(
7353 PrintableString("test").encode(),
7354 hexdec("130474657374"),
7356 self.assertSequenceEqual(
7357 PrintableString("x" * 127).encode(),
7358 hexdec("137F" + "78" * 127),
7360 self.assertSequenceEqual(
7361 PrintableString("x" * 128).encode(),
7362 hexdec("138180" + "78" * 128),
7364 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7366 class Seq(Sequence):
7368 ("erste", IA5String()),
7371 seq["erste"] = IA5String("test")
7372 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7374 class Seq(Sequence):
7376 ("erste", PrintableString()),
7379 seq["erste"] = PrintableString("test")
7380 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7381 # Asterisk is actually not allowable
7382 pyderasn.PRINTABLE_ALLOWABLE_CHARS |= set(b"*")
7383 seq["erste"] = PrintableString("test*")
7384 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7385 pyderasn.PRINTABLE_ALLOWABLE_CHARS -= set(b"*")
7387 class Seq(Sequence):
7389 ("erste", Any(optional=True)),
7390 ("zweite", Integer()),
7393 seq["zweite"] = Integer(64)
7394 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7399 seq.append(Integer(10))
7400 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7402 class _SeqOf(SequenceOf):
7403 schema = PrintableString()
7405 class SeqOf(SequenceOf):
7408 _seqof.append(PrintableString("1"))
7410 seqof.append(_seqof)
7411 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7413 class Seq(Sequence):
7415 ("erste", Integer(default=1)),
7418 seq["erste"] = Integer(0)
7419 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7420 seq["erste"] = Integer(1)
7421 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7422 seq["erste"] = Integer(2)
7423 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7426 class TestPP(TestCase):
7427 @given(data_strategy())
7428 def test_oid_printing(self, d):
7430 str(ObjectIdentifier(k)): v * 2
7431 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7433 chosen = d.draw(sampled_from(sorted(oids)))
7434 chosen_id = oids[chosen]
7435 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7436 self.assertNotIn(chosen_id, pp_console_row(pp))
7439 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7443 class TestAutoAddSlots(TestCase):
7445 class Inher(Integer):
7448 with self.assertRaises(AttributeError):
7450 inher.unexistent = "whatever"
7453 class TestOIDDefines(TestCase):
7454 @given(data_strategy())
7455 def runTest(self, d):
7456 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7457 value_name_chosen = d.draw(sampled_from(value_names))
7459 ObjectIdentifier(oid)
7460 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7462 oid_chosen = d.draw(sampled_from(oids))
7463 values = d.draw(lists(
7465 min_size=len(value_names),
7466 max_size=len(value_names),
7468 for definable_class in (Any, OctetString, BitString):
7470 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7471 oid: Integer() for oid in oids[:-1]
7474 for i, value_name in enumerate(value_names):
7475 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7477 class Seq(Sequence):
7480 for value_name, value in zip(value_names, values):
7481 seq[value_name] = definable_class(Integer(value).encode())
7482 seq["type"] = oid_chosen
7483 seq, _ = Seq().decode(seq.encode())
7484 for value_name in value_names:
7485 if value_name == value_name_chosen:
7487 self.assertIsNone(seq[value_name].defined)
7488 if value_name_chosen in oids[:-1]:
7489 self.assertIsNotNone(seq[value_name_chosen].defined)
7490 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7491 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7494 pprint(seq, big_blobs=True, with_decode_path=True)
7497 class TestDefinesByPath(TestCase):
7498 def test_generated(self):
7499 class Seq(Sequence):
7501 ("type", ObjectIdentifier()),
7502 ("value", OctetString(expl=tag_ctxc(123))),
7505 class SeqInner(Sequence):
7507 ("typeInner", ObjectIdentifier()),
7508 ("valueInner", Any()),
7511 class PairValue(SetOf):
7514 class Pair(Sequence):
7516 ("type", ObjectIdentifier()),
7517 ("value", PairValue()),
7520 class Pairs(SequenceOf):
7527 type_octet_stringed,
7529 ObjectIdentifier(oid)
7530 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7532 seq_integered = Seq()
7533 seq_integered["type"] = type_integered
7534 seq_integered["value"] = OctetString(Integer(123).encode())
7535 seq_integered_raw = seq_integered.encode()
7539 (type_octet_stringed, OctetString(b"whatever")),
7540 (type_integered, Integer(123)),
7541 (type_octet_stringed, OctetString(b"whenever")),
7542 (type_integered, Integer(234)),
7544 for t, v in pairs_input:
7547 ("value", PairValue((Any(v),))),
7549 seq_inner = SeqInner()
7550 seq_inner["typeInner"] = type_innered
7551 seq_inner["valueInner"] = Any(pairs)
7552 seq_sequenced = Seq()
7553 seq_sequenced["type"] = type_sequenced
7554 seq_sequenced["value"] = OctetString(seq_inner.encode())
7555 seq_sequenced_raw = seq_sequenced.encode()
7557 list(seq_sequenced.pps())
7558 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7560 defines_by_path = []
7561 ctx_copied = deepcopy(ctx_dummy)
7562 seq_integered, _ = Seq().decode(
7566 self.assertDictEqual(ctx_copied, ctx_dummy)
7567 self.assertIsNone(seq_integered["value"].defined)
7568 defines_by_path.append(
7569 (("type",), ((("value",), {
7570 type_integered: Integer(),
7571 type_sequenced: SeqInner(),
7574 ctx_copied["defines_by_path"] = defines_by_path
7575 seq_integered, _ = Seq().decode(
7579 del ctx_copied["defines_by_path"]
7580 self.assertDictEqual(ctx_copied, ctx_dummy)
7581 self.assertIsNotNone(seq_integered["value"].defined)
7582 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7583 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7584 self.assertTrue(seq_integered_raw[
7585 seq_integered["value"].defined[1].offset:
7586 ].startswith(Integer(123).encode()))
7588 list(seq_integered.pps())
7589 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7591 ctx_copied["defines_by_path"] = defines_by_path
7592 seq_sequenced, _ = Seq().decode(
7596 del ctx_copied["defines_by_path"]
7597 self.assertDictEqual(ctx_copied, ctx_dummy)
7598 self.assertIsNotNone(seq_sequenced["value"].defined)
7599 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7600 seq_inner = seq_sequenced["value"].defined[1]
7601 self.assertIsNone(seq_inner["valueInner"].defined)
7603 list(seq_sequenced.pps())
7604 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7606 defines_by_path.append((
7607 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7608 ((("valueInner",), {type_innered: Pairs()}),),
7610 ctx_copied["defines_by_path"] = defines_by_path
7611 seq_sequenced, _ = Seq().decode(
7615 del ctx_copied["defines_by_path"]
7616 self.assertDictEqual(ctx_copied, ctx_dummy)
7617 self.assertIsNotNone(seq_sequenced["value"].defined)
7618 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7619 seq_inner = seq_sequenced["value"].defined[1]
7620 self.assertIsNotNone(seq_inner["valueInner"].defined)
7621 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7622 pairs = seq_inner["valueInner"].defined[1]
7624 self.assertIsNone(pair["value"][0].defined)
7626 list(seq_sequenced.pps())
7627 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7629 defines_by_path.append((
7632 DecodePathDefBy(type_sequenced),
7634 DecodePathDefBy(type_innered),
7639 type_integered: Integer(),
7640 type_octet_stringed: OctetString(),
7643 ctx_copied["defines_by_path"] = defines_by_path
7644 seq_sequenced, _ = Seq().decode(
7648 del ctx_copied["defines_by_path"]
7649 self.assertDictEqual(ctx_copied, ctx_dummy)
7650 self.assertIsNotNone(seq_sequenced["value"].defined)
7651 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7652 seq_inner = seq_sequenced["value"].defined[1]
7653 self.assertIsNotNone(seq_inner["valueInner"].defined)
7654 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7655 pairs_got = seq_inner["valueInner"].defined[1]
7656 for pair_input, pair_got in zip(pairs_input, pairs_got):
7657 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7658 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7660 list(seq_sequenced.pps())
7661 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7663 @given(oid_strategy(), integers())
7664 def test_simple(self, oid, tgt):
7665 class Inner(Sequence):
7667 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7668 ObjectIdentifier(oid): Integer(),
7672 class Outer(Sequence):
7675 ("tgt", OctetString()),
7679 inner["oid"] = ObjectIdentifier(oid)
7681 outer["inner"] = inner
7682 outer["tgt"] = OctetString(Integer(tgt).encode())
7683 decoded, _ = Outer().decode(outer.encode())
7684 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7686 def test_remaining_data(self):
7687 oid = ObjectIdentifier("1.2.3")
7689 class Seq(Sequence):
7691 ("oid", ObjectIdentifier(defines=((("tgt",), {
7694 ("tgt", OctetString()),
7699 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7701 with self.assertRaisesRegex(DecodeError, "remaining data"):
7702 Seq().decode(seq.encode())
7704 def test_remaining_data_seqof(self):
7705 oid = ObjectIdentifier("1.2.3")
7708 schema = OctetString()
7710 class Seq(Sequence):
7712 ("oid", ObjectIdentifier(defines=((("tgt",), {
7720 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7722 with self.assertRaisesRegex(DecodeError, "remaining data"):
7723 Seq().decode(seq.encode())
7726 class TestAbsDecodePath(TestCase):
7728 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7729 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7731 def test_concat(self, decode_path, rel_path):
7732 dp = abs_decode_path(decode_path, rel_path)
7733 self.assertSequenceEqual(dp, decode_path + rel_path)
7737 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7738 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7740 def test_abs(self, decode_path, rel_path):
7741 self.assertSequenceEqual(
7742 abs_decode_path(decode_path, ("/",) + rel_path),
7747 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7748 integers(min_value=1, max_value=3),
7749 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7751 def test_dots(self, decode_path, number_of_dots, rel_path):
7752 self.assertSequenceEqual(
7753 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7754 decode_path[:-number_of_dots] + rel_path,
7758 class TestStrictDefaultExistence(TestCase):
7759 @given(data_strategy())
7760 def runTest(self, d):
7761 count = d.draw(integers(min_value=1, max_value=10))
7762 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7764 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7765 for i in range(count)
7767 for klass in (Sequence, Set):
7771 for i in range(count):
7772 seq["int%d" % i] = Integer(123)
7774 chosen_choice = "int%d" % chosen
7775 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7776 with self.assertRaisesRegex(DecodeError, "DEFAULT value met"):
7778 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7779 self.assertTrue(decoded.ber_encoded)
7780 self.assertTrue(decoded.bered)
7781 decoded = copy(decoded)
7782 self.assertTrue(decoded.ber_encoded)
7783 self.assertTrue(decoded.bered)
7784 decoded, _ = seq.decode(raw, ctx={"bered": True})
7785 self.assertTrue(decoded.ber_encoded)
7786 self.assertTrue(decoded.bered)
7787 decoded = copy(decoded)
7788 self.assertTrue(decoded.ber_encoded)
7789 self.assertTrue(decoded.bered)
7792 class TestX690PrefixedType(TestCase):
7794 self.assertSequenceEqual(
7795 VisibleString("Jones").encode(),
7796 hexdec("1A054A6F6E6573"),
7800 self.assertSequenceEqual(
7803 impl=tag_encode(3, klass=TagClassApplication),
7805 hexdec("43054A6F6E6573"),
7809 self.assertSequenceEqual(
7813 impl=tag_encode(3, klass=TagClassApplication),
7817 hexdec("A20743054A6F6E6573"),
7821 self.assertSequenceEqual(
7825 impl=tag_encode(3, klass=TagClassApplication),
7827 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7829 hexdec("670743054A6F6E6573"),
7833 self.assertSequenceEqual(
7834 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7835 hexdec("82054A6F6E6573"),
7839 class TestExplOOB(TestCase):
7841 expl = tag_ctxc(123)
7842 raw = Integer(123).encode() + Integer(234).encode()
7843 raw = b"".join((expl, len_encode(len(raw)), raw))
7844 with self.assertRaisesRegex(DecodeError, "explicit tag out-of-bound"):
7845 Integer(expl=expl).decode(raw)
7846 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7849 class TestPickleDifferentVersion(TestCase):
7851 pickled = pickle_dumps(Integer(123), pickle_proto)
7853 version_orig = pyderasn.__version__
7854 pyderasn.__version__ += "different"
7855 with self.assertRaisesRegex(ValueError, "different PyDERASN version"):
7856 pickle_loads(pickled)
7857 pyderasn.__version__ = version_orig
7858 pickle_loads(pickled)
7861 class TestCERSetOrdering(TestCase):
7862 def test_vectors(self):
7863 """Taken from X.690-201508
7867 ("c", Integer(impl=tag_ctxp(2))),
7868 ("d", Integer(impl=tag_ctxp(4))),
7873 ("g", Integer(impl=tag_ctxp(5))),
7874 ("h", Integer(impl=tag_ctxp(6))),
7879 ("j", Integer(impl=tag_ctxp(0))),
7890 ("a", Integer(impl=tag_ctxp(3))),
7891 ("b", B(expl=tag_ctxc(1))),
7896 ("a", Integer(123)),
7897 ("b", B(("d", Integer(234)))),
7898 ("e", E(("f", F(("g", Integer(345)))))),
7900 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7901 self.assertSequenceEqual(
7902 [i.__class__.__name__ for i in order],
7903 ("E", "B", "Integer"),