2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this program. If not, see
16 # <http://www.gnu.org/licenses/>.
19 from copy import deepcopy
20 from datetime import datetime
21 from datetime import timedelta
22 from importlib import import_module
23 from operator import attrgetter
24 from os import environ
25 from os import urandom
26 from random import random
27 from string import ascii_letters
28 from string import digits
29 from string import printable
30 from string import whitespace
31 from time import mktime
33 from unittest import TestCase
35 from hypothesis import assume
36 from hypothesis import given
37 from hypothesis import settings
38 from hypothesis.strategies import binary
39 from hypothesis.strategies import booleans
40 from hypothesis.strategies import composite
41 from hypothesis.strategies import data as data_strategy
42 from hypothesis.strategies import datetimes
43 from hypothesis.strategies import dictionaries
44 from hypothesis.strategies import integers
45 from hypothesis.strategies import just
46 from hypothesis.strategies import lists
47 from hypothesis.strategies import none
48 from hypothesis.strategies import one_of
49 from hypothesis.strategies import permutations
50 from hypothesis.strategies import sampled_from
51 from hypothesis.strategies import sets
52 from hypothesis.strategies import text
53 from hypothesis.strategies import tuples
54 from six import assertRaisesRegex
55 from six import binary_type
56 from six import byte2int
57 from six import indexbytes
58 from six import int2byte
59 from six import iterbytes
61 from six import text_type
62 from six import unichr as six_unichr
63 from six.moves.cPickle import dumps as pickle_dumps
64 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
65 from six.moves.cPickle import loads as pickle_loads
67 from pyderasn import _pp
68 from pyderasn import abs_decode_path
69 from pyderasn import Any
70 from pyderasn import BitString
71 from pyderasn import BMPString
72 from pyderasn import Boolean
73 from pyderasn import BoundsError
74 from pyderasn import Choice
75 from pyderasn import DecodeError
76 from pyderasn import DecodePathDefBy
77 from pyderasn import encode_cer
78 from pyderasn import Enumerated
79 from pyderasn import EOC
80 from pyderasn import EOC_LEN
81 from pyderasn import ExceedingData
82 from pyderasn import GeneralizedTime
83 from pyderasn import GeneralString
84 from pyderasn import GraphicString
85 from pyderasn import hexdec
86 from pyderasn import hexenc
87 from pyderasn import IA5String
88 from pyderasn import Integer
89 from pyderasn import InvalidLength
90 from pyderasn import InvalidOID
91 from pyderasn import InvalidValueType
92 from pyderasn import len_decode
93 from pyderasn import len_encode
94 from pyderasn import LEN_YYMMDDHHMMSSZ
95 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
96 from pyderasn import LEN_YYYYMMDDHHMMSSZ
97 from pyderasn import LENINDEF
98 from pyderasn import LenIndefForm
99 from pyderasn import NotEnoughData
100 from pyderasn import Null
101 from pyderasn import NumericString
102 from pyderasn import ObjectIdentifier
103 from pyderasn import ObjNotReady
104 from pyderasn import ObjUnknown
105 from pyderasn import OctetString
106 from pyderasn import pp_console_row
107 from pyderasn import pprint
108 from pyderasn import PrintableString
109 from pyderasn import Sequence
110 from pyderasn import SequenceOf
111 from pyderasn import Set
112 from pyderasn import SetOf
113 from pyderasn import tag_ctxc
114 from pyderasn import tag_ctxp
115 from pyderasn import tag_decode
116 from pyderasn import tag_encode
117 from pyderasn import tag_strip
118 from pyderasn import TagClassApplication
119 from pyderasn import TagClassContext
120 from pyderasn import TagClassPrivate
121 from pyderasn import TagClassUniversal
122 from pyderasn import TagFormConstructed
123 from pyderasn import TagFormPrimitive
124 from pyderasn import TagMismatch
125 from pyderasn import TeletexString
126 from pyderasn import UniversalString
127 from pyderasn import UTCTime
128 from pyderasn import UTF8String
129 from pyderasn import VideotexString
130 from pyderasn import VisibleString
133 max_examples = environ.get("MAX_EXAMPLES")
134 settings.register_profile("local", settings(
136 **({"max_examples": int(max_examples)} if max_examples else {})
138 settings.load_profile("local")
139 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
141 tag_classes = sampled_from((
147 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
148 decode_path_strat = lists(integers(), max_size=3).map(
149 lambda decode_path: tuple(str(dp) for dp in decode_path)
151 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
154 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
156 self_module = import_module(__name__)
159 def register_class(klass):
160 klassname = klass.__name__ + str(time()).replace(".", "")
161 klass.__name__ = klassname
162 klass.__qualname__ = klassname
163 setattr(self_module, klassname, klass)
166 def assert_exceeding_data(self, call, junk):
169 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
174 class TestHex(TestCase):
176 def test_symmetric(self, data):
177 self.assertEqual(hexdec(hexenc(data)), data)
180 class TestTagCoder(TestCase):
181 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
185 integers(min_value=0, max_value=30),
188 def test_short(self, klass, form, num, junk):
189 raw = tag_encode(klass=klass, form=form, num=num)
190 self.assertEqual(tag_decode(raw), (klass, form, num))
191 self.assertEqual(len(raw), 1)
193 byte2int(tag_encode(klass=klass, form=form, num=0)),
194 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
196 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
197 self.assertSequenceEqual(stripped.tobytes(), raw)
198 self.assertEqual(tlen, len(raw))
199 self.assertSequenceEqual(tail, junk)
201 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
205 integers(min_value=31),
208 def test_long(self, klass, form, num, junk):
209 raw = tag_encode(klass=klass, form=form, num=num)
210 self.assertEqual(tag_decode(raw), (klass, form, num))
211 self.assertGreater(len(raw), 1)
213 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
216 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
217 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
218 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
219 self.assertSequenceEqual(stripped.tobytes(), raw)
220 self.assertEqual(tlen, len(raw))
221 self.assertSequenceEqual(tail, junk)
223 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
224 @given(integers(min_value=31))
225 def test_unfinished_tag(self, num):
226 raw = bytearray(tag_encode(num=num))
227 for i in range(1, len(raw)):
229 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
230 tag_strip(bytes(raw))
232 def test_go_vectors_valid(self):
233 for data, (eklass, etag, elen, eform) in (
234 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
235 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
236 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
237 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
238 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
239 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
240 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
241 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
242 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
243 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
245 tag, _, len_encoded = tag_strip(memoryview(data))
246 klass, form, num = tag_decode(tag)
247 _len, _, tail = len_decode(len_encoded)
248 self.assertSequenceEqual(tail, b"")
249 self.assertEqual(klass, eklass)
250 self.assertEqual(num, etag)
251 self.assertEqual(_len, elen)
252 self.assertEqual(form, eform)
254 def test_go_vectors_invalid(self):
262 with self.assertRaises(DecodeError):
263 _, _, len_encoded = tag_strip(memoryview(data))
264 len_decode(len_encoded)
267 integers(min_value=0, max_value=127),
268 integers(min_value=0, max_value=2),
270 def test_long_instead_of_short(self, l, dummy_num):
271 octets = (b"\x00" * dummy_num) + int2byte(l)
272 octets = int2byte((dummy_num + 1) | 0x80) + octets
273 with self.assertRaises(DecodeError):
277 class TestLenCoder(TestCase):
278 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
280 integers(min_value=0, max_value=127),
283 def test_short(self, l, junk):
284 raw = len_encode(l) + junk
285 decoded, llen, tail = len_decode(memoryview(raw))
286 self.assertEqual(decoded, l)
287 self.assertEqual(llen, 1)
288 self.assertEqual(len(raw), 1 + len(junk))
289 self.assertEqual(tail.tobytes(), junk)
291 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
293 integers(min_value=128),
296 def test_long(self, l, junk):
297 raw = len_encode(l) + junk
298 decoded, llen, tail = len_decode(memoryview(raw))
299 self.assertEqual(decoded, l)
300 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
301 self.assertEqual(llen, len(raw) - len(junk))
302 self.assertNotEqual(indexbytes(raw, 1), 0)
303 self.assertSequenceEqual(tail.tobytes(), junk)
305 def test_empty(self):
306 with self.assertRaises(NotEnoughData):
309 @given(integers(min_value=128))
310 def test_stripped(self, _len):
311 with self.assertRaises(NotEnoughData):
312 len_decode(len_encode(_len)[:-1])
315 text_printable = text(alphabet=printable, min_size=1)
319 def text_letters(draw):
320 result = draw(text(alphabet=ascii_letters, min_size=1))
322 result = result.encode("ascii")
326 class CommonMixin(object):
327 def test_tag_default(self):
328 obj = self.base_klass()
329 self.assertEqual(obj.tag, obj.tag_default)
331 def test_simultaneous_impl_expl(self):
332 with self.assertRaises(ValueError):
333 self.base_klass(impl=b"whatever", expl=b"whenever")
335 @given(binary(min_size=1), integers(), integers(), integers())
336 def test_decoded(self, impl, offset, llen, vlen):
337 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
338 self.assertEqual(obj.offset, offset)
339 self.assertEqual(obj.llen, llen)
340 self.assertEqual(obj.vlen, vlen)
341 self.assertEqual(obj.tlen, len(impl))
342 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
344 @given(binary(min_size=1))
345 def test_impl_inherited(self, impl_tag):
346 class Inherited(self.base_klass):
349 self.assertSequenceEqual(obj.impl, impl_tag)
350 self.assertFalse(obj.expled)
352 tag_class, _, tag_num = tag_decode(impl_tag)
353 self.assertEqual(obj.tag_order, (tag_class, tag_num))
355 @given(binary(min_size=1))
356 def test_expl_inherited(self, expl_tag):
357 class Inherited(self.base_klass):
360 self.assertSequenceEqual(obj.expl, expl_tag)
361 self.assertTrue(obj.expled)
363 tag_class, _, tag_num = tag_decode(expl_tag)
364 self.assertEqual(obj.tag_order, (tag_class, tag_num))
366 def assert_copied_basic_fields(self, obj, obj_copied):
367 self.assertEqual(obj, obj_copied)
368 self.assertSequenceEqual(obj.tag, obj_copied.tag)
369 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
370 self.assertEqual(obj.default, obj_copied.default)
371 self.assertEqual(obj.optional, obj_copied.optional)
372 self.assertEqual(obj.offset, obj_copied.offset)
373 self.assertEqual(obj.llen, obj_copied.llen)
374 self.assertEqual(obj.vlen, obj_copied.vlen)
376 self.assertEqual(obj.tag_order, obj_copied.tag_order)
380 def boolean_values_strategy(draw, do_expl=False):
381 value = draw(one_of(none(), booleans()))
385 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
387 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
388 default = draw(one_of(none(), booleans()))
389 optional = draw(one_of(none(), booleans()))
391 draw(integers(min_value=0)),
392 draw(integers(min_value=0)),
393 draw(integers(min_value=0)),
395 return (value, impl, expl, default, optional, _decoded)
398 class BooleanInherited(Boolean):
402 class TestBoolean(CommonMixin, TestCase):
405 def test_invalid_value_type(self):
406 with self.assertRaises(InvalidValueType) as err:
411 def test_optional(self, optional):
412 obj = Boolean(default=Boolean(False), optional=optional)
413 self.assertTrue(obj.optional)
416 def test_ready(self, value):
418 self.assertFalse(obj.ready)
421 pprint(obj, big_blobs=True, with_decode_path=True)
422 with self.assertRaises(ObjNotReady) as err:
426 self.assertTrue(obj.ready)
429 pprint(obj, big_blobs=True, with_decode_path=True)
431 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
432 def test_comparison(self, value1, value2, tag1, tag2):
433 for klass in (Boolean, BooleanInherited):
436 self.assertEqual(obj1 == obj2, value1 == value2)
437 self.assertEqual(obj1 != obj2, value1 != value2)
438 self.assertEqual(obj1 == bool(obj2), value1 == value2)
439 obj1 = klass(value1, impl=tag1)
440 obj2 = klass(value1, impl=tag2)
441 self.assertEqual(obj1 == obj2, tag1 == tag2)
442 self.assertEqual(obj1 != obj2, tag1 != tag2)
444 @given(data_strategy())
445 def test_call(self, d):
446 for klass in (Boolean, BooleanInherited):
454 ) = d.draw(boolean_values_strategy())
460 optional_initial or False,
470 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
471 obj = obj_initial(value, impl, expl, default, optional)
473 value_expected = default if value is None else value
475 default_initial if value_expected is None
478 self.assertEqual(obj, value_expected)
479 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
480 self.assertEqual(obj.expl_tag, expl or expl_initial)
483 default_initial if default is None else default,
485 if obj.default is None:
486 optional = optional_initial if optional is None else optional
487 optional = False if optional is None else optional
490 self.assertEqual(obj.optional, optional)
492 @given(boolean_values_strategy())
493 def test_copy(self, values):
494 for klass in (Boolean, BooleanInherited):
496 for copy_func in copy_funcs:
497 obj_copied = copy_func(obj)
498 self.assert_copied_basic_fields(obj, obj_copied)
502 integers(min_value=1).map(tag_encode),
504 def test_stripped(self, value, tag_impl):
505 obj = Boolean(value, impl=tag_impl)
506 with self.assertRaises(NotEnoughData):
507 obj.decode(obj.encode()[:-1])
511 integers(min_value=1).map(tag_ctxc),
513 def test_stripped_expl(self, value, tag_expl):
514 obj = Boolean(value, expl=tag_expl)
515 with self.assertRaises(NotEnoughData):
516 obj.decode(obj.encode()[:-1])
519 integers(min_value=31),
520 integers(min_value=0),
523 def test_bad_tag(self, tag, offset, decode_path):
524 with self.assertRaises(DecodeError) as err:
526 tag_encode(tag)[:-1],
528 decode_path=decode_path,
531 self.assertEqual(err.exception.offset, offset)
532 self.assertEqual(err.exception.decode_path, decode_path)
535 integers(min_value=31),
536 integers(min_value=0),
539 def test_bad_expl_tag(self, tag, offset, decode_path):
540 with self.assertRaises(DecodeError) as err:
541 Boolean(expl=Boolean.tag_default).decode(
542 tag_encode(tag)[:-1],
544 decode_path=decode_path,
547 self.assertEqual(err.exception.offset, offset)
548 self.assertEqual(err.exception.decode_path, decode_path)
551 integers(min_value=128),
552 integers(min_value=0),
555 def test_bad_len(self, l, offset, decode_path):
556 with self.assertRaises(DecodeError) as err:
558 Boolean.tag_default + len_encode(l)[:-1],
560 decode_path=decode_path,
563 self.assertEqual(err.exception.offset, offset)
564 self.assertEqual(err.exception.decode_path, decode_path)
567 integers(min_value=128),
568 integers(min_value=0),
571 def test_bad_expl_len(self, l, offset, decode_path):
572 with self.assertRaises(DecodeError) as err:
573 Boolean(expl=Boolean.tag_default).decode(
574 Boolean.tag_default + len_encode(l)[:-1],
576 decode_path=decode_path,
579 self.assertEqual(err.exception.offset, offset)
580 self.assertEqual(err.exception.decode_path, decode_path)
582 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
584 boolean_values_strategy(),
586 integers(min_value=1).map(tag_ctxc),
587 integers(min_value=0),
591 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
592 for klass in (Boolean, BooleanInherited):
593 _, _, _, default, optional, _decoded = values
602 pprint(obj, big_blobs=True, with_decode_path=True)
603 self.assertFalse(obj.expled)
604 obj_encoded = obj.encode()
605 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
606 obj_expled = obj(value, expl=tag_expl)
607 self.assertTrue(obj_expled.expled)
609 list(obj_expled.pps())
610 pprint(obj_expled, big_blobs=True, with_decode_path=True)
611 obj_expled_cer = encode_cer(obj_expled)
612 self.assertNotEqual(obj_expled_cer, obj_encoded)
613 self.assertSequenceEqual(
614 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
617 obj_expled_hex_encoded = obj_expled.hexencode()
618 ctx_copied = deepcopy(ctx_dummy)
619 obj_decoded, tail = obj_expled.hexdecode(
620 obj_expled_hex_encoded + hexenc(tail_junk),
624 self.assertDictEqual(ctx_copied, ctx_dummy)
626 list(obj_decoded.pps())
627 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
628 self.assertEqual(tail, tail_junk)
629 self.assertEqual(obj_decoded, obj_expled)
630 self.assertNotEqual(obj_decoded, obj)
631 self.assertEqual(bool(obj_decoded), bool(obj_expled))
632 self.assertEqual(bool(obj_decoded), bool(obj))
633 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
634 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
635 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
637 obj_decoded.expl_llen,
638 len(len_encode(len(obj_encoded))),
640 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
641 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
644 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
646 self.assertEqual(obj_decoded.expl_offset, offset)
647 assert_exceeding_data(
649 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
653 evgens = list(obj_expled.decode_evgen(
654 hexdec(obj_expled_hex_encoded) + tail_junk,
656 decode_path=decode_path,
659 self.assertEqual(len(evgens), 1)
660 _decode_path, obj, tail = evgens[0]
661 self.assertSequenceEqual(tail, tail_junk)
662 self.assertEqual(_decode_path, decode_path)
663 self.assertEqual(obj, obj_decoded)
664 self.assertEqual(obj.expl_offset, offset)
668 @given(integers(min_value=2))
669 def test_invalid_len(self, l):
670 with self.assertRaises(InvalidLength):
671 Boolean().decode(b"".join((
677 @given(integers(min_value=0 + 1, max_value=255 - 1))
678 def test_ber_value(self, value):
679 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
680 Boolean().decode(b"".join((
690 obj, _ = Boolean().decode(encoded, ctx={"bered": True})
691 list(Boolean().decode_evgen(encoded, ctx={"bered": True}))
692 self.assertTrue(bool(obj))
693 self.assertTrue(obj.ber_encoded)
694 self.assertFalse(obj.lenindef)
695 self.assertTrue(obj.bered)
697 self.assertTrue(obj.ber_encoded)
698 self.assertFalse(obj.lenindef)
699 self.assertTrue(obj.bered)
702 integers(min_value=1).map(tag_ctxc),
703 binary().filter(lambda x: not x.startswith(EOC)),
705 def test_ber_expl_no_eoc(self, expl, junk):
706 encoded = expl + LENINDEF + Boolean(False).encode()
707 with self.assertRaises(LenIndefForm):
708 Boolean(expl=expl).decode(encoded + junk)
709 with assertRaisesRegex(self, DecodeError, "no EOC"):
710 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
711 obj, tail = Boolean(expl=expl).decode(
712 encoded + EOC + junk,
715 self.assertTrue(obj.expl_lenindef)
716 self.assertFalse(obj.lenindef)
717 self.assertFalse(obj.ber_encoded)
718 self.assertTrue(obj.bered)
720 self.assertTrue(obj.expl_lenindef)
721 self.assertFalse(obj.lenindef)
722 self.assertFalse(obj.ber_encoded)
723 self.assertTrue(obj.bered)
724 self.assertSequenceEqual(tail, junk)
727 pprint(obj, big_blobs=True, with_decode_path=True)
730 integers(min_value=1).map(tag_ctxc),
737 def test_ber_expl(self, expl, values):
743 Boolean(value).encode() +
746 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
748 class SeqOf(SequenceOf):
749 schema = Boolean(expl=expl)
750 with self.assertRaises(LenIndefForm):
751 SeqOf().decode(encoded)
752 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
753 list(SeqOf().decode_evgen(encoded, ctx={"bered": True}))
754 self.assertSequenceEqual(tail, b"")
755 self.assertSequenceEqual([bool(v) for v in seqof], values)
771 len(expl) + 1 + 3 + EOC_LEN,
782 pprint(seqof, big_blobs=True, with_decode_path=True)
786 def integer_values_strategy(draw, do_expl=False):
787 bound_min, value, default, bound_max = sorted(draw(sets(
796 _specs = draw(sets(text_letters()))
799 min_size=len(_specs),
800 max_size=len(_specs),
802 _specs = list(zip(_specs, values))
805 bounds = (bound_min, bound_max)
809 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
811 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
814 optional = draw(one_of(none(), booleans()))
816 draw(integers(min_value=0)),
817 draw(integers(min_value=0)),
818 draw(integers(min_value=0)),
820 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
823 class IntegerInherited(Integer):
827 class TestInteger(CommonMixin, TestCase):
830 def test_invalid_value_type(self):
831 with self.assertRaises(InvalidValueType) as err:
835 @given(sets(text_letters(), min_size=2))
836 def test_unknown_name(self, names_input):
837 missing = names_input.pop()
840 schema = [(n, 123) for n in names_input]
841 with self.assertRaises(ObjUnknown) as err:
845 @given(sets(text_letters(), min_size=2))
846 def test_known_name(self, names_input):
848 schema = [(n, 123) for n in names_input]
849 Int(names_input.pop())
852 def test_optional(self, optional):
853 obj = Integer(default=Integer(0), optional=optional)
854 self.assertTrue(obj.optional)
857 def test_ready(self, value):
859 self.assertFalse(obj.ready)
862 pprint(obj, big_blobs=True, with_decode_path=True)
863 with self.assertRaises(ObjNotReady) as err:
867 self.assertTrue(obj.ready)
870 pprint(obj, big_blobs=True, with_decode_path=True)
873 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
874 def test_comparison(self, value1, value2, tag1, tag2):
875 for klass in (Integer, IntegerInherited):
878 self.assertEqual(obj1 == obj2, value1 == value2)
879 self.assertEqual(obj1 != obj2, value1 != value2)
880 self.assertEqual(obj1 == int(obj2), value1 == value2)
881 obj1 = klass(value1, impl=tag1)
882 obj2 = klass(value1, impl=tag2)
883 self.assertEqual(obj1 == obj2, tag1 == tag2)
884 self.assertEqual(obj1 != obj2, tag1 != tag2)
886 @given(lists(integers()))
887 def test_sorted_works(self, values):
888 self.assertSequenceEqual(
889 [int(v) for v in sorted(Integer(v) for v in values)],
893 @given(data_strategy())
894 def test_named(self, d):
895 names_input = list(d.draw(sets(text_letters(), min_size=1)))
896 values_input = list(d.draw(sets(
898 min_size=len(names_input),
899 max_size=len(names_input),
901 chosen_name = d.draw(sampled_from(names_input))
902 names_input = dict(zip(names_input, values_input))
906 _int = Int(chosen_name)
907 self.assertEqual(_int.named, chosen_name)
908 self.assertEqual(int(_int), names_input[chosen_name])
910 @given(integers(), integers(min_value=0), integers(min_value=0))
911 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
912 value = bound_min + value_delta
913 bound_max = value + bound_delta
914 Integer(value=value, bounds=(bound_min, bound_max))
916 @given(sets(integers(), min_size=3, max_size=3))
917 def test_bounds_unsatisfied(self, values):
918 values = sorted(values)
919 with self.assertRaises(BoundsError) as err:
920 Integer(value=values[0], bounds=(values[1], values[2]))
922 with assertRaisesRegex(self, DecodeError, "bounds") as err:
923 Integer(bounds=(values[1], values[2])).decode(
924 Integer(values[0]).encode()
927 with self.assertRaises(BoundsError) as err:
928 Integer(value=values[2], bounds=(values[0], values[1]))
930 with assertRaisesRegex(self, DecodeError, "bounds") as err:
931 Integer(bounds=(values[0], values[1])).decode(
932 Integer(values[2]).encode()
936 @given(data_strategy())
937 def test_call(self, d):
938 for klass in (Integer, IntegerInherited):
948 ) = d.draw(integer_values_strategy())
955 optional_initial or False,
968 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
969 if (default is None) and (obj_initial.default is not None):
973 (value is not None) and
974 (bounds_initial is not None) and
975 not (bounds_initial[0] <= value <= bounds_initial[1])
980 (default is not None) and
981 (bounds_initial is not None) and
982 not (bounds_initial[0] <= default <= bounds_initial[1])
985 obj = obj_initial(value, bounds, impl, expl, default, optional)
987 value_expected = default if value is None else value
989 default_initial if value_expected is None
992 self.assertEqual(obj, value_expected)
993 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
994 self.assertEqual(obj.expl_tag, expl or expl_initial)
997 default_initial if default is None else default,
999 if obj.default is None:
1000 optional = optional_initial if optional is None else optional
1001 optional = False if optional is None else optional
1004 self.assertEqual(obj.optional, optional)
1006 (obj._bound_min, obj._bound_max),
1007 bounds or bounds_initial or (float("-inf"), float("+inf")),
1011 {} if _specs_initial is None else dict(_specs_initial),
1014 @given(integer_values_strategy())
1015 def test_copy(self, values):
1016 for klass in (Integer, IntegerInherited):
1017 obj = klass(*values)
1018 for copy_func in copy_funcs:
1019 obj_copied = copy_func(obj)
1020 self.assert_copied_basic_fields(obj, obj_copied)
1021 self.assertEqual(obj.specs, obj_copied.specs)
1022 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1023 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1024 self.assertEqual(obj._value, obj_copied._value)
1028 integers(min_value=1).map(tag_encode),
1030 def test_stripped(self, value, tag_impl):
1031 obj = Integer(value, impl=tag_impl)
1032 with self.assertRaises(NotEnoughData):
1033 obj.decode(obj.encode()[:-1])
1037 integers(min_value=1).map(tag_ctxc),
1039 def test_stripped_expl(self, value, tag_expl):
1040 obj = Integer(value, expl=tag_expl)
1041 with self.assertRaises(NotEnoughData):
1042 obj.decode(obj.encode()[:-1])
1044 def test_zero_len(self):
1045 with self.assertRaises(NotEnoughData):
1046 Integer().decode(b"".join((
1047 Integer.tag_default,
1052 integers(min_value=31),
1053 integers(min_value=0),
1056 def test_bad_tag(self, tag, offset, decode_path):
1057 with self.assertRaises(DecodeError) as err:
1059 tag_encode(tag)[:-1],
1061 decode_path=decode_path,
1064 self.assertEqual(err.exception.offset, offset)
1065 self.assertEqual(err.exception.decode_path, decode_path)
1068 integers(min_value=128),
1069 integers(min_value=0),
1072 def test_bad_len(self, l, offset, decode_path):
1073 with self.assertRaises(DecodeError) as err:
1075 Integer.tag_default + len_encode(l)[:-1],
1077 decode_path=decode_path,
1080 self.assertEqual(err.exception.offset, offset)
1081 self.assertEqual(err.exception.decode_path, decode_path)
1084 sets(integers(), min_size=2, max_size=2),
1085 integers(min_value=0),
1088 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1089 value, bound_min = list(sorted(ints))
1092 bounds = (bound_min, bound_min)
1093 with self.assertRaises(DecodeError) as err:
1095 Integer(value).encode(),
1097 decode_path=decode_path,
1100 self.assertEqual(err.exception.offset, offset)
1101 self.assertEqual(err.exception.decode_path, decode_path)
1103 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1105 integer_values_strategy(),
1107 integers(min_value=1).map(tag_ctxc),
1108 integers(min_value=0),
1112 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
1113 for klass in (Integer, IntegerInherited):
1114 _, _, _, _, default, optional, _, _decoded = values
1123 pprint(obj, big_blobs=True, with_decode_path=True)
1124 self.assertFalse(obj.expled)
1125 obj_encoded = obj.encode()
1126 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1127 obj_expled = obj(value, expl=tag_expl)
1128 self.assertTrue(obj_expled.expled)
1130 list(obj_expled.pps())
1131 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1132 obj_expled_encoded = obj_expled.encode()
1133 obj_expled_cer = encode_cer(obj_expled)
1134 self.assertNotEqual(obj_expled_cer, obj_encoded)
1135 self.assertSequenceEqual(
1136 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1139 ctx_copied = deepcopy(ctx_dummy)
1140 obj_decoded, tail = obj_expled.decode(
1141 obj_expled_encoded + tail_junk,
1145 self.assertDictEqual(ctx_copied, ctx_dummy)
1147 list(obj_decoded.pps())
1148 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1149 self.assertEqual(tail, tail_junk)
1150 self.assertEqual(obj_decoded, obj_expled)
1151 self.assertNotEqual(obj_decoded, obj)
1152 self.assertEqual(int(obj_decoded), int(obj_expled))
1153 self.assertEqual(int(obj_decoded), int(obj))
1154 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1155 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1156 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1158 obj_decoded.expl_llen,
1159 len(len_encode(len(obj_encoded))),
1161 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1162 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1165 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1167 self.assertEqual(obj_decoded.expl_offset, offset)
1168 assert_exceeding_data(
1170 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1174 evgens = list(obj_expled.decode_evgen(
1175 obj_expled_encoded + tail_junk,
1177 decode_path=decode_path,
1180 self.assertEqual(len(evgens), 1)
1181 _decode_path, obj, tail = evgens[0]
1182 self.assertSequenceEqual(tail, tail_junk)
1183 self.assertEqual(_decode_path, decode_path)
1184 self.assertEqual(obj, obj_decoded)
1185 self.assertEqual(obj.expl_offset, offset)
1189 def test_go_vectors_valid(self):
1190 for data, expect in ((
1194 (b"\xff\x7f", -129),
1198 (b"\xff\x00", -256),
1202 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1203 (b"\x80\x00\x00\x00", -2147483648),
1206 Integer().decode(b"".join((
1207 Integer.tag_default,
1208 len_encode(len(data)),
1214 def test_go_vectors_invalid(self):
1219 with self.assertRaises(DecodeError):
1220 Integer().decode(b"".join((
1221 Integer.tag_default,
1222 len_encode(len(data)),
1228 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1231 if draw(booleans()):
1232 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1234 integers(min_value=0, max_value=255),
1235 min_size=len(schema),
1236 max_size=len(schema),
1238 schema = list(zip(schema, bits))
1240 def _value(value_required):
1241 if not value_required and draw(booleans()):
1243 generation_choice = 0
1245 generation_choice = draw(sampled_from((1, 2, 3)))
1246 if generation_choice == 1 or draw(booleans()):
1247 return "'%s'B" % "".join(draw(lists(
1248 sampled_from(("0", "1")),
1249 max_size=len(schema),
1251 if generation_choice == 2 or draw(booleans()):
1252 return draw(binary(max_size=len(schema) // 8))
1253 if generation_choice == 3 or draw(booleans()):
1254 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1256 value = _value(value_required)
1257 default = _value(value_required=False)
1261 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1263 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1264 optional = draw(one_of(none(), booleans()))
1266 draw(integers(min_value=0)),
1267 draw(integers(min_value=0)),
1268 draw(integers(min_value=0)),
1270 return (schema, value, impl, expl, default, optional, _decoded)
1273 class BitStringInherited(BitString):
1277 class TestBitString(CommonMixin, TestCase):
1278 base_klass = BitString
1280 @given(lists(booleans()))
1281 def test_b_encoding(self, bits):
1282 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1283 self.assertEqual(obj.bit_len, len(bits))
1284 self.assertSequenceEqual(list(obj), bits)
1285 for i, bit in enumerate(bits):
1286 self.assertEqual(obj[i], bit)
1288 @given(lists(booleans()))
1289 def test_out_of_bounds_bits(self, bits):
1290 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1291 for i in range(len(bits), len(bits) * 2):
1292 self.assertFalse(obj[i])
1294 def test_bad_b_encoding(self):
1295 with self.assertRaises(ValueError):
1296 BitString("'010120101'B")
1299 integers(min_value=1, max_value=255),
1300 integers(min_value=1, max_value=255),
1302 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1303 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1304 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1305 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1307 class BS(BitString):
1308 schema = (("whatever", 0),)
1309 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1310 self.assertEqual(obj.bit_len, leading_zeros + 1)
1311 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1313 def test_zero_len(self):
1314 with self.assertRaises(NotEnoughData):
1315 BitString().decode(b"".join((
1316 BitString.tag_default,
1320 def test_invalid_value_type(self):
1321 with self.assertRaises(InvalidValueType) as err:
1324 with self.assertRaises(InvalidValueType) as err:
1328 def test_obj_unknown(self):
1329 with self.assertRaises(ObjUnknown) as err:
1330 BitString(b"whatever")["whenever"]
1333 def test_get_invalid_type(self):
1334 with self.assertRaises(InvalidValueType) as err:
1335 BitString(b"whatever")[(1, 2, 3)]
1338 @given(data_strategy())
1339 def test_unknown_name(self, d):
1340 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1341 missing = _schema.pop()
1343 class BS(BitString):
1344 schema = [(n, i) for i, n in enumerate(_schema)]
1345 with self.assertRaises(ObjUnknown) as err:
1350 def test_optional(self, optional):
1351 obj = BitString(default=BitString(b""), optional=optional)
1352 self.assertTrue(obj.optional)
1355 def test_ready(self, value):
1357 self.assertFalse(obj.ready)
1360 pprint(obj, big_blobs=True, with_decode_path=True)
1361 with self.assertRaises(ObjNotReady) as err:
1364 obj = BitString(value)
1365 self.assertTrue(obj.ready)
1368 pprint(obj, big_blobs=True, with_decode_path=True)
1371 tuples(integers(min_value=0), binary()),
1372 tuples(integers(min_value=0), binary()),
1376 def test_comparison(self, value1, value2, tag1, tag2):
1377 for klass in (BitString, BitStringInherited):
1378 obj1 = klass(value1)
1379 obj2 = klass(value2)
1380 self.assertEqual(obj1 == obj2, value1 == value2)
1381 self.assertEqual(obj1 != obj2, value1 != value2)
1382 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1383 obj1 = klass(value1, impl=tag1)
1384 obj2 = klass(value1, impl=tag2)
1385 self.assertEqual(obj1 == obj2, tag1 == tag2)
1386 self.assertEqual(obj1 != obj2, tag1 != tag2)
1388 @given(data_strategy())
1389 def test_call(self, d):
1390 for klass in (BitString, BitStringInherited):
1399 ) = d.draw(bit_string_values_strategy())
1402 schema = schema_initial
1404 value=value_initial,
1407 default=default_initial,
1408 optional=optional_initial or False,
1409 _decoded=_decoded_initial,
1419 ) = d.draw(bit_string_values_strategy(
1420 schema=schema_initial,
1421 do_expl=impl_initial is None,
1430 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1431 self.assertEqual(obj.expl_tag, expl or expl_initial)
1432 if obj.default is None:
1433 optional = optional_initial if optional is None else optional
1434 optional = False if optional is None else optional
1437 self.assertEqual(obj.optional, optional)
1438 self.assertEqual(obj.specs, obj_initial.specs)
1440 @given(bit_string_values_strategy())
1441 def test_copy(self, values):
1442 for klass in (BitString, BitStringInherited):
1443 _schema, value, impl, expl, default, optional, _decoded = values
1453 optional=optional or False,
1456 for copy_func in copy_funcs:
1457 obj_copied = copy_func(obj)
1458 self.assert_copied_basic_fields(obj, obj_copied)
1459 self.assertEqual(obj.specs, obj_copied.specs)
1460 self.assertEqual(obj._value, obj_copied._value)
1464 integers(min_value=1).map(tag_encode),
1466 def test_stripped(self, value, tag_impl):
1467 obj = BitString(value, impl=tag_impl)
1468 with self.assertRaises(NotEnoughData):
1469 obj.decode(obj.encode()[:-1])
1473 integers(min_value=1).map(tag_ctxc),
1475 def test_stripped_expl(self, value, tag_expl):
1476 obj = BitString(value, expl=tag_expl)
1477 with self.assertRaises(NotEnoughData):
1478 obj.decode(obj.encode()[:-1])
1481 integers(min_value=31),
1482 integers(min_value=0),
1485 def test_bad_tag(self, tag, offset, decode_path):
1486 with self.assertRaises(DecodeError) as err:
1488 tag_encode(tag)[:-1],
1490 decode_path=decode_path,
1493 self.assertEqual(err.exception.offset, offset)
1494 self.assertEqual(err.exception.decode_path, decode_path)
1497 integers(min_value=128),
1498 integers(min_value=0),
1501 def test_bad_len(self, l, offset, decode_path):
1502 with self.assertRaises(DecodeError) as err:
1504 BitString.tag_default + len_encode(l)[:-1],
1506 decode_path=decode_path,
1509 self.assertEqual(err.exception.offset, offset)
1510 self.assertEqual(err.exception.decode_path, decode_path)
1512 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1513 @given(data_strategy())
1514 def test_symmetric(self, d):
1523 ) = d.draw(bit_string_values_strategy(value_required=True))
1524 tail_junk = d.draw(binary(max_size=5))
1525 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1526 offset = d.draw(integers(min_value=0))
1527 decode_path = d.draw(decode_path_strat)
1528 for klass in (BitString, BitStringInherited):
1539 pprint(obj, big_blobs=True, with_decode_path=True)
1540 self.assertFalse(obj.expled)
1541 obj_encoded = obj.encode()
1542 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
1543 obj_expled = obj(value, expl=tag_expl)
1544 self.assertTrue(obj_expled.expled)
1546 list(obj_expled.pps())
1547 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1548 obj_expled_encoded = obj_expled.encode()
1549 obj_expled_cer = encode_cer(obj_expled)
1550 self.assertNotEqual(obj_expled_cer, obj_encoded)
1551 self.assertSequenceEqual(
1552 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
1555 ctx_copied = deepcopy(ctx_dummy)
1556 obj_decoded, tail = obj_expled.decode(
1557 obj_expled_encoded + tail_junk,
1561 self.assertDictEqual(ctx_copied, ctx_dummy)
1563 list(obj_decoded.pps())
1564 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1565 self.assertEqual(tail, tail_junk)
1566 self.assertEqual(obj_decoded, obj_expled)
1567 self.assertNotEqual(obj_decoded, obj)
1568 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1569 self.assertEqual(bytes(obj_decoded), bytes(obj))
1570 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1571 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1572 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1574 obj_decoded.expl_llen,
1575 len(len_encode(len(obj_encoded))),
1577 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1578 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1581 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1583 self.assertEqual(obj_decoded.expl_offset, offset)
1584 if isinstance(value, tuple):
1585 self.assertSetEqual(set(value), set(obj_decoded.named))
1588 assert_exceeding_data(
1590 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1594 evgens = list(obj_expled.decode_evgen(
1595 obj_expled_encoded + tail_junk,
1597 decode_path=decode_path,
1600 self.assertEqual(len(evgens), 1)
1601 _decode_path, obj, tail = evgens[0]
1602 self.assertSequenceEqual(tail, tail_junk)
1603 self.assertEqual(_decode_path, decode_path)
1604 self.assertEqual(obj.expl_offset, offset)
1608 @given(integers(min_value=1, max_value=255))
1609 def test_bad_zero_value(self, pad_size):
1610 with self.assertRaises(DecodeError):
1611 BitString().decode(b"".join((
1612 BitString.tag_default,
1617 def test_go_vectors_invalid(self):
1623 with self.assertRaises(DecodeError):
1624 BitString().decode(b"".join((
1625 BitString.tag_default,
1630 def test_go_vectors_valid(self):
1631 obj, _ = BitString().decode(b"".join((
1632 BitString.tag_default,
1636 self.assertEqual(bytes(obj), b"")
1637 self.assertEqual(obj.bit_len, 0)
1639 obj, _ = BitString().decode(b"".join((
1640 BitString.tag_default,
1644 self.assertEqual(bytes(obj), b"\x00")
1645 self.assertEqual(obj.bit_len, 1)
1647 obj = BitString((16, b"\x82\x40"))
1648 self.assertTrue(obj[0])
1649 self.assertFalse(obj[1])
1650 self.assertTrue(obj[6])
1651 self.assertTrue(obj[9])
1652 self.assertFalse(obj[17])
1654 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1656 integers(min_value=1, max_value=30),
1659 binary(min_size=1, max_size=5),
1661 binary(min_size=1, max_size=5),
1669 lists(booleans(), min_size=1),
1673 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk, decode_path):
1674 def chunk_constructed(contents):
1676 tag_encode(form=TagFormConstructed, num=3) +
1678 b"".join(BitString(content).encode() for content in contents) +
1682 chunks_len_expected = []
1683 payload_expected = b""
1684 bit_len_expected = 0
1685 for chunk_input in chunk_inputs:
1686 if isinstance(chunk_input, binary_type):
1687 chunks.append(BitString(chunk_input).encode())
1688 payload_expected += chunk_input
1689 bit_len_expected += len(chunk_input) * 8
1690 chunks_len_expected.append(len(chunk_input) + 1)
1692 chunks.append(chunk_constructed(chunk_input))
1693 payload = b"".join(chunk_input)
1694 payload_expected += payload
1695 bit_len_expected += len(payload) * 8
1696 for c in chunk_input:
1697 chunks_len_expected.append(len(c) + 1)
1698 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
1699 chunk_last = BitString("'%s'B" % "".join(
1700 "1" if bit else "0" for bit in chunk_last_bits
1702 chunks_len_expected.append(BitString().decod(chunk_last.encode()).vlen)
1703 payload_expected += bytes(chunk_last)
1704 bit_len_expected += chunk_last.bit_len
1705 encoded_indefinite = (
1706 tag_encode(form=TagFormConstructed, num=impl) +
1709 chunk_last.encode() +
1712 encoded_definite = (
1713 tag_encode(form=TagFormConstructed, num=impl) +
1714 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1718 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1719 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1720 for lenindef_expected, encoded in (
1721 (True, encoded_indefinite),
1722 (False, encoded_definite),
1724 obj, tail = BitString(impl=tag_encode(impl)).decode(
1726 ctx={"bered": True},
1728 self.assertSequenceEqual(tail, junk)
1729 self.assertEqual(obj.bit_len, bit_len_expected)
1730 self.assertSequenceEqual(bytes(obj), payload_expected)
1731 self.assertTrue(obj.ber_encoded)
1732 self.assertEqual(obj.lenindef, lenindef_expected)
1733 self.assertTrue(obj.bered)
1735 self.assertTrue(obj.ber_encoded)
1736 self.assertEqual(obj.lenindef, lenindef_expected)
1737 self.assertTrue(obj.bered)
1738 self.assertEqual(len(encoded), obj.tlvlen)
1741 pprint(obj, big_blobs=True, with_decode_path=True)
1743 evgens = list(BitString(impl=tag_encode(impl)).decode_evgen(
1745 decode_path=decode_path,
1746 ctx={"bered": True},
1748 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
1749 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
1750 self.assertGreater(len(dp), len(decode_path))
1751 self.assertEqual(obj.vlen, chunk_len_expected)
1754 integers(min_value=0),
1757 def test_ber_definite_too_short(self, offset, decode_path):
1758 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1760 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1762 decode_path=decode_path,
1763 ctx={"bered": True},
1765 self.assertEqual(err.exception.decode_path, decode_path)
1766 self.assertEqual(err.exception.offset, offset)
1769 integers(min_value=0),
1772 def test_ber_definite_no_data(self, offset, decode_path):
1773 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1775 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1777 decode_path=decode_path,
1778 ctx={"bered": True},
1780 self.assertEqual(err.exception.decode_path, decode_path)
1781 self.assertEqual(err.exception.offset, offset)
1784 integers(min_value=0),
1786 integers(min_value=1, max_value=3),
1788 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1789 bs = BitString(b"data").encode()
1790 with self.assertRaises(NotEnoughData) as err:
1792 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1794 decode_path=decode_path,
1795 ctx={"bered": True},
1797 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1798 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1801 integers(min_value=0),
1803 integers(min_value=1, max_value=3),
1805 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1806 bs = BitString(b"data").encode()
1807 bs_longer = BitString(b"data-longer").encode()
1808 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1811 tag_encode(3, form=TagFormConstructed) +
1812 len_encode((chunks + 1) * len(bs)) +
1817 decode_path=decode_path,
1818 ctx={"bered": True},
1820 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1821 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1824 integers(min_value=0),
1827 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1828 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1830 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1832 decode_path=decode_path,
1833 ctx={"bered": True},
1835 self.assertEqual(err.exception.decode_path, decode_path)
1836 self.assertEqual(err.exception.offset, offset)
1838 @given(data_strategy())
1839 def test_ber_indefinite_not_multiple(self, d):
1840 bs_short = BitString("'A'H").encode()
1841 bs_full = BitString("'AA'H").encode()
1842 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1843 chunks.append(bs_short)
1844 d.draw(permutations(chunks))
1845 chunks.append(bs_short)
1846 offset = d.draw(integers(min_value=0))
1847 decode_path = d.draw(decode_path_strat)
1848 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1851 tag_encode(3, form=TagFormConstructed) +
1857 decode_path=decode_path,
1858 ctx={"bered": True},
1861 err.exception.decode_path,
1862 decode_path + (str(chunks.index(bs_short)),),
1865 err.exception.offset,
1866 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1869 def test_x690_vector(self):
1870 vector = BitString("'0A3B5F291CD'H")
1871 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1872 self.assertSequenceEqual(tail, b"")
1873 self.assertEqual(obj, vector)
1874 obj, tail = BitString().decode(
1875 hexdec("23800303000A3B0305045F291CD00000"),
1876 ctx={"bered": True},
1878 self.assertSequenceEqual(tail, b"")
1879 self.assertEqual(obj, vector)
1880 self.assertTrue(obj.ber_encoded)
1881 self.assertTrue(obj.lenindef)
1882 self.assertTrue(obj.bered)
1884 self.assertTrue(obj.ber_encoded)
1885 self.assertTrue(obj.lenindef)
1886 self.assertTrue(obj.bered)
1888 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1889 @given(integers(min_value=1000, max_value=3000))
1890 def test_cer(self, data_len):
1891 data = urandom(data_len)
1892 encoded = encode_cer(BitString(data))
1893 ctx = {"bered": True}
1894 self.assertSequenceEqual(bytes(BitString().decod(encoded, ctx=ctx)), data)
1895 evgens = list(BitString().decode_evgen(encoded, ctx=ctx))
1896 evgens_expected = data_len // 999
1897 if evgens_expected * 999 != data_len:
1898 evgens_expected += 1
1899 evgens_expected += 1
1900 self.assertEqual(len(evgens), evgens_expected)
1901 for (_, obj, _) in evgens[:-2]:
1902 self.assertEqual(obj.vlen, 1000)
1903 _, obj, _ = evgens[-2]
1904 self.assertEqual(obj.vlen, 1 + data_len - len(evgens[:-2]) * 999)
1908 def octet_string_values_strategy(draw, do_expl=False):
1909 bound_min, bound_max = sorted(draw(sets(
1910 integers(min_value=0, max_value=1 << 7),
1914 value = draw(one_of(
1916 binary(min_size=bound_min, max_size=bound_max),
1918 default = draw(one_of(
1920 binary(min_size=bound_min, max_size=bound_max),
1923 if draw(booleans()):
1924 bounds = (bound_min, bound_max)
1928 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1930 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1931 optional = draw(one_of(none(), booleans()))
1933 draw(integers(min_value=0)),
1934 draw(integers(min_value=0)),
1935 draw(integers(min_value=0)),
1937 return (value, bounds, impl, expl, default, optional, _decoded)
1940 class OctetStringInherited(OctetString):
1944 class TestOctetString(CommonMixin, TestCase):
1945 base_klass = OctetString
1947 def test_invalid_value_type(self):
1948 with self.assertRaises(InvalidValueType) as err:
1949 OctetString(text_type(123))
1953 def test_optional(self, optional):
1954 obj = OctetString(default=OctetString(b""), optional=optional)
1955 self.assertTrue(obj.optional)
1958 def test_ready(self, value):
1960 self.assertFalse(obj.ready)
1963 pprint(obj, big_blobs=True, with_decode_path=True)
1964 with self.assertRaises(ObjNotReady) as err:
1967 obj = OctetString(value)
1968 self.assertTrue(obj.ready)
1971 pprint(obj, big_blobs=True, with_decode_path=True)
1973 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1974 def test_comparison(self, value1, value2, tag1, tag2):
1975 for klass in (OctetString, OctetStringInherited):
1976 obj1 = klass(value1)
1977 obj2 = klass(value2)
1978 self.assertEqual(obj1 == obj2, value1 == value2)
1979 self.assertEqual(obj1 != obj2, value1 != value2)
1980 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1981 obj1 = klass(value1, impl=tag1)
1982 obj2 = klass(value1, impl=tag2)
1983 self.assertEqual(obj1 == obj2, tag1 == tag2)
1984 self.assertEqual(obj1 != obj2, tag1 != tag2)
1986 @given(lists(binary()))
1987 def test_sorted_works(self, values):
1988 self.assertSequenceEqual(
1989 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1993 @given(data_strategy())
1994 def test_bounds_satisfied(self, d):
1995 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1996 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1997 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1998 OctetString(value=value, bounds=(bound_min, bound_max))
2000 @given(data_strategy())
2001 def test_bounds_unsatisfied(self, d):
2002 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2003 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2004 value = d.draw(binary(max_size=bound_min - 1))
2005 with self.assertRaises(BoundsError) as err:
2006 OctetString(value=value, bounds=(bound_min, bound_max))
2008 with assertRaisesRegex(self, DecodeError, "bounds") as err:
2009 OctetString(bounds=(bound_min, bound_max)).decode(
2010 OctetString(value).encode()
2013 value = d.draw(binary(min_size=bound_max + 1))
2014 with self.assertRaises(BoundsError) as err:
2015 OctetString(value=value, bounds=(bound_min, bound_max))
2017 with assertRaisesRegex(self, DecodeError, "bounds") as err:
2018 OctetString(bounds=(bound_min, bound_max)).decode(
2019 OctetString(value).encode()
2023 @given(data_strategy())
2024 def test_call(self, d):
2025 for klass in (OctetString, OctetStringInherited):
2034 ) = d.draw(octet_string_values_strategy())
2035 obj_initial = klass(
2041 optional_initial or False,
2052 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
2053 if (default is None) and (obj_initial.default is not None):
2056 (bounds is None) and
2057 (value is not None) and
2058 (bounds_initial is not None) and
2059 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2063 (bounds is None) and
2064 (default is not None) and
2065 (bounds_initial is not None) and
2066 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2069 obj = obj_initial(value, bounds, impl, expl, default, optional)
2071 value_expected = default if value is None else value
2073 default_initial if value_expected is None
2076 self.assertEqual(obj, value_expected)
2077 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2078 self.assertEqual(obj.expl_tag, expl or expl_initial)
2081 default_initial if default is None else default,
2083 if obj.default is None:
2084 optional = optional_initial if optional is None else optional
2085 optional = False if optional is None else optional
2088 self.assertEqual(obj.optional, optional)
2090 (obj._bound_min, obj._bound_max),
2091 bounds or bounds_initial or (0, float("+inf")),
2094 @given(octet_string_values_strategy())
2095 def test_copy(self, values):
2096 for klass in (OctetString, OctetStringInherited):
2097 obj = klass(*values)
2098 for copy_func in copy_funcs:
2099 obj_copied = copy_func(obj)
2100 self.assert_copied_basic_fields(obj, obj_copied)
2101 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2102 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2103 self.assertEqual(obj._value, obj_copied._value)
2107 integers(min_value=1).map(tag_encode),
2109 def test_stripped(self, value, tag_impl):
2110 obj = OctetString(value, impl=tag_impl)
2111 with self.assertRaises(NotEnoughData):
2112 obj.decode(obj.encode()[:-1])
2116 integers(min_value=1).map(tag_ctxc),
2118 def test_stripped_expl(self, value, tag_expl):
2119 obj = OctetString(value, expl=tag_expl)
2120 with self.assertRaises(NotEnoughData):
2121 obj.decode(obj.encode()[:-1])
2124 integers(min_value=31),
2125 integers(min_value=0),
2128 def test_bad_tag(self, tag, offset, decode_path):
2129 with self.assertRaises(DecodeError) as err:
2130 OctetString().decode(
2131 tag_encode(tag)[:-1],
2133 decode_path=decode_path,
2136 self.assertEqual(err.exception.offset, offset)
2137 self.assertEqual(err.exception.decode_path, decode_path)
2140 integers(min_value=128),
2141 integers(min_value=0),
2144 def test_bad_len(self, l, offset, decode_path):
2145 with self.assertRaises(DecodeError) as err:
2146 OctetString().decode(
2147 OctetString.tag_default + len_encode(l)[:-1],
2149 decode_path=decode_path,
2152 self.assertEqual(err.exception.offset, offset)
2153 self.assertEqual(err.exception.decode_path, decode_path)
2156 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2157 integers(min_value=0),
2160 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2161 value, bound_min = list(sorted(ints))
2163 class String(OctetString):
2164 bounds = (bound_min, bound_min)
2165 with self.assertRaises(DecodeError) as err:
2167 OctetString(b"\x00" * value).encode(),
2169 decode_path=decode_path,
2172 self.assertEqual(err.exception.offset, offset)
2173 self.assertEqual(err.exception.decode_path, decode_path)
2175 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2177 octet_string_values_strategy(),
2179 integers(min_value=1).map(tag_ctxc),
2180 integers(min_value=0),
2184 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2185 for klass in (OctetString, OctetStringInherited):
2186 _, _, _, _, default, optional, _decoded = values
2195 pprint(obj, big_blobs=True, with_decode_path=True)
2196 self.assertFalse(obj.expled)
2197 obj_encoded = obj.encode()
2198 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2199 obj_expled = obj(value, expl=tag_expl)
2200 self.assertTrue(obj_expled.expled)
2202 list(obj_expled.pps())
2203 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2204 obj_expled_encoded = obj_expled.encode()
2205 obj_expled_cer = encode_cer(obj_expled)
2206 self.assertNotEqual(obj_expled_cer, obj_encoded)
2207 self.assertSequenceEqual(
2208 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2211 ctx_copied = deepcopy(ctx_dummy)
2212 obj_decoded, tail = obj_expled.decode(
2213 obj_expled_encoded + tail_junk,
2217 self.assertDictEqual(ctx_copied, ctx_dummy)
2219 list(obj_decoded.pps())
2220 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2221 self.assertEqual(tail, tail_junk)
2222 self.assertEqual(obj_decoded, obj_expled)
2223 self.assertNotEqual(obj_decoded, obj)
2224 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2225 self.assertEqual(bytes(obj_decoded), bytes(obj))
2226 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2227 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2228 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2230 obj_decoded.expl_llen,
2231 len(len_encode(len(obj_encoded))),
2233 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2234 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2237 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2239 self.assertEqual(obj_decoded.expl_offset, offset)
2240 assert_exceeding_data(
2242 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2246 evgens = list(obj_expled.decode_evgen(
2247 obj_expled_encoded + tail_junk,
2249 decode_path=decode_path,
2252 self.assertEqual(len(evgens), 1)
2253 _decode_path, obj, tail = evgens[0]
2254 self.assertSequenceEqual(tail, tail_junk)
2255 self.assertEqual(_decode_path, decode_path)
2256 self.assertEqual(obj.expl_offset, offset)
2260 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2262 integers(min_value=1, max_value=30),
2265 binary(min_size=1, max_size=5),
2267 binary(min_size=1, max_size=5),
2278 def test_constructed(self, impl, chunk_inputs, junk, decode_path):
2279 def chunk_constructed(contents):
2281 tag_encode(form=TagFormConstructed, num=4) +
2283 b"".join(OctetString(content).encode() for content in contents) +
2287 chunks_len_expected = []
2288 payload_expected = b""
2289 for chunk_input in chunk_inputs:
2290 if isinstance(chunk_input, binary_type):
2291 chunks.append(OctetString(chunk_input).encode())
2292 payload_expected += chunk_input
2293 chunks_len_expected.append(len(chunk_input))
2295 chunks.append(chunk_constructed(chunk_input))
2296 payload = b"".join(chunk_input)
2297 payload_expected += payload
2298 for c in chunk_input:
2299 chunks_len_expected.append(len(c))
2300 chunks_len_expected.append(len(chunks[-1]) - 1 - 1)
2301 encoded_indefinite = (
2302 tag_encode(form=TagFormConstructed, num=impl) +
2307 encoded_definite = (
2308 tag_encode(form=TagFormConstructed, num=impl) +
2309 len_encode(len(b"".join(chunks))) +
2312 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2313 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2314 for lenindef_expected, encoded in (
2315 (True, encoded_indefinite),
2316 (False, encoded_definite),
2318 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2320 ctx={"bered": True},
2322 self.assertSequenceEqual(tail, junk)
2323 self.assertSequenceEqual(bytes(obj), payload_expected)
2324 self.assertTrue(obj.ber_encoded)
2325 self.assertEqual(obj.lenindef, lenindef_expected)
2326 self.assertTrue(obj.bered)
2328 self.assertTrue(obj.ber_encoded)
2329 self.assertEqual(obj.lenindef, lenindef_expected)
2330 self.assertTrue(obj.bered)
2331 self.assertEqual(len(encoded), obj.tlvlen)
2334 pprint(obj, big_blobs=True, with_decode_path=True)
2336 evgens = list(OctetString(impl=tag_encode(impl)).decode_evgen(
2338 decode_path=decode_path,
2339 ctx={"bered": True},
2341 self.assertEqual(len(evgens), len(chunks_len_expected) + 1)
2342 for chunk_len_expected, (dp, obj, _) in zip(chunks_len_expected, evgens):
2343 self.assertGreater(len(dp), len(decode_path))
2344 self.assertEqual(obj.vlen, chunk_len_expected)
2347 integers(min_value=0),
2350 def test_ber_definite_too_short(self, offset, decode_path):
2351 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2352 OctetString().decode(
2353 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2355 decode_path=decode_path,
2356 ctx={"bered": True},
2358 self.assertEqual(err.exception.decode_path, decode_path)
2359 self.assertEqual(err.exception.offset, offset)
2362 integers(min_value=0),
2364 integers(min_value=1, max_value=3),
2366 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2367 bs = OctetString(b"data").encode()
2368 with self.assertRaises(NotEnoughData) as err:
2369 OctetString().decode(
2370 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2372 decode_path=decode_path,
2373 ctx={"bered": True},
2375 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2376 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2379 integers(min_value=0),
2381 integers(min_value=1, max_value=3),
2383 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2384 bs = OctetString(b"data").encode()
2385 bs_longer = OctetString(b"data-longer").encode()
2386 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2387 OctetString().decode(
2389 tag_encode(4, form=TagFormConstructed) +
2390 len_encode((chunks + 1) * len(bs)) +
2395 decode_path=decode_path,
2396 ctx={"bered": True},
2398 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2399 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2401 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2402 @given(integers(min_value=1001, max_value=3000))
2403 def test_cer(self, data_len):
2404 data = urandom(data_len)
2405 encoded = encode_cer(OctetString(data))
2406 ctx = {"bered": True}
2407 self.assertSequenceEqual(bytes(OctetString().decod(encoded, ctx=ctx)), data)
2408 evgens = list(OctetString().decode_evgen(encoded, ctx=ctx))
2409 evgens_expected = data_len // 1000
2410 if evgens_expected * 1000 != data_len:
2411 evgens_expected += 1
2412 evgens_expected += 1
2413 self.assertEqual(len(evgens), evgens_expected)
2414 for (_, obj, _) in evgens[:-2]:
2415 self.assertEqual(obj.vlen, 1000)
2416 _, obj, _ = evgens[-2]
2417 self.assertEqual(obj.vlen, data_len - len(evgens[:-2]) * 1000)
2421 def null_values_strategy(draw, do_expl=False):
2425 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2427 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2428 optional = draw(one_of(none(), booleans()))
2430 draw(integers(min_value=0)),
2431 draw(integers(min_value=0)),
2432 draw(integers(min_value=0)),
2434 return (impl, expl, optional, _decoded)
2437 class NullInherited(Null):
2441 class TestNull(CommonMixin, TestCase):
2444 def test_ready(self):
2446 self.assertTrue(obj.ready)
2449 pprint(obj, big_blobs=True, with_decode_path=True)
2451 @given(binary(min_size=1), binary(min_size=1))
2452 def test_comparison(self, tag1, tag2):
2453 for klass in (Null, NullInherited):
2454 obj1 = klass(impl=tag1)
2455 obj2 = klass(impl=tag2)
2456 self.assertEqual(obj1 == obj2, tag1 == tag2)
2457 self.assertEqual(obj1 != obj2, tag1 != tag2)
2458 self.assertNotEqual(obj1, tag2)
2460 @given(data_strategy())
2461 def test_call(self, d):
2462 for klass in (Null, NullInherited):
2468 ) = d.draw(null_values_strategy())
2469 obj_initial = klass(
2472 optional=optional_initial or False,
2473 _decoded=_decoded_initial,
2480 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2481 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2482 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2483 self.assertEqual(obj.expl_tag, expl or expl_initial)
2484 optional = optional_initial if optional is None else optional
2485 optional = False if optional is None else optional
2486 self.assertEqual(obj.optional, optional)
2488 @given(null_values_strategy())
2489 def test_copy(self, values):
2490 for klass in (Null, NullInherited):
2491 impl, expl, optional, _decoded = values
2495 optional=optional or False,
2498 for copy_func in copy_funcs:
2499 obj_copied = copy_func(obj)
2500 self.assert_copied_basic_fields(obj, obj_copied)
2502 @given(integers(min_value=1).map(tag_encode))
2503 def test_stripped(self, tag_impl):
2504 obj = Null(impl=tag_impl)
2505 with self.assertRaises(NotEnoughData):
2506 obj.decode(obj.encode()[:-1])
2508 @given(integers(min_value=1).map(tag_ctxc))
2509 def test_stripped_expl(self, tag_expl):
2510 obj = Null(expl=tag_expl)
2511 with self.assertRaises(NotEnoughData):
2512 obj.decode(obj.encode()[:-1])
2515 integers(min_value=31),
2516 integers(min_value=0),
2519 def test_bad_tag(self, tag, offset, decode_path):
2520 with self.assertRaises(DecodeError) as err:
2522 tag_encode(tag)[:-1],
2524 decode_path=decode_path,
2527 self.assertEqual(err.exception.offset, offset)
2528 self.assertEqual(err.exception.decode_path, decode_path)
2531 integers(min_value=128),
2532 integers(min_value=0),
2535 def test_bad_len(self, l, offset, decode_path):
2536 with self.assertRaises(DecodeError) as err:
2538 Null.tag_default + len_encode(l)[:-1],
2540 decode_path=decode_path,
2543 self.assertEqual(err.exception.offset, offset)
2544 self.assertEqual(err.exception.decode_path, decode_path)
2546 @given(binary(min_size=1))
2547 def test_tag_mismatch(self, impl):
2548 assume(impl != Null.tag_default)
2549 with self.assertRaises(TagMismatch):
2550 Null(impl=impl).decode(Null().encode())
2553 null_values_strategy(),
2554 integers(min_value=1).map(tag_ctxc),
2555 integers(min_value=0),
2559 def test_symmetric(self, values, tag_expl, offset, tail_junk, decode_path):
2560 for klass in (Null, NullInherited):
2561 _, _, optional, _decoded = values
2562 obj = klass(optional=optional, _decoded=_decoded)
2565 pprint(obj, big_blobs=True, with_decode_path=True)
2566 self.assertFalse(obj.expled)
2567 obj_encoded = obj.encode()
2568 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2569 obj_expled = obj(expl=tag_expl)
2570 self.assertTrue(obj_expled.expled)
2572 list(obj_expled.pps())
2573 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2574 obj_expled_encoded = obj_expled.encode()
2575 obj_expled_cer = encode_cer(obj_expled)
2576 self.assertNotEqual(obj_expled_cer, obj_encoded)
2577 self.assertSequenceEqual(
2578 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2581 ctx_copied = deepcopy(ctx_dummy)
2582 obj_decoded, tail = obj_expled.decode(
2583 obj_expled_encoded + tail_junk,
2587 self.assertDictEqual(ctx_copied, ctx_dummy)
2589 list(obj_decoded.pps())
2590 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2591 self.assertEqual(tail, tail_junk)
2592 self.assertEqual(obj_decoded, obj_expled)
2593 self.assertNotEqual(obj_decoded, obj)
2594 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2595 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2596 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2598 obj_decoded.expl_llen,
2599 len(len_encode(len(obj_encoded))),
2601 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2602 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2605 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2607 self.assertEqual(obj_decoded.expl_offset, offset)
2608 assert_exceeding_data(
2610 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2614 evgens = list(obj_expled.decode_evgen(
2615 obj_expled_encoded + tail_junk,
2617 decode_path=decode_path,
2620 self.assertEqual(len(evgens), 1)
2621 _decode_path, obj, tail = evgens[0]
2622 self.assertSequenceEqual(tail, tail_junk)
2623 self.assertEqual(_decode_path, decode_path)
2624 self.assertEqual(obj, obj_decoded)
2625 self.assertEqual(obj.expl_offset, offset)
2630 @given(integers(min_value=1))
2631 def test_invalid_len(self, l):
2632 with self.assertRaises(InvalidLength):
2633 Null().decode(b"".join((
2640 def oid_strategy(draw):
2641 first_arc = draw(integers(min_value=0, max_value=2))
2643 if first_arc in (0, 1):
2644 second_arc = draw(integers(min_value=0, max_value=39))
2646 second_arc = draw(integers(min_value=0))
2647 other_arcs = draw(lists(integers(min_value=0)))
2648 return tuple([first_arc, second_arc] + other_arcs)
2652 def oid_values_strategy(draw, do_expl=False):
2653 value = draw(one_of(none(), oid_strategy()))
2657 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2659 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2660 default = draw(one_of(none(), oid_strategy()))
2661 optional = draw(one_of(none(), booleans()))
2663 draw(integers(min_value=0)),
2664 draw(integers(min_value=0)),
2665 draw(integers(min_value=0)),
2667 return (value, impl, expl, default, optional, _decoded)
2670 class ObjectIdentifierInherited(ObjectIdentifier):
2674 class TestObjectIdentifier(CommonMixin, TestCase):
2675 base_klass = ObjectIdentifier
2677 def test_invalid_value_type(self):
2678 with self.assertRaises(InvalidValueType) as err:
2679 ObjectIdentifier(123)
2683 def test_optional(self, optional):
2684 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2685 self.assertTrue(obj.optional)
2687 @given(oid_strategy())
2688 def test_ready(self, value):
2689 obj = ObjectIdentifier()
2690 self.assertFalse(obj.ready)
2693 pprint(obj, big_blobs=True, with_decode_path=True)
2694 with self.assertRaises(ObjNotReady) as err:
2697 obj = ObjectIdentifier(value)
2698 self.assertTrue(obj.ready)
2699 self.assertFalse(obj.ber_encoded)
2702 pprint(obj, big_blobs=True, with_decode_path=True)
2705 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2706 def test_comparison(self, value1, value2, tag1, tag2):
2707 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2708 obj1 = klass(value1)
2709 obj2 = klass(value2)
2710 self.assertEqual(obj1 == obj2, value1 == value2)
2711 self.assertEqual(obj1 != obj2, value1 != value2)
2712 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2713 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2714 obj1 = klass(value1, impl=tag1)
2715 obj2 = klass(value1, impl=tag2)
2716 self.assertEqual(obj1 == obj2, tag1 == tag2)
2717 self.assertEqual(obj1 != obj2, tag1 != tag2)
2719 @given(lists(oid_strategy()))
2720 def test_sorted_works(self, values):
2721 self.assertSequenceEqual(
2722 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2726 @given(data_strategy())
2727 def test_call(self, d):
2728 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2736 ) = d.draw(oid_values_strategy())
2737 obj_initial = klass(
2738 value=value_initial,
2741 default=default_initial,
2742 optional=optional_initial or False,
2743 _decoded=_decoded_initial,
2752 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2761 value_expected = default if value is None else value
2763 default_initial if value_expected is None
2766 self.assertEqual(obj, value_expected)
2767 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2768 self.assertEqual(obj.expl_tag, expl or expl_initial)
2771 default_initial if default is None else default,
2773 if obj.default is None:
2774 optional = optional_initial if optional is None else optional
2775 optional = False if optional is None else optional
2778 self.assertEqual(obj.optional, optional)
2780 @given(oid_values_strategy())
2781 def test_copy(self, values):
2782 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2799 for copy_func in copy_funcs:
2800 obj_copied = copy_func(obj)
2801 self.assert_copied_basic_fields(obj, obj_copied)
2802 self.assertEqual(obj._value, obj_copied._value)
2804 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2807 integers(min_value=1).map(tag_encode),
2809 def test_stripped(self, value, tag_impl):
2810 obj = ObjectIdentifier(value, impl=tag_impl)
2811 with self.assertRaises(NotEnoughData):
2812 obj.decode(obj.encode()[:-1])
2816 integers(min_value=1).map(tag_ctxc),
2818 def test_stripped_expl(self, value, tag_expl):
2819 obj = ObjectIdentifier(value, expl=tag_expl)
2820 with self.assertRaises(NotEnoughData):
2821 obj.decode(obj.encode()[:-1])
2824 integers(min_value=31),
2825 integers(min_value=0),
2828 def test_bad_tag(self, tag, offset, decode_path):
2829 with self.assertRaises(DecodeError) as err:
2830 ObjectIdentifier().decode(
2831 tag_encode(tag)[:-1],
2833 decode_path=decode_path,
2836 self.assertEqual(err.exception.offset, offset)
2837 self.assertEqual(err.exception.decode_path, decode_path)
2840 integers(min_value=128),
2841 integers(min_value=0),
2844 def test_bad_len(self, l, offset, decode_path):
2845 with self.assertRaises(DecodeError) as err:
2846 ObjectIdentifier().decode(
2847 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2849 decode_path=decode_path,
2852 self.assertEqual(err.exception.offset, offset)
2853 self.assertEqual(err.exception.decode_path, decode_path)
2855 def test_zero_oid(self):
2856 with self.assertRaises(NotEnoughData):
2857 ObjectIdentifier().decode(
2858 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2861 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2862 @given(oid_strategy())
2863 def test_unfinished_oid(self, value):
2864 assume(list(value)[-1] > 255)
2865 obj_encoded = ObjectIdentifier(value).encode()
2866 obj, _ = ObjectIdentifier().decode(obj_encoded)
2867 data = obj_encoded[obj.tlen + obj.llen:-1]
2869 ObjectIdentifier.tag_default,
2870 len_encode(len(data)),
2873 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2876 @given(integers(min_value=0))
2877 def test_invalid_short(self, value):
2878 with self.assertRaises(InvalidOID):
2879 ObjectIdentifier((value,))
2880 with self.assertRaises(InvalidOID):
2881 ObjectIdentifier("%d" % value)
2883 @given(integers(min_value=3), integers(min_value=0))
2884 def test_invalid_first_arc(self, first_arc, second_arc):
2885 with self.assertRaises(InvalidOID):
2886 ObjectIdentifier((first_arc, second_arc))
2887 with self.assertRaises(InvalidOID):
2888 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2890 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2891 def test_invalid_second_arc(self, first_arc, second_arc):
2892 with self.assertRaises(InvalidOID):
2893 ObjectIdentifier((first_arc, second_arc))
2894 with self.assertRaises(InvalidOID):
2895 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2897 @given(text(alphabet=ascii_letters + ".", min_size=1))
2898 def test_junk(self, oid):
2899 with self.assertRaises(InvalidOID):
2900 ObjectIdentifier(oid)
2902 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2903 @given(oid_strategy())
2904 def test_validness(self, oid):
2905 obj = ObjectIdentifier(oid)
2906 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2909 pprint(obj, big_blobs=True, with_decode_path=True)
2911 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2913 oid_values_strategy(),
2915 integers(min_value=1).map(tag_ctxc),
2916 integers(min_value=0),
2920 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
2921 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2922 _, _, _, default, optional, _decoded = values
2931 pprint(obj, big_blobs=True, with_decode_path=True)
2932 self.assertFalse(obj.expled)
2933 obj_encoded = obj.encode()
2934 self.assertSequenceEqual(encode_cer(obj), obj_encoded)
2935 obj_expled = obj(value, expl=tag_expl)
2936 self.assertTrue(obj_expled.expled)
2938 list(obj_expled.pps())
2939 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2940 obj_expled_encoded = obj_expled.encode()
2941 obj_expled_cer = encode_cer(obj_expled)
2942 self.assertNotEqual(obj_expled_cer, obj_encoded)
2943 self.assertSequenceEqual(
2944 obj_expled.decod(obj_expled_cer, ctx={"bered": True}).encode(),
2947 ctx_copied = deepcopy(ctx_dummy)
2948 obj_decoded, tail = obj_expled.decode(
2949 obj_expled_encoded + tail_junk,
2953 self.assertDictEqual(ctx_copied, ctx_dummy)
2955 list(obj_decoded.pps())
2956 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2957 self.assertEqual(tail, tail_junk)
2958 self.assertEqual(obj_decoded, obj_expled)
2959 self.assertNotEqual(obj_decoded, obj)
2960 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2961 self.assertEqual(tuple(obj_decoded), tuple(obj))
2962 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2963 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2964 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2966 obj_decoded.expl_llen,
2967 len(len_encode(len(obj_encoded))),
2969 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2970 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2973 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2975 self.assertEqual(obj_decoded.expl_offset, offset)
2976 assert_exceeding_data(
2978 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2982 evgens = list(obj_expled.decode_evgen(
2983 obj_expled_encoded + tail_junk,
2985 decode_path=decode_path,
2988 self.assertEqual(len(evgens), 1)
2989 _decode_path, obj, tail = evgens[0]
2990 self.assertSequenceEqual(tail, tail_junk)
2991 self.assertEqual(_decode_path, decode_path)
2992 self.assertEqual(obj, obj_decoded)
2993 self.assertEqual(obj.expl_offset, offset)
2998 oid_strategy().map(ObjectIdentifier),
2999 oid_strategy().map(ObjectIdentifier),
3001 def test_add(self, oid1, oid2):
3002 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
3003 for oid_to_add in (oid2, tuple(oid2)):
3004 self.assertEqual(oid1 + oid_to_add, oid_expect)
3005 with self.assertRaises(InvalidValueType):
3008 def test_go_vectors_valid(self):
3009 for data, expect in (
3011 (b"\x55\x02", (2, 5, 2)),
3012 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
3013 (b"\x81\x34\x03", (2, 100, 3)),
3016 ObjectIdentifier().decode(b"".join((
3017 ObjectIdentifier.tag_default,
3018 len_encode(len(data)),
3024 def test_go_vectors_invalid(self):
3025 data = b"\x55\x02\xc0\x80\x80\x80\x80"
3026 with self.assertRaises(DecodeError):
3027 ObjectIdentifier().decode(b"".join((
3028 Integer.tag_default,
3029 len_encode(len(data)),
3033 def test_x690_vector(self):
3035 ObjectIdentifier().decode(hexdec("0603883703"))[0],
3036 ObjectIdentifier((2, 999, 3)),
3039 def test_nonnormalized_first_arc(self):
3041 ObjectIdentifier.tag_default +
3044 ObjectIdentifier((1, 0)).encode()[-1:]
3046 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3047 self.assertTrue(obj.ber_encoded)
3048 self.assertTrue(obj.bered)
3050 self.assertTrue(obj.ber_encoded)
3051 self.assertTrue(obj.bered)
3052 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
3053 ObjectIdentifier().decode(tampered)
3055 @given(data_strategy())
3056 def test_negative_arcs(self, d):
3057 oid = list(d.draw(oid_strategy()))
3060 idx = d.draw(integers(min_value=3, max_value=len(oid)))
3062 if oid[idx - 1] == 0:
3064 with self.assertRaises(InvalidOID):
3065 ObjectIdentifier(tuple(oid))
3066 with self.assertRaises(InvalidOID):
3067 ObjectIdentifier(".".join(str(i) for i in oid))
3069 @given(data_strategy())
3070 def test_plused_arcs(self, d):
3071 oid = [str(arc) for arc in d.draw(oid_strategy())]
3072 idx = d.draw(integers(min_value=0, max_value=len(oid)))
3073 oid[idx - 1] = "+" + oid[idx - 1]
3074 with self.assertRaises(InvalidOID):
3075 ObjectIdentifier(".".join(str(i) for i in oid))
3077 @given(data_strategy())
3078 def test_nonnormalized_arcs(self, d):
3079 arcs = d.draw(lists(
3080 integers(min_value=0, max_value=100),
3084 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
3085 _, _, lv = tag_strip(dered)
3086 _, _, v = len_decode(lv)
3087 v_no_first_arc = v[1:]
3088 idx_for_tamper = d.draw(integers(
3090 max_value=len(v_no_first_arc) - 1,
3092 tampered = list(bytearray(v_no_first_arc))
3093 for _ in range(d.draw(integers(min_value=1, max_value=3))):
3094 tampered.insert(idx_for_tamper, 0x80)
3095 tampered = bytes(bytearray(tampered))
3097 ObjectIdentifier.tag_default +
3098 len_encode(len(tampered)) +
3101 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
3102 self.assertTrue(obj.ber_encoded)
3103 self.assertTrue(obj.bered)
3105 self.assertTrue(obj.ber_encoded)
3106 self.assertTrue(obj.bered)
3107 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
3108 ObjectIdentifier().decode(tampered)
3112 def enumerated_values_strategy(draw, schema=None, do_expl=False):
3114 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
3115 values = list(draw(sets(
3117 min_size=len(schema),
3118 max_size=len(schema),
3120 schema = list(zip(schema, values))
3121 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
3125 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3127 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3128 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
3129 optional = draw(one_of(none(), booleans()))
3131 draw(integers(min_value=0)),
3132 draw(integers(min_value=0)),
3133 draw(integers(min_value=0)),
3135 return (schema, value, impl, expl, default, optional, _decoded)
3138 class TestEnumerated(CommonMixin, TestCase):
3139 class EWhatever(Enumerated):
3140 schema = (("whatever", 0),)
3142 base_klass = EWhatever
3144 def test_schema_required(self):
3145 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3148 def test_invalid_value_type(self):
3149 with self.assertRaises(InvalidValueType) as err:
3150 self.base_klass((1, 2))
3153 @given(sets(text_letters(), min_size=2))
3154 def test_unknown_name(self, schema_input):
3155 missing = schema_input.pop()
3157 class E(Enumerated):
3158 schema = [(n, 123) for n in schema_input]
3159 with self.assertRaises(ObjUnknown) as err:
3164 sets(text_letters(), min_size=2),
3165 sets(integers(), min_size=2),
3167 def test_unknown_value(self, schema_input, values_input):
3169 missing_value = values_input.pop()
3170 _input = list(zip(schema_input, values_input))
3172 class E(Enumerated):
3174 with self.assertRaises(DecodeError) as err:
3179 def test_optional(self, optional):
3180 obj = self.base_klass(default="whatever", optional=optional)
3181 self.assertTrue(obj.optional)
3183 def test_ready(self):
3184 obj = self.base_klass()
3185 self.assertFalse(obj.ready)
3188 pprint(obj, big_blobs=True, with_decode_path=True)
3189 with self.assertRaises(ObjNotReady) as err:
3192 obj = self.base_klass("whatever")
3193 self.assertTrue(obj.ready)
3196 pprint(obj, big_blobs=True, with_decode_path=True)
3198 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
3199 def test_comparison(self, value1, value2, tag1, tag2):
3200 class E(Enumerated):
3202 ("whatever0", value1),
3203 ("whatever1", value2),
3206 class EInherited(E):
3208 for klass in (E, EInherited):
3209 obj1 = klass(value1)
3210 obj2 = klass(value2)
3211 self.assertEqual(obj1 == obj2, value1 == value2)
3212 self.assertEqual(obj1 != obj2, value1 != value2)
3213 self.assertEqual(obj1 == int(obj2), value1 == value2)
3214 obj1 = klass(value1, impl=tag1)
3215 obj2 = klass(value1, impl=tag2)
3216 self.assertEqual(obj1 == obj2, tag1 == tag2)
3217 self.assertEqual(obj1 != obj2, tag1 != tag2)
3219 @given(data_strategy())
3220 def test_call(self, d):
3229 ) = d.draw(enumerated_values_strategy())
3231 class E(Enumerated):
3232 schema = schema_initial
3234 value=value_initial,
3237 default=default_initial,
3238 optional=optional_initial or False,
3239 _decoded=_decoded_initial,
3249 ) = d.draw(enumerated_values_strategy(
3250 schema=schema_initial,
3251 do_expl=impl_initial is None,
3261 value_expected = default if value is None else value
3263 default_initial if value_expected is None
3268 dict(schema_initial).get(value_expected, value_expected),
3270 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3271 self.assertEqual(obj.expl_tag, expl or expl_initial)
3274 default_initial if default is None else default,
3276 if obj.default is None:
3277 optional = optional_initial if optional is None else optional
3278 optional = False if optional is None else optional
3281 self.assertEqual(obj.optional, optional)
3282 self.assertEqual(obj.specs, dict(schema_initial))
3284 @given(enumerated_values_strategy())
3285 def test_copy(self, values):
3286 schema_input, value, impl, expl, default, optional, _decoded = values
3288 class E(Enumerated):
3289 schema = schema_input
3299 for copy_func in copy_funcs:
3300 obj_copied = copy_func(obj)
3301 self.assert_copied_basic_fields(obj, obj_copied)
3302 self.assertEqual(obj.specs, obj_copied.specs)
3304 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3305 @given(data_strategy())
3306 def test_symmetric(self, d):
3307 schema_input, _, _, _, default, optional, _decoded = d.draw(
3308 enumerated_values_strategy(),
3310 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3311 offset = d.draw(integers(min_value=0))
3312 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3313 tail_junk = d.draw(binary(max_size=5))
3314 decode_path = d.draw(decode_path_strat)
3316 class E(Enumerated):
3317 schema = schema_input
3326 pprint(obj, big_blobs=True, with_decode_path=True)
3327 self.assertFalse(obj.expled)
3328 obj_encoded = obj.encode()
3329 obj_expled = obj(value, expl=tag_expl)
3330 self.assertTrue(obj_expled.expled)
3332 list(obj_expled.pps())
3333 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3334 obj_expled_encoded = obj_expled.encode()
3335 ctx_copied = deepcopy(ctx_dummy)
3336 obj_decoded, tail = obj_expled.decode(
3337 obj_expled_encoded + tail_junk,
3341 self.assertDictEqual(ctx_copied, ctx_dummy)
3343 list(obj_decoded.pps())
3344 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3345 self.assertEqual(tail, tail_junk)
3346 self.assertEqual(obj_decoded, obj_expled)
3347 self.assertNotEqual(obj_decoded, obj)
3348 self.assertEqual(int(obj_decoded), int(obj_expled))
3349 self.assertEqual(int(obj_decoded), int(obj))
3350 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3351 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3352 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3354 obj_decoded.expl_llen,
3355 len(len_encode(len(obj_encoded))),
3357 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3358 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3361 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3363 self.assertEqual(obj_decoded.expl_offset, offset)
3364 assert_exceeding_data(
3366 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3370 evgens = list(obj_expled.decode_evgen(
3371 obj_expled_encoded + tail_junk,
3373 decode_path=decode_path,
3376 self.assertEqual(len(evgens), 1)
3377 _decode_path, obj, tail = evgens[0]
3378 self.assertSequenceEqual(tail, tail_junk)
3379 self.assertEqual(_decode_path, decode_path)
3380 self.assertEqual(obj, obj_decoded)
3381 self.assertEqual(obj.expl_offset, offset)
3387 def string_values_strategy(draw, alphabet, do_expl=False):
3388 bound_min, bound_max = sorted(draw(sets(
3389 integers(min_value=0, max_value=1 << 7),
3393 value = draw(one_of(
3395 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3397 default = draw(one_of(
3399 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3402 if draw(booleans()):
3403 bounds = (bound_min, bound_max)
3407 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3409 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3410 optional = draw(one_of(none(), booleans()))
3412 draw(integers(min_value=0)),
3413 draw(integers(min_value=0)),
3414 draw(integers(min_value=0)),
3416 return (value, bounds, impl, expl, default, optional, _decoded)
3419 class StringMixin(object):
3420 def test_invalid_value_type(self):
3421 with self.assertRaises(InvalidValueType) as err:
3422 self.base_klass((1, 2))
3425 def text_alphabet(self):
3426 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3427 return printable + whitespace
3431 def test_optional(self, optional):
3432 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3433 self.assertTrue(obj.optional)
3435 @given(data_strategy())
3436 def test_ready(self, d):
3437 obj = self.base_klass()
3438 self.assertFalse(obj.ready)
3441 pprint(obj, big_blobs=True, with_decode_path=True)
3443 with self.assertRaises(ObjNotReady) as err:
3446 value = d.draw(text(alphabet=self.text_alphabet()))
3447 obj = self.base_klass(value)
3448 self.assertTrue(obj.ready)
3451 pprint(obj, big_blobs=True, with_decode_path=True)
3454 @given(data_strategy())
3455 def test_comparison(self, d):
3456 value1 = d.draw(text(alphabet=self.text_alphabet()))
3457 value2 = d.draw(text(alphabet=self.text_alphabet()))
3458 tag1 = d.draw(binary(min_size=1))
3459 tag2 = d.draw(binary(min_size=1))
3460 obj1 = self.base_klass(value1)
3461 obj2 = self.base_klass(value2)
3462 self.assertEqual(obj1 == obj2, value1 == value2)
3463 self.assertEqual(obj1 != obj2, value1 != value2)
3464 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3465 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3466 obj1 = self.base_klass(value1, impl=tag1)
3467 obj2 = self.base_klass(value1, impl=tag2)
3468 self.assertEqual(obj1 == obj2, tag1 == tag2)
3469 self.assertEqual(obj1 != obj2, tag1 != tag2)
3471 @given(data_strategy())
3472 def test_bounds_satisfied(self, d):
3473 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3474 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3475 value = d.draw(text(
3476 alphabet=self.text_alphabet(),
3480 self.base_klass(value=value, bounds=(bound_min, bound_max))
3482 @given(data_strategy())
3483 def test_bounds_unsatisfied(self, d):
3484 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3485 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3486 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3487 with self.assertRaises(BoundsError) as err:
3488 self.base_klass(value=value, bounds=(bound_min, bound_max))
3490 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3491 self.base_klass(bounds=(bound_min, bound_max)).decode(
3492 self.base_klass(value).encode()
3495 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3496 with self.assertRaises(BoundsError) as err:
3497 self.base_klass(value=value, bounds=(bound_min, bound_max))
3499 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3500 self.base_klass(bounds=(bound_min, bound_max)).decode(
3501 self.base_klass(value).encode()
3505 @given(data_strategy())
3506 def test_call(self, d):
3515 ) = d.draw(string_values_strategy(self.text_alphabet()))
3516 obj_initial = self.base_klass(
3522 optional_initial or False,
3533 ) = d.draw(string_values_strategy(
3534 self.text_alphabet(),
3535 do_expl=impl_initial is None,
3537 if (default is None) and (obj_initial.default is not None):
3540 (bounds is None) and
3541 (value is not None) and
3542 (bounds_initial is not None) and
3543 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3547 (bounds is None) and
3548 (default is not None) and
3549 (bounds_initial is not None) and
3550 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3553 obj = obj_initial(value, bounds, impl, expl, default, optional)
3555 value_expected = default if value is None else value
3557 default_initial if value_expected is None
3560 self.assertEqual(obj, value_expected)
3561 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3562 self.assertEqual(obj.expl_tag, expl or expl_initial)
3565 default_initial if default is None else default,
3567 if obj.default is None:
3568 optional = optional_initial if optional is None else optional
3569 optional = False if optional is None else optional
3572 self.assertEqual(obj.optional, optional)
3574 (obj._bound_min, obj._bound_max),
3575 bounds or bounds_initial or (0, float("+inf")),
3578 @given(data_strategy())
3579 def test_copy(self, d):
3580 values = d.draw(string_values_strategy(self.text_alphabet()))
3581 obj = self.base_klass(*values)
3582 for copy_func in copy_funcs:
3583 obj_copied = copy_func(obj)
3584 self.assert_copied_basic_fields(obj, obj_copied)
3585 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3586 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3587 self.assertEqual(obj._value, obj_copied._value)
3589 @given(data_strategy())
3590 def test_stripped(self, d):
3591 value = d.draw(text(alphabet=self.text_alphabet()))
3592 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3593 obj = self.base_klass(value, impl=tag_impl)
3594 with self.assertRaises(NotEnoughData):
3595 obj.decode(obj.encode()[:-1])
3597 @given(data_strategy())
3598 def test_stripped_expl(self, d):
3599 value = d.draw(text(alphabet=self.text_alphabet()))
3600 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3601 obj = self.base_klass(value, expl=tag_expl)
3602 with self.assertRaises(NotEnoughData):
3603 obj.decode(obj.encode()[:-1])
3606 integers(min_value=31),
3607 integers(min_value=0),
3610 def test_bad_tag(self, tag, offset, decode_path):
3611 with self.assertRaises(DecodeError) as err:
3612 self.base_klass().decode(
3613 tag_encode(tag)[:-1],
3615 decode_path=decode_path,
3618 self.assertEqual(err.exception.offset, offset)
3619 self.assertEqual(err.exception.decode_path, decode_path)
3622 integers(min_value=128),
3623 integers(min_value=0),
3626 def test_bad_len(self, l, offset, decode_path):
3627 with self.assertRaises(DecodeError) as err:
3628 self.base_klass().decode(
3629 self.base_klass.tag_default + len_encode(l)[:-1],
3631 decode_path=decode_path,
3634 self.assertEqual(err.exception.offset, offset)
3635 self.assertEqual(err.exception.decode_path, decode_path)
3638 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3639 integers(min_value=0),
3642 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3643 value, bound_min = list(sorted(ints))
3645 class String(self.base_klass):
3646 # Multiply this value by four, to satisfy UTF-32 bounds
3647 # (4 bytes per character) validation
3648 bounds = (bound_min * 4, bound_min * 4)
3649 with self.assertRaises(DecodeError) as err:
3651 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3653 decode_path=decode_path,
3656 self.assertEqual(err.exception.offset, offset)
3657 self.assertEqual(err.exception.decode_path, decode_path)
3659 @given(data_strategy())
3660 def test_symmetric(self, d):
3661 values = d.draw(string_values_strategy(self.text_alphabet()))
3662 value = d.draw(text(alphabet=self.text_alphabet()))
3663 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3664 offset = d.draw(integers(min_value=0))
3665 tail_junk = d.draw(binary(max_size=5))
3666 decode_path = d.draw(decode_path_strat)
3667 _, _, _, _, default, optional, _decoded = values
3668 obj = self.base_klass(
3676 pprint(obj, big_blobs=True, with_decode_path=True)
3677 self.assertFalse(obj.expled)
3678 obj_encoded = obj.encode()
3679 obj_expled = obj(value, expl=tag_expl)
3680 self.assertTrue(obj_expled.expled)
3682 list(obj_expled.pps())
3683 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3684 obj_expled_encoded = obj_expled.encode()
3685 ctx_copied = deepcopy(ctx_dummy)
3686 obj_decoded, tail = obj_expled.decode(
3687 obj_expled_encoded + tail_junk,
3691 self.assertDictEqual(ctx_copied, ctx_dummy)
3693 list(obj_decoded.pps())
3694 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3695 self.assertEqual(tail, tail_junk)
3696 self.assertEqual(obj_decoded, obj_expled)
3697 self.assertNotEqual(obj_decoded, obj)
3698 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3699 self.assertEqual(bytes(obj_decoded), bytes(obj))
3700 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3701 self.assertEqual(text_type(obj_decoded), text_type(obj))
3702 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3703 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3704 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3706 obj_decoded.expl_llen,
3707 len(len_encode(len(obj_encoded))),
3709 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3710 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3713 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3715 self.assertEqual(obj_decoded.expl_offset, offset)
3716 assert_exceeding_data(
3718 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3722 evgens = list(obj_expled.decode_evgen(
3723 obj_expled_encoded + tail_junk,
3725 decode_path=decode_path,
3728 self.assertEqual(len(evgens), 1)
3729 _decode_path, obj, tail = evgens[0]
3730 self.assertSequenceEqual(tail, tail_junk)
3731 self.assertEqual(_decode_path, decode_path)
3732 if not getattr(self, "evgen_mode_skip_value", True):
3733 self.assertEqual(obj, obj_decoded)
3734 self.assertEqual(obj.expl_offset, offset)
3739 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3740 base_klass = UTF8String
3743 cyrillic_letters = text(
3744 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3750 class UnicodeDecodeErrorMixin(object):
3751 @given(cyrillic_letters)
3752 def test_unicode_decode_error(self, cyrillic_text):
3753 with self.assertRaises(DecodeError):
3754 self.base_klass(cyrillic_text)
3757 class TestNumericString(StringMixin, CommonMixin, TestCase):
3758 base_klass = NumericString
3760 def text_alphabet(self):
3763 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3764 def test_non_numeric(self, non_numeric_text):
3765 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3766 self.base_klass(non_numeric_text)
3769 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3770 integers(min_value=0),
3773 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3774 value, bound_min = list(sorted(ints))
3776 class String(self.base_klass):
3777 bounds = (bound_min, bound_min)
3778 with self.assertRaises(DecodeError) as err:
3780 self.base_klass(b"1" * value).encode(),
3782 decode_path=decode_path,
3785 self.assertEqual(err.exception.offset, offset)
3786 self.assertEqual(err.exception.decode_path, decode_path)
3789 class TestPrintableString(
3790 UnicodeDecodeErrorMixin,
3795 base_klass = PrintableString
3797 def text_alphabet(self):
3798 return ascii_letters + digits + " '()+,-./:=?"
3800 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3801 def test_non_printable(self, non_printable_text):
3802 with assertRaisesRegex(self, DecodeError, "non-printable"):
3803 self.base_klass(non_printable_text)
3806 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3807 integers(min_value=0),
3810 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3811 value, bound_min = list(sorted(ints))
3813 class String(self.base_klass):
3814 bounds = (bound_min, bound_min)
3815 with self.assertRaises(DecodeError) as err:
3817 self.base_klass(b"1" * value).encode(),
3819 decode_path=decode_path,
3822 self.assertEqual(err.exception.offset, offset)
3823 self.assertEqual(err.exception.decode_path, decode_path)
3825 def test_allowable_invalid_chars(self):
3827 ("*", {"allow_asterisk": True}),
3828 ("&", {"allow_ampersand": True}),
3829 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3832 obj = self.base_klass(s)
3833 for prop in kwargs.keys():
3834 self.assertFalse(getattr(obj, prop))
3836 with assertRaisesRegex(self, DecodeError, "non-printable"):
3838 self.base_klass(s, **kwargs)
3839 klass = self.base_klass(**kwargs)
3841 for prop in kwargs.keys():
3842 self.assertTrue(getattr(obj, prop))
3845 for prop in kwargs.keys():
3846 self.assertTrue(getattr(obj, prop))
3849 class TestTeletexString(
3850 UnicodeDecodeErrorMixin,
3855 base_klass = TeletexString
3858 class TestVideotexString(
3859 UnicodeDecodeErrorMixin,
3864 base_klass = VideotexString
3867 class TestIA5String(
3868 UnicodeDecodeErrorMixin,
3873 base_klass = IA5String
3876 class TestGraphicString(
3877 UnicodeDecodeErrorMixin,
3882 base_klass = GraphicString
3885 class TestVisibleString(
3886 UnicodeDecodeErrorMixin,
3891 base_klass = VisibleString
3893 def test_x690_vector(self):
3894 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3895 self.assertSequenceEqual(tail, b"")
3896 self.assertEqual(str(obj), "Jones")
3897 self.assertFalse(obj.ber_encoded)
3898 self.assertFalse(obj.lenindef)
3899 self.assertFalse(obj.bered)
3901 obj, tail = VisibleString().decode(
3902 hexdec("3A0904034A6F6E04026573"),
3903 ctx={"bered": True},
3905 self.assertSequenceEqual(tail, b"")
3906 self.assertEqual(str(obj), "Jones")
3907 self.assertTrue(obj.ber_encoded)
3908 self.assertFalse(obj.lenindef)
3909 self.assertTrue(obj.bered)
3911 self.assertTrue(obj.ber_encoded)
3912 self.assertFalse(obj.lenindef)
3913 self.assertTrue(obj.bered)
3915 obj, tail = VisibleString().decode(
3916 hexdec("3A8004034A6F6E040265730000"),
3917 ctx={"bered": True},
3919 self.assertSequenceEqual(tail, b"")
3920 self.assertEqual(str(obj), "Jones")
3921 self.assertTrue(obj.ber_encoded)
3922 self.assertTrue(obj.lenindef)
3923 self.assertTrue(obj.bered)
3925 self.assertTrue(obj.ber_encoded)
3926 self.assertTrue(obj.lenindef)
3927 self.assertTrue(obj.bered)
3930 class TestGeneralString(
3931 UnicodeDecodeErrorMixin,
3936 base_klass = GeneralString
3939 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3940 base_klass = UniversalString
3943 class TestBMPString(StringMixin, CommonMixin, TestCase):
3944 base_klass = BMPString
3948 def generalized_time_values_strategy(
3956 if draw(booleans()):
3957 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3959 value = value.replace(microsecond=0)
3961 if draw(booleans()):
3962 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3964 default = default.replace(microsecond=0)
3968 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3970 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3971 optional = draw(one_of(none(), booleans()))
3973 draw(integers(min_value=0)),
3974 draw(integers(min_value=0)),
3975 draw(integers(min_value=0)),
3977 return (value, impl, expl, default, optional, _decoded)
3980 class TimeMixin(object):
3981 def test_invalid_value_type(self):
3982 with self.assertRaises(InvalidValueType) as err:
3983 self.base_klass(datetime.now().timetuple())
3986 @given(data_strategy())
3987 def test_optional(self, d):
3988 default = d.draw(datetimes(
3989 min_value=self.min_datetime,
3990 max_value=self.max_datetime,
3992 optional = d.draw(booleans())
3993 obj = self.base_klass(default=default, optional=optional)
3994 self.assertTrue(obj.optional)
3996 @given(data_strategy())
3997 def test_ready(self, d):
3998 obj = self.base_klass()
3999 self.assertFalse(obj.ready)
4002 pprint(obj, big_blobs=True, with_decode_path=True)
4003 with self.assertRaises(ObjNotReady) as err:
4006 value = d.draw(datetimes(
4007 min_value=self.min_datetime,
4008 max_value=self.max_datetime,
4010 obj = self.base_klass(value)
4011 self.assertTrue(obj.ready)
4014 pprint(obj, big_blobs=True, with_decode_path=True)
4016 @given(data_strategy())
4017 def test_comparison(self, d):
4018 value1 = d.draw(datetimes(
4019 min_value=self.min_datetime,
4020 max_value=self.max_datetime,
4022 value2 = d.draw(datetimes(
4023 min_value=self.min_datetime,
4024 max_value=self.max_datetime,
4026 tag1 = d.draw(binary(min_size=1))
4027 tag2 = d.draw(binary(min_size=1))
4029 value1 = value1.replace(microsecond=0)
4030 value2 = value2.replace(microsecond=0)
4031 obj1 = self.base_klass(value1)
4032 obj2 = self.base_klass(value2)
4033 self.assertEqual(obj1 == obj2, value1 == value2)
4034 self.assertEqual(obj1 != obj2, value1 != value2)
4035 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
4036 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4037 obj1 = self.base_klass(value1, impl=tag1)
4038 obj2 = self.base_klass(value1, impl=tag2)
4039 self.assertEqual(obj1 == obj2, tag1 == tag2)
4040 self.assertEqual(obj1 != obj2, tag1 != tag2)
4042 @given(data_strategy())
4043 def test_call(self, d):
4051 ) = d.draw(generalized_time_values_strategy(
4052 min_datetime=self.min_datetime,
4053 max_datetime=self.max_datetime,
4054 omit_ms=self.omit_ms,
4056 obj_initial = self.base_klass(
4057 value=value_initial,
4060 default=default_initial,
4061 optional=optional_initial or False,
4062 _decoded=_decoded_initial,
4071 ) = d.draw(generalized_time_values_strategy(
4072 min_datetime=self.min_datetime,
4073 max_datetime=self.max_datetime,
4074 omit_ms=self.omit_ms,
4075 do_expl=impl_initial is None,
4085 value_expected = default if value is None else value
4087 default_initial if value_expected is None
4090 self.assertEqual(obj, value_expected)
4091 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4092 self.assertEqual(obj.expl_tag, expl or expl_initial)
4095 default_initial if default is None else default,
4097 if obj.default is None:
4098 optional = optional_initial if optional is None else optional
4099 optional = False if optional is None else optional
4102 self.assertEqual(obj.optional, optional)
4104 @given(data_strategy())
4105 def test_copy(self, d):
4106 values = d.draw(generalized_time_values_strategy(
4107 min_datetime=self.min_datetime,
4108 max_datetime=self.max_datetime,
4110 obj = self.base_klass(*values)
4111 for copy_func in copy_funcs:
4112 obj_copied = copy_func(obj)
4113 self.assert_copied_basic_fields(obj, obj_copied)
4114 self.assertEqual(obj._value, obj_copied._value)
4116 @given(data_strategy())
4117 def test_stripped(self, d):
4118 value = d.draw(datetimes(
4119 min_value=self.min_datetime,
4120 max_value=self.max_datetime,
4122 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4123 obj = self.base_klass(value, impl=tag_impl)
4124 with self.assertRaises(NotEnoughData):
4125 obj.decode(obj.encode()[:-1])
4127 @given(data_strategy())
4128 def test_stripped_expl(self, d):
4129 value = d.draw(datetimes(
4130 min_value=self.min_datetime,
4131 max_value=self.max_datetime,
4133 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4134 obj = self.base_klass(value, expl=tag_expl)
4135 with self.assertRaises(NotEnoughData):
4136 obj.decode(obj.encode()[:-1])
4138 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4139 @given(data_strategy())
4140 def test_symmetric(self, d):
4141 values = d.draw(generalized_time_values_strategy(
4142 min_datetime=self.min_datetime,
4143 max_datetime=self.max_datetime,
4145 value = d.draw(datetimes(
4146 min_value=self.min_datetime,
4147 max_value=self.max_datetime,
4149 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4150 offset = d.draw(integers(min_value=0))
4151 tail_junk = d.draw(binary(max_size=5))
4152 _, _, _, default, optional, _decoded = values
4153 obj = self.base_klass(
4161 pprint(obj, big_blobs=True, with_decode_path=True)
4162 self.assertFalse(obj.expled)
4163 obj_encoded = obj.encode()
4164 self.additional_symmetric_check(value, obj_encoded)
4165 obj_expled = obj(value, expl=tag_expl)
4166 self.assertTrue(obj_expled.expled)
4168 list(obj_expled.pps())
4169 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4170 obj_expled_encoded = obj_expled.encode()
4171 ctx_copied = deepcopy(ctx_dummy)
4172 obj_decoded, tail = obj_expled.decode(
4173 obj_expled_encoded + tail_junk,
4177 self.assertDictEqual(ctx_copied, ctx_dummy)
4179 list(obj_decoded.pps())
4180 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4181 self.assertEqual(tail, tail_junk)
4182 self.assertEqual(obj_decoded, obj_expled)
4183 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
4184 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
4185 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4186 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4187 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4189 obj_decoded.expl_llen,
4190 len(len_encode(len(obj_encoded))),
4192 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4193 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4196 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4198 self.assertEqual(obj_decoded.expl_offset, offset)
4199 assert_exceeding_data(
4201 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4206 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
4207 base_klass = GeneralizedTime
4209 min_datetime = datetime(1900, 1, 1)
4210 max_datetime = datetime(9999, 12, 31)
4211 evgen_mode_skip_value = False
4213 def additional_symmetric_check(self, value, obj_encoded):
4214 if value.microsecond > 0:
4215 self.assertFalse(obj_encoded.endswith(b"0Z"))
4217 def test_repr_not_ready(self):
4218 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4219 repr(GeneralizedTime())
4221 def test_x690_vector_valid(self):
4225 b"19920722132100.3Z",
4227 GeneralizedTime(data)
4229 def test_x690_vector_invalid(self):
4232 b"19920622123421.0Z",
4233 b"19920722132100.30Z",
4235 with self.assertRaises(DecodeError) as err:
4236 GeneralizedTime(data)
4239 def test_go_vectors_invalid(self):
4251 b"-20100102030410Z",
4252 b"2010-0102030410Z",
4253 b"2010-0002030410Z",
4254 b"201001-02030410Z",
4255 b"20100102-030410Z",
4256 b"2010010203-0410Z",
4257 b"201001020304-10Z",
4258 # These ones are INVALID in *DER*, but accepted
4259 # by Go's encoding/asn1
4260 b"20100102030405+0607",
4261 b"20100102030405-0607",
4263 with self.assertRaises(DecodeError) as err:
4264 GeneralizedTime(data)
4267 def test_go_vectors_valid(self):
4269 GeneralizedTime(b"20100102030405Z").todatetime(),
4270 datetime(2010, 1, 2, 3, 4, 5, 0),
4273 def test_go_vectors_valid_ber(self):
4275 b"20100102030405+0607",
4276 b"20100102030405-0607",
4278 GeneralizedTime(data, ctx={"bered": True})
4280 def test_utc_offsets(self):
4281 """Some know equal UTC offsets
4284 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4288 "200101011130-0700",
4289 "200101011500-03:30",
4292 self.assertEqual(dts[0], dts[1])
4293 self.assertEqual(dts[0], dts[2])
4294 self.assertEqual(dts[0], dts[3])
4296 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4297 @given(data_strategy())
4298 def test_valid_ber(self, d):
4299 min_year = 1901 if PY2 else 2
4300 year = d.draw(integers(min_value=min_year, max_value=9999))
4301 month = d.draw(integers(min_value=1, max_value=12))
4302 day = d.draw(integers(min_value=1, max_value=28))
4303 hours = d.draw(integers(min_value=0, max_value=23))
4304 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4305 dt = datetime(year, month, day, hours)
4306 fractions_sign = d.draw(sampled_from(" ,."))
4308 if fractions_sign != " ":
4309 fractions = random()
4310 if d.draw(booleans()):
4311 minutes = d.draw(integers(min_value=0, max_value=59))
4312 data += "%02d" % minutes
4313 dt += timedelta(seconds=60 * minutes)
4314 if d.draw(booleans()):
4315 seconds = d.draw(integers(min_value=0, max_value=59))
4316 data += "%02d" % seconds
4317 dt += timedelta(seconds=seconds)
4318 if fractions is not None:
4319 dt += timedelta(microseconds=10**6 * fractions)
4320 elif fractions is not None:
4321 dt += timedelta(seconds=60 * fractions)
4322 elif fractions is not None:
4323 dt += timedelta(seconds=3600 * fractions)
4324 if fractions is not None:
4325 data += fractions_sign + str(fractions)[2:]
4326 if d.draw(booleans()):
4328 elif d.draw(booleans()):
4329 offset_hour = d.draw(integers(min_value=0, max_value=13))
4331 if d.draw(booleans()):
4336 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4337 data += "%02d" % offset_hour
4338 minutes_separator = d.draw(sampled_from((None, "", ":")))
4339 if minutes_separator is not None:
4340 offset_minute = d.draw(integers(min_value=0, max_value=59))
4341 dt -= timedelta(seconds=sign * 60 * offset_minute)
4342 data += "%s%02d" % (minutes_separator, offset_minute)
4343 data = data.encode("ascii")
4344 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4346 GeneralizedTime().decod(data_der)
4351 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4354 mktime(obj.todatetime().timetuple()),
4355 mktime(dt.timetuple()),
4358 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4359 self.assertEqual(obj.ber_encoded, not dered)
4360 self.assertEqual(obj.bered, not dered)
4361 self.assertEqual(obj.ber_raw, None if dered else data)
4362 self.assertEqual(obj.encode() == data_der, dered)
4367 def test_invalid_ber(self):
4369 # "00010203040506.07",
4370 "-0010203040506.07",
4371 "0001-203040506.07",
4372 "000102-3040506.07",
4373 "00010203-40506.07",
4374 "0001020304-506.07",
4375 "000102030405-6.07",
4376 "00010203040506.-7",
4377 "+0010203040506.07",
4378 "0001+203040506.07",
4379 "000102+3040506.07",
4380 "00010203+40506.07",
4381 "0001020304+506.07",
4382 "000102030405+6.07",
4383 "00010203040506.+7",
4384 " 0010203040506.07",
4385 "0001 203040506.07",
4386 "000102 3040506.07",
4387 "00010203 40506.07",
4388 "0001020304 506.07",
4389 "000102030405 6.07",
4390 "00010203040506. 7",
4391 "001 0203040506.07",
4392 "00012 03040506.07",
4393 "0001023 040506.07",
4394 "000102034 0506.07",
4395 "00010203045 06.07",
4396 "0001020304056 .07",
4397 "00010203040506.7 ",
4477 "00010203040506.07+15",
4478 "00010203040506.07-15",
4479 "00010203040506.07+14:60",
4480 "00010203040506.07+1460",
4481 "00010203040506.07-1460",
4482 "00010203040506.07+00:60",
4483 "00010203040506.07-00:60",
4485 "00010203040506+15",
4486 "00010203040506-15",
4487 "00010203040506+14:60",
4488 "00010203040506+1460",
4489 "00010203040506-1460",
4490 "00010203040506+00:60",
4491 "00010203040506-00:60",
4500 with self.assertRaises(DecodeError):
4501 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4502 data = data.replace(".", ",")
4503 with self.assertRaises(DecodeError):
4504 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4508 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4509 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4511 binary(min_size=1, max_size=1),
4513 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4514 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4517 def test_junk(self, part0, part1, part2):
4518 junk = part0 + part1 + part2
4519 assume(not (set(junk) <= set(digits.encode("ascii"))))
4520 with self.assertRaises(DecodeError):
4521 GeneralizedTime().decode(
4522 GeneralizedTime.tag_default +
4523 len_encode(len(junk)) +
4529 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4530 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4532 binary(min_size=1, max_size=1),
4534 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4535 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4538 def test_junk_dm(self, part0, part1, part2):
4539 junk = part0 + part1 + part2
4540 assume(not (set(junk) <= set(digits.encode("ascii"))))
4541 with self.assertRaises(DecodeError):
4542 GeneralizedTime().decode(
4543 GeneralizedTime.tag_default +
4544 len_encode(len(junk)) +
4548 def test_ns_fractions(self):
4549 GeneralizedTime(b"20010101000000.000001Z")
4550 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4551 GeneralizedTime(b"20010101000000.0000001Z")
4553 def test_non_pure_integers(self):
4555 # b"20000102030405Z,
4562 b"20000102030405.+6Z",
4563 b"20000102030405.-6Z",
4570 b"20000102030405._6Z",
4571 b"20000102030405.6_Z",
4578 b"20000102030405. 6Z",
4585 b"20000102030405.6 Z",
4587 with self.assertRaises(DecodeError):
4588 GeneralizedTime(data)
4591 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4592 base_klass = UTCTime
4594 min_datetime = datetime(2000, 1, 1)
4595 max_datetime = datetime(2049, 12, 31)
4596 evgen_mode_skip_value = False
4598 def additional_symmetric_check(self, value, obj_encoded):
4601 def test_repr_not_ready(self):
4602 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4605 def test_x690_vector_valid(self):
4613 def test_x690_vector_invalid(self):
4618 with self.assertRaises(DecodeError) as err:
4622 def test_go_vectors_invalid(self):
4648 # These ones are INVALID in *DER*, but accepted
4649 # by Go's encoding/asn1
4650 b"910506164540-0700",
4651 b"910506164540+0730",
4655 with self.assertRaises(DecodeError) as err:
4659 def test_go_vectors_valid(self):
4661 UTCTime(b"910506234540Z").todatetime(),
4662 datetime(1991, 5, 6, 23, 45, 40, 0),
4665 def test_non_pure_integers(self):
4694 with self.assertRaises(DecodeError):
4697 def test_x680_vector_valid_ber(self):
4699 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4700 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4701 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4702 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4704 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4705 obj = UTCTime().decod(data_der, ctx={"bered": True})
4706 self.assertEqual(obj, dt)
4707 self.assertEqual(obj.todatetime(), dt)
4708 self.assertTrue(obj.ber_encoded)
4709 self.assertTrue(obj.bered)
4710 self.assertEqual(obj.ber_raw, data)
4711 self.assertNotEqual(obj.encode(), data_der)
4714 def test_go_vectors_valid_ber(self):
4716 b"910506164540-0700",
4717 b"910506164540+0730",
4721 data = UTCTime.tag_default + len_encode(len(data)) + data
4722 obj = UTCTime().decod(data, ctx={"bered": True})
4723 self.assertTrue(obj.ber_encoded)
4724 self.assertTrue(obj.bered)
4725 self.assertNotEqual(obj.encode(), data)
4728 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4729 @given(data_strategy())
4730 def test_valid_ber(self, d):
4731 year = d.draw(integers(min_value=0, max_value=99))
4732 month = d.draw(integers(min_value=1, max_value=12))
4733 day = d.draw(integers(min_value=1, max_value=28))
4734 hours = d.draw(integers(min_value=0, max_value=23))
4735 minute = d.draw(integers(min_value=0, max_value=59))
4736 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4738 year + (2000 if year < 50 else 1900),
4745 if d.draw(booleans()):
4747 seconds = d.draw(integers(min_value=0, max_value=59))
4748 data += "%02d" % seconds
4749 dt += timedelta(seconds=seconds)
4750 if d.draw(booleans()):
4754 offset_hour = d.draw(integers(min_value=0, max_value=13))
4755 offset_minute = d.draw(integers(min_value=0, max_value=59))
4756 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4757 if d.draw(booleans()):
4763 data += "%02d%02d" % (offset_hour, offset_minute)
4764 data = data.encode("ascii")
4765 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4766 obj = UTCTime().decod(data_der, ctx={"bered": True})
4767 self.assertEqual(obj, dt)
4768 self.assertEqual(obj.todatetime(), dt)
4769 self.assertEqual(obj.ber_encoded, not dered)
4770 self.assertEqual(obj.bered, not dered)
4771 self.assertEqual(obj.ber_raw, None if dered else data)
4772 self.assertEqual(obj.encode() == data_der, dered)
4777 def test_invalid_ber(self):
4818 b"0001020304+0000Z",
4827 with self.assertRaises(DecodeError):
4828 UTCTime(data, ctx={"bered": True})
4829 data = data[:8] + data[8+2:]
4830 with self.assertRaises(DecodeError):
4831 UTCTime(data, ctx={"bered": True})
4876 b"000102030405+000",
4877 b"000102030405+000Z",
4878 b"000102030405+0000Z",
4879 b"000102030405+-101",
4880 b"000102030405+01-1",
4881 b"000102030405+0060",
4882 b"000102030405+1401",
4883 b"500101000002+0003",
4885 with self.assertRaises(DecodeError):
4886 UTCTime(data, ctx={"bered": True})
4888 @given(integers(min_value=0, max_value=49))
4889 def test_pre50(self, year):
4891 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4895 @given(integers(min_value=50, max_value=99))
4896 def test_post50(self, year):
4898 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4904 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4905 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4907 binary(min_size=1, max_size=1),
4909 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4910 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4913 def test_junk(self, part0, part1, part2):
4914 junk = part0 + part1 + part2
4915 assume(not (set(junk) <= set(digits.encode("ascii"))))
4916 with self.assertRaises(DecodeError):
4918 UTCTime.tag_default +
4919 len_encode(len(junk)) +
4925 def tlv_value_strategy(draw):
4926 tag_num = draw(integers(min_value=1))
4927 data = draw(binary())
4928 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
4932 def any_values_strategy(draw, do_expl=False):
4933 value = draw(one_of(none(), tlv_value_strategy()))
4936 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4937 optional = draw(one_of(none(), booleans()))
4939 draw(integers(min_value=0)),
4940 draw(integers(min_value=0)),
4941 draw(integers(min_value=0)),
4943 return (value, expl, optional, _decoded)
4946 class AnyInherited(Any):
4950 class TestAny(CommonMixin, TestCase):
4953 def test_invalid_value_type(self):
4954 with self.assertRaises(InvalidValueType) as err:
4959 def test_optional(self, optional):
4960 obj = Any(optional=optional)
4961 self.assertEqual(obj.optional, optional)
4963 @given(tlv_value_strategy())
4964 def test_ready(self, value):
4966 self.assertFalse(obj.ready)
4969 pprint(obj, big_blobs=True, with_decode_path=True)
4970 with self.assertRaises(ObjNotReady) as err:
4974 self.assertTrue(obj.ready)
4977 pprint(obj, big_blobs=True, with_decode_path=True)
4980 def test_basic(self, value):
4981 integer_encoded = Integer(value).encode()
4983 Any(integer_encoded),
4984 Any(Integer(value)),
4985 Any(Any(Integer(value))),
4987 self.assertSequenceEqual(bytes(obj), integer_encoded)
4989 obj.decode(obj.encode())[0].vlen,
4990 len(integer_encoded),
4994 pprint(obj, big_blobs=True, with_decode_path=True)
4995 self.assertSequenceEqual(obj.encode(), integer_encoded)
4997 @given(tlv_value_strategy(), tlv_value_strategy())
4998 def test_comparison(self, value1, value2):
4999 for klass in (Any, AnyInherited):
5000 obj1 = klass(value1)
5001 obj2 = klass(value2)
5002 self.assertEqual(obj1 == obj2, value1 == value2)
5003 self.assertEqual(obj1 != obj2, value1 != value2)
5004 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
5006 @given(data_strategy())
5007 def test_call(self, d):
5008 for klass in (Any, AnyInherited):
5014 ) = d.draw(any_values_strategy())
5015 obj_initial = klass(
5018 optional_initial or False,
5026 ) = d.draw(any_values_strategy(do_expl=True))
5027 obj = obj_initial(value, expl, optional)
5029 value_expected = None if value is None else value
5030 self.assertEqual(obj, value_expected)
5031 self.assertEqual(obj.expl_tag, expl or expl_initial)
5032 if obj.default is None:
5033 optional = optional_initial if optional is None else optional
5034 optional = False if optional is None else optional
5035 self.assertEqual(obj.optional, optional)
5037 def test_simultaneous_impl_expl(self):
5038 # override it, as Any does not have implicit tag
5041 def test_decoded(self):
5042 # override it, as Any does not have implicit tag
5045 @given(any_values_strategy())
5046 def test_copy(self, values):
5047 for klass in (Any, AnyInherited):
5048 obj = klass(*values)
5049 for copy_func in copy_funcs:
5050 obj_copied = copy_func(obj)
5051 self.assert_copied_basic_fields(obj, obj_copied)
5052 self.assertEqual(obj._value, obj_copied._value)
5054 @given(binary().map(OctetString))
5055 def test_stripped(self, value):
5057 with self.assertRaises(NotEnoughData):
5058 obj.decode(obj.encode()[:-1])
5061 tlv_value_strategy(),
5062 integers(min_value=1).map(tag_ctxc),
5064 def test_stripped_expl(self, value, tag_expl):
5065 obj = Any(value, expl=tag_expl)
5066 with self.assertRaises(NotEnoughData):
5067 obj.decode(obj.encode()[:-1])
5070 integers(min_value=31),
5071 integers(min_value=0),
5074 def test_bad_tag(self, tag, offset, decode_path):
5075 with self.assertRaises(DecodeError) as err:
5077 tag_encode(tag)[:-1],
5079 decode_path=decode_path,
5082 self.assertEqual(err.exception.offset, offset)
5083 self.assertEqual(err.exception.decode_path, decode_path)
5086 integers(min_value=128),
5087 integers(min_value=0),
5090 def test_bad_len(self, l, offset, decode_path):
5091 with self.assertRaises(DecodeError) as err:
5093 Any.tag_default + len_encode(l)[:-1],
5095 decode_path=decode_path,
5098 self.assertEqual(err.exception.offset, offset)
5099 self.assertEqual(err.exception.decode_path, decode_path)
5101 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5103 any_values_strategy(),
5104 integers().map(lambda x: Integer(x).encode()),
5105 integers(min_value=1).map(tag_ctxc),
5106 integers(min_value=0),
5110 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
5111 for klass in (Any, AnyInherited):
5112 _, _, optional, _decoded = values
5113 obj = klass(value=value, optional=optional, _decoded=_decoded)
5116 pprint(obj, big_blobs=True, with_decode_path=True)
5117 self.assertFalse(obj.expled)
5118 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
5119 self.assertEqual(obj.tag_order, (tag_class, tag_num))
5120 obj_encoded = obj.encode()
5121 obj_expled = obj(value, expl=tag_expl)
5122 self.assertTrue(obj_expled.expled)
5123 tag_class, _, tag_num = tag_decode(tag_expl)
5124 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5126 list(obj_expled.pps())
5127 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5128 obj_expled_encoded = obj_expled.encode()
5129 ctx_copied = deepcopy(ctx_dummy)
5130 obj_decoded, tail = obj_expled.decode(
5131 obj_expled_encoded + tail_junk,
5135 self.assertDictEqual(ctx_copied, ctx_dummy)
5137 list(obj_decoded.pps())
5138 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5139 self.assertEqual(tail, tail_junk)
5140 self.assertEqual(obj_decoded, obj_expled)
5141 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
5142 self.assertEqual(bytes(obj_decoded), bytes(obj))
5143 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5144 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5145 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5147 obj_decoded.expl_llen,
5148 len(len_encode(len(obj_encoded))),
5150 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5151 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5154 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5156 self.assertEqual(obj_decoded.expl_offset, offset)
5157 self.assertEqual(obj_decoded.tlen, 0)
5158 self.assertEqual(obj_decoded.llen, 0)
5159 self.assertEqual(obj_decoded.vlen, len(value))
5160 assert_exceeding_data(
5162 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5166 evgens = list(obj_expled.decode_evgen(
5167 obj_expled_encoded + tail_junk,
5169 decode_path=decode_path,
5172 self.assertEqual(len(evgens), 1)
5173 _decode_path, obj, tail = evgens[0]
5174 self.assertSequenceEqual(tail, tail_junk)
5175 self.assertEqual(_decode_path, decode_path)
5176 self.assertEqual(obj.expl_offset, offset)
5181 integers(min_value=1).map(tag_ctxc),
5182 integers(min_value=0, max_value=3),
5183 integers(min_value=0),
5187 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
5188 chunk = Boolean(False, expl=expl).encode()
5190 OctetString.tag_default +
5192 b"".join([chunk] * chunks) +
5195 with self.assertRaises(LenIndefForm):
5199 decode_path=decode_path,
5201 obj, tail = Any().decode(
5204 decode_path=decode_path,
5205 ctx={"bered": True},
5207 self.assertSequenceEqual(tail, junk)
5208 self.assertEqual(obj.offset, offset)
5209 self.assertEqual(obj.tlvlen, len(encoded))
5210 self.assertTrue(obj.lenindef)
5211 self.assertFalse(obj.ber_encoded)
5212 self.assertTrue(obj.bered)
5214 self.assertTrue(obj.lenindef)
5215 self.assertFalse(obj.ber_encoded)
5216 self.assertTrue(obj.bered)
5219 pprint(obj, big_blobs=True, with_decode_path=True)
5220 with self.assertRaises(NotEnoughData) as err:
5224 decode_path=decode_path,
5225 ctx={"bered": True},
5227 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
5228 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
5230 class SeqOf(SequenceOf):
5231 schema = Boolean(expl=expl)
5233 class Seq(Sequence):
5235 ("type", ObjectIdentifier(defines=((("value",), {
5236 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
5241 ("type", ObjectIdentifier("1.2.3")),
5242 ("value", Any(encoded)),
5244 seq_encoded = seq.encode()
5245 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5246 self.assertIsNotNone(seq_decoded["value"].defined)
5248 list(seq_decoded.pps())
5249 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5250 self.assertTrue(seq_decoded.bered)
5251 self.assertFalse(seq_decoded["type"].bered)
5252 self.assertTrue(seq_decoded["value"].bered)
5254 chunk = chunk[:-1] + b"\x01"
5255 chunks = b"".join([chunk] * (chunks + 1))
5256 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
5258 ("type", ObjectIdentifier("1.2.3")),
5259 ("value", Any(encoded)),
5261 seq_encoded = seq.encode()
5262 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5263 self.assertIsNotNone(seq_decoded["value"].defined)
5265 list(seq_decoded.pps())
5266 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5267 self.assertTrue(seq_decoded.bered)
5268 self.assertFalse(seq_decoded["type"].bered)
5269 self.assertTrue(seq_decoded["value"].bered)
5273 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5275 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5276 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5278 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5279 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5281 min_size=len(names),
5282 max_size=len(names),
5285 (name, Integer(**tag_kwargs))
5286 for name, tag_kwargs in zip(names, tags)
5289 if value_required or draw(booleans()):
5290 value = draw(tuples(
5291 sampled_from([name for name, _ in schema]),
5292 integers().map(Integer),
5296 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5297 default = draw(one_of(
5299 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5301 optional = draw(one_of(none(), booleans()))
5303 draw(integers(min_value=0)),
5304 draw(integers(min_value=0)),
5305 draw(integers(min_value=0)),
5307 return (schema, value, expl, default, optional, _decoded)
5310 class ChoiceInherited(Choice):
5314 class TestChoice(CommonMixin, TestCase):
5316 schema = (("whatever", Boolean()),)
5319 def test_schema_required(self):
5320 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5323 def test_impl_forbidden(self):
5324 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
5325 Choice(impl=b"whatever")
5327 def test_invalid_value_type(self):
5328 with self.assertRaises(InvalidValueType) as err:
5329 self.base_klass(123)
5331 with self.assertRaises(ObjUnknown) as err:
5332 self.base_klass(("whenever", Boolean(False)))
5334 with self.assertRaises(InvalidValueType) as err:
5335 self.base_klass(("whatever", Integer(123)))
5339 def test_optional(self, optional):
5340 obj = self.base_klass(
5341 default=self.base_klass(("whatever", Boolean(False))),
5344 self.assertTrue(obj.optional)
5347 def test_ready(self, value):
5348 obj = self.base_klass()
5349 self.assertFalse(obj.ready)
5352 pprint(obj, big_blobs=True, with_decode_path=True)
5353 self.assertIsNone(obj["whatever"])
5354 with self.assertRaises(ObjNotReady) as err:
5357 obj["whatever"] = Boolean()
5358 self.assertFalse(obj.ready)
5361 pprint(obj, big_blobs=True, with_decode_path=True)
5362 obj["whatever"] = Boolean(value)
5363 self.assertTrue(obj.ready)
5366 pprint(obj, big_blobs=True, with_decode_path=True)
5368 @given(booleans(), booleans())
5369 def test_comparison(self, value1, value2):
5370 class WahlInherited(self.base_klass):
5372 for klass in (self.base_klass, WahlInherited):
5373 obj1 = klass(("whatever", Boolean(value1)))
5374 obj2 = klass(("whatever", Boolean(value2)))
5375 self.assertEqual(obj1 == obj2, value1 == value2)
5376 self.assertEqual(obj1 != obj2, value1 != value2)
5377 self.assertEqual(obj1 == obj2._value, value1 == value2)
5378 self.assertFalse(obj1 == obj2._value[1])
5380 @given(data_strategy())
5381 def test_call(self, d):
5382 for klass in (Choice, ChoiceInherited):
5390 ) = d.draw(choice_values_strategy())
5393 schema = schema_initial
5395 value=value_initial,
5397 default=default_initial,
5398 optional=optional_initial or False,
5399 _decoded=_decoded_initial,
5408 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5409 obj = obj_initial(value, expl, default, optional)
5411 value_expected = default if value is None else value
5413 default_initial if value_expected is None
5416 self.assertEqual(obj.choice, value_expected[0])
5417 self.assertEqual(obj.value, int(value_expected[1]))
5418 self.assertEqual(obj.expl_tag, expl or expl_initial)
5419 default_expect = default_initial if default is None else default
5420 if default_expect is not None:
5421 self.assertEqual(obj.default.choice, default_expect[0])
5422 self.assertEqual(obj.default.value, int(default_expect[1]))
5423 if obj.default is None:
5424 optional = optional_initial if optional is None else optional
5425 optional = False if optional is None else optional
5428 self.assertEqual(obj.optional, optional)
5429 self.assertEqual(obj.specs, obj_initial.specs)
5431 def test_simultaneous_impl_expl(self):
5432 # override it, as Any does not have implicit tag
5435 def test_decoded(self):
5436 # override it, as Any does not have implicit tag
5439 @given(choice_values_strategy())
5440 def test_copy(self, values):
5441 _schema, value, expl, default, optional, _decoded = values
5443 class Wahl(self.base_klass):
5445 register_class(Wahl)
5450 optional=optional or False,
5453 for copy_func in copy_funcs:
5454 obj_copied = copy_func(obj)
5455 self.assertIsNone(obj.tag)
5456 self.assertIsNone(obj_copied.tag)
5457 # hack for assert_copied_basic_fields
5458 obj.tag = "whatever"
5459 obj_copied.tag = "whatever"
5460 self.assert_copied_basic_fields(obj, obj_copied)
5462 self.assertEqual(obj._value, obj_copied._value)
5463 self.assertEqual(obj.specs, obj_copied.specs)
5466 def test_stripped(self, value):
5467 obj = self.base_klass(("whatever", Boolean(value)))
5468 with self.assertRaises(NotEnoughData):
5469 obj.decode(obj.encode()[:-1])
5473 integers(min_value=1).map(tag_ctxc),
5475 def test_stripped_expl(self, value, tag_expl):
5476 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5477 with self.assertRaises(NotEnoughData):
5478 obj.decode(obj.encode()[:-1])
5480 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5481 @given(data_strategy())
5482 def test_symmetric(self, d):
5483 _schema, value, _, default, optional, _decoded = d.draw(
5484 choice_values_strategy(value_required=True)
5486 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5487 offset = d.draw(integers(min_value=0))
5488 tail_junk = d.draw(binary(max_size=5))
5489 decode_path = d.draw(decode_path_strat)
5491 class Wahl(self.base_klass):
5501 pprint(obj, big_blobs=True, with_decode_path=True)
5502 self.assertFalse(obj.expled)
5503 self.assertEqual(obj.tag_order, obj.value.tag_order)
5504 obj_encoded = obj.encode()
5505 obj_expled = obj(value, expl=tag_expl)
5506 self.assertTrue(obj_expled.expled)
5507 tag_class, _, tag_num = tag_decode(tag_expl)
5508 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5510 list(obj_expled.pps())
5511 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5512 obj_expled_encoded = obj_expled.encode()
5513 ctx_copied = deepcopy(ctx_dummy)
5514 obj_decoded, tail = obj_expled.decode(
5515 obj_expled_encoded + tail_junk,
5519 self.assertDictEqual(ctx_copied, ctx_dummy)
5521 list(obj_decoded.pps())
5522 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5523 self.assertEqual(tail, tail_junk)
5524 self.assertEqual(obj_decoded, obj_expled)
5525 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5526 self.assertEqual(obj_decoded.value, obj_expled.value)
5527 self.assertEqual(obj_decoded.choice, obj.choice)
5528 self.assertEqual(obj_decoded.value, obj.value)
5529 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5530 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5531 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5533 obj_decoded.expl_llen,
5534 len(len_encode(len(obj_encoded))),
5536 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5537 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5540 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5542 self.assertEqual(obj_decoded.expl_offset, offset)
5543 self.assertSequenceEqual(
5545 obj_decoded.value.fulloffset - offset:
5546 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5550 assert_exceeding_data(
5552 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5556 evgens = list(obj_expled.decode_evgen(
5557 obj_expled_encoded + tail_junk,
5559 decode_path=decode_path,
5562 self.assertEqual(len(evgens), 2)
5563 _decode_path, obj, tail = evgens[0]
5564 self.assertEqual(_decode_path, decode_path + (obj_decoded.choice,))
5565 _decode_path, obj, tail = evgens[1]
5566 self.assertSequenceEqual(tail, tail_junk)
5567 self.assertEqual(_decode_path, decode_path)
5568 self.assertEqual(obj.expl_offset, offset)
5573 def test_set_get(self, value):
5576 ("erste", Boolean()),
5577 ("zweite", Integer()),
5580 with self.assertRaises(ObjUnknown) as err:
5581 obj["whatever"] = "whenever"
5582 with self.assertRaises(InvalidValueType) as err:
5583 obj["zweite"] = Boolean(False)
5584 obj["zweite"] = Integer(value)
5586 with self.assertRaises(ObjUnknown) as err:
5589 self.assertIsNone(obj["erste"])
5590 self.assertEqual(obj["zweite"], Integer(value))
5592 def test_tag_mismatch(self):
5595 ("erste", Boolean()),
5597 int_encoded = Integer(123).encode()
5598 bool_encoded = Boolean(False).encode()
5600 obj.decode(bool_encoded)
5601 with self.assertRaises(TagMismatch):
5602 obj.decode(int_encoded)
5604 def test_tag_mismatch_underlying(self):
5605 class SeqOfBoolean(SequenceOf):
5608 class SeqOfInteger(SequenceOf):
5613 ("erste", SeqOfBoolean()),
5616 int_encoded = SeqOfInteger((Integer(123),)).encode()
5617 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5619 obj.decode(bool_encoded)
5620 with self.assertRaises(TagMismatch) as err:
5621 obj.decode(int_encoded)
5622 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5626 def seq_values_strategy(draw, seq_klass, do_expl=False):
5628 if draw(booleans()):
5630 value._value = draw(dictionaries(
5633 booleans().map(Boolean),
5634 integers().map(Integer),
5638 if draw(booleans()):
5639 schema = list(draw(dictionaries(
5642 booleans().map(Boolean),
5643 integers().map(Integer),
5649 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5651 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5653 if draw(booleans()):
5654 default = seq_klass()
5655 default._value = draw(dictionaries(
5658 booleans().map(Boolean),
5659 integers().map(Integer),
5662 optional = draw(one_of(none(), booleans()))
5664 draw(integers(min_value=0)),
5665 draw(integers(min_value=0)),
5666 draw(integers(min_value=0)),
5668 return (value, schema, impl, expl, default, optional, _decoded)
5672 def sequence_strategy(draw, seq_klass):
5673 inputs = draw(lists(
5675 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5676 tuples(just(Integer), integers(), one_of(none(), integers())),
5681 integers(min_value=1),
5682 min_size=len(inputs),
5683 max_size=len(inputs),
5686 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5687 for tag, expled in zip(tags, draw(lists(
5689 min_size=len(inputs),
5690 max_size=len(inputs),
5694 for i, optional in enumerate(draw(lists(
5695 sampled_from(("required", "optional", "empty")),
5696 min_size=len(inputs),
5697 max_size=len(inputs),
5699 if optional in ("optional", "empty"):
5700 inits[i]["optional"] = True
5701 if optional == "empty":
5703 empties = set(empties)
5704 names = list(draw(sets(
5706 min_size=len(inputs),
5707 max_size=len(inputs),
5710 for i, (klass, value, default) in enumerate(inputs):
5711 schema.append((names[i], klass(default=default, **inits[i])))
5712 seq_name = draw(text_letters())
5713 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5716 for i, (klass, value, default) in enumerate(inputs):
5723 "default_value": None if spec.default is None else default,
5727 expect["optional"] = True
5729 expect["presented"] = True
5730 expect["value"] = value
5732 expect["optional"] = True
5733 if default is not None and default == value:
5734 expect["presented"] = False
5735 seq[name] = klass(value)
5736 expects.append(expect)
5741 def sequences_strategy(draw, seq_klass):
5742 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5744 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5745 for tag, expled in zip(tags, draw(lists(
5752 i for i, is_default in enumerate(draw(lists(
5758 names = list(draw(sets(
5763 seq_expectses = draw(lists(
5764 sequence_strategy(seq_klass=seq_klass),
5768 seqs = [seq for seq, _ in seq_expectses]
5770 for i, (name, seq) in enumerate(zip(names, seqs)):
5773 seq(default=(seq if i in defaulted else None), **inits[i]),
5775 seq_name = draw(text_letters())
5776 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5779 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5782 "expects": expects_inner,
5785 seq_outer[name] = seq_inner
5786 if seq_outer.specs[name].default is None:
5787 expect["presented"] = True
5788 expect_outers.append(expect)
5789 return seq_outer, expect_outers
5792 class SeqMixing(object):
5793 def test_invalid_value_type(self):
5794 with self.assertRaises(InvalidValueType) as err:
5795 self.base_klass(123)
5798 def test_invalid_value_type_set(self):
5799 class Seq(self.base_klass):
5800 schema = (("whatever", Boolean()),)
5802 with self.assertRaises(InvalidValueType) as err:
5803 seq["whatever"] = Integer(123)
5807 def test_optional(self, optional):
5808 obj = self.base_klass(default=self.base_klass(), optional=optional)
5809 self.assertTrue(obj.optional)
5811 @given(data_strategy())
5812 def test_ready(self, d):
5814 str(i): v for i, v in enumerate(d.draw(lists(
5821 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5828 for name in d.draw(permutations(
5829 list(ready.keys()) + list(non_ready.keys()),
5831 schema_input.append((name, Boolean()))
5833 class Seq(self.base_klass):
5834 schema = tuple(schema_input)
5836 for name in ready.keys():
5838 seq[name] = Boolean()
5839 self.assertFalse(seq.ready)
5842 pprint(seq, big_blobs=True, with_decode_path=True)
5843 for name, value in ready.items():
5844 seq[name] = Boolean(value)
5845 self.assertFalse(seq.ready)
5848 pprint(seq, big_blobs=True, with_decode_path=True)
5849 with self.assertRaises(ObjNotReady) as err:
5852 for name, value in non_ready.items():
5853 seq[name] = Boolean(value)
5854 self.assertTrue(seq.ready)
5857 pprint(seq, big_blobs=True, with_decode_path=True)
5859 @given(data_strategy())
5860 def test_call(self, d):
5861 class SeqInherited(self.base_klass):
5863 for klass in (self.base_klass, SeqInherited):
5872 ) = d.draw(seq_values_strategy(seq_klass=klass))
5873 obj_initial = klass(
5879 optional_initial or False,
5890 ) = d.draw(seq_values_strategy(
5892 do_expl=impl_initial is None,
5894 obj = obj_initial(value, impl, expl, default, optional)
5895 value_expected = default if value is None else value
5897 default_initial if value_expected is None
5900 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5901 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5902 self.assertEqual(obj.expl_tag, expl or expl_initial)
5904 {} if obj.default is None else obj.default._value,
5905 getattr(default_initial if default is None else default, "_value", {}),
5907 if obj.default is None:
5908 optional = optional_initial if optional is None else optional
5909 optional = False if optional is None else optional
5912 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5913 self.assertEqual(obj.optional, optional)
5915 @given(data_strategy())
5916 def test_copy(self, d):
5917 class SeqInherited(self.base_klass):
5919 register_class(SeqInherited)
5920 for klass in (self.base_klass, SeqInherited):
5921 values = d.draw(seq_values_strategy(seq_klass=klass))
5922 obj = klass(*values)
5923 for copy_func in copy_funcs:
5924 obj_copied = copy_func(obj)
5925 self.assert_copied_basic_fields(obj, obj_copied)
5926 self.assertEqual(obj.specs, obj_copied.specs)
5927 self.assertEqual(obj._value, obj_copied._value)
5929 @given(data_strategy())
5930 def test_stripped(self, d):
5931 value = d.draw(integers())
5932 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5934 class Seq(self.base_klass):
5936 schema = (("whatever", Integer()),)
5938 seq["whatever"] = Integer(value)
5939 with self.assertRaises(NotEnoughData):
5940 seq.decode(seq.encode()[:-1])
5942 @given(data_strategy())
5943 def test_stripped_expl(self, d):
5944 value = d.draw(integers())
5945 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5947 class Seq(self.base_klass):
5949 schema = (("whatever", Integer()),)
5951 seq["whatever"] = Integer(value)
5952 with self.assertRaises(NotEnoughData):
5953 seq.decode(seq.encode()[:-1])
5955 @given(integers(min_value=3), binary(min_size=2))
5956 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
5957 junk = tag_encode(junk_tag_num) + junk
5959 _, _, len_encoded = tag_strip(memoryview(junk))
5960 len_decode(len_encoded)
5966 class Seq(self.base_klass):
5968 ("whatever", Integer()),
5970 ("whenever", Integer()),
5973 seq["whatever"] = Integer(123)
5974 seq["junk"] = Any(junk)
5975 seq["whenever"] = Integer(123)
5976 with self.assertRaises(DecodeError):
5977 seq.decode(seq.encode())
5980 integers(min_value=31),
5981 integers(min_value=0),
5984 def test_bad_tag(self, tag, offset, decode_path):
5985 with self.assertRaises(DecodeError) as err:
5986 self.base_klass().decode(
5987 tag_encode(tag)[:-1],
5989 decode_path=decode_path,
5992 self.assertEqual(err.exception.offset, offset)
5993 self.assertEqual(err.exception.decode_path, decode_path)
5996 integers(min_value=128),
5997 integers(min_value=0),
6000 def test_bad_len(self, l, offset, decode_path):
6001 with self.assertRaises(DecodeError) as err:
6002 self.base_klass().decode(
6003 self.base_klass.tag_default + len_encode(l)[:-1],
6005 decode_path=decode_path,
6008 self.assertEqual(err.exception.offset, offset)
6009 self.assertEqual(err.exception.decode_path, decode_path)
6011 def _assert_expects(self, seq, expects):
6012 for expect in expects:
6014 seq.specs[expect["name"]].optional,
6017 if expect["default_value"] is not None:
6019 seq.specs[expect["name"]].default,
6020 expect["default_value"],
6022 if expect["presented"]:
6023 self.assertIn(expect["name"], seq)
6024 self.assertEqual(seq[expect["name"]], expect["value"])
6026 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6027 @given(data_strategy())
6028 def test_symmetric(self, d):
6029 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
6030 tail_junk = d.draw(binary(max_size=5))
6031 decode_path = d.draw(decode_path_strat)
6032 self.assertTrue(seq.ready)
6033 self.assertFalse(seq.decoded)
6034 self._assert_expects(seq, expects)
6037 pprint(seq, big_blobs=True, with_decode_path=True)
6038 self.assertTrue(seq.ready)
6039 seq_encoded = seq.encode()
6040 seq_encoded_cer = encode_cer(seq)
6041 self.assertNotEqual(seq_encoded_cer, seq_encoded)
6042 self.assertSequenceEqual(
6043 seq.decod(seq_encoded_cer, ctx={"bered": True}).encode(),
6046 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
6047 self.assertFalse(seq_decoded.lenindef)
6048 self.assertFalse(seq_decoded.ber_encoded)
6049 self.assertFalse(seq_decoded.bered)
6051 t, _, lv = tag_strip(seq_encoded)
6052 _, _, v = len_decode(lv)
6053 seq_encoded_lenindef = t + LENINDEF + v + EOC
6054 with self.assertRaises(DecodeError):
6055 seq.decode(seq_encoded_lenindef)
6056 ctx_copied = deepcopy(ctx_dummy)
6057 ctx_copied["bered"] = True
6058 seq_decoded_lenindef, tail_lenindef = seq.decode(
6059 seq_encoded_lenindef + tail_junk,
6062 del ctx_copied["bered"]
6063 self.assertDictEqual(ctx_copied, ctx_dummy)
6064 self.assertTrue(seq_decoded_lenindef.lenindef)
6065 self.assertTrue(seq_decoded_lenindef.bered)
6066 seq_decoded_lenindef = copy(seq_decoded_lenindef)
6067 self.assertTrue(seq_decoded_lenindef.lenindef)
6068 self.assertTrue(seq_decoded_lenindef.bered)
6069 with self.assertRaises(DecodeError):
6070 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
6071 with self.assertRaises(DecodeError):
6072 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
6073 repr(seq_decoded_lenindef)
6074 list(seq_decoded_lenindef.pps())
6075 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
6076 self.assertTrue(seq_decoded_lenindef.ready)
6078 for decoded, decoded_tail, encoded in (
6079 (seq_decoded, tail, seq_encoded),
6080 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
6082 self.assertEqual(decoded_tail, tail_junk)
6083 self._assert_expects(decoded, expects)
6084 self.assertEqual(seq, decoded)
6085 self.assertEqual(decoded.encode(), seq_encoded)
6086 self.assertEqual(decoded.tlvlen, len(encoded))
6087 for expect in expects:
6088 if not expect["presented"]:
6089 self.assertNotIn(expect["name"], decoded)
6091 self.assertIn(expect["name"], decoded)
6092 obj = decoded[expect["name"]]
6093 self.assertTrue(obj.decoded)
6094 offset = obj.expl_offset if obj.expled else obj.offset
6095 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6096 self.assertSequenceEqual(
6097 seq_encoded[offset:offset + tlvlen],
6101 evgens = list(seq.decode_evgen(
6102 encoded + decoded_tail,
6103 decode_path=decode_path,
6104 ctx={"bered": True},
6106 self.assertEqual(len(evgens), len(list(decoded._values_for_encoding())) + 1)
6107 for _decode_path, obj, _ in evgens[:-1]:
6108 self.assertEqual(_decode_path[:-1], decode_path)
6111 _decode_path, obj, tail = evgens[-1]
6112 self.assertEqual(_decode_path, decode_path)
6116 assert_exceeding_data(
6118 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
6122 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6123 @given(data_strategy())
6124 def test_symmetric_with_seq(self, d):
6125 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
6126 self.assertTrue(seq.ready)
6127 seq_encoded = seq.encode()
6128 seq_decoded, tail = seq.decode(seq_encoded)
6129 self.assertEqual(tail, b"")
6130 self.assertTrue(seq.ready)
6131 self.assertEqual(seq, seq_decoded)
6132 self.assertEqual(seq_decoded.encode(), seq_encoded)
6133 for expect_outer in expect_outers:
6134 if not expect_outer["presented"]:
6135 self.assertNotIn(expect_outer["name"], seq_decoded)
6137 self.assertIn(expect_outer["name"], seq_decoded)
6138 obj = seq_decoded[expect_outer["name"]]
6139 self.assertTrue(obj.decoded)
6140 offset = obj.expl_offset if obj.expled else obj.offset
6141 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
6142 self.assertSequenceEqual(
6143 seq_encoded[offset:offset + tlvlen],
6146 self._assert_expects(obj, expect_outer["expects"])
6148 @given(data_strategy())
6149 def test_default_disappears(self, d):
6150 _schema = list(d.draw(dictionaries(
6152 sets(integers(), min_size=2, max_size=2),
6156 class Seq(self.base_klass):
6158 (n, Integer(default=d))
6159 for n, (_, d) in _schema
6162 for name, (value, _) in _schema:
6163 seq[name] = Integer(value)
6164 self.assertEqual(len(seq._value), len(_schema))
6165 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
6166 self.assertGreater(len(seq.encode()), len(empty_seq))
6167 for name, (_, default) in _schema:
6168 seq[name] = Integer(default)
6169 self.assertEqual(len(seq._value), 0)
6170 self.assertSequenceEqual(seq.encode(), empty_seq)
6172 @given(data_strategy())
6173 def test_encoded_default_not_accepted(self, d):
6174 _schema = list(d.draw(dictionaries(
6179 tags = [tag_encode(tag) for tag in d.draw(sets(
6180 integers(min_value=1),
6181 min_size=len(_schema),
6182 max_size=len(_schema),
6185 class SeqWithoutDefault(self.base_klass):
6187 (n, Integer(impl=t))
6188 for (n, _), t in zip(_schema, tags)
6190 seq_without_default = SeqWithoutDefault()
6191 for name, value in _schema:
6192 seq_without_default[name] = Integer(value)
6193 seq_encoded = seq_without_default.encode()
6195 class SeqWithDefault(self.base_klass):
6197 (n, Integer(default=v, impl=t))
6198 for (n, v), t in zip(_schema, tags)
6200 seq_with_default = SeqWithDefault()
6201 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
6202 seq_with_default.decode(seq_encoded)
6203 for ctx in ({"bered": True}, {"allow_default_values": True}):
6204 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
6205 self.assertTrue(seq_decoded.ber_encoded)
6206 self.assertTrue(seq_decoded.bered)
6207 seq_decoded = copy(seq_decoded)
6208 self.assertTrue(seq_decoded.ber_encoded)
6209 self.assertTrue(seq_decoded.bered)
6210 for name, value in _schema:
6211 self.assertEqual(seq_decoded[name], seq_with_default[name])
6212 self.assertEqual(seq_decoded[name], value)
6214 @given(data_strategy())
6215 def test_missing_from_spec(self, d):
6216 names = list(d.draw(sets(text_letters(), min_size=2)))
6217 tags = [tag_encode(tag) for tag in d.draw(sets(
6218 integers(min_value=1),
6219 min_size=len(names),
6220 max_size=len(names),
6222 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
6224 class SeqFull(self.base_klass):
6225 schema = [(n, Integer(impl=t)) for n, t in names_tags]
6226 seq_full = SeqFull()
6227 for i, name in enumerate(names):
6228 seq_full[name] = Integer(i)
6229 seq_encoded = seq_full.encode()
6230 altered = names_tags[:-2] + names_tags[-1:]
6232 class SeqMissing(self.base_klass):
6233 schema = [(n, Integer(impl=t)) for n, t in altered]
6234 seq_missing = SeqMissing()
6235 with self.assertRaises(TagMismatch):
6236 seq_missing.decode(seq_encoded)
6238 def test_bered(self):
6239 class Seq(self.base_klass):
6240 schema = (("underlying", Boolean()),)
6241 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
6242 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6243 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6244 self.assertFalse(decoded.ber_encoded)
6245 self.assertFalse(decoded.lenindef)
6246 self.assertTrue(decoded.bered)
6247 decoded = copy(decoded)
6248 self.assertFalse(decoded.ber_encoded)
6249 self.assertFalse(decoded.lenindef)
6250 self.assertTrue(decoded.bered)
6252 class Seq(self.base_klass):
6253 schema = (("underlying", OctetString()),)
6255 tag_encode(form=TagFormConstructed, num=4) +
6257 OctetString(b"whatever").encode() +
6260 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6261 with self.assertRaises(DecodeError):
6262 Seq().decode(encoded)
6263 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
6264 self.assertFalse(decoded.ber_encoded)
6265 self.assertFalse(decoded.lenindef)
6266 self.assertTrue(decoded.bered)
6267 decoded = copy(decoded)
6268 self.assertFalse(decoded.ber_encoded)
6269 self.assertFalse(decoded.lenindef)
6270 self.assertTrue(decoded.bered)
6273 class TestSequence(SeqMixing, CommonMixin, TestCase):
6274 base_klass = Sequence
6280 def test_remaining(self, value, junk):
6281 class Seq(Sequence):
6283 ("whatever", Integer()),
6285 int_encoded = Integer(value).encode()
6287 Sequence.tag_default,
6288 len_encode(len(int_encoded + junk)),
6291 with assertRaisesRegex(self, DecodeError, "remaining"):
6292 Seq().decode(junked)
6294 @given(sets(text_letters(), min_size=2))
6295 def test_obj_unknown(self, names):
6296 missing = names.pop()
6298 class Seq(Sequence):
6299 schema = [(n, Boolean()) for n in names]
6301 with self.assertRaises(ObjUnknown) as err:
6304 with self.assertRaises(ObjUnknown) as err:
6305 seq[missing] = Boolean()
6308 def test_x690_vector(self):
6309 class Seq(Sequence):
6311 ("name", IA5String()),
6314 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6315 self.assertEqual(seq["name"], "Smith")
6316 self.assertEqual(seq["ok"], True)
6319 class TestSet(SeqMixing, CommonMixin, TestCase):
6322 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6323 @given(data_strategy())
6324 def test_sorted(self, d):
6325 class DummySeq(Sequence):
6326 schema = (("null", Null()),)
6328 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6329 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6330 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6331 tag_nums -= set([dummy_seq_tag_num])
6332 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6333 _schema.append(("seq", DummySeq()))
6336 schema = d.draw(permutations(_schema))
6338 for name, _ in _schema:
6340 seq[name] = OctetString(name.encode("ascii"))
6341 seq["seq"] = DummySeq((("null", Null()),))
6343 seq_encoded = seq.encode()
6344 seq_decoded, _ = seq.decode(seq_encoded)
6345 seq_encoded_expected = []
6346 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6347 if tag_num == dummy_seq_tag_num:
6348 seq_encoded_expected.append(seq["seq"].encode())
6350 seq_encoded_expected.append(seq[str(tag_num)].encode())
6351 self.assertSequenceEqual(
6352 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6353 b"".join(seq_encoded_expected),
6356 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6357 encoded += seq["seq"].encode()
6358 seq_encoded = b"".join((
6360 len_encode(len(encoded)),
6363 with assertRaisesRegex(self, DecodeError, "unordered SET"):
6364 seq.decode(seq_encoded)
6365 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6366 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6367 self.assertTrue(seq_decoded.ber_encoded)
6368 self.assertTrue(seq_decoded.bered)
6369 seq_decoded = copy(seq_decoded)
6370 self.assertTrue(seq_decoded.ber_encoded)
6371 self.assertTrue(seq_decoded.bered)
6373 def test_same_value_twice(self):
6376 ("bool", Boolean()),
6380 encoded = b"".join((
6381 Integer(123).encode(),
6382 Integer(234).encode(),
6383 Boolean(True).encode(),
6385 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6386 with self.assertRaises(TagMismatch):
6387 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6391 def seqof_values_strategy(draw, schema=None, do_expl=False):
6393 schema = draw(sampled_from((Boolean(), Integer())))
6394 bound_min, bound_max = sorted(draw(sets(
6395 integers(min_value=0, max_value=10),
6399 if isinstance(schema, Boolean):
6400 values_generator = booleans().map(Boolean)
6401 elif isinstance(schema, Integer):
6402 values_generator = integers().map(Integer)
6403 values_generator = lists(
6408 values = draw(one_of(none(), values_generator))
6412 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6414 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6415 default = draw(one_of(none(), values_generator))
6416 optional = draw(one_of(none(), booleans()))
6418 draw(integers(min_value=0)),
6419 draw(integers(min_value=0)),
6420 draw(integers(min_value=0)),
6425 (bound_min, bound_max),
6434 class SeqOfMixing(object):
6435 def test_invalid_value_type(self):
6436 with self.assertRaises(InvalidValueType) as err:
6437 self.base_klass(123)
6440 def test_invalid_values_type(self):
6441 class SeqOf(self.base_klass):
6443 with self.assertRaises(InvalidValueType) as err:
6444 SeqOf([Integer(123), Boolean(False), Integer(234)])
6447 def test_schema_required(self):
6448 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6449 self.base_klass.__mro__[1]()
6451 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6452 def test_comparison(self, value1, value2, tag1, tag2):
6453 class SeqOf(self.base_klass):
6455 obj1 = SeqOf([Boolean(value1)])
6456 obj2 = SeqOf([Boolean(value2)])
6457 self.assertEqual(obj1 == obj2, value1 == value2)
6458 self.assertEqual(obj1 != obj2, value1 != value2)
6459 self.assertEqual(obj1 == list(obj2), value1 == value2)
6460 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6461 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6462 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6463 self.assertEqual(obj1 == obj2, tag1 == tag2)
6464 self.assertEqual(obj1 != obj2, tag1 != tag2)
6466 @given(lists(booleans()))
6467 def test_iter(self, values):
6468 class SeqOf(self.base_klass):
6470 obj = SeqOf([Boolean(value) for value in values])
6471 self.assertEqual(len(obj), len(values))
6472 for i, value in enumerate(obj):
6473 self.assertEqual(value, values[i])
6475 @given(data_strategy())
6476 def test_ready(self, d):
6477 ready = [Integer(v) for v in d.draw(lists(
6484 range(d.draw(integers(min_value=1, max_value=5)))
6487 class SeqOf(self.base_klass):
6489 values = d.draw(permutations(ready + non_ready))
6491 for value in values:
6493 self.assertFalse(seqof.ready)
6496 pprint(seqof, big_blobs=True, with_decode_path=True)
6497 with self.assertRaises(ObjNotReady) as err:
6500 for i, value in enumerate(values):
6501 self.assertEqual(seqof[i], value)
6502 if not seqof[i].ready:
6503 seqof[i] = Integer(i)
6504 self.assertTrue(seqof.ready)
6507 pprint(seqof, big_blobs=True, with_decode_path=True)
6509 def test_spec_mismatch(self):
6510 class SeqOf(self.base_klass):
6513 seqof.append(Integer(123))
6514 with self.assertRaises(ValueError):
6515 seqof.append(Boolean(False))
6516 with self.assertRaises(ValueError):
6517 seqof[0] = Boolean(False)
6519 @given(data_strategy())
6520 def test_bounds_satisfied(self, d):
6521 class SeqOf(self.base_klass):
6523 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6524 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6525 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6526 SeqOf(value=value, bounds=(bound_min, bound_max))
6528 @given(data_strategy())
6529 def test_bounds_unsatisfied(self, d):
6530 class SeqOf(self.base_klass):
6532 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6533 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6534 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6535 with self.assertRaises(BoundsError) as err:
6536 SeqOf(value=value, bounds=(bound_min, bound_max))
6538 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6539 SeqOf(bounds=(bound_min, bound_max)).decode(
6540 SeqOf(value).encode()
6543 value = [Boolean(True)] * d.draw(integers(
6544 min_value=bound_max + 1,
6545 max_value=bound_max + 10,
6547 with self.assertRaises(BoundsError) as err:
6548 SeqOf(value=value, bounds=(bound_min, bound_max))
6550 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6551 SeqOf(bounds=(bound_min, bound_max)).decode(
6552 SeqOf(value).encode()
6556 @given(integers(min_value=1, max_value=10))
6557 def test_out_of_bounds(self, bound_max):
6558 class SeqOf(self.base_klass):
6560 bounds = (0, bound_max)
6562 for _ in range(bound_max):
6563 seqof.append(Integer(123))
6564 with self.assertRaises(BoundsError):
6565 seqof.append(Integer(123))
6567 @given(data_strategy())
6568 def test_call(self, d):
6578 ) = d.draw(seqof_values_strategy())
6580 class SeqOf(self.base_klass):
6581 schema = schema_initial
6582 obj_initial = SeqOf(
6583 value=value_initial,
6584 bounds=bounds_initial,
6587 default=default_initial,
6588 optional=optional_initial or False,
6589 _decoded=_decoded_initial,
6600 ) = d.draw(seqof_values_strategy(
6601 schema=schema_initial,
6602 do_expl=impl_initial is None,
6604 if (default is None) and (obj_initial.default is not None):
6607 (bounds is None) and
6608 (value is not None) and
6609 (bounds_initial is not None) and
6610 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6614 (bounds is None) and
6615 (default is not None) and
6616 (bounds_initial is not None) and
6617 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6629 value_expected = default if value is None else value
6631 default_initial if value_expected is None
6634 value_expected = () if value_expected is None else value_expected
6635 self.assertEqual(obj, value_expected)
6636 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6637 self.assertEqual(obj.expl_tag, expl or expl_initial)
6640 default_initial if default is None else default,
6642 if obj.default is None:
6643 optional = optional_initial if optional is None else optional
6644 optional = False if optional is None else optional
6647 self.assertEqual(obj.optional, optional)
6649 (obj._bound_min, obj._bound_max),
6650 bounds or bounds_initial or (0, float("+inf")),
6653 @given(seqof_values_strategy())
6654 def test_copy(self, values):
6655 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6657 class SeqOf(self.base_klass):
6659 register_class(SeqOf)
6666 optional=optional or False,
6669 for copy_func in copy_funcs:
6670 obj_copied = copy_func(obj)
6671 self.assert_copied_basic_fields(obj, obj_copied)
6672 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6673 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6674 self.assertEqual(obj._value, obj_copied._value)
6678 integers(min_value=1).map(tag_encode),
6680 def test_stripped(self, values, tag_impl):
6681 class SeqOf(self.base_klass):
6682 schema = OctetString()
6683 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6684 with self.assertRaises(NotEnoughData):
6685 obj.decode(obj.encode()[:-1])
6689 integers(min_value=1).map(tag_ctxc),
6691 def test_stripped_expl(self, values, tag_expl):
6692 class SeqOf(self.base_klass):
6693 schema = OctetString()
6694 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6695 with self.assertRaises(NotEnoughData):
6696 obj.decode(obj.encode()[:-1])
6699 integers(min_value=31),
6700 integers(min_value=0),
6703 def test_bad_tag(self, tag, offset, decode_path):
6704 with self.assertRaises(DecodeError) as err:
6705 self.base_klass().decode(
6706 tag_encode(tag)[:-1],
6708 decode_path=decode_path,
6711 self.assertEqual(err.exception.offset, offset)
6712 self.assertEqual(err.exception.decode_path, decode_path)
6715 integers(min_value=128),
6716 integers(min_value=0),
6719 def test_bad_len(self, l, offset, decode_path):
6720 with self.assertRaises(DecodeError) as err:
6721 self.base_klass().decode(
6722 self.base_klass.tag_default + len_encode(l)[:-1],
6724 decode_path=decode_path,
6727 self.assertEqual(err.exception.offset, offset)
6728 self.assertEqual(err.exception.decode_path, decode_path)
6730 @given(binary(min_size=1))
6731 def test_tag_mismatch(self, impl):
6732 assume(impl != self.base_klass.tag_default)
6733 with self.assertRaises(TagMismatch):
6734 self.base_klass(impl=impl).decode(self.base_klass().encode())
6736 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6738 seqof_values_strategy(schema=Integer()),
6739 lists(integers().map(Integer)),
6740 integers(min_value=1).map(tag_ctxc),
6741 integers(min_value=0),
6745 def test_symmetric(self, values, value, tag_expl, offset, tail_junk, decode_path):
6746 _, _, _, _, _, default, optional, _decoded = values
6748 class SeqOf(self.base_klass):
6758 pprint(obj, big_blobs=True, with_decode_path=True)
6759 self.assertFalse(obj.expled)
6760 obj_encoded = obj.encode()
6761 obj_encoded_cer = encode_cer(obj)
6762 self.assertNotEqual(obj_encoded_cer, obj_encoded)
6763 self.assertSequenceEqual(
6764 obj.decod(obj_encoded_cer, ctx={"bered": True}).encode(),
6767 obj_expled = obj(value, expl=tag_expl)
6768 self.assertTrue(obj_expled.expled)
6770 list(obj_expled.pps())
6771 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6772 obj_expled_encoded = obj_expled.encode()
6773 ctx_copied = deepcopy(ctx_dummy)
6774 obj_decoded, tail = obj_expled.decode(
6775 obj_expled_encoded + tail_junk,
6779 self.assertDictEqual(ctx_copied, ctx_dummy)
6781 list(obj_decoded.pps())
6782 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6783 self.assertEqual(tail, tail_junk)
6784 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6785 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6786 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6787 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6789 obj_decoded.expl_llen,
6790 len(len_encode(len(obj_encoded))),
6792 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6793 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6796 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6798 self.assertEqual(obj_decoded.expl_offset, offset)
6799 for obj_inner in obj_decoded:
6800 self.assertIn(obj_inner, obj_decoded)
6801 self.assertSequenceEqual(
6804 obj_inner.offset - offset:
6805 obj_inner.offset + obj_inner.tlvlen - offset
6809 t, _, lv = tag_strip(obj_encoded)
6810 _, _, v = len_decode(lv)
6811 obj_encoded_lenindef = t + LENINDEF + v + EOC
6812 with self.assertRaises(DecodeError):
6813 obj.decode(obj_encoded_lenindef)
6814 obj_decoded_lenindef, tail_lenindef = obj.decode(
6815 obj_encoded_lenindef + tail_junk,
6816 ctx={"bered": True},
6818 self.assertTrue(obj_decoded_lenindef.lenindef)
6819 self.assertTrue(obj_decoded_lenindef.bered)
6820 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6821 self.assertTrue(obj_decoded_lenindef.lenindef)
6822 self.assertTrue(obj_decoded_lenindef.bered)
6823 repr(obj_decoded_lenindef)
6824 list(obj_decoded_lenindef.pps())
6825 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6826 self.assertEqual(tail_lenindef, tail_junk)
6827 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6828 with self.assertRaises(DecodeError):
6829 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6830 with self.assertRaises(DecodeError):
6831 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6833 evgens = list(obj.decode_evgen(
6834 obj_encoded_lenindef + tail_junk,
6835 decode_path=decode_path,
6836 ctx={"bered": True},
6838 self.assertEqual(len(evgens), len(obj_decoded_lenindef) + 1)
6839 for i, (_decode_path, obj, _) in enumerate(evgens[:-1]):
6840 self.assertEqual(_decode_path, decode_path + (str(i),))
6843 _decode_path, obj, tail = evgens[-1]
6844 self.assertEqual(_decode_path, decode_path)
6848 assert_exceeding_data(
6850 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6854 def test_bered(self):
6855 class SeqOf(self.base_klass):
6857 encoded = Boolean(False).encode()
6858 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6859 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6860 with self.assertRaises(DecodeError):
6861 SeqOf().decode(encoded)
6862 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6863 self.assertFalse(decoded.ber_encoded)
6864 self.assertFalse(decoded.lenindef)
6865 self.assertTrue(decoded.bered)
6866 decoded = copy(decoded)
6867 self.assertFalse(decoded.ber_encoded)
6868 self.assertFalse(decoded.lenindef)
6869 self.assertTrue(decoded.bered)
6871 class SeqOf(self.base_klass):
6872 schema = OctetString()
6873 encoded = OctetString(b"whatever").encode()
6875 tag_encode(form=TagFormConstructed, num=4) +
6877 OctetString(b"whatever").encode() +
6880 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6881 with self.assertRaises(DecodeError):
6882 SeqOf().decode(encoded)
6883 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6884 self.assertFalse(decoded.ber_encoded)
6885 self.assertFalse(decoded.lenindef)
6886 self.assertTrue(decoded.bered)
6887 decoded = copy(decoded)
6888 self.assertFalse(decoded.ber_encoded)
6889 self.assertFalse(decoded.lenindef)
6890 self.assertTrue(decoded.bered)
6893 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6894 class SeqOf(SequenceOf):
6898 def _test_symmetric_compare_objs(self, obj1, obj2):
6899 self.assertEqual(obj1, obj2)
6900 self.assertSequenceEqual(list(obj1), list(obj2))
6903 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6908 def _test_symmetric_compare_objs(self, obj1, obj2):
6909 self.assertSetEqual(
6910 set(int(v) for v in obj1),
6911 set(int(v) for v in obj2),
6914 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6915 @given(data_strategy())
6916 def test_sorted(self, d):
6917 values = [OctetString(v) for v in d.draw(lists(binary()))]
6920 schema = OctetString()
6922 seq_encoded = seq.encode()
6923 seq_decoded, _ = seq.decode(seq_encoded)
6924 self.assertSequenceEqual(
6925 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6926 b"".join(sorted([v.encode() for v in values])),
6929 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6930 @given(data_strategy())
6931 def test_unsorted(self, d):
6932 values = [OctetString(v).encode() for v in d.draw(sets(
6933 binary(min_size=1, max_size=5),
6937 values = d.draw(permutations(values))
6938 assume(values != sorted(values))
6939 encoded = b"".join(values)
6940 seq_encoded = b"".join((
6942 len_encode(len(encoded)),
6947 schema = OctetString()
6949 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6950 seq.decode(seq_encoded)
6952 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6953 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6954 self.assertTrue(seq_decoded.ber_encoded)
6955 self.assertTrue(seq_decoded.bered)
6956 seq_decoded = copy(seq_decoded)
6957 self.assertTrue(seq_decoded.ber_encoded)
6958 self.assertTrue(seq_decoded.bered)
6959 self.assertSequenceEqual(
6960 [obj.encode() for obj in seq_decoded],
6965 class TestGoMarshalVectors(TestCase):
6967 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6968 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6969 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6970 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6971 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6973 class Seq(Sequence):
6975 ("erste", Integer()),
6976 ("zweite", Integer(optional=True))
6979 seq["erste"] = Integer(64)
6980 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6981 seq["erste"] = Integer(0x123456)
6982 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6983 seq["erste"] = Integer(64)
6984 seq["zweite"] = Integer(65)
6985 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6987 class NestedSeq(Sequence):
6991 seq["erste"] = Integer(127)
6992 seq["zweite"] = None
6993 nested = NestedSeq()
6994 nested["nest"] = seq
6995 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6997 self.assertSequenceEqual(
6998 OctetString(b"\x01\x02\x03").encode(),
6999 hexdec("0403010203"),
7002 class Seq(Sequence):
7004 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
7007 seq["erste"] = Integer(64)
7008 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
7010 class Seq(Sequence):
7012 ("erste", Integer(expl=tag_ctxc(5))),
7015 seq["erste"] = Integer(64)
7016 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
7018 class Seq(Sequence):
7021 impl=tag_encode(0, klass=TagClassContext),
7026 seq["erste"] = Null()
7027 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
7029 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7031 self.assertSequenceEqual(
7032 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
7033 hexdec("170d3730303130313030303030305a"),
7035 self.assertSequenceEqual(
7036 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
7037 hexdec("170d3039313131353232353631365a"),
7039 self.assertSequenceEqual(
7040 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
7041 hexdec("180f32313030303430353132303130315a"),
7044 class Seq(Sequence):
7046 ("erste", GeneralizedTime()),
7049 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
7050 self.assertSequenceEqual(
7052 hexdec("3011180f32303039313131353232353631365a"),
7055 self.assertSequenceEqual(
7056 BitString((1, b"\x80")).encode(),
7059 self.assertSequenceEqual(
7060 BitString((12, b"\x81\xF0")).encode(),
7061 hexdec("03030481f0"),
7064 self.assertSequenceEqual(
7065 ObjectIdentifier("1.2.3.4").encode(),
7066 hexdec("06032a0304"),
7068 self.assertSequenceEqual(
7069 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
7070 hexdec("06092a864888932d010105"),
7072 self.assertSequenceEqual(
7073 ObjectIdentifier("2.100.3").encode(),
7074 hexdec("0603813403"),
7077 self.assertSequenceEqual(
7078 PrintableString("test").encode(),
7079 hexdec("130474657374"),
7081 self.assertSequenceEqual(
7082 PrintableString("x" * 127).encode(),
7083 hexdec("137F" + "78" * 127),
7085 self.assertSequenceEqual(
7086 PrintableString("x" * 128).encode(),
7087 hexdec("138180" + "78" * 128),
7089 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
7091 class Seq(Sequence):
7093 ("erste", IA5String()),
7096 seq["erste"] = IA5String("test")
7097 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
7099 class Seq(Sequence):
7101 ("erste", PrintableString()),
7104 seq["erste"] = PrintableString("test")
7105 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
7106 # Asterisk is actually not allowable
7107 PrintableString._allowable_chars |= set(b"*")
7108 seq["erste"] = PrintableString("test*")
7109 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
7110 PrintableString._allowable_chars -= set(b"*")
7112 class Seq(Sequence):
7114 ("erste", Any(optional=True)),
7115 ("zweite", Integer()),
7118 seq["zweite"] = Integer(64)
7119 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
7124 seq.append(Integer(10))
7125 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
7127 class _SeqOf(SequenceOf):
7128 schema = PrintableString()
7130 class SeqOf(SequenceOf):
7133 _seqof.append(PrintableString("1"))
7135 seqof.append(_seqof)
7136 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
7138 class Seq(Sequence):
7140 ("erste", Integer(default=1)),
7143 seq["erste"] = Integer(0)
7144 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
7145 seq["erste"] = Integer(1)
7146 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
7147 seq["erste"] = Integer(2)
7148 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
7151 class TestPP(TestCase):
7152 @given(data_strategy())
7153 def test_oid_printing(self, d):
7155 str(ObjectIdentifier(k)): v * 2
7156 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
7158 chosen = d.draw(sampled_from(sorted(oids)))
7159 chosen_id = oids[chosen]
7160 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
7161 self.assertNotIn(chosen_id, pp_console_row(pp))
7164 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
7168 class TestAutoAddSlots(TestCase):
7170 class Inher(Integer):
7173 with self.assertRaises(AttributeError):
7175 inher.unexistent = "whatever"
7178 class TestOIDDefines(TestCase):
7179 @given(data_strategy())
7180 def runTest(self, d):
7181 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
7182 value_name_chosen = d.draw(sampled_from(value_names))
7184 ObjectIdentifier(oid)
7185 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
7187 oid_chosen = d.draw(sampled_from(oids))
7188 values = d.draw(lists(
7190 min_size=len(value_names),
7191 max_size=len(value_names),
7193 for definable_class in (Any, OctetString, BitString):
7195 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
7196 oid: Integer() for oid in oids[:-1]
7199 for i, value_name in enumerate(value_names):
7200 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
7202 class Seq(Sequence):
7205 for value_name, value in zip(value_names, values):
7206 seq[value_name] = definable_class(Integer(value).encode())
7207 seq["type"] = oid_chosen
7208 seq, _ = Seq().decode(seq.encode())
7209 for value_name in value_names:
7210 if value_name == value_name_chosen:
7212 self.assertIsNone(seq[value_name].defined)
7213 if value_name_chosen in oids[:-1]:
7214 self.assertIsNotNone(seq[value_name_chosen].defined)
7215 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
7216 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
7219 pprint(seq, big_blobs=True, with_decode_path=True)
7222 class TestDefinesByPath(TestCase):
7223 def test_generated(self):
7224 class Seq(Sequence):
7226 ("type", ObjectIdentifier()),
7227 ("value", OctetString(expl=tag_ctxc(123))),
7230 class SeqInner(Sequence):
7232 ("typeInner", ObjectIdentifier()),
7233 ("valueInner", Any()),
7236 class PairValue(SetOf):
7239 class Pair(Sequence):
7241 ("type", ObjectIdentifier()),
7242 ("value", PairValue()),
7245 class Pairs(SequenceOf):
7252 type_octet_stringed,
7254 ObjectIdentifier(oid)
7255 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
7257 seq_integered = Seq()
7258 seq_integered["type"] = type_integered
7259 seq_integered["value"] = OctetString(Integer(123).encode())
7260 seq_integered_raw = seq_integered.encode()
7264 (type_octet_stringed, OctetString(b"whatever")),
7265 (type_integered, Integer(123)),
7266 (type_octet_stringed, OctetString(b"whenever")),
7267 (type_integered, Integer(234)),
7269 for t, v in pairs_input:
7272 ("value", PairValue((Any(v),))),
7274 seq_inner = SeqInner()
7275 seq_inner["typeInner"] = type_innered
7276 seq_inner["valueInner"] = Any(pairs)
7277 seq_sequenced = Seq()
7278 seq_sequenced["type"] = type_sequenced
7279 seq_sequenced["value"] = OctetString(seq_inner.encode())
7280 seq_sequenced_raw = seq_sequenced.encode()
7282 list(seq_sequenced.pps())
7283 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7285 defines_by_path = []
7286 ctx_copied = deepcopy(ctx_dummy)
7287 seq_integered, _ = Seq().decode(
7291 self.assertDictEqual(ctx_copied, ctx_dummy)
7292 self.assertIsNone(seq_integered["value"].defined)
7293 defines_by_path.append(
7294 (("type",), ((("value",), {
7295 type_integered: Integer(),
7296 type_sequenced: SeqInner(),
7299 ctx_copied["defines_by_path"] = defines_by_path
7300 seq_integered, _ = Seq().decode(
7304 del ctx_copied["defines_by_path"]
7305 self.assertDictEqual(ctx_copied, ctx_dummy)
7306 self.assertIsNotNone(seq_integered["value"].defined)
7307 self.assertEqual(seq_integered["value"].defined[0], type_integered)
7308 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
7309 self.assertTrue(seq_integered_raw[
7310 seq_integered["value"].defined[1].offset:
7311 ].startswith(Integer(123).encode()))
7313 list(seq_integered.pps())
7314 pprint(seq_integered, big_blobs=True, with_decode_path=True)
7316 ctx_copied["defines_by_path"] = defines_by_path
7317 seq_sequenced, _ = Seq().decode(
7321 del ctx_copied["defines_by_path"]
7322 self.assertDictEqual(ctx_copied, ctx_dummy)
7323 self.assertIsNotNone(seq_sequenced["value"].defined)
7324 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7325 seq_inner = seq_sequenced["value"].defined[1]
7326 self.assertIsNone(seq_inner["valueInner"].defined)
7328 list(seq_sequenced.pps())
7329 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7331 defines_by_path.append((
7332 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7333 ((("valueInner",), {type_innered: Pairs()}),),
7335 ctx_copied["defines_by_path"] = defines_by_path
7336 seq_sequenced, _ = Seq().decode(
7340 del ctx_copied["defines_by_path"]
7341 self.assertDictEqual(ctx_copied, ctx_dummy)
7342 self.assertIsNotNone(seq_sequenced["value"].defined)
7343 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7344 seq_inner = seq_sequenced["value"].defined[1]
7345 self.assertIsNotNone(seq_inner["valueInner"].defined)
7346 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7347 pairs = seq_inner["valueInner"].defined[1]
7349 self.assertIsNone(pair["value"][0].defined)
7351 list(seq_sequenced.pps())
7352 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7354 defines_by_path.append((
7357 DecodePathDefBy(type_sequenced),
7359 DecodePathDefBy(type_innered),
7364 type_integered: Integer(),
7365 type_octet_stringed: OctetString(),
7368 ctx_copied["defines_by_path"] = defines_by_path
7369 seq_sequenced, _ = Seq().decode(
7373 del ctx_copied["defines_by_path"]
7374 self.assertDictEqual(ctx_copied, ctx_dummy)
7375 self.assertIsNotNone(seq_sequenced["value"].defined)
7376 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7377 seq_inner = seq_sequenced["value"].defined[1]
7378 self.assertIsNotNone(seq_inner["valueInner"].defined)
7379 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7380 pairs_got = seq_inner["valueInner"].defined[1]
7381 for pair_input, pair_got in zip(pairs_input, pairs_got):
7382 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7383 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7385 list(seq_sequenced.pps())
7386 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7388 @given(oid_strategy(), integers())
7389 def test_simple(self, oid, tgt):
7390 class Inner(Sequence):
7392 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7393 ObjectIdentifier(oid): Integer(),
7397 class Outer(Sequence):
7400 ("tgt", OctetString()),
7404 inner["oid"] = ObjectIdentifier(oid)
7406 outer["inner"] = inner
7407 outer["tgt"] = OctetString(Integer(tgt).encode())
7408 decoded, _ = Outer().decode(outer.encode())
7409 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7411 def test_remaining_data(self):
7412 oid = ObjectIdentifier("1.2.3")
7413 class Seq(Sequence):
7415 ("oid", ObjectIdentifier(defines=((("tgt",), {
7418 ("tgt", OctetString()),
7423 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7425 with assertRaisesRegex(self, DecodeError, "remaining data"):
7426 Seq().decode(seq.encode())
7428 def test_remaining_data_seqof(self):
7429 oid = ObjectIdentifier("1.2.3")
7431 schema = OctetString()
7433 class Seq(Sequence):
7435 ("oid", ObjectIdentifier(defines=((("tgt",), {
7443 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7445 with assertRaisesRegex(self, DecodeError, "remaining data"):
7446 Seq().decode(seq.encode())
7449 class TestAbsDecodePath(TestCase):
7451 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7452 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7454 def test_concat(self, decode_path, rel_path):
7455 dp = abs_decode_path(decode_path, rel_path)
7456 self.assertSequenceEqual(dp, decode_path + rel_path)
7460 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7461 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7463 def test_abs(self, decode_path, rel_path):
7464 self.assertSequenceEqual(
7465 abs_decode_path(decode_path, ("/",) + rel_path),
7470 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7471 integers(min_value=1, max_value=3),
7472 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7474 def test_dots(self, decode_path, number_of_dots, rel_path):
7475 self.assertSequenceEqual(
7476 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7477 decode_path[:-number_of_dots] + rel_path,
7481 class TestStrictDefaultExistence(TestCase):
7482 @given(data_strategy())
7483 def runTest(self, d):
7484 count = d.draw(integers(min_value=1, max_value=10))
7485 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7487 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7488 for i in range(count)
7490 for klass in (Sequence, Set):
7494 for i in range(count):
7495 seq["int%d" % i] = Integer(123)
7497 chosen_choice = "int%d" % chosen
7498 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7499 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7501 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7502 self.assertTrue(decoded.ber_encoded)
7503 self.assertTrue(decoded.bered)
7504 decoded = copy(decoded)
7505 self.assertTrue(decoded.ber_encoded)
7506 self.assertTrue(decoded.bered)
7507 decoded, _ = seq.decode(raw, ctx={"bered": True})
7508 self.assertTrue(decoded.ber_encoded)
7509 self.assertTrue(decoded.bered)
7510 decoded = copy(decoded)
7511 self.assertTrue(decoded.ber_encoded)
7512 self.assertTrue(decoded.bered)
7515 class TestX690PrefixedType(TestCase):
7517 self.assertSequenceEqual(
7518 VisibleString("Jones").encode(),
7519 hexdec("1A054A6F6E6573"),
7521 self.assertSequenceEqual(
7524 impl=tag_encode(3, klass=TagClassApplication),
7526 hexdec("43054A6F6E6573"),
7528 self.assertSequenceEqual(
7532 impl=tag_encode(3, klass=TagClassApplication),
7536 hexdec("A20743054A6F6E6573"),
7538 self.assertSequenceEqual(
7542 impl=tag_encode(3, klass=TagClassApplication),
7544 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7546 hexdec("670743054A6F6E6573"),
7548 self.assertSequenceEqual(
7549 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7550 hexdec("82054A6F6E6573"),
7554 class TestExplOOB(TestCase):
7556 expl = tag_ctxc(123)
7557 raw = Integer(123).encode() + Integer(234).encode()
7558 raw = b"".join((expl, len_encode(len(raw)), raw))
7559 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7560 Integer(expl=expl).decode(raw)
7561 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7564 class TestPickleDifferentVersion(TestCase):
7566 pickled = pickle_dumps(Integer(123), pickle_proto)
7568 version_orig = pyderasn.__version__
7569 pyderasn.__version__ += "different"
7570 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7571 pickle_loads(pickled)
7572 pyderasn.__version__ = version_orig
7573 pickle_loads(pickled)
7576 class TestCERSetOrdering(TestCase):
7577 def test_vectors(self):
7578 """Taken from X.690-201508
7582 ("c", Integer(impl=tag_ctxp(2))),
7583 ("d", Integer(impl=tag_ctxp(4))),
7588 ("g", Integer(impl=tag_ctxp(5))),
7589 ("h", Integer(impl=tag_ctxp(6))),
7594 ("j", Integer(impl=tag_ctxp(0))),
7605 ("a", Integer(impl=tag_ctxp(3))),
7606 ("b", B(expl=tag_ctxc(1))),
7611 ("a", Integer(123)),
7612 ("b", B(("d", Integer(234)))),
7613 ("e", E(("f", F(("g", Integer(345)))))),
7615 order = sorted(a._values_for_encoding(), key=attrgetter("tag_order_cer"))
7616 self.assertSequenceEqual(
7617 [i.__class__.__name__ for i in order],
7618 ("E", "B", "Integer"),