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 random import random
24 from string import ascii_letters
25 from string import digits
26 from string import printable
27 from string import whitespace
28 from time import mktime
30 from unittest import TestCase
32 from hypothesis import assume
33 from hypothesis import given
34 from hypothesis import settings
35 from hypothesis.strategies import binary
36 from hypothesis.strategies import booleans
37 from hypothesis.strategies import composite
38 from hypothesis.strategies import data as data_strategy
39 from hypothesis.strategies import datetimes
40 from hypothesis.strategies import dictionaries
41 from hypothesis.strategies import integers
42 from hypothesis.strategies import just
43 from hypothesis.strategies import lists
44 from hypothesis.strategies import none
45 from hypothesis.strategies import one_of
46 from hypothesis.strategies import permutations
47 from hypothesis.strategies import sampled_from
48 from hypothesis.strategies import sets
49 from hypothesis.strategies import text
50 from hypothesis.strategies import tuples
51 from six import assertRaisesRegex
52 from six import binary_type
53 from six import byte2int
54 from six import indexbytes
55 from six import int2byte
56 from six import iterbytes
58 from six import text_type
59 from six import unichr as six_unichr
60 from six.moves.cPickle import dumps as pickle_dumps
61 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
62 from six.moves.cPickle import loads as pickle_loads
64 from pyderasn import _pp
65 from pyderasn import abs_decode_path
66 from pyderasn import Any
67 from pyderasn import BitString
68 from pyderasn import BMPString
69 from pyderasn import Boolean
70 from pyderasn import BoundsError
71 from pyderasn import Choice
72 from pyderasn import DecodeError
73 from pyderasn import DecodePathDefBy
74 from pyderasn import Enumerated
75 from pyderasn import EOC
76 from pyderasn import EOC_LEN
77 from pyderasn import ExceedingData
78 from pyderasn import GeneralizedTime
79 from pyderasn import GeneralString
80 from pyderasn import GraphicString
81 from pyderasn import hexdec
82 from pyderasn import hexenc
83 from pyderasn import IA5String
84 from pyderasn import Integer
85 from pyderasn import InvalidLength
86 from pyderasn import InvalidOID
87 from pyderasn import InvalidValueType
88 from pyderasn import len_decode
89 from pyderasn import len_encode
90 from pyderasn import LEN_YYMMDDHHMMSSZ
91 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
92 from pyderasn import LEN_YYYYMMDDHHMMSSZ
93 from pyderasn import LENINDEF
94 from pyderasn import LenIndefForm
95 from pyderasn import NotEnoughData
96 from pyderasn import Null
97 from pyderasn import NumericString
98 from pyderasn import ObjectIdentifier
99 from pyderasn import ObjNotReady
100 from pyderasn import ObjUnknown
101 from pyderasn import OctetString
102 from pyderasn import pp_console_row
103 from pyderasn import pprint
104 from pyderasn import PrintableString
105 from pyderasn import Sequence
106 from pyderasn import SequenceOf
107 from pyderasn import Set
108 from pyderasn import SetOf
109 from pyderasn import tag_ctxc
110 from pyderasn import tag_ctxp
111 from pyderasn import tag_decode
112 from pyderasn import tag_encode
113 from pyderasn import tag_strip
114 from pyderasn import TagClassApplication
115 from pyderasn import TagClassContext
116 from pyderasn import TagClassPrivate
117 from pyderasn import TagClassUniversal
118 from pyderasn import TagFormConstructed
119 from pyderasn import TagFormPrimitive
120 from pyderasn import TagMismatch
121 from pyderasn import TeletexString
122 from pyderasn import UniversalString
123 from pyderasn import UTCTime
124 from pyderasn import UTF8String
125 from pyderasn import VideotexString
126 from pyderasn import VisibleString
129 settings.register_profile("local", settings(
132 settings.load_profile("local")
133 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
135 tag_classes = sampled_from((
141 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
142 decode_path_strat = lists(integers(), max_size=3).map(
143 lambda decode_path: tuple(str(dp) for dp in decode_path)
145 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
148 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
150 self_module = import_module(__name__)
153 def register_class(klass):
154 klassname = klass.__name__ + str(time()).replace(".", "")
155 klass.__name__ = klassname
156 klass.__qualname__ = klassname
157 setattr(self_module, klassname, klass)
160 def assert_exceeding_data(self, call, junk):
163 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
168 class TestHex(TestCase):
170 def test_symmetric(self, data):
171 self.assertEqual(hexdec(hexenc(data)), data)
174 class TestTagCoder(TestCase):
175 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
179 integers(min_value=0, max_value=30),
182 def test_short(self, klass, form, num, junk):
183 raw = tag_encode(klass=klass, form=form, num=num)
184 self.assertEqual(tag_decode(raw), (klass, form, num))
185 self.assertEqual(len(raw), 1)
187 byte2int(tag_encode(klass=klass, form=form, num=0)),
188 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
190 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
191 self.assertSequenceEqual(stripped.tobytes(), raw)
192 self.assertEqual(tlen, len(raw))
193 self.assertSequenceEqual(tail, junk)
195 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
199 integers(min_value=31),
202 def test_long(self, klass, form, num, junk):
203 raw = tag_encode(klass=klass, form=form, num=num)
204 self.assertEqual(tag_decode(raw), (klass, form, num))
205 self.assertGreater(len(raw), 1)
207 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
210 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
211 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
212 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
213 self.assertSequenceEqual(stripped.tobytes(), raw)
214 self.assertEqual(tlen, len(raw))
215 self.assertSequenceEqual(tail, junk)
217 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
218 @given(integers(min_value=31))
219 def test_unfinished_tag(self, num):
220 raw = bytearray(tag_encode(num=num))
221 for i in range(1, len(raw)):
223 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
224 tag_strip(bytes(raw))
226 def test_go_vectors_valid(self):
227 for data, (eklass, etag, elen, eform) in (
228 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
229 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
230 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
231 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
232 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
233 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
234 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
235 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
236 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
237 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
239 tag, _, len_encoded = tag_strip(memoryview(data))
240 klass, form, num = tag_decode(tag)
241 _len, _, tail = len_decode(len_encoded)
242 self.assertSequenceEqual(tail, b"")
243 self.assertEqual(klass, eklass)
244 self.assertEqual(num, etag)
245 self.assertEqual(_len, elen)
246 self.assertEqual(form, eform)
248 def test_go_vectors_invalid(self):
256 with self.assertRaises(DecodeError):
257 _, _, len_encoded = tag_strip(memoryview(data))
258 len_decode(len_encoded)
261 integers(min_value=0, max_value=127),
262 integers(min_value=0, max_value=2),
264 def test_long_instead_of_short(self, l, dummy_num):
265 octets = (b"\x00" * dummy_num) + int2byte(l)
266 octets = int2byte((dummy_num + 1) | 0x80) + octets
267 with self.assertRaises(DecodeError):
271 class TestLenCoder(TestCase):
272 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
274 integers(min_value=0, max_value=127),
277 def test_short(self, l, junk):
278 raw = len_encode(l) + junk
279 decoded, llen, tail = len_decode(memoryview(raw))
280 self.assertEqual(decoded, l)
281 self.assertEqual(llen, 1)
282 self.assertEqual(len(raw), 1 + len(junk))
283 self.assertEqual(tail.tobytes(), junk)
285 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
287 integers(min_value=128),
290 def test_long(self, l, junk):
291 raw = len_encode(l) + junk
292 decoded, llen, tail = len_decode(memoryview(raw))
293 self.assertEqual(decoded, l)
294 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
295 self.assertEqual(llen, len(raw) - len(junk))
296 self.assertNotEqual(indexbytes(raw, 1), 0)
297 self.assertSequenceEqual(tail.tobytes(), junk)
299 def test_empty(self):
300 with self.assertRaises(NotEnoughData):
303 @given(integers(min_value=128))
304 def test_stripped(self, _len):
305 with self.assertRaises(NotEnoughData):
306 len_decode(len_encode(_len)[:-1])
309 text_printable = text(alphabet=printable, min_size=1)
313 def text_letters(draw):
314 result = draw(text(alphabet=ascii_letters, min_size=1))
316 result = result.encode("ascii")
320 class CommonMixin(object):
321 def test_tag_default(self):
322 obj = self.base_klass()
323 self.assertEqual(obj.tag, obj.tag_default)
325 def test_simultaneous_impl_expl(self):
326 with self.assertRaises(ValueError):
327 self.base_klass(impl=b"whatever", expl=b"whenever")
329 @given(binary(min_size=1), integers(), integers(), integers())
330 def test_decoded(self, impl, offset, llen, vlen):
331 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
332 self.assertEqual(obj.offset, offset)
333 self.assertEqual(obj.llen, llen)
334 self.assertEqual(obj.vlen, vlen)
335 self.assertEqual(obj.tlen, len(impl))
336 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
338 @given(binary(min_size=1))
339 def test_impl_inherited(self, impl_tag):
340 class Inherited(self.base_klass):
343 self.assertSequenceEqual(obj.impl, impl_tag)
344 self.assertFalse(obj.expled)
347 def test_expl_inherited(self, expl_tag):
348 class Inherited(self.base_klass):
351 self.assertSequenceEqual(obj.expl, expl_tag)
352 self.assertTrue(obj.expled)
354 def assert_copied_basic_fields(self, obj, obj_copied):
355 self.assertEqual(obj, obj_copied)
356 self.assertSequenceEqual(obj.tag, obj_copied.tag)
357 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
358 self.assertEqual(obj.default, obj_copied.default)
359 self.assertEqual(obj.optional, obj_copied.optional)
360 self.assertEqual(obj.offset, obj_copied.offset)
361 self.assertEqual(obj.llen, obj_copied.llen)
362 self.assertEqual(obj.vlen, obj_copied.vlen)
366 def boolean_values_strategy(draw, do_expl=False):
367 value = draw(one_of(none(), booleans()))
371 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
373 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
374 default = draw(one_of(none(), booleans()))
375 optional = draw(one_of(none(), booleans()))
377 draw(integers(min_value=0)),
378 draw(integers(min_value=0)),
379 draw(integers(min_value=0)),
381 return (value, impl, expl, default, optional, _decoded)
384 class BooleanInherited(Boolean):
388 class TestBoolean(CommonMixin, TestCase):
391 def test_invalid_value_type(self):
392 with self.assertRaises(InvalidValueType) as err:
397 def test_optional(self, optional):
398 obj = Boolean(default=Boolean(False), optional=optional)
399 self.assertTrue(obj.optional)
402 def test_ready(self, value):
404 self.assertFalse(obj.ready)
407 pprint(obj, big_blobs=True, with_decode_path=True)
408 with self.assertRaises(ObjNotReady) as err:
412 self.assertTrue(obj.ready)
415 pprint(obj, big_blobs=True, with_decode_path=True)
417 @given(booleans(), booleans(), binary(), binary())
418 def test_comparison(self, value1, value2, tag1, tag2):
419 for klass in (Boolean, BooleanInherited):
422 self.assertEqual(obj1 == obj2, value1 == value2)
423 self.assertEqual(obj1 != obj2, value1 != value2)
424 self.assertEqual(obj1 == bool(obj2), value1 == value2)
425 obj1 = klass(value1, impl=tag1)
426 obj2 = klass(value1, impl=tag2)
427 self.assertEqual(obj1 == obj2, tag1 == tag2)
428 self.assertEqual(obj1 != obj2, tag1 != tag2)
430 @given(data_strategy())
431 def test_call(self, d):
432 for klass in (Boolean, BooleanInherited):
440 ) = d.draw(boolean_values_strategy())
446 optional_initial or False,
456 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
457 obj = obj_initial(value, impl, expl, default, optional)
459 value_expected = default if value is None else value
461 default_initial if value_expected is None
464 self.assertEqual(obj, value_expected)
465 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
466 self.assertEqual(obj.expl_tag, expl or expl_initial)
469 default_initial if default is None else default,
471 if obj.default is None:
472 optional = optional_initial if optional is None else optional
473 optional = False if optional is None else optional
476 self.assertEqual(obj.optional, optional)
478 @given(boolean_values_strategy())
479 def test_copy(self, values):
480 for klass in (Boolean, BooleanInherited):
482 for copy_func in copy_funcs:
483 obj_copied = copy_func(obj)
484 self.assert_copied_basic_fields(obj, obj_copied)
488 integers(min_value=1).map(tag_encode),
490 def test_stripped(self, value, tag_impl):
491 obj = Boolean(value, impl=tag_impl)
492 with self.assertRaises(NotEnoughData):
493 obj.decode(obj.encode()[:-1])
497 integers(min_value=1).map(tag_ctxc),
499 def test_stripped_expl(self, value, tag_expl):
500 obj = Boolean(value, expl=tag_expl)
501 with self.assertRaises(NotEnoughData):
502 obj.decode(obj.encode()[:-1])
505 integers(min_value=31),
506 integers(min_value=0),
509 def test_bad_tag(self, tag, offset, decode_path):
510 with self.assertRaises(DecodeError) as err:
512 tag_encode(tag)[:-1],
514 decode_path=decode_path,
517 self.assertEqual(err.exception.offset, offset)
518 self.assertEqual(err.exception.decode_path, decode_path)
521 integers(min_value=31),
522 integers(min_value=0),
525 def test_bad_expl_tag(self, tag, offset, decode_path):
526 with self.assertRaises(DecodeError) as err:
527 Boolean(expl=Boolean.tag_default).decode(
528 tag_encode(tag)[:-1],
530 decode_path=decode_path,
533 self.assertEqual(err.exception.offset, offset)
534 self.assertEqual(err.exception.decode_path, decode_path)
537 integers(min_value=128),
538 integers(min_value=0),
541 def test_bad_len(self, l, offset, decode_path):
542 with self.assertRaises(DecodeError) as err:
544 Boolean.tag_default + len_encode(l)[:-1],
546 decode_path=decode_path,
549 self.assertEqual(err.exception.offset, offset)
550 self.assertEqual(err.exception.decode_path, decode_path)
553 integers(min_value=128),
554 integers(min_value=0),
557 def test_bad_expl_len(self, l, offset, decode_path):
558 with self.assertRaises(DecodeError) as err:
559 Boolean(expl=Boolean.tag_default).decode(
560 Boolean.tag_default + len_encode(l)[:-1],
562 decode_path=decode_path,
565 self.assertEqual(err.exception.offset, offset)
566 self.assertEqual(err.exception.decode_path, decode_path)
568 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
570 boolean_values_strategy(),
572 integers(min_value=1).map(tag_ctxc),
573 integers(min_value=0),
576 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
577 for klass in (Boolean, BooleanInherited):
578 _, _, _, default, optional, _decoded = values
587 pprint(obj, big_blobs=True, with_decode_path=True)
588 self.assertFalse(obj.expled)
589 obj_encoded = obj.encode()
590 obj_expled = obj(value, expl=tag_expl)
591 self.assertTrue(obj_expled.expled)
593 list(obj_expled.pps())
594 pprint(obj_expled, big_blobs=True, with_decode_path=True)
595 obj_expled_hex_encoded = obj_expled.hexencode()
596 ctx_copied = deepcopy(ctx_dummy)
597 obj_decoded, tail = obj_expled.hexdecode(
598 obj_expled_hex_encoded + hexenc(tail_junk),
602 self.assertDictEqual(ctx_copied, ctx_dummy)
604 list(obj_decoded.pps())
605 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
606 self.assertEqual(tail, tail_junk)
607 self.assertEqual(obj_decoded, obj_expled)
608 self.assertNotEqual(obj_decoded, obj)
609 self.assertEqual(bool(obj_decoded), bool(obj_expled))
610 self.assertEqual(bool(obj_decoded), bool(obj))
611 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
612 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
613 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
615 obj_decoded.expl_llen,
616 len(len_encode(len(obj_encoded))),
618 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
619 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
622 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
624 self.assertEqual(obj_decoded.expl_offset, offset)
625 assert_exceeding_data(
627 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
631 @given(integers(min_value=2))
632 def test_invalid_len(self, l):
633 with self.assertRaises(InvalidLength):
634 Boolean().decode(b"".join((
640 @given(integers(min_value=0 + 1, max_value=255 - 1))
641 def test_ber_value(self, value):
642 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
643 Boolean().decode(b"".join((
648 obj, _ = Boolean().decode(
656 self.assertTrue(bool(obj))
657 self.assertTrue(obj.ber_encoded)
658 self.assertFalse(obj.lenindef)
659 self.assertTrue(obj.bered)
661 self.assertTrue(obj.ber_encoded)
662 self.assertFalse(obj.lenindef)
663 self.assertTrue(obj.bered)
666 integers(min_value=1).map(tag_ctxc),
667 binary().filter(lambda x: not x.startswith(EOC)),
669 def test_ber_expl_no_eoc(self, expl, junk):
670 encoded = expl + LENINDEF + Boolean(False).encode()
671 with self.assertRaises(LenIndefForm):
672 Boolean(expl=expl).decode(encoded + junk)
673 with assertRaisesRegex(self, DecodeError, "no EOC"):
674 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
675 obj, tail = Boolean(expl=expl).decode(
676 encoded + EOC + junk,
679 self.assertTrue(obj.expl_lenindef)
680 self.assertFalse(obj.lenindef)
681 self.assertFalse(obj.ber_encoded)
682 self.assertTrue(obj.bered)
684 self.assertTrue(obj.expl_lenindef)
685 self.assertFalse(obj.lenindef)
686 self.assertFalse(obj.ber_encoded)
687 self.assertTrue(obj.bered)
688 self.assertSequenceEqual(tail, junk)
691 pprint(obj, big_blobs=True, with_decode_path=True)
694 integers(min_value=1).map(tag_ctxc),
701 def test_ber_expl(self, expl, values):
707 Boolean(value).encode() +
710 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
712 class SeqOf(SequenceOf):
713 schema = Boolean(expl=expl)
714 with self.assertRaises(LenIndefForm):
715 SeqOf().decode(encoded)
716 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
717 self.assertSequenceEqual(tail, b"")
718 self.assertSequenceEqual([bool(v) for v in seqof], values)
734 len(expl) + 1 + 3 + EOC_LEN,
745 pprint(seqof, big_blobs=True, with_decode_path=True)
749 def integer_values_strategy(draw, do_expl=False):
750 bound_min, value, default, bound_max = sorted(draw(sets(
759 _specs = draw(sets(text_letters()))
762 min_size=len(_specs),
763 max_size=len(_specs),
765 _specs = list(zip(_specs, values))
768 bounds = (bound_min, bound_max)
772 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
774 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
777 optional = draw(one_of(none(), booleans()))
779 draw(integers(min_value=0)),
780 draw(integers(min_value=0)),
781 draw(integers(min_value=0)),
783 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
786 class IntegerInherited(Integer):
790 class TestInteger(CommonMixin, TestCase):
793 def test_invalid_value_type(self):
794 with self.assertRaises(InvalidValueType) as err:
798 @given(sets(text_letters(), min_size=2))
799 def test_unknown_name(self, names_input):
800 missing = names_input.pop()
803 schema = [(n, 123) for n in names_input]
804 with self.assertRaises(ObjUnknown) as err:
808 @given(sets(text_letters(), min_size=2))
809 def test_known_name(self, names_input):
811 schema = [(n, 123) for n in names_input]
812 Int(names_input.pop())
815 def test_optional(self, optional):
816 obj = Integer(default=Integer(0), optional=optional)
817 self.assertTrue(obj.optional)
820 def test_ready(self, value):
822 self.assertFalse(obj.ready)
825 pprint(obj, big_blobs=True, with_decode_path=True)
826 with self.assertRaises(ObjNotReady) as err:
830 self.assertTrue(obj.ready)
833 pprint(obj, big_blobs=True, with_decode_path=True)
836 @given(integers(), integers(), binary(), binary())
837 def test_comparison(self, value1, value2, tag1, tag2):
838 for klass in (Integer, IntegerInherited):
841 self.assertEqual(obj1 == obj2, value1 == value2)
842 self.assertEqual(obj1 != obj2, value1 != value2)
843 self.assertEqual(obj1 == int(obj2), value1 == value2)
844 obj1 = klass(value1, impl=tag1)
845 obj2 = klass(value1, impl=tag2)
846 self.assertEqual(obj1 == obj2, tag1 == tag2)
847 self.assertEqual(obj1 != obj2, tag1 != tag2)
849 @given(lists(integers()))
850 def test_sorted_works(self, values):
851 self.assertSequenceEqual(
852 [int(v) for v in sorted(Integer(v) for v in values)],
856 @given(data_strategy())
857 def test_named(self, d):
858 names_input = list(d.draw(sets(text_letters(), min_size=1)))
859 values_input = list(d.draw(sets(
861 min_size=len(names_input),
862 max_size=len(names_input),
864 chosen_name = d.draw(sampled_from(names_input))
865 names_input = dict(zip(names_input, values_input))
869 _int = Int(chosen_name)
870 self.assertEqual(_int.named, chosen_name)
871 self.assertEqual(int(_int), names_input[chosen_name])
873 @given(integers(), integers(min_value=0), integers(min_value=0))
874 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
875 value = bound_min + value_delta
876 bound_max = value + bound_delta
877 Integer(value=value, bounds=(bound_min, bound_max))
879 @given(sets(integers(), min_size=3, max_size=3))
880 def test_bounds_unsatisfied(self, values):
881 values = sorted(values)
882 with self.assertRaises(BoundsError) as err:
883 Integer(value=values[0], bounds=(values[1], values[2]))
885 with assertRaisesRegex(self, DecodeError, "bounds") as err:
886 Integer(bounds=(values[1], values[2])).decode(
887 Integer(values[0]).encode()
890 with self.assertRaises(BoundsError) as err:
891 Integer(value=values[2], bounds=(values[0], values[1]))
893 with assertRaisesRegex(self, DecodeError, "bounds") as err:
894 Integer(bounds=(values[0], values[1])).decode(
895 Integer(values[2]).encode()
899 @given(data_strategy())
900 def test_call(self, d):
901 for klass in (Integer, IntegerInherited):
911 ) = d.draw(integer_values_strategy())
918 optional_initial or False,
931 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
932 if (default is None) and (obj_initial.default is not None):
936 (value is not None) and
937 (bounds_initial is not None) and
938 not (bounds_initial[0] <= value <= bounds_initial[1])
943 (default is not None) and
944 (bounds_initial is not None) and
945 not (bounds_initial[0] <= default <= bounds_initial[1])
948 obj = obj_initial(value, bounds, impl, expl, default, optional)
950 value_expected = default if value is None else value
952 default_initial if value_expected is None
955 self.assertEqual(obj, value_expected)
956 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
957 self.assertEqual(obj.expl_tag, expl or expl_initial)
960 default_initial if default is None else default,
962 if obj.default is None:
963 optional = optional_initial if optional is None else optional
964 optional = False if optional is None else optional
967 self.assertEqual(obj.optional, optional)
969 (obj._bound_min, obj._bound_max),
970 bounds or bounds_initial or (float("-inf"), float("+inf")),
974 {} if _specs_initial is None else dict(_specs_initial),
977 @given(integer_values_strategy())
978 def test_copy(self, values):
979 for klass in (Integer, IntegerInherited):
981 for copy_func in copy_funcs:
982 obj_copied = copy_func(obj)
983 self.assert_copied_basic_fields(obj, obj_copied)
984 self.assertEqual(obj.specs, obj_copied.specs)
985 self.assertEqual(obj._bound_min, obj_copied._bound_min)
986 self.assertEqual(obj._bound_max, obj_copied._bound_max)
987 self.assertEqual(obj._value, obj_copied._value)
991 integers(min_value=1).map(tag_encode),
993 def test_stripped(self, value, tag_impl):
994 obj = Integer(value, impl=tag_impl)
995 with self.assertRaises(NotEnoughData):
996 obj.decode(obj.encode()[:-1])
1000 integers(min_value=1).map(tag_ctxc),
1002 def test_stripped_expl(self, value, tag_expl):
1003 obj = Integer(value, expl=tag_expl)
1004 with self.assertRaises(NotEnoughData):
1005 obj.decode(obj.encode()[:-1])
1007 def test_zero_len(self):
1008 with self.assertRaises(NotEnoughData):
1009 Integer().decode(b"".join((
1010 Integer.tag_default,
1015 integers(min_value=31),
1016 integers(min_value=0),
1019 def test_bad_tag(self, tag, offset, decode_path):
1020 with self.assertRaises(DecodeError) as err:
1022 tag_encode(tag)[:-1],
1024 decode_path=decode_path,
1027 self.assertEqual(err.exception.offset, offset)
1028 self.assertEqual(err.exception.decode_path, decode_path)
1031 integers(min_value=128),
1032 integers(min_value=0),
1035 def test_bad_len(self, l, offset, decode_path):
1036 with self.assertRaises(DecodeError) as err:
1038 Integer.tag_default + len_encode(l)[:-1],
1040 decode_path=decode_path,
1043 self.assertEqual(err.exception.offset, offset)
1044 self.assertEqual(err.exception.decode_path, decode_path)
1047 sets(integers(), min_size=2, max_size=2),
1048 integers(min_value=0),
1051 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1052 value, bound_min = list(sorted(ints))
1055 bounds = (bound_min, bound_min)
1056 with self.assertRaises(DecodeError) as err:
1058 Integer(value).encode(),
1060 decode_path=decode_path,
1063 self.assertEqual(err.exception.offset, offset)
1064 self.assertEqual(err.exception.decode_path, decode_path)
1066 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1068 integer_values_strategy(),
1070 integers(min_value=1).map(tag_ctxc),
1071 integers(min_value=0),
1074 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1075 for klass in (Integer, IntegerInherited):
1076 _, _, _, _, default, optional, _, _decoded = values
1085 pprint(obj, big_blobs=True, with_decode_path=True)
1086 self.assertFalse(obj.expled)
1087 obj_encoded = obj.encode()
1088 obj_expled = obj(value, expl=tag_expl)
1089 self.assertTrue(obj_expled.expled)
1091 list(obj_expled.pps())
1092 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1093 obj_expled_encoded = obj_expled.encode()
1094 ctx_copied = deepcopy(ctx_dummy)
1095 obj_decoded, tail = obj_expled.decode(
1096 obj_expled_encoded + tail_junk,
1100 self.assertDictEqual(ctx_copied, ctx_dummy)
1102 list(obj_decoded.pps())
1103 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1104 self.assertEqual(tail, tail_junk)
1105 self.assertEqual(obj_decoded, obj_expled)
1106 self.assertNotEqual(obj_decoded, obj)
1107 self.assertEqual(int(obj_decoded), int(obj_expled))
1108 self.assertEqual(int(obj_decoded), int(obj))
1109 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1110 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1111 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1113 obj_decoded.expl_llen,
1114 len(len_encode(len(obj_encoded))),
1116 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1117 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1120 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1122 self.assertEqual(obj_decoded.expl_offset, offset)
1123 assert_exceeding_data(
1125 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1129 def test_go_vectors_valid(self):
1130 for data, expect in ((
1134 (b"\xff\x7f", -129),
1138 (b"\xff\x00", -256),
1142 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1143 (b"\x80\x00\x00\x00", -2147483648),
1146 Integer().decode(b"".join((
1147 Integer.tag_default,
1148 len_encode(len(data)),
1154 def test_go_vectors_invalid(self):
1159 with self.assertRaises(DecodeError):
1160 Integer().decode(b"".join((
1161 Integer.tag_default,
1162 len_encode(len(data)),
1168 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1171 if draw(booleans()):
1172 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1174 integers(min_value=0, max_value=255),
1175 min_size=len(schema),
1176 max_size=len(schema),
1178 schema = list(zip(schema, bits))
1180 def _value(value_required):
1181 if not value_required and draw(booleans()):
1183 generation_choice = 0
1185 generation_choice = draw(sampled_from((1, 2, 3)))
1186 if generation_choice == 1 or draw(booleans()):
1187 return "'%s'B" % "".join(draw(lists(
1188 sampled_from(("0", "1")),
1189 max_size=len(schema),
1191 if generation_choice == 2 or draw(booleans()):
1192 return draw(binary(max_size=len(schema) // 8))
1193 if generation_choice == 3 or draw(booleans()):
1194 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1196 value = _value(value_required)
1197 default = _value(value_required=False)
1201 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1203 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1204 optional = draw(one_of(none(), booleans()))
1206 draw(integers(min_value=0)),
1207 draw(integers(min_value=0)),
1208 draw(integers(min_value=0)),
1210 return (schema, value, impl, expl, default, optional, _decoded)
1213 class BitStringInherited(BitString):
1217 class TestBitString(CommonMixin, TestCase):
1218 base_klass = BitString
1220 @given(lists(booleans()))
1221 def test_b_encoding(self, bits):
1222 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1223 self.assertEqual(obj.bit_len, len(bits))
1224 self.assertSequenceEqual(list(obj), bits)
1225 for i, bit in enumerate(bits):
1226 self.assertEqual(obj[i], bit)
1228 @given(lists(booleans()))
1229 def test_out_of_bounds_bits(self, bits):
1230 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1231 for i in range(len(bits), len(bits) * 2):
1232 self.assertFalse(obj[i])
1234 def test_bad_b_encoding(self):
1235 with self.assertRaises(ValueError):
1236 BitString("'010120101'B")
1239 integers(min_value=1, max_value=255),
1240 integers(min_value=1, max_value=255),
1242 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1243 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1244 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1245 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1247 class BS(BitString):
1248 schema = (("whatever", 0),)
1249 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1250 self.assertEqual(obj.bit_len, leading_zeros + 1)
1251 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1253 def test_zero_len(self):
1254 with self.assertRaises(NotEnoughData):
1255 BitString().decode(b"".join((
1256 BitString.tag_default,
1260 def test_invalid_value_type(self):
1261 with self.assertRaises(InvalidValueType) as err:
1264 with self.assertRaises(InvalidValueType) as err:
1268 def test_obj_unknown(self):
1269 with self.assertRaises(ObjUnknown) as err:
1270 BitString(b"whatever")["whenever"]
1273 def test_get_invalid_type(self):
1274 with self.assertRaises(InvalidValueType) as err:
1275 BitString(b"whatever")[(1, 2, 3)]
1278 @given(data_strategy())
1279 def test_unknown_name(self, d):
1280 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1281 missing = _schema.pop()
1283 class BS(BitString):
1284 schema = [(n, i) for i, n in enumerate(_schema)]
1285 with self.assertRaises(ObjUnknown) as err:
1290 def test_optional(self, optional):
1291 obj = BitString(default=BitString(b""), optional=optional)
1292 self.assertTrue(obj.optional)
1295 def test_ready(self, value):
1297 self.assertFalse(obj.ready)
1300 pprint(obj, big_blobs=True, with_decode_path=True)
1301 with self.assertRaises(ObjNotReady) as err:
1304 obj = BitString(value)
1305 self.assertTrue(obj.ready)
1308 pprint(obj, big_blobs=True, with_decode_path=True)
1311 tuples(integers(min_value=0), binary()),
1312 tuples(integers(min_value=0), binary()),
1316 def test_comparison(self, value1, value2, tag1, tag2):
1317 for klass in (BitString, BitStringInherited):
1318 obj1 = klass(value1)
1319 obj2 = klass(value2)
1320 self.assertEqual(obj1 == obj2, value1 == value2)
1321 self.assertEqual(obj1 != obj2, value1 != value2)
1322 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1323 obj1 = klass(value1, impl=tag1)
1324 obj2 = klass(value1, impl=tag2)
1325 self.assertEqual(obj1 == obj2, tag1 == tag2)
1326 self.assertEqual(obj1 != obj2, tag1 != tag2)
1328 @given(data_strategy())
1329 def test_call(self, d):
1330 for klass in (BitString, BitStringInherited):
1339 ) = d.draw(bit_string_values_strategy())
1342 schema = schema_initial
1344 value=value_initial,
1347 default=default_initial,
1348 optional=optional_initial or False,
1349 _decoded=_decoded_initial,
1359 ) = d.draw(bit_string_values_strategy(
1360 schema=schema_initial,
1361 do_expl=impl_initial is None,
1370 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1371 self.assertEqual(obj.expl_tag, expl or expl_initial)
1372 if obj.default is None:
1373 optional = optional_initial if optional is None else optional
1374 optional = False if optional is None else optional
1377 self.assertEqual(obj.optional, optional)
1378 self.assertEqual(obj.specs, obj_initial.specs)
1380 @given(bit_string_values_strategy())
1381 def test_copy(self, values):
1382 for klass in (BitString, BitStringInherited):
1383 _schema, value, impl, expl, default, optional, _decoded = values
1393 optional=optional or False,
1396 for copy_func in copy_funcs:
1397 obj_copied = copy_func(obj)
1398 self.assert_copied_basic_fields(obj, obj_copied)
1399 self.assertEqual(obj.specs, obj_copied.specs)
1400 self.assertEqual(obj._value, obj_copied._value)
1404 integers(min_value=1).map(tag_encode),
1406 def test_stripped(self, value, tag_impl):
1407 obj = BitString(value, impl=tag_impl)
1408 with self.assertRaises(NotEnoughData):
1409 obj.decode(obj.encode()[:-1])
1413 integers(min_value=1).map(tag_ctxc),
1415 def test_stripped_expl(self, value, tag_expl):
1416 obj = BitString(value, expl=tag_expl)
1417 with self.assertRaises(NotEnoughData):
1418 obj.decode(obj.encode()[:-1])
1421 integers(min_value=31),
1422 integers(min_value=0),
1425 def test_bad_tag(self, tag, offset, decode_path):
1426 with self.assertRaises(DecodeError) as err:
1428 tag_encode(tag)[:-1],
1430 decode_path=decode_path,
1433 self.assertEqual(err.exception.offset, offset)
1434 self.assertEqual(err.exception.decode_path, decode_path)
1437 integers(min_value=128),
1438 integers(min_value=0),
1441 def test_bad_len(self, l, offset, decode_path):
1442 with self.assertRaises(DecodeError) as err:
1444 BitString.tag_default + len_encode(l)[:-1],
1446 decode_path=decode_path,
1449 self.assertEqual(err.exception.offset, offset)
1450 self.assertEqual(err.exception.decode_path, decode_path)
1452 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1453 @given(data_strategy())
1454 def test_symmetric(self, d):
1463 ) = d.draw(bit_string_values_strategy(value_required=True))
1464 tail_junk = d.draw(binary(max_size=5))
1465 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1466 offset = d.draw(integers(min_value=0))
1467 for klass in (BitString, BitStringInherited):
1478 pprint(obj, big_blobs=True, with_decode_path=True)
1479 self.assertFalse(obj.expled)
1480 obj_encoded = obj.encode()
1481 obj_expled = obj(value, expl=tag_expl)
1482 self.assertTrue(obj_expled.expled)
1484 list(obj_expled.pps())
1485 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1486 obj_expled_encoded = obj_expled.encode()
1487 ctx_copied = deepcopy(ctx_dummy)
1488 obj_decoded, tail = obj_expled.decode(
1489 obj_expled_encoded + tail_junk,
1493 self.assertDictEqual(ctx_copied, ctx_dummy)
1495 list(obj_decoded.pps())
1496 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1497 self.assertEqual(tail, tail_junk)
1498 self.assertEqual(obj_decoded, obj_expled)
1499 self.assertNotEqual(obj_decoded, obj)
1500 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1501 self.assertEqual(bytes(obj_decoded), bytes(obj))
1502 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1503 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1504 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1506 obj_decoded.expl_llen,
1507 len(len_encode(len(obj_encoded))),
1509 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1510 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1513 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1515 self.assertEqual(obj_decoded.expl_offset, offset)
1516 if isinstance(value, tuple):
1517 self.assertSetEqual(set(value), set(obj_decoded.named))
1520 assert_exceeding_data(
1522 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1526 @given(integers(min_value=1, max_value=255))
1527 def test_bad_zero_value(self, pad_size):
1528 with self.assertRaises(DecodeError):
1529 BitString().decode(b"".join((
1530 BitString.tag_default,
1535 def test_go_vectors_invalid(self):
1541 with self.assertRaises(DecodeError):
1542 BitString().decode(b"".join((
1543 BitString.tag_default,
1548 def test_go_vectors_valid(self):
1549 obj, _ = BitString().decode(b"".join((
1550 BitString.tag_default,
1554 self.assertEqual(bytes(obj), b"")
1555 self.assertEqual(obj.bit_len, 0)
1557 obj, _ = BitString().decode(b"".join((
1558 BitString.tag_default,
1562 self.assertEqual(bytes(obj), b"\x00")
1563 self.assertEqual(obj.bit_len, 1)
1565 obj = BitString((16, b"\x82\x40"))
1566 self.assertTrue(obj[0])
1567 self.assertFalse(obj[1])
1568 self.assertTrue(obj[6])
1569 self.assertTrue(obj[9])
1570 self.assertFalse(obj[17])
1573 integers(min_value=1, max_value=30),
1576 binary(min_size=1, max_size=5),
1578 binary(min_size=1, max_size=5),
1586 lists(booleans(), min_size=1),
1589 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1590 def chunk_constructed(contents):
1592 tag_encode(form=TagFormConstructed, num=3) +
1594 b"".join(BitString(content).encode() for content in contents) +
1598 payload_expected = b""
1599 bit_len_expected = 0
1600 for chunk_input in chunk_inputs:
1601 if isinstance(chunk_input, binary_type):
1602 chunks.append(BitString(chunk_input).encode())
1603 payload_expected += chunk_input
1604 bit_len_expected += len(chunk_input) * 8
1606 chunks.append(chunk_constructed(chunk_input))
1607 payload = b"".join(chunk_input)
1608 payload_expected += payload
1609 bit_len_expected += len(payload) * 8
1610 chunk_last = BitString("'%s'B" % "".join(
1611 "1" if bit else "0" for bit in chunk_last_bits
1613 payload_expected += bytes(chunk_last)
1614 bit_len_expected += chunk_last.bit_len
1615 encoded_indefinite = (
1616 tag_encode(form=TagFormConstructed, num=impl) +
1619 chunk_last.encode() +
1622 encoded_definite = (
1623 tag_encode(form=TagFormConstructed, num=impl) +
1624 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1628 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1629 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1630 for lenindef_expected, encoded in (
1631 (True, encoded_indefinite),
1632 (False, encoded_definite),
1634 obj, tail = BitString(impl=tag_encode(impl)).decode(
1636 ctx={"bered": True},
1638 self.assertSequenceEqual(tail, junk)
1639 self.assertEqual(obj.bit_len, bit_len_expected)
1640 self.assertSequenceEqual(bytes(obj), payload_expected)
1641 self.assertTrue(obj.ber_encoded)
1642 self.assertEqual(obj.lenindef, lenindef_expected)
1643 self.assertTrue(obj.bered)
1645 self.assertTrue(obj.ber_encoded)
1646 self.assertEqual(obj.lenindef, lenindef_expected)
1647 self.assertTrue(obj.bered)
1648 self.assertEqual(len(encoded), obj.tlvlen)
1651 pprint(obj, big_blobs=True, with_decode_path=True)
1654 integers(min_value=0),
1657 def test_ber_definite_too_short(self, offset, decode_path):
1658 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1660 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1662 decode_path=decode_path,
1663 ctx={"bered": True},
1665 self.assertEqual(err.exception.decode_path, decode_path)
1666 self.assertEqual(err.exception.offset, offset)
1669 integers(min_value=0),
1672 def test_ber_definite_no_data(self, offset, decode_path):
1673 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1675 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1677 decode_path=decode_path,
1678 ctx={"bered": True},
1680 self.assertEqual(err.exception.decode_path, decode_path)
1681 self.assertEqual(err.exception.offset, offset)
1684 integers(min_value=0),
1686 integers(min_value=1, max_value=3),
1688 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1689 bs = BitString(b"data").encode()
1690 with self.assertRaises(NotEnoughData) as err:
1692 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1694 decode_path=decode_path,
1695 ctx={"bered": True},
1697 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1698 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1701 integers(min_value=0),
1703 integers(min_value=1, max_value=3),
1705 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1706 bs = BitString(b"data").encode()
1707 bs_longer = BitString(b"data-longer").encode()
1708 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1711 tag_encode(3, form=TagFormConstructed) +
1712 len_encode((chunks + 1) * len(bs)) +
1717 decode_path=decode_path,
1718 ctx={"bered": True},
1720 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1721 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1724 integers(min_value=0),
1727 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1728 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1730 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1732 decode_path=decode_path,
1733 ctx={"bered": True},
1735 self.assertEqual(err.exception.decode_path, decode_path)
1736 self.assertEqual(err.exception.offset, offset)
1738 @given(data_strategy())
1739 def test_ber_indefinite_not_multiple(self, d):
1740 bs_short = BitString("'A'H").encode()
1741 bs_full = BitString("'AA'H").encode()
1742 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1743 chunks.append(bs_short)
1744 d.draw(permutations(chunks))
1745 chunks.append(bs_short)
1746 offset = d.draw(integers(min_value=0))
1747 decode_path = d.draw(decode_path_strat)
1748 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1751 tag_encode(3, form=TagFormConstructed) +
1757 decode_path=decode_path,
1758 ctx={"bered": True},
1761 err.exception.decode_path,
1762 decode_path + (str(chunks.index(bs_short)),),
1765 err.exception.offset,
1766 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1769 def test_x690_vector(self):
1770 vector = BitString("'0A3B5F291CD'H")
1771 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1772 self.assertSequenceEqual(tail, b"")
1773 self.assertEqual(obj, vector)
1774 obj, tail = BitString().decode(
1775 hexdec("23800303000A3B0305045F291CD00000"),
1776 ctx={"bered": True},
1778 self.assertSequenceEqual(tail, b"")
1779 self.assertEqual(obj, vector)
1780 self.assertTrue(obj.ber_encoded)
1781 self.assertTrue(obj.lenindef)
1782 self.assertTrue(obj.bered)
1784 self.assertTrue(obj.ber_encoded)
1785 self.assertTrue(obj.lenindef)
1786 self.assertTrue(obj.bered)
1790 def octet_string_values_strategy(draw, do_expl=False):
1791 bound_min, bound_max = sorted(draw(sets(
1792 integers(min_value=0, max_value=1 << 7),
1796 value = draw(one_of(
1798 binary(min_size=bound_min, max_size=bound_max),
1800 default = draw(one_of(
1802 binary(min_size=bound_min, max_size=bound_max),
1805 if draw(booleans()):
1806 bounds = (bound_min, bound_max)
1810 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1812 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1813 optional = draw(one_of(none(), booleans()))
1815 draw(integers(min_value=0)),
1816 draw(integers(min_value=0)),
1817 draw(integers(min_value=0)),
1819 return (value, bounds, impl, expl, default, optional, _decoded)
1822 class OctetStringInherited(OctetString):
1826 class TestOctetString(CommonMixin, TestCase):
1827 base_klass = OctetString
1829 def test_invalid_value_type(self):
1830 with self.assertRaises(InvalidValueType) as err:
1831 OctetString(text_type(123))
1835 def test_optional(self, optional):
1836 obj = OctetString(default=OctetString(b""), optional=optional)
1837 self.assertTrue(obj.optional)
1840 def test_ready(self, value):
1842 self.assertFalse(obj.ready)
1845 pprint(obj, big_blobs=True, with_decode_path=True)
1846 with self.assertRaises(ObjNotReady) as err:
1849 obj = OctetString(value)
1850 self.assertTrue(obj.ready)
1853 pprint(obj, big_blobs=True, with_decode_path=True)
1855 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1856 def test_comparison(self, value1, value2, tag1, tag2):
1857 for klass in (OctetString, OctetStringInherited):
1858 obj1 = klass(value1)
1859 obj2 = klass(value2)
1860 self.assertEqual(obj1 == obj2, value1 == value2)
1861 self.assertEqual(obj1 != obj2, value1 != value2)
1862 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1863 obj1 = klass(value1, impl=tag1)
1864 obj2 = klass(value1, impl=tag2)
1865 self.assertEqual(obj1 == obj2, tag1 == tag2)
1866 self.assertEqual(obj1 != obj2, tag1 != tag2)
1868 @given(lists(binary()))
1869 def test_sorted_works(self, values):
1870 self.assertSequenceEqual(
1871 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1875 @given(data_strategy())
1876 def test_bounds_satisfied(self, d):
1877 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1878 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1879 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1880 OctetString(value=value, bounds=(bound_min, bound_max))
1882 @given(data_strategy())
1883 def test_bounds_unsatisfied(self, d):
1884 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1885 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1886 value = d.draw(binary(max_size=bound_min - 1))
1887 with self.assertRaises(BoundsError) as err:
1888 OctetString(value=value, bounds=(bound_min, bound_max))
1890 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1891 OctetString(bounds=(bound_min, bound_max)).decode(
1892 OctetString(value).encode()
1895 value = d.draw(binary(min_size=bound_max + 1))
1896 with self.assertRaises(BoundsError) as err:
1897 OctetString(value=value, bounds=(bound_min, bound_max))
1899 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1900 OctetString(bounds=(bound_min, bound_max)).decode(
1901 OctetString(value).encode()
1905 @given(data_strategy())
1906 def test_call(self, d):
1907 for klass in (OctetString, OctetStringInherited):
1916 ) = d.draw(octet_string_values_strategy())
1917 obj_initial = klass(
1923 optional_initial or False,
1934 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1935 if (default is None) and (obj_initial.default is not None):
1938 (bounds is None) and
1939 (value is not None) and
1940 (bounds_initial is not None) and
1941 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1945 (bounds is None) and
1946 (default is not None) and
1947 (bounds_initial is not None) and
1948 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1951 obj = obj_initial(value, bounds, impl, expl, default, optional)
1953 value_expected = default if value is None else value
1955 default_initial if value_expected is None
1958 self.assertEqual(obj, value_expected)
1959 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1960 self.assertEqual(obj.expl_tag, expl or expl_initial)
1963 default_initial if default is None else default,
1965 if obj.default is None:
1966 optional = optional_initial if optional is None else optional
1967 optional = False if optional is None else optional
1970 self.assertEqual(obj.optional, optional)
1972 (obj._bound_min, obj._bound_max),
1973 bounds or bounds_initial or (0, float("+inf")),
1976 @given(octet_string_values_strategy())
1977 def test_copy(self, values):
1978 for klass in (OctetString, OctetStringInherited):
1979 obj = klass(*values)
1980 for copy_func in copy_funcs:
1981 obj_copied = copy_func(obj)
1982 self.assert_copied_basic_fields(obj, obj_copied)
1983 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1984 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1985 self.assertEqual(obj._value, obj_copied._value)
1989 integers(min_value=1).map(tag_encode),
1991 def test_stripped(self, value, tag_impl):
1992 obj = OctetString(value, impl=tag_impl)
1993 with self.assertRaises(NotEnoughData):
1994 obj.decode(obj.encode()[:-1])
1998 integers(min_value=1).map(tag_ctxc),
2000 def test_stripped_expl(self, value, tag_expl):
2001 obj = OctetString(value, expl=tag_expl)
2002 with self.assertRaises(NotEnoughData):
2003 obj.decode(obj.encode()[:-1])
2006 integers(min_value=31),
2007 integers(min_value=0),
2010 def test_bad_tag(self, tag, offset, decode_path):
2011 with self.assertRaises(DecodeError) as err:
2012 OctetString().decode(
2013 tag_encode(tag)[:-1],
2015 decode_path=decode_path,
2018 self.assertEqual(err.exception.offset, offset)
2019 self.assertEqual(err.exception.decode_path, decode_path)
2022 integers(min_value=128),
2023 integers(min_value=0),
2026 def test_bad_len(self, l, offset, decode_path):
2027 with self.assertRaises(DecodeError) as err:
2028 OctetString().decode(
2029 OctetString.tag_default + len_encode(l)[:-1],
2031 decode_path=decode_path,
2034 self.assertEqual(err.exception.offset, offset)
2035 self.assertEqual(err.exception.decode_path, decode_path)
2038 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2039 integers(min_value=0),
2042 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2043 value, bound_min = list(sorted(ints))
2045 class String(OctetString):
2046 bounds = (bound_min, bound_min)
2047 with self.assertRaises(DecodeError) as err:
2049 OctetString(b"\x00" * value).encode(),
2051 decode_path=decode_path,
2054 self.assertEqual(err.exception.offset, offset)
2055 self.assertEqual(err.exception.decode_path, decode_path)
2057 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2059 octet_string_values_strategy(),
2061 integers(min_value=1).map(tag_ctxc),
2062 integers(min_value=0),
2065 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2066 for klass in (OctetString, OctetStringInherited):
2067 _, _, _, _, default, optional, _decoded = values
2076 pprint(obj, big_blobs=True, with_decode_path=True)
2077 self.assertFalse(obj.expled)
2078 obj_encoded = obj.encode()
2079 obj_expled = obj(value, expl=tag_expl)
2080 self.assertTrue(obj_expled.expled)
2082 list(obj_expled.pps())
2083 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2084 obj_expled_encoded = obj_expled.encode()
2085 ctx_copied = deepcopy(ctx_dummy)
2086 obj_decoded, tail = obj_expled.decode(
2087 obj_expled_encoded + tail_junk,
2091 self.assertDictEqual(ctx_copied, ctx_dummy)
2093 list(obj_decoded.pps())
2094 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2095 self.assertEqual(tail, tail_junk)
2096 self.assertEqual(obj_decoded, obj_expled)
2097 self.assertNotEqual(obj_decoded, obj)
2098 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2099 self.assertEqual(bytes(obj_decoded), bytes(obj))
2100 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2101 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2102 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2104 obj_decoded.expl_llen,
2105 len(len_encode(len(obj_encoded))),
2107 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2108 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2111 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2113 self.assertEqual(obj_decoded.expl_offset, offset)
2114 assert_exceeding_data(
2116 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2121 integers(min_value=1, max_value=30),
2124 binary(min_size=1, max_size=5),
2126 binary(min_size=1, max_size=5),
2136 def test_constructed(self, impl, chunk_inputs, junk):
2137 def chunk_constructed(contents):
2139 tag_encode(form=TagFormConstructed, num=4) +
2141 b"".join(OctetString(content).encode() for content in contents) +
2145 payload_expected = b""
2146 for chunk_input in chunk_inputs:
2147 if isinstance(chunk_input, binary_type):
2148 chunks.append(OctetString(chunk_input).encode())
2149 payload_expected += chunk_input
2151 chunks.append(chunk_constructed(chunk_input))
2152 payload = b"".join(chunk_input)
2153 payload_expected += payload
2154 encoded_indefinite = (
2155 tag_encode(form=TagFormConstructed, num=impl) +
2160 encoded_definite = (
2161 tag_encode(form=TagFormConstructed, num=impl) +
2162 len_encode(len(b"".join(chunks))) +
2165 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2166 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2167 for lenindef_expected, encoded in (
2168 (True, encoded_indefinite),
2169 (False, encoded_definite),
2171 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2173 ctx={"bered": True},
2175 self.assertSequenceEqual(tail, junk)
2176 self.assertSequenceEqual(bytes(obj), payload_expected)
2177 self.assertTrue(obj.ber_encoded)
2178 self.assertEqual(obj.lenindef, lenindef_expected)
2179 self.assertTrue(obj.bered)
2181 self.assertTrue(obj.ber_encoded)
2182 self.assertEqual(obj.lenindef, lenindef_expected)
2183 self.assertTrue(obj.bered)
2184 self.assertEqual(len(encoded), obj.tlvlen)
2187 pprint(obj, big_blobs=True, with_decode_path=True)
2190 integers(min_value=0),
2193 def test_ber_definite_too_short(self, offset, decode_path):
2194 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2195 OctetString().decode(
2196 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2198 decode_path=decode_path,
2199 ctx={"bered": True},
2201 self.assertEqual(err.exception.decode_path, decode_path)
2202 self.assertEqual(err.exception.offset, offset)
2205 integers(min_value=0),
2207 integers(min_value=1, max_value=3),
2209 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2210 bs = OctetString(b"data").encode()
2211 with self.assertRaises(NotEnoughData) as err:
2212 OctetString().decode(
2213 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2215 decode_path=decode_path,
2216 ctx={"bered": True},
2218 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2219 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2222 integers(min_value=0),
2224 integers(min_value=1, max_value=3),
2226 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2227 bs = OctetString(b"data").encode()
2228 bs_longer = OctetString(b"data-longer").encode()
2229 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2230 OctetString().decode(
2232 tag_encode(4, form=TagFormConstructed) +
2233 len_encode((chunks + 1) * len(bs)) +
2238 decode_path=decode_path,
2239 ctx={"bered": True},
2241 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2242 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2246 def null_values_strategy(draw, do_expl=False):
2250 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2252 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2253 optional = draw(one_of(none(), booleans()))
2255 draw(integers(min_value=0)),
2256 draw(integers(min_value=0)),
2257 draw(integers(min_value=0)),
2259 return (impl, expl, optional, _decoded)
2262 class NullInherited(Null):
2266 class TestNull(CommonMixin, TestCase):
2269 def test_ready(self):
2271 self.assertTrue(obj.ready)
2274 pprint(obj, big_blobs=True, with_decode_path=True)
2276 @given(binary(), binary())
2277 def test_comparison(self, tag1, tag2):
2278 for klass in (Null, NullInherited):
2279 obj1 = klass(impl=tag1)
2280 obj2 = klass(impl=tag2)
2281 self.assertEqual(obj1 == obj2, tag1 == tag2)
2282 self.assertEqual(obj1 != obj2, tag1 != tag2)
2283 self.assertNotEqual(obj1, tag2)
2285 @given(data_strategy())
2286 def test_call(self, d):
2287 for klass in (Null, NullInherited):
2293 ) = d.draw(null_values_strategy())
2294 obj_initial = klass(
2297 optional=optional_initial or False,
2298 _decoded=_decoded_initial,
2305 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2306 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2307 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2308 self.assertEqual(obj.expl_tag, expl or expl_initial)
2309 optional = optional_initial if optional is None else optional
2310 optional = False if optional is None else optional
2311 self.assertEqual(obj.optional, optional)
2313 @given(null_values_strategy())
2314 def test_copy(self, values):
2315 for klass in (Null, NullInherited):
2316 impl, expl, optional, _decoded = values
2320 optional=optional or False,
2323 for copy_func in copy_funcs:
2324 obj_copied = copy_func(obj)
2325 self.assert_copied_basic_fields(obj, obj_copied)
2327 @given(integers(min_value=1).map(tag_encode))
2328 def test_stripped(self, tag_impl):
2329 obj = Null(impl=tag_impl)
2330 with self.assertRaises(NotEnoughData):
2331 obj.decode(obj.encode()[:-1])
2333 @given(integers(min_value=1).map(tag_ctxc))
2334 def test_stripped_expl(self, tag_expl):
2335 obj = Null(expl=tag_expl)
2336 with self.assertRaises(NotEnoughData):
2337 obj.decode(obj.encode()[:-1])
2340 integers(min_value=31),
2341 integers(min_value=0),
2344 def test_bad_tag(self, tag, offset, decode_path):
2345 with self.assertRaises(DecodeError) as err:
2347 tag_encode(tag)[:-1],
2349 decode_path=decode_path,
2352 self.assertEqual(err.exception.offset, offset)
2353 self.assertEqual(err.exception.decode_path, decode_path)
2356 integers(min_value=128),
2357 integers(min_value=0),
2360 def test_bad_len(self, l, offset, decode_path):
2361 with self.assertRaises(DecodeError) as err:
2363 Null.tag_default + len_encode(l)[:-1],
2365 decode_path=decode_path,
2368 self.assertEqual(err.exception.offset, offset)
2369 self.assertEqual(err.exception.decode_path, decode_path)
2371 @given(binary(min_size=1))
2372 def test_tag_mismatch(self, impl):
2373 assume(impl != Null.tag_default)
2374 with self.assertRaises(TagMismatch):
2375 Null(impl=impl).decode(Null().encode())
2378 null_values_strategy(),
2379 integers(min_value=1).map(tag_ctxc),
2380 integers(min_value=0),
2383 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2384 for klass in (Null, NullInherited):
2385 _, _, optional, _decoded = values
2386 obj = klass(optional=optional, _decoded=_decoded)
2389 pprint(obj, big_blobs=True, with_decode_path=True)
2390 self.assertFalse(obj.expled)
2391 obj_encoded = obj.encode()
2392 obj_expled = obj(expl=tag_expl)
2393 self.assertTrue(obj_expled.expled)
2395 list(obj_expled.pps())
2396 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2397 obj_expled_encoded = obj_expled.encode()
2398 ctx_copied = deepcopy(ctx_dummy)
2399 obj_decoded, tail = obj_expled.decode(
2400 obj_expled_encoded + tail_junk,
2404 self.assertDictEqual(ctx_copied, ctx_dummy)
2406 list(obj_decoded.pps())
2407 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2408 self.assertEqual(tail, tail_junk)
2409 self.assertEqual(obj_decoded, obj_expled)
2410 self.assertNotEqual(obj_decoded, obj)
2411 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2412 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2413 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2415 obj_decoded.expl_llen,
2416 len(len_encode(len(obj_encoded))),
2418 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2419 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2422 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2424 self.assertEqual(obj_decoded.expl_offset, offset)
2425 assert_exceeding_data(
2427 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2431 @given(integers(min_value=1))
2432 def test_invalid_len(self, l):
2433 with self.assertRaises(InvalidLength):
2434 Null().decode(b"".join((
2441 def oid_strategy(draw):
2442 first_arc = draw(integers(min_value=0, max_value=2))
2444 if first_arc in (0, 1):
2445 second_arc = draw(integers(min_value=0, max_value=39))
2447 second_arc = draw(integers(min_value=0))
2448 other_arcs = draw(lists(integers(min_value=0)))
2449 return tuple([first_arc, second_arc] + other_arcs)
2453 def oid_values_strategy(draw, do_expl=False):
2454 value = draw(one_of(none(), oid_strategy()))
2458 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2460 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2461 default = draw(one_of(none(), oid_strategy()))
2462 optional = draw(one_of(none(), booleans()))
2464 draw(integers(min_value=0)),
2465 draw(integers(min_value=0)),
2466 draw(integers(min_value=0)),
2468 return (value, impl, expl, default, optional, _decoded)
2471 class ObjectIdentifierInherited(ObjectIdentifier):
2475 class TestObjectIdentifier(CommonMixin, TestCase):
2476 base_klass = ObjectIdentifier
2478 def test_invalid_value_type(self):
2479 with self.assertRaises(InvalidValueType) as err:
2480 ObjectIdentifier(123)
2484 def test_optional(self, optional):
2485 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2486 self.assertTrue(obj.optional)
2488 @given(oid_strategy())
2489 def test_ready(self, value):
2490 obj = ObjectIdentifier()
2491 self.assertFalse(obj.ready)
2494 pprint(obj, big_blobs=True, with_decode_path=True)
2495 with self.assertRaises(ObjNotReady) as err:
2498 obj = ObjectIdentifier(value)
2499 self.assertTrue(obj.ready)
2500 self.assertFalse(obj.ber_encoded)
2503 pprint(obj, big_blobs=True, with_decode_path=True)
2506 @given(oid_strategy(), oid_strategy(), binary(), binary())
2507 def test_comparison(self, value1, value2, tag1, tag2):
2508 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2509 obj1 = klass(value1)
2510 obj2 = klass(value2)
2511 self.assertEqual(obj1 == obj2, value1 == value2)
2512 self.assertEqual(obj1 != obj2, value1 != value2)
2513 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2514 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2515 obj1 = klass(value1, impl=tag1)
2516 obj2 = klass(value1, impl=tag2)
2517 self.assertEqual(obj1 == obj2, tag1 == tag2)
2518 self.assertEqual(obj1 != obj2, tag1 != tag2)
2520 @given(lists(oid_strategy()))
2521 def test_sorted_works(self, values):
2522 self.assertSequenceEqual(
2523 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2527 @given(data_strategy())
2528 def test_call(self, d):
2529 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2537 ) = d.draw(oid_values_strategy())
2538 obj_initial = klass(
2539 value=value_initial,
2542 default=default_initial,
2543 optional=optional_initial or False,
2544 _decoded=_decoded_initial,
2553 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2562 value_expected = default if value is None else value
2564 default_initial if value_expected is None
2567 self.assertEqual(obj, value_expected)
2568 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2569 self.assertEqual(obj.expl_tag, expl or expl_initial)
2572 default_initial if default is None else default,
2574 if obj.default is None:
2575 optional = optional_initial if optional is None else optional
2576 optional = False if optional is None else optional
2579 self.assertEqual(obj.optional, optional)
2581 @given(oid_values_strategy())
2582 def test_copy(self, values):
2583 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2600 for copy_func in copy_funcs:
2601 obj_copied = copy_func(obj)
2602 self.assert_copied_basic_fields(obj, obj_copied)
2603 self.assertEqual(obj._value, obj_copied._value)
2605 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2608 integers(min_value=1).map(tag_encode),
2610 def test_stripped(self, value, tag_impl):
2611 obj = ObjectIdentifier(value, impl=tag_impl)
2612 with self.assertRaises(NotEnoughData):
2613 obj.decode(obj.encode()[:-1])
2617 integers(min_value=1).map(tag_ctxc),
2619 def test_stripped_expl(self, value, tag_expl):
2620 obj = ObjectIdentifier(value, expl=tag_expl)
2621 with self.assertRaises(NotEnoughData):
2622 obj.decode(obj.encode()[:-1])
2625 integers(min_value=31),
2626 integers(min_value=0),
2629 def test_bad_tag(self, tag, offset, decode_path):
2630 with self.assertRaises(DecodeError) as err:
2631 ObjectIdentifier().decode(
2632 tag_encode(tag)[:-1],
2634 decode_path=decode_path,
2637 self.assertEqual(err.exception.offset, offset)
2638 self.assertEqual(err.exception.decode_path, decode_path)
2641 integers(min_value=128),
2642 integers(min_value=0),
2645 def test_bad_len(self, l, offset, decode_path):
2646 with self.assertRaises(DecodeError) as err:
2647 ObjectIdentifier().decode(
2648 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2650 decode_path=decode_path,
2653 self.assertEqual(err.exception.offset, offset)
2654 self.assertEqual(err.exception.decode_path, decode_path)
2656 def test_zero_oid(self):
2657 with self.assertRaises(NotEnoughData):
2658 ObjectIdentifier().decode(
2659 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2662 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2663 @given(oid_strategy())
2664 def test_unfinished_oid(self, value):
2665 assume(list(value)[-1] > 255)
2666 obj_encoded = ObjectIdentifier(value).encode()
2667 obj, _ = ObjectIdentifier().decode(obj_encoded)
2668 data = obj_encoded[obj.tlen + obj.llen:-1]
2670 ObjectIdentifier.tag_default,
2671 len_encode(len(data)),
2674 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2677 @given(integers(min_value=0))
2678 def test_invalid_short(self, value):
2679 with self.assertRaises(InvalidOID):
2680 ObjectIdentifier((value,))
2681 with self.assertRaises(InvalidOID):
2682 ObjectIdentifier("%d" % value)
2684 @given(integers(min_value=3), integers(min_value=0))
2685 def test_invalid_first_arc(self, first_arc, second_arc):
2686 with self.assertRaises(InvalidOID):
2687 ObjectIdentifier((first_arc, second_arc))
2688 with self.assertRaises(InvalidOID):
2689 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2691 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2692 def test_invalid_second_arc(self, first_arc, second_arc):
2693 with self.assertRaises(InvalidOID):
2694 ObjectIdentifier((first_arc, second_arc))
2695 with self.assertRaises(InvalidOID):
2696 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2698 @given(text(alphabet=ascii_letters + ".", min_size=1))
2699 def test_junk(self, oid):
2700 with self.assertRaises(InvalidOID):
2701 ObjectIdentifier(oid)
2703 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2704 @given(oid_strategy())
2705 def test_validness(self, oid):
2706 obj = ObjectIdentifier(oid)
2707 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2710 pprint(obj, big_blobs=True, with_decode_path=True)
2712 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2714 oid_values_strategy(),
2716 integers(min_value=1).map(tag_ctxc),
2717 integers(min_value=0),
2720 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2721 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2722 _, _, _, default, optional, _decoded = values
2731 pprint(obj, big_blobs=True, with_decode_path=True)
2732 self.assertFalse(obj.expled)
2733 obj_encoded = obj.encode()
2734 obj_expled = obj(value, expl=tag_expl)
2735 self.assertTrue(obj_expled.expled)
2737 list(obj_expled.pps())
2738 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2739 obj_expled_encoded = obj_expled.encode()
2740 ctx_copied = deepcopy(ctx_dummy)
2741 obj_decoded, tail = obj_expled.decode(
2742 obj_expled_encoded + tail_junk,
2746 self.assertDictEqual(ctx_copied, ctx_dummy)
2748 list(obj_decoded.pps())
2749 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2750 self.assertEqual(tail, tail_junk)
2751 self.assertEqual(obj_decoded, obj_expled)
2752 self.assertNotEqual(obj_decoded, obj)
2753 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2754 self.assertEqual(tuple(obj_decoded), tuple(obj))
2755 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2756 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2757 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2759 obj_decoded.expl_llen,
2760 len(len_encode(len(obj_encoded))),
2762 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2763 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2766 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2768 self.assertEqual(obj_decoded.expl_offset, offset)
2769 assert_exceeding_data(
2771 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2776 oid_strategy().map(ObjectIdentifier),
2777 oid_strategy().map(ObjectIdentifier),
2779 def test_add(self, oid1, oid2):
2780 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2781 for oid_to_add in (oid2, tuple(oid2)):
2782 self.assertEqual(oid1 + oid_to_add, oid_expect)
2783 with self.assertRaises(InvalidValueType):
2786 def test_go_vectors_valid(self):
2787 for data, expect in (
2789 (b"\x55\x02", (2, 5, 2)),
2790 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2791 (b"\x81\x34\x03", (2, 100, 3)),
2794 ObjectIdentifier().decode(b"".join((
2795 ObjectIdentifier.tag_default,
2796 len_encode(len(data)),
2802 def test_go_vectors_invalid(self):
2803 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2804 with self.assertRaises(DecodeError):
2805 ObjectIdentifier().decode(b"".join((
2806 Integer.tag_default,
2807 len_encode(len(data)),
2811 def test_x690_vector(self):
2813 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2814 ObjectIdentifier((2, 999, 3)),
2817 def test_nonnormalized_first_arc(self):
2819 ObjectIdentifier.tag_default +
2822 ObjectIdentifier((1, 0)).encode()[-1:]
2824 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2825 self.assertTrue(obj.ber_encoded)
2826 self.assertTrue(obj.bered)
2828 self.assertTrue(obj.ber_encoded)
2829 self.assertTrue(obj.bered)
2830 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2831 ObjectIdentifier().decode(tampered)
2833 @given(data_strategy())
2834 def test_negative_arcs(self, d):
2835 oid = list(d.draw(oid_strategy()))
2838 idx = d.draw(integers(min_value=3, max_value=len(oid)))
2840 if oid[idx - 1] == 0:
2842 with self.assertRaises(InvalidOID):
2843 ObjectIdentifier(tuple(oid))
2844 with self.assertRaises(InvalidOID):
2845 ObjectIdentifier(".".join(str(i) for i in oid))
2847 @given(data_strategy())
2848 def test_plused_arcs(self, d):
2849 oid = [str(arc) for arc in d.draw(oid_strategy())]
2850 idx = d.draw(integers(min_value=0, max_value=len(oid)))
2851 oid[idx - 1] = "+" + oid[idx - 1]
2852 with self.assertRaises(InvalidOID):
2853 ObjectIdentifier(".".join(str(i) for i in oid))
2855 @given(data_strategy())
2856 def test_nonnormalized_arcs(self, d):
2857 arcs = d.draw(lists(
2858 integers(min_value=0, max_value=100),
2862 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2863 _, _, lv = tag_strip(dered)
2864 _, _, v = len_decode(lv)
2865 v_no_first_arc = v[1:]
2866 idx_for_tamper = d.draw(integers(
2868 max_value=len(v_no_first_arc) - 1,
2870 tampered = list(bytearray(v_no_first_arc))
2871 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2872 tampered.insert(idx_for_tamper, 0x80)
2873 tampered = bytes(bytearray(tampered))
2875 ObjectIdentifier.tag_default +
2876 len_encode(len(tampered)) +
2879 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2880 self.assertTrue(obj.ber_encoded)
2881 self.assertTrue(obj.bered)
2883 self.assertTrue(obj.ber_encoded)
2884 self.assertTrue(obj.bered)
2885 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2886 ObjectIdentifier().decode(tampered)
2890 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2892 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2893 values = list(draw(sets(
2895 min_size=len(schema),
2896 max_size=len(schema),
2898 schema = list(zip(schema, values))
2899 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2903 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2905 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2906 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2907 optional = draw(one_of(none(), booleans()))
2909 draw(integers(min_value=0)),
2910 draw(integers(min_value=0)),
2911 draw(integers(min_value=0)),
2913 return (schema, value, impl, expl, default, optional, _decoded)
2916 class TestEnumerated(CommonMixin, TestCase):
2917 class EWhatever(Enumerated):
2918 schema = (("whatever", 0),)
2920 base_klass = EWhatever
2922 def test_schema_required(self):
2923 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2926 def test_invalid_value_type(self):
2927 with self.assertRaises(InvalidValueType) as err:
2928 self.base_klass((1, 2))
2931 @given(sets(text_letters(), min_size=2))
2932 def test_unknown_name(self, schema_input):
2933 missing = schema_input.pop()
2935 class E(Enumerated):
2936 schema = [(n, 123) for n in schema_input]
2937 with self.assertRaises(ObjUnknown) as err:
2942 sets(text_letters(), min_size=2),
2943 sets(integers(), min_size=2),
2945 def test_unknown_value(self, schema_input, values_input):
2947 missing_value = values_input.pop()
2948 _input = list(zip(schema_input, values_input))
2950 class E(Enumerated):
2952 with self.assertRaises(DecodeError) as err:
2957 def test_optional(self, optional):
2958 obj = self.base_klass(default="whatever", optional=optional)
2959 self.assertTrue(obj.optional)
2961 def test_ready(self):
2962 obj = self.base_klass()
2963 self.assertFalse(obj.ready)
2966 pprint(obj, big_blobs=True, with_decode_path=True)
2967 with self.assertRaises(ObjNotReady) as err:
2970 obj = self.base_klass("whatever")
2971 self.assertTrue(obj.ready)
2974 pprint(obj, big_blobs=True, with_decode_path=True)
2976 @given(integers(), integers(), binary(), binary())
2977 def test_comparison(self, value1, value2, tag1, tag2):
2978 class E(Enumerated):
2980 ("whatever0", value1),
2981 ("whatever1", value2),
2984 class EInherited(E):
2986 for klass in (E, EInherited):
2987 obj1 = klass(value1)
2988 obj2 = klass(value2)
2989 self.assertEqual(obj1 == obj2, value1 == value2)
2990 self.assertEqual(obj1 != obj2, value1 != value2)
2991 self.assertEqual(obj1 == int(obj2), value1 == value2)
2992 obj1 = klass(value1, impl=tag1)
2993 obj2 = klass(value1, impl=tag2)
2994 self.assertEqual(obj1 == obj2, tag1 == tag2)
2995 self.assertEqual(obj1 != obj2, tag1 != tag2)
2997 @given(data_strategy())
2998 def test_call(self, d):
3007 ) = d.draw(enumerated_values_strategy())
3009 class E(Enumerated):
3010 schema = schema_initial
3012 value=value_initial,
3015 default=default_initial,
3016 optional=optional_initial or False,
3017 _decoded=_decoded_initial,
3027 ) = d.draw(enumerated_values_strategy(
3028 schema=schema_initial,
3029 do_expl=impl_initial is None,
3039 value_expected = default if value is None else value
3041 default_initial if value_expected is None
3046 dict(schema_initial).get(value_expected, value_expected),
3048 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3049 self.assertEqual(obj.expl_tag, expl or expl_initial)
3052 default_initial if default is None else default,
3054 if obj.default is None:
3055 optional = optional_initial if optional is None else optional
3056 optional = False if optional is None else optional
3059 self.assertEqual(obj.optional, optional)
3060 self.assertEqual(obj.specs, dict(schema_initial))
3062 @given(enumerated_values_strategy())
3063 def test_copy(self, values):
3064 schema_input, value, impl, expl, default, optional, _decoded = values
3066 class E(Enumerated):
3067 schema = schema_input
3077 for copy_func in copy_funcs:
3078 obj_copied = copy_func(obj)
3079 self.assert_copied_basic_fields(obj, obj_copied)
3080 self.assertEqual(obj.specs, obj_copied.specs)
3082 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3083 @given(data_strategy())
3084 def test_symmetric(self, d):
3085 schema_input, _, _, _, default, optional, _decoded = d.draw(
3086 enumerated_values_strategy(),
3088 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3089 offset = d.draw(integers(min_value=0))
3090 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3091 tail_junk = d.draw(binary(max_size=5))
3093 class E(Enumerated):
3094 schema = schema_input
3103 pprint(obj, big_blobs=True, with_decode_path=True)
3104 self.assertFalse(obj.expled)
3105 obj_encoded = obj.encode()
3106 obj_expled = obj(value, expl=tag_expl)
3107 self.assertTrue(obj_expled.expled)
3109 list(obj_expled.pps())
3110 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3111 obj_expled_encoded = obj_expled.encode()
3112 ctx_copied = deepcopy(ctx_dummy)
3113 obj_decoded, tail = obj_expled.decode(
3114 obj_expled_encoded + tail_junk,
3118 self.assertDictEqual(ctx_copied, ctx_dummy)
3120 list(obj_decoded.pps())
3121 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3122 self.assertEqual(tail, tail_junk)
3123 self.assertEqual(obj_decoded, obj_expled)
3124 self.assertNotEqual(obj_decoded, obj)
3125 self.assertEqual(int(obj_decoded), int(obj_expled))
3126 self.assertEqual(int(obj_decoded), int(obj))
3127 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3128 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3129 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3131 obj_decoded.expl_llen,
3132 len(len_encode(len(obj_encoded))),
3134 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3135 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3138 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3140 self.assertEqual(obj_decoded.expl_offset, offset)
3141 assert_exceeding_data(
3143 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3149 def string_values_strategy(draw, alphabet, do_expl=False):
3150 bound_min, bound_max = sorted(draw(sets(
3151 integers(min_value=0, max_value=1 << 7),
3155 value = draw(one_of(
3157 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3159 default = draw(one_of(
3161 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3164 if draw(booleans()):
3165 bounds = (bound_min, bound_max)
3169 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3171 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3172 optional = draw(one_of(none(), booleans()))
3174 draw(integers(min_value=0)),
3175 draw(integers(min_value=0)),
3176 draw(integers(min_value=0)),
3178 return (value, bounds, impl, expl, default, optional, _decoded)
3181 class StringMixin(object):
3182 def test_invalid_value_type(self):
3183 with self.assertRaises(InvalidValueType) as err:
3184 self.base_klass((1, 2))
3187 def text_alphabet(self):
3188 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3189 return printable + whitespace
3193 def test_optional(self, optional):
3194 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3195 self.assertTrue(obj.optional)
3197 @given(data_strategy())
3198 def test_ready(self, d):
3199 obj = self.base_klass()
3200 self.assertFalse(obj.ready)
3203 pprint(obj, big_blobs=True, with_decode_path=True)
3205 with self.assertRaises(ObjNotReady) as err:
3208 value = d.draw(text(alphabet=self.text_alphabet()))
3209 obj = self.base_klass(value)
3210 self.assertTrue(obj.ready)
3213 pprint(obj, big_blobs=True, with_decode_path=True)
3216 @given(data_strategy())
3217 def test_comparison(self, d):
3218 value1 = d.draw(text(alphabet=self.text_alphabet()))
3219 value2 = d.draw(text(alphabet=self.text_alphabet()))
3220 tag1 = d.draw(binary(min_size=1))
3221 tag2 = d.draw(binary(min_size=1))
3222 obj1 = self.base_klass(value1)
3223 obj2 = self.base_klass(value2)
3224 self.assertEqual(obj1 == obj2, value1 == value2)
3225 self.assertEqual(obj1 != obj2, value1 != value2)
3226 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3227 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3228 obj1 = self.base_klass(value1, impl=tag1)
3229 obj2 = self.base_klass(value1, impl=tag2)
3230 self.assertEqual(obj1 == obj2, tag1 == tag2)
3231 self.assertEqual(obj1 != obj2, tag1 != tag2)
3233 @given(data_strategy())
3234 def test_bounds_satisfied(self, d):
3235 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3236 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3237 value = d.draw(text(
3238 alphabet=self.text_alphabet(),
3242 self.base_klass(value=value, bounds=(bound_min, bound_max))
3244 @given(data_strategy())
3245 def test_bounds_unsatisfied(self, d):
3246 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3247 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3248 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3249 with self.assertRaises(BoundsError) as err:
3250 self.base_klass(value=value, bounds=(bound_min, bound_max))
3252 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3253 self.base_klass(bounds=(bound_min, bound_max)).decode(
3254 self.base_klass(value).encode()
3257 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3258 with self.assertRaises(BoundsError) as err:
3259 self.base_klass(value=value, bounds=(bound_min, bound_max))
3261 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3262 self.base_klass(bounds=(bound_min, bound_max)).decode(
3263 self.base_klass(value).encode()
3267 @given(data_strategy())
3268 def test_call(self, d):
3277 ) = d.draw(string_values_strategy(self.text_alphabet()))
3278 obj_initial = self.base_klass(
3284 optional_initial or False,
3295 ) = d.draw(string_values_strategy(
3296 self.text_alphabet(),
3297 do_expl=impl_initial is None,
3299 if (default is None) and (obj_initial.default is not None):
3302 (bounds is None) and
3303 (value is not None) and
3304 (bounds_initial is not None) and
3305 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3309 (bounds is None) and
3310 (default is not None) and
3311 (bounds_initial is not None) and
3312 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3315 obj = obj_initial(value, bounds, impl, expl, default, optional)
3317 value_expected = default if value is None else value
3319 default_initial if value_expected is None
3322 self.assertEqual(obj, value_expected)
3323 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3324 self.assertEqual(obj.expl_tag, expl or expl_initial)
3327 default_initial if default is None else default,
3329 if obj.default is None:
3330 optional = optional_initial if optional is None else optional
3331 optional = False if optional is None else optional
3334 self.assertEqual(obj.optional, optional)
3336 (obj._bound_min, obj._bound_max),
3337 bounds or bounds_initial or (0, float("+inf")),
3340 @given(data_strategy())
3341 def test_copy(self, d):
3342 values = d.draw(string_values_strategy(self.text_alphabet()))
3343 obj = self.base_klass(*values)
3344 for copy_func in copy_funcs:
3345 obj_copied = copy_func(obj)
3346 self.assert_copied_basic_fields(obj, obj_copied)
3347 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3348 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3349 self.assertEqual(obj._value, obj_copied._value)
3351 @given(data_strategy())
3352 def test_stripped(self, d):
3353 value = d.draw(text(alphabet=self.text_alphabet()))
3354 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3355 obj = self.base_klass(value, impl=tag_impl)
3356 with self.assertRaises(NotEnoughData):
3357 obj.decode(obj.encode()[:-1])
3359 @given(data_strategy())
3360 def test_stripped_expl(self, d):
3361 value = d.draw(text(alphabet=self.text_alphabet()))
3362 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3363 obj = self.base_klass(value, expl=tag_expl)
3364 with self.assertRaises(NotEnoughData):
3365 obj.decode(obj.encode()[:-1])
3368 integers(min_value=31),
3369 integers(min_value=0),
3372 def test_bad_tag(self, tag, offset, decode_path):
3373 with self.assertRaises(DecodeError) as err:
3374 self.base_klass().decode(
3375 tag_encode(tag)[:-1],
3377 decode_path=decode_path,
3380 self.assertEqual(err.exception.offset, offset)
3381 self.assertEqual(err.exception.decode_path, decode_path)
3384 integers(min_value=128),
3385 integers(min_value=0),
3388 def test_bad_len(self, l, offset, decode_path):
3389 with self.assertRaises(DecodeError) as err:
3390 self.base_klass().decode(
3391 self.base_klass.tag_default + len_encode(l)[:-1],
3393 decode_path=decode_path,
3396 self.assertEqual(err.exception.offset, offset)
3397 self.assertEqual(err.exception.decode_path, decode_path)
3400 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3401 integers(min_value=0),
3404 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3405 value, bound_min = list(sorted(ints))
3407 class String(self.base_klass):
3408 # Multiply this value by four, to satisfy UTF-32 bounds
3409 # (4 bytes per character) validation
3410 bounds = (bound_min * 4, bound_min * 4)
3411 with self.assertRaises(DecodeError) as err:
3413 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3415 decode_path=decode_path,
3418 self.assertEqual(err.exception.offset, offset)
3419 self.assertEqual(err.exception.decode_path, decode_path)
3421 @given(data_strategy())
3422 def test_symmetric(self, d):
3423 values = d.draw(string_values_strategy(self.text_alphabet()))
3424 value = d.draw(text(alphabet=self.text_alphabet()))
3425 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3426 offset = d.draw(integers(min_value=0))
3427 tail_junk = d.draw(binary(max_size=5))
3428 _, _, _, _, default, optional, _decoded = values
3429 obj = self.base_klass(
3437 pprint(obj, big_blobs=True, with_decode_path=True)
3438 self.assertFalse(obj.expled)
3439 obj_encoded = obj.encode()
3440 obj_expled = obj(value, expl=tag_expl)
3441 self.assertTrue(obj_expled.expled)
3443 list(obj_expled.pps())
3444 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3445 obj_expled_encoded = obj_expled.encode()
3446 ctx_copied = deepcopy(ctx_dummy)
3447 obj_decoded, tail = obj_expled.decode(
3448 obj_expled_encoded + tail_junk,
3452 self.assertDictEqual(ctx_copied, ctx_dummy)
3454 list(obj_decoded.pps())
3455 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3456 self.assertEqual(tail, tail_junk)
3457 self.assertEqual(obj_decoded, obj_expled)
3458 self.assertNotEqual(obj_decoded, obj)
3459 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3460 self.assertEqual(bytes(obj_decoded), bytes(obj))
3461 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3462 self.assertEqual(text_type(obj_decoded), text_type(obj))
3463 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3464 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3465 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3467 obj_decoded.expl_llen,
3468 len(len_encode(len(obj_encoded))),
3470 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3471 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3474 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3476 self.assertEqual(obj_decoded.expl_offset, offset)
3477 assert_exceeding_data(
3479 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3484 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3485 base_klass = UTF8String
3488 cyrillic_letters = text(
3489 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3495 class UnicodeDecodeErrorMixin(object):
3496 @given(cyrillic_letters)
3497 def test_unicode_decode_error(self, cyrillic_text):
3498 with self.assertRaises(DecodeError):
3499 self.base_klass(cyrillic_text)
3502 class TestNumericString(StringMixin, CommonMixin, TestCase):
3503 base_klass = NumericString
3505 def text_alphabet(self):
3508 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3509 def test_non_numeric(self, non_numeric_text):
3510 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3511 self.base_klass(non_numeric_text)
3514 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3515 integers(min_value=0),
3518 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3519 value, bound_min = list(sorted(ints))
3521 class String(self.base_klass):
3522 bounds = (bound_min, bound_min)
3523 with self.assertRaises(DecodeError) as err:
3525 self.base_klass(b"1" * value).encode(),
3527 decode_path=decode_path,
3530 self.assertEqual(err.exception.offset, offset)
3531 self.assertEqual(err.exception.decode_path, decode_path)
3534 class TestPrintableString(
3535 UnicodeDecodeErrorMixin,
3540 base_klass = PrintableString
3542 def text_alphabet(self):
3543 return ascii_letters + digits + " '()+,-./:=?"
3545 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3546 def test_non_printable(self, non_printable_text):
3547 with assertRaisesRegex(self, DecodeError, "non-printable"):
3548 self.base_klass(non_printable_text)
3551 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3552 integers(min_value=0),
3555 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3556 value, bound_min = list(sorted(ints))
3558 class String(self.base_klass):
3559 bounds = (bound_min, bound_min)
3560 with self.assertRaises(DecodeError) as err:
3562 self.base_klass(b"1" * value).encode(),
3564 decode_path=decode_path,
3567 self.assertEqual(err.exception.offset, offset)
3568 self.assertEqual(err.exception.decode_path, decode_path)
3570 def test_allowable_invalid_chars(self):
3572 ("*", {"allow_asterisk": True}),
3573 ("&", {"allow_ampersand": True}),
3574 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3577 obj = self.base_klass(s)
3578 for prop in kwargs.keys():
3579 self.assertFalse(getattr(obj, prop))
3581 with assertRaisesRegex(self, DecodeError, "non-printable"):
3583 self.base_klass(s, **kwargs)
3584 klass = self.base_klass(**kwargs)
3586 for prop in kwargs.keys():
3587 self.assertTrue(getattr(obj, prop))
3590 for prop in kwargs.keys():
3591 self.assertTrue(getattr(obj, prop))
3594 class TestTeletexString(
3595 UnicodeDecodeErrorMixin,
3600 base_klass = TeletexString
3603 class TestVideotexString(
3604 UnicodeDecodeErrorMixin,
3609 base_klass = VideotexString
3612 class TestIA5String(
3613 UnicodeDecodeErrorMixin,
3618 base_klass = IA5String
3621 class TestGraphicString(
3622 UnicodeDecodeErrorMixin,
3627 base_klass = GraphicString
3630 class TestVisibleString(
3631 UnicodeDecodeErrorMixin,
3636 base_klass = VisibleString
3638 def test_x690_vector(self):
3639 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3640 self.assertSequenceEqual(tail, b"")
3641 self.assertEqual(str(obj), "Jones")
3642 self.assertFalse(obj.ber_encoded)
3643 self.assertFalse(obj.lenindef)
3644 self.assertFalse(obj.bered)
3646 obj, tail = VisibleString().decode(
3647 hexdec("3A0904034A6F6E04026573"),
3648 ctx={"bered": True},
3650 self.assertSequenceEqual(tail, b"")
3651 self.assertEqual(str(obj), "Jones")
3652 self.assertTrue(obj.ber_encoded)
3653 self.assertFalse(obj.lenindef)
3654 self.assertTrue(obj.bered)
3656 self.assertTrue(obj.ber_encoded)
3657 self.assertFalse(obj.lenindef)
3658 self.assertTrue(obj.bered)
3660 obj, tail = VisibleString().decode(
3661 hexdec("3A8004034A6F6E040265730000"),
3662 ctx={"bered": True},
3664 self.assertSequenceEqual(tail, b"")
3665 self.assertEqual(str(obj), "Jones")
3666 self.assertTrue(obj.ber_encoded)
3667 self.assertTrue(obj.lenindef)
3668 self.assertTrue(obj.bered)
3670 self.assertTrue(obj.ber_encoded)
3671 self.assertTrue(obj.lenindef)
3672 self.assertTrue(obj.bered)
3675 class TestGeneralString(
3676 UnicodeDecodeErrorMixin,
3681 base_klass = GeneralString
3684 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3685 base_klass = UniversalString
3688 class TestBMPString(StringMixin, CommonMixin, TestCase):
3689 base_klass = BMPString
3693 def generalized_time_values_strategy(
3701 if draw(booleans()):
3702 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3704 value = value.replace(microsecond=0)
3706 if draw(booleans()):
3707 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3709 default = default.replace(microsecond=0)
3713 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3715 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3716 optional = draw(one_of(none(), booleans()))
3718 draw(integers(min_value=0)),
3719 draw(integers(min_value=0)),
3720 draw(integers(min_value=0)),
3722 return (value, impl, expl, default, optional, _decoded)
3725 class TimeMixin(object):
3726 def test_invalid_value_type(self):
3727 with self.assertRaises(InvalidValueType) as err:
3728 self.base_klass(datetime.now().timetuple())
3731 @given(data_strategy())
3732 def test_optional(self, d):
3733 default = d.draw(datetimes(
3734 min_value=self.min_datetime,
3735 max_value=self.max_datetime,
3737 optional = d.draw(booleans())
3738 obj = self.base_klass(default=default, optional=optional)
3739 self.assertTrue(obj.optional)
3741 @given(data_strategy())
3742 def test_ready(self, d):
3743 obj = self.base_klass()
3744 self.assertFalse(obj.ready)
3747 pprint(obj, big_blobs=True, with_decode_path=True)
3748 with self.assertRaises(ObjNotReady) as err:
3751 value = d.draw(datetimes(
3752 min_value=self.min_datetime,
3753 max_value=self.max_datetime,
3755 obj = self.base_klass(value)
3756 self.assertTrue(obj.ready)
3759 pprint(obj, big_blobs=True, with_decode_path=True)
3761 @given(data_strategy())
3762 def test_comparison(self, d):
3763 value1 = d.draw(datetimes(
3764 min_value=self.min_datetime,
3765 max_value=self.max_datetime,
3767 value2 = d.draw(datetimes(
3768 min_value=self.min_datetime,
3769 max_value=self.max_datetime,
3771 tag1 = d.draw(binary(min_size=1))
3772 tag2 = d.draw(binary(min_size=1))
3774 value1 = value1.replace(microsecond=0)
3775 value2 = value2.replace(microsecond=0)
3776 obj1 = self.base_klass(value1)
3777 obj2 = self.base_klass(value2)
3778 self.assertEqual(obj1 == obj2, value1 == value2)
3779 self.assertEqual(obj1 != obj2, value1 != value2)
3780 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3781 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3782 obj1 = self.base_klass(value1, impl=tag1)
3783 obj2 = self.base_klass(value1, impl=tag2)
3784 self.assertEqual(obj1 == obj2, tag1 == tag2)
3785 self.assertEqual(obj1 != obj2, tag1 != tag2)
3787 @given(data_strategy())
3788 def test_call(self, d):
3796 ) = d.draw(generalized_time_values_strategy(
3797 min_datetime=self.min_datetime,
3798 max_datetime=self.max_datetime,
3799 omit_ms=self.omit_ms,
3801 obj_initial = self.base_klass(
3802 value=value_initial,
3805 default=default_initial,
3806 optional=optional_initial or False,
3807 _decoded=_decoded_initial,
3816 ) = d.draw(generalized_time_values_strategy(
3817 min_datetime=self.min_datetime,
3818 max_datetime=self.max_datetime,
3819 omit_ms=self.omit_ms,
3820 do_expl=impl_initial is None,
3830 value_expected = default if value is None else value
3832 default_initial if value_expected is None
3835 self.assertEqual(obj, value_expected)
3836 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3837 self.assertEqual(obj.expl_tag, expl or expl_initial)
3840 default_initial if default is None else default,
3842 if obj.default is None:
3843 optional = optional_initial if optional is None else optional
3844 optional = False if optional is None else optional
3847 self.assertEqual(obj.optional, optional)
3849 @given(data_strategy())
3850 def test_copy(self, d):
3851 values = d.draw(generalized_time_values_strategy(
3852 min_datetime=self.min_datetime,
3853 max_datetime=self.max_datetime,
3855 obj = self.base_klass(*values)
3856 for copy_func in copy_funcs:
3857 obj_copied = copy_func(obj)
3858 self.assert_copied_basic_fields(obj, obj_copied)
3859 self.assertEqual(obj._value, obj_copied._value)
3861 @given(data_strategy())
3862 def test_stripped(self, d):
3863 value = d.draw(datetimes(
3864 min_value=self.min_datetime,
3865 max_value=self.max_datetime,
3867 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3868 obj = self.base_klass(value, impl=tag_impl)
3869 with self.assertRaises(NotEnoughData):
3870 obj.decode(obj.encode()[:-1])
3872 @given(data_strategy())
3873 def test_stripped_expl(self, d):
3874 value = d.draw(datetimes(
3875 min_value=self.min_datetime,
3876 max_value=self.max_datetime,
3878 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3879 obj = self.base_klass(value, expl=tag_expl)
3880 with self.assertRaises(NotEnoughData):
3881 obj.decode(obj.encode()[:-1])
3883 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3884 @given(data_strategy())
3885 def test_symmetric(self, d):
3886 values = d.draw(generalized_time_values_strategy(
3887 min_datetime=self.min_datetime,
3888 max_datetime=self.max_datetime,
3890 value = d.draw(datetimes(
3891 min_value=self.min_datetime,
3892 max_value=self.max_datetime,
3894 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3895 offset = d.draw(integers(min_value=0))
3896 tail_junk = d.draw(binary(max_size=5))
3897 _, _, _, default, optional, _decoded = values
3898 obj = self.base_klass(
3906 pprint(obj, big_blobs=True, with_decode_path=True)
3907 self.assertFalse(obj.expled)
3908 obj_encoded = obj.encode()
3909 self.additional_symmetric_check(value, obj_encoded)
3910 obj_expled = obj(value, expl=tag_expl)
3911 self.assertTrue(obj_expled.expled)
3913 list(obj_expled.pps())
3914 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3915 obj_expled_encoded = obj_expled.encode()
3916 ctx_copied = deepcopy(ctx_dummy)
3917 obj_decoded, tail = obj_expled.decode(
3918 obj_expled_encoded + tail_junk,
3922 self.assertDictEqual(ctx_copied, ctx_dummy)
3924 list(obj_decoded.pps())
3925 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3926 self.assertEqual(tail, tail_junk)
3927 self.assertEqual(obj_decoded, obj_expled)
3928 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3929 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3930 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3931 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3932 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3934 obj_decoded.expl_llen,
3935 len(len_encode(len(obj_encoded))),
3937 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3938 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3941 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3943 self.assertEqual(obj_decoded.expl_offset, offset)
3944 assert_exceeding_data(
3946 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3951 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3952 base_klass = GeneralizedTime
3954 min_datetime = datetime(1900, 1, 1)
3955 max_datetime = datetime(9999, 12, 31)
3957 def additional_symmetric_check(self, value, obj_encoded):
3958 if value.microsecond > 0:
3959 self.assertFalse(obj_encoded.endswith(b"0Z"))
3961 def test_repr_not_ready(self):
3962 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
3963 repr(GeneralizedTime())
3965 def test_x690_vector_valid(self):
3969 b"19920722132100.3Z",
3971 GeneralizedTime(data)
3973 def test_x690_vector_invalid(self):
3976 b"19920622123421.0Z",
3977 b"19920722132100.30Z",
3979 with self.assertRaises(DecodeError) as err:
3980 GeneralizedTime(data)
3983 def test_go_vectors_invalid(self):
3995 b"-20100102030410Z",
3996 b"2010-0102030410Z",
3997 b"2010-0002030410Z",
3998 b"201001-02030410Z",
3999 b"20100102-030410Z",
4000 b"2010010203-0410Z",
4001 b"201001020304-10Z",
4002 # These ones are INVALID in *DER*, but accepted
4003 # by Go's encoding/asn1
4004 b"20100102030405+0607",
4005 b"20100102030405-0607",
4007 with self.assertRaises(DecodeError) as err:
4008 GeneralizedTime(data)
4011 def test_go_vectors_valid(self):
4013 GeneralizedTime(b"20100102030405Z").todatetime(),
4014 datetime(2010, 1, 2, 3, 4, 5, 0),
4017 def test_go_vectors_valid_ber(self):
4019 b"20100102030405+0607",
4020 b"20100102030405-0607",
4022 GeneralizedTime(data, ctx={"bered": True})
4024 def test_utc_offsets(self):
4025 """Some know equal UTC offsets
4028 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4032 "200101011130-0700",
4033 "200101011500-03:30",
4036 self.assertEqual(dts[0], dts[1])
4037 self.assertEqual(dts[0], dts[2])
4038 self.assertEqual(dts[0], dts[3])
4040 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4041 @given(data_strategy())
4042 def test_valid_ber(self, d):
4043 min_year = 1901 if PY2 else 2
4044 year = d.draw(integers(min_value=min_year, max_value=9999))
4045 month = d.draw(integers(min_value=1, max_value=12))
4046 day = d.draw(integers(min_value=1, max_value=28))
4047 hours = d.draw(integers(min_value=0, max_value=23))
4048 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4049 dt = datetime(year, month, day, hours)
4050 fractions_sign = d.draw(sampled_from(" ,."))
4052 if fractions_sign != " ":
4053 fractions = random()
4054 if d.draw(booleans()):
4055 minutes = d.draw(integers(min_value=0, max_value=59))
4056 data += "%02d" % minutes
4057 dt += timedelta(seconds=60 * minutes)
4058 if d.draw(booleans()):
4059 seconds = d.draw(integers(min_value=0, max_value=59))
4060 data += "%02d" % seconds
4061 dt += timedelta(seconds=seconds)
4062 if fractions is not None:
4063 dt += timedelta(microseconds=10**6 * fractions)
4064 elif fractions is not None:
4065 dt += timedelta(seconds=60 * fractions)
4066 elif fractions is not None:
4067 dt += timedelta(seconds=3600 * fractions)
4068 if fractions is not None:
4069 data += fractions_sign + str(fractions)[2:]
4070 if d.draw(booleans()):
4072 elif d.draw(booleans()):
4073 offset_hour = d.draw(integers(min_value=0, max_value=13))
4075 if d.draw(booleans()):
4080 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4081 data += "%02d" % offset_hour
4082 minutes_separator = d.draw(sampled_from((None, "", ":")))
4083 if minutes_separator is not None:
4084 offset_minute = d.draw(integers(min_value=0, max_value=59))
4085 dt -= timedelta(seconds=sign * 60 * offset_minute)
4086 data += "%s%02d" % (minutes_separator, offset_minute)
4087 data = data.encode("ascii")
4088 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4090 GeneralizedTime().decod(data_der)
4095 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4098 mktime(obj.todatetime().timetuple()),
4099 mktime(dt.timetuple()),
4102 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4103 self.assertEqual(obj.ber_encoded, not dered)
4104 self.assertEqual(obj.bered, not dered)
4105 self.assertEqual(obj.ber_raw, None if dered else data)
4106 self.assertEqual(obj.encode() == data_der, dered)
4111 def test_invalid_ber(self):
4113 # "00010203040506.07",
4114 "-0010203040506.07",
4115 "0001-203040506.07",
4116 "000102-3040506.07",
4117 "00010203-40506.07",
4118 "0001020304-506.07",
4119 "000102030405-6.07",
4120 "00010203040506.-7",
4121 "+0010203040506.07",
4122 "0001+203040506.07",
4123 "000102+3040506.07",
4124 "00010203+40506.07",
4125 "0001020304+506.07",
4126 "000102030405+6.07",
4127 "00010203040506.+7",
4128 " 0010203040506.07",
4129 "0001 203040506.07",
4130 "000102 3040506.07",
4131 "00010203 40506.07",
4132 "0001020304 506.07",
4133 "000102030405 6.07",
4134 "00010203040506. 7",
4135 "001 0203040506.07",
4136 "00012 03040506.07",
4137 "0001023 040506.07",
4138 "000102034 0506.07",
4139 "00010203045 06.07",
4140 "0001020304056 .07",
4141 "00010203040506.7 ",
4221 "00010203040506.07+15",
4222 "00010203040506.07-15",
4223 "00010203040506.07+14:60",
4224 "00010203040506.07+1460",
4225 "00010203040506.07-1460",
4226 "00010203040506.07+00:60",
4227 "00010203040506.07-00:60",
4229 "00010203040506+15",
4230 "00010203040506-15",
4231 "00010203040506+14:60",
4232 "00010203040506+1460",
4233 "00010203040506-1460",
4234 "00010203040506+00:60",
4235 "00010203040506-00:60",
4244 with self.assertRaises(DecodeError):
4245 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4246 data = data.replace(".", ",")
4247 with self.assertRaises(DecodeError):
4248 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4252 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4253 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4255 binary(min_size=1, max_size=1),
4257 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4258 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4261 def test_junk(self, part0, part1, part2):
4262 junk = part0 + part1 + part2
4263 assume(not (set(junk) <= set(digits.encode("ascii"))))
4264 with self.assertRaises(DecodeError):
4265 GeneralizedTime().decode(
4266 GeneralizedTime.tag_default +
4267 len_encode(len(junk)) +
4273 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4274 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4276 binary(min_size=1, max_size=1),
4278 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4279 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4282 def test_junk_dm(self, part0, part1, part2):
4283 junk = part0 + part1 + part2
4284 assume(not (set(junk) <= set(digits.encode("ascii"))))
4285 with self.assertRaises(DecodeError):
4286 GeneralizedTime().decode(
4287 GeneralizedTime.tag_default +
4288 len_encode(len(junk)) +
4292 def test_ns_fractions(self):
4293 GeneralizedTime(b"20010101000000.000001Z")
4294 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4295 GeneralizedTime(b"20010101000000.0000001Z")
4297 def test_non_pure_integers(self):
4299 # b"20000102030405Z,
4306 b"20000102030405.+6Z",
4307 b"20000102030405.-6Z",
4314 b"20000102030405._6Z",
4315 b"20000102030405.6_Z",
4322 b"20000102030405. 6Z",
4329 b"20000102030405.6 Z",
4331 with self.assertRaises(DecodeError):
4332 GeneralizedTime(data)
4335 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4336 base_klass = UTCTime
4338 min_datetime = datetime(2000, 1, 1)
4339 max_datetime = datetime(2049, 12, 31)
4341 def additional_symmetric_check(self, value, obj_encoded):
4344 def test_repr_not_ready(self):
4345 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4348 def test_x690_vector_valid(self):
4356 def test_x690_vector_invalid(self):
4361 with self.assertRaises(DecodeError) as err:
4365 def test_go_vectors_invalid(self):
4391 # These ones are INVALID in *DER*, but accepted
4392 # by Go's encoding/asn1
4393 b"910506164540-0700",
4394 b"910506164540+0730",
4398 with self.assertRaises(DecodeError) as err:
4402 def test_go_vectors_valid(self):
4404 UTCTime(b"910506234540Z").todatetime(),
4405 datetime(1991, 5, 6, 23, 45, 40, 0),
4408 def test_non_pure_integers(self):
4437 with self.assertRaises(DecodeError):
4440 def test_x680_vector_valid_ber(self):
4442 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4443 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4444 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4445 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4447 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4448 obj = UTCTime().decod(data_der, ctx={"bered": True})
4449 self.assertEqual(obj, dt)
4450 self.assertEqual(obj.todatetime(), dt)
4451 self.assertTrue(obj.ber_encoded)
4452 self.assertTrue(obj.bered)
4453 self.assertEqual(obj.ber_raw, data)
4454 self.assertNotEqual(obj.encode(), data_der)
4457 def test_go_vectors_valid_ber(self):
4459 b"910506164540-0700",
4460 b"910506164540+0730",
4464 data = UTCTime.tag_default + len_encode(len(data)) + data
4465 obj = UTCTime().decod(data, ctx={"bered": True})
4466 self.assertTrue(obj.ber_encoded)
4467 self.assertTrue(obj.bered)
4468 self.assertNotEqual(obj.encode(), data)
4471 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4472 @given(data_strategy())
4473 def test_valid_ber(self, d):
4474 year = d.draw(integers(min_value=0, max_value=99))
4475 month = d.draw(integers(min_value=1, max_value=12))
4476 day = d.draw(integers(min_value=1, max_value=28))
4477 hours = d.draw(integers(min_value=0, max_value=23))
4478 minute = d.draw(integers(min_value=0, max_value=59))
4479 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4481 year + (2000 if year < 50 else 1900),
4488 if d.draw(booleans()):
4490 seconds = d.draw(integers(min_value=0, max_value=59))
4491 data += "%02d" % seconds
4492 dt += timedelta(seconds=seconds)
4493 if d.draw(booleans()):
4497 offset_hour = d.draw(integers(min_value=0, max_value=13))
4498 offset_minute = d.draw(integers(min_value=0, max_value=59))
4499 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4500 if d.draw(booleans()):
4506 data += "%02d%02d" % (offset_hour, offset_minute)
4507 data = data.encode("ascii")
4508 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4509 obj = UTCTime().decod(data_der, ctx={"bered": True})
4510 self.assertEqual(obj, dt)
4511 self.assertEqual(obj.todatetime(), dt)
4512 self.assertEqual(obj.ber_encoded, not dered)
4513 self.assertEqual(obj.bered, not dered)
4514 self.assertEqual(obj.ber_raw, None if dered else data)
4515 self.assertEqual(obj.encode() == data_der, dered)
4520 def test_invalid_ber(self):
4561 b"0001020304+0000Z",
4570 with self.assertRaises(DecodeError):
4571 UTCTime(data, ctx={"bered": True})
4572 data = data[:8] + data[8+2:]
4573 with self.assertRaises(DecodeError):
4574 UTCTime(data, ctx={"bered": True})
4619 b"000102030405+000",
4620 b"000102030405+000Z",
4621 b"000102030405+0000Z",
4622 b"000102030405+-101",
4623 b"000102030405+01-1",
4624 b"000102030405+0060",
4625 b"000102030405+1401",
4626 b"500101000002+0003",
4628 with self.assertRaises(DecodeError):
4629 UTCTime(data, ctx={"bered": True})
4631 @given(integers(min_value=0, max_value=49))
4632 def test_pre50(self, year):
4634 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4638 @given(integers(min_value=50, max_value=99))
4639 def test_post50(self, year):
4641 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4647 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4648 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4650 binary(min_size=1, max_size=1),
4652 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4653 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4656 def test_junk(self, part0, part1, part2):
4657 junk = part0 + part1 + part2
4658 assume(not (set(junk) <= set(digits.encode("ascii"))))
4659 with self.assertRaises(DecodeError):
4661 UTCTime.tag_default +
4662 len_encode(len(junk)) +
4668 def any_values_strategy(draw, do_expl=False):
4669 value = draw(one_of(none(), binary()))
4672 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4673 optional = draw(one_of(none(), booleans()))
4675 draw(integers(min_value=0)),
4676 draw(integers(min_value=0)),
4677 draw(integers(min_value=0)),
4679 return (value, expl, optional, _decoded)
4682 class AnyInherited(Any):
4686 class TestAny(CommonMixin, TestCase):
4689 def test_invalid_value_type(self):
4690 with self.assertRaises(InvalidValueType) as err:
4695 def test_optional(self, optional):
4696 obj = Any(optional=optional)
4697 self.assertEqual(obj.optional, optional)
4700 def test_ready(self, value):
4702 self.assertFalse(obj.ready)
4705 pprint(obj, big_blobs=True, with_decode_path=True)
4706 with self.assertRaises(ObjNotReady) as err:
4710 self.assertTrue(obj.ready)
4713 pprint(obj, big_blobs=True, with_decode_path=True)
4716 def test_basic(self, value):
4717 integer_encoded = Integer(value).encode()
4719 Any(integer_encoded),
4720 Any(Integer(value)),
4721 Any(Any(Integer(value))),
4723 self.assertSequenceEqual(bytes(obj), integer_encoded)
4725 obj.decode(obj.encode())[0].vlen,
4726 len(integer_encoded),
4730 pprint(obj, big_blobs=True, with_decode_path=True)
4731 self.assertSequenceEqual(obj.encode(), integer_encoded)
4733 @given(binary(), binary())
4734 def test_comparison(self, value1, value2):
4735 for klass in (Any, AnyInherited):
4736 obj1 = klass(value1)
4737 obj2 = klass(value2)
4738 self.assertEqual(obj1 == obj2, value1 == value2)
4739 self.assertEqual(obj1 != obj2, value1 != value2)
4740 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4742 @given(data_strategy())
4743 def test_call(self, d):
4744 for klass in (Any, AnyInherited):
4750 ) = d.draw(any_values_strategy())
4751 obj_initial = klass(
4754 optional_initial or False,
4762 ) = d.draw(any_values_strategy(do_expl=True))
4763 obj = obj_initial(value, expl, optional)
4765 value_expected = None if value is None else value
4766 self.assertEqual(obj, value_expected)
4767 self.assertEqual(obj.expl_tag, expl or expl_initial)
4768 if obj.default is None:
4769 optional = optional_initial if optional is None else optional
4770 optional = False if optional is None else optional
4771 self.assertEqual(obj.optional, optional)
4773 def test_simultaneous_impl_expl(self):
4774 # override it, as Any does not have implicit tag
4777 def test_decoded(self):
4778 # override it, as Any does not have implicit tag
4781 @given(any_values_strategy())
4782 def test_copy(self, values):
4783 for klass in (Any, AnyInherited):
4784 obj = klass(*values)
4785 for copy_func in copy_funcs:
4786 obj_copied = copy_func(obj)
4787 self.assert_copied_basic_fields(obj, obj_copied)
4788 self.assertEqual(obj._value, obj_copied._value)
4790 @given(binary().map(OctetString))
4791 def test_stripped(self, value):
4793 with self.assertRaises(NotEnoughData):
4794 obj.decode(obj.encode()[:-1])
4798 integers(min_value=1).map(tag_ctxc),
4800 def test_stripped_expl(self, value, tag_expl):
4801 obj = Any(value, expl=tag_expl)
4802 with self.assertRaises(NotEnoughData):
4803 obj.decode(obj.encode()[:-1])
4806 integers(min_value=31),
4807 integers(min_value=0),
4810 def test_bad_tag(self, tag, offset, decode_path):
4811 with self.assertRaises(DecodeError) as err:
4813 tag_encode(tag)[:-1],
4815 decode_path=decode_path,
4818 self.assertEqual(err.exception.offset, offset)
4819 self.assertEqual(err.exception.decode_path, decode_path)
4822 integers(min_value=128),
4823 integers(min_value=0),
4826 def test_bad_len(self, l, offset, decode_path):
4827 with self.assertRaises(DecodeError) as err:
4829 Any.tag_default + len_encode(l)[:-1],
4831 decode_path=decode_path,
4834 self.assertEqual(err.exception.offset, offset)
4835 self.assertEqual(err.exception.decode_path, decode_path)
4837 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4839 any_values_strategy(),
4840 integers().map(lambda x: Integer(x).encode()),
4841 integers(min_value=1).map(tag_ctxc),
4842 integers(min_value=0),
4845 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4846 for klass in (Any, AnyInherited):
4847 _, _, optional, _decoded = values
4848 obj = klass(value=value, optional=optional, _decoded=_decoded)
4851 pprint(obj, big_blobs=True, with_decode_path=True)
4852 self.assertFalse(obj.expled)
4853 obj_encoded = obj.encode()
4854 obj_expled = obj(value, expl=tag_expl)
4855 self.assertTrue(obj_expled.expled)
4857 list(obj_expled.pps())
4858 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4859 obj_expled_encoded = obj_expled.encode()
4860 ctx_copied = deepcopy(ctx_dummy)
4861 obj_decoded, tail = obj_expled.decode(
4862 obj_expled_encoded + tail_junk,
4866 self.assertDictEqual(ctx_copied, ctx_dummy)
4868 list(obj_decoded.pps())
4869 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4870 self.assertEqual(tail, tail_junk)
4871 self.assertEqual(obj_decoded, obj_expled)
4872 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4873 self.assertEqual(bytes(obj_decoded), bytes(obj))
4874 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4875 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4876 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4878 obj_decoded.expl_llen,
4879 len(len_encode(len(obj_encoded))),
4881 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4882 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4885 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4887 self.assertEqual(obj_decoded.expl_offset, offset)
4888 self.assertEqual(obj_decoded.tlen, 0)
4889 self.assertEqual(obj_decoded.llen, 0)
4890 self.assertEqual(obj_decoded.vlen, len(value))
4891 assert_exceeding_data(
4893 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4898 integers(min_value=1).map(tag_ctxc),
4899 integers(min_value=0, max_value=3),
4900 integers(min_value=0),
4904 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4905 chunk = Boolean(False, expl=expl).encode()
4907 OctetString.tag_default +
4909 b"".join([chunk] * chunks) +
4912 with self.assertRaises(LenIndefForm):
4916 decode_path=decode_path,
4918 obj, tail = Any().decode(
4921 decode_path=decode_path,
4922 ctx={"bered": True},
4924 self.assertSequenceEqual(tail, junk)
4925 self.assertEqual(obj.offset, offset)
4926 self.assertEqual(obj.tlvlen, len(encoded))
4927 self.assertTrue(obj.lenindef)
4928 self.assertFalse(obj.ber_encoded)
4929 self.assertTrue(obj.bered)
4931 self.assertTrue(obj.lenindef)
4932 self.assertFalse(obj.ber_encoded)
4933 self.assertTrue(obj.bered)
4936 pprint(obj, big_blobs=True, with_decode_path=True)
4937 with self.assertRaises(NotEnoughData) as err:
4941 decode_path=decode_path,
4942 ctx={"bered": True},
4944 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4945 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4947 class SeqOf(SequenceOf):
4948 schema = Boolean(expl=expl)
4950 class Seq(Sequence):
4952 ("type", ObjectIdentifier(defines=((("value",), {
4953 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4958 ("type", ObjectIdentifier("1.2.3")),
4959 ("value", Any(encoded)),
4961 seq_encoded = seq.encode()
4962 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4963 self.assertIsNotNone(seq_decoded["value"].defined)
4965 list(seq_decoded.pps())
4966 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4967 self.assertTrue(seq_decoded.bered)
4968 self.assertFalse(seq_decoded["type"].bered)
4969 self.assertTrue(seq_decoded["value"].bered)
4971 chunk = chunk[:-1] + b"\x01"
4972 chunks = b"".join([chunk] * (chunks + 1))
4973 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4975 ("type", ObjectIdentifier("1.2.3")),
4976 ("value", Any(encoded)),
4978 seq_encoded = seq.encode()
4979 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4980 self.assertIsNotNone(seq_decoded["value"].defined)
4982 list(seq_decoded.pps())
4983 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4984 self.assertTrue(seq_decoded.bered)
4985 self.assertFalse(seq_decoded["type"].bered)
4986 self.assertTrue(seq_decoded["value"].bered)
4990 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
4992 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
4993 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
4995 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
4996 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
4998 min_size=len(names),
4999 max_size=len(names),
5002 (name, Integer(**tag_kwargs))
5003 for name, tag_kwargs in zip(names, tags)
5006 if value_required or draw(booleans()):
5007 value = draw(tuples(
5008 sampled_from([name for name, _ in schema]),
5009 integers().map(Integer),
5013 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5014 default = draw(one_of(
5016 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5018 optional = draw(one_of(none(), booleans()))
5020 draw(integers(min_value=0)),
5021 draw(integers(min_value=0)),
5022 draw(integers(min_value=0)),
5024 return (schema, value, expl, default, optional, _decoded)
5027 class ChoiceInherited(Choice):
5031 class TestChoice(CommonMixin, TestCase):
5033 schema = (("whatever", Boolean()),)
5036 def test_schema_required(self):
5037 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5040 def test_impl_forbidden(self):
5041 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
5042 Choice(impl=b"whatever")
5044 def test_invalid_value_type(self):
5045 with self.assertRaises(InvalidValueType) as err:
5046 self.base_klass(123)
5048 with self.assertRaises(ObjUnknown) as err:
5049 self.base_klass(("whenever", Boolean(False)))
5051 with self.assertRaises(InvalidValueType) as err:
5052 self.base_klass(("whatever", Integer(123)))
5056 def test_optional(self, optional):
5057 obj = self.base_klass(
5058 default=self.base_klass(("whatever", Boolean(False))),
5061 self.assertTrue(obj.optional)
5064 def test_ready(self, value):
5065 obj = self.base_klass()
5066 self.assertFalse(obj.ready)
5069 pprint(obj, big_blobs=True, with_decode_path=True)
5070 self.assertIsNone(obj["whatever"])
5071 with self.assertRaises(ObjNotReady) as err:
5074 obj["whatever"] = Boolean()
5075 self.assertFalse(obj.ready)
5078 pprint(obj, big_blobs=True, with_decode_path=True)
5079 obj["whatever"] = Boolean(value)
5080 self.assertTrue(obj.ready)
5083 pprint(obj, big_blobs=True, with_decode_path=True)
5085 @given(booleans(), booleans())
5086 def test_comparison(self, value1, value2):
5087 class WahlInherited(self.base_klass):
5089 for klass in (self.base_klass, WahlInherited):
5090 obj1 = klass(("whatever", Boolean(value1)))
5091 obj2 = klass(("whatever", Boolean(value2)))
5092 self.assertEqual(obj1 == obj2, value1 == value2)
5093 self.assertEqual(obj1 != obj2, value1 != value2)
5094 self.assertEqual(obj1 == obj2._value, value1 == value2)
5095 self.assertFalse(obj1 == obj2._value[1])
5097 @given(data_strategy())
5098 def test_call(self, d):
5099 for klass in (Choice, ChoiceInherited):
5107 ) = d.draw(choice_values_strategy())
5110 schema = schema_initial
5112 value=value_initial,
5114 default=default_initial,
5115 optional=optional_initial or False,
5116 _decoded=_decoded_initial,
5125 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5126 obj = obj_initial(value, expl, default, optional)
5128 value_expected = default if value is None else value
5130 default_initial if value_expected is None
5133 self.assertEqual(obj.choice, value_expected[0])
5134 self.assertEqual(obj.value, int(value_expected[1]))
5135 self.assertEqual(obj.expl_tag, expl or expl_initial)
5136 default_expect = default_initial if default is None else default
5137 if default_expect is not None:
5138 self.assertEqual(obj.default.choice, default_expect[0])
5139 self.assertEqual(obj.default.value, int(default_expect[1]))
5140 if obj.default is None:
5141 optional = optional_initial if optional is None else optional
5142 optional = False if optional is None else optional
5145 self.assertEqual(obj.optional, optional)
5146 self.assertEqual(obj.specs, obj_initial.specs)
5148 def test_simultaneous_impl_expl(self):
5149 # override it, as Any does not have implicit tag
5152 def test_decoded(self):
5153 # override it, as Any does not have implicit tag
5156 @given(choice_values_strategy())
5157 def test_copy(self, values):
5158 _schema, value, expl, default, optional, _decoded = values
5160 class Wahl(self.base_klass):
5162 register_class(Wahl)
5167 optional=optional or False,
5170 for copy_func in copy_funcs:
5171 obj_copied = copy_func(obj)
5172 self.assertIsNone(obj.tag)
5173 self.assertIsNone(obj_copied.tag)
5174 # hack for assert_copied_basic_fields
5175 obj.tag = "whatever"
5176 obj_copied.tag = "whatever"
5177 self.assert_copied_basic_fields(obj, obj_copied)
5179 self.assertEqual(obj._value, obj_copied._value)
5180 self.assertEqual(obj.specs, obj_copied.specs)
5183 def test_stripped(self, value):
5184 obj = self.base_klass(("whatever", Boolean(value)))
5185 with self.assertRaises(NotEnoughData):
5186 obj.decode(obj.encode()[:-1])
5190 integers(min_value=1).map(tag_ctxc),
5192 def test_stripped_expl(self, value, tag_expl):
5193 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5194 with self.assertRaises(NotEnoughData):
5195 obj.decode(obj.encode()[:-1])
5197 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5198 @given(data_strategy())
5199 def test_symmetric(self, d):
5200 _schema, value, _, default, optional, _decoded = d.draw(
5201 choice_values_strategy(value_required=True)
5203 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5204 offset = d.draw(integers(min_value=0))
5205 tail_junk = d.draw(binary(max_size=5))
5207 class Wahl(self.base_klass):
5217 pprint(obj, big_blobs=True, with_decode_path=True)
5218 self.assertFalse(obj.expled)
5219 obj_encoded = obj.encode()
5220 obj_expled = obj(value, expl=tag_expl)
5221 self.assertTrue(obj_expled.expled)
5223 list(obj_expled.pps())
5224 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5225 obj_expled_encoded = obj_expled.encode()
5226 ctx_copied = deepcopy(ctx_dummy)
5227 obj_decoded, tail = obj_expled.decode(
5228 obj_expled_encoded + tail_junk,
5232 self.assertDictEqual(ctx_copied, ctx_dummy)
5234 list(obj_decoded.pps())
5235 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5236 self.assertEqual(tail, tail_junk)
5237 self.assertEqual(obj_decoded, obj_expled)
5238 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5239 self.assertEqual(obj_decoded.value, obj_expled.value)
5240 self.assertEqual(obj_decoded.choice, obj.choice)
5241 self.assertEqual(obj_decoded.value, obj.value)
5242 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5243 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5244 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5246 obj_decoded.expl_llen,
5247 len(len_encode(len(obj_encoded))),
5249 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5250 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5253 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5255 self.assertEqual(obj_decoded.expl_offset, offset)
5256 self.assertSequenceEqual(
5258 obj_decoded.value.fulloffset - offset:
5259 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5263 assert_exceeding_data(
5265 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5270 def test_set_get(self, value):
5273 ("erste", Boolean()),
5274 ("zweite", Integer()),
5277 with self.assertRaises(ObjUnknown) as err:
5278 obj["whatever"] = "whenever"
5279 with self.assertRaises(InvalidValueType) as err:
5280 obj["zweite"] = Boolean(False)
5281 obj["zweite"] = Integer(value)
5283 with self.assertRaises(ObjUnknown) as err:
5286 self.assertIsNone(obj["erste"])
5287 self.assertEqual(obj["zweite"], Integer(value))
5289 def test_tag_mismatch(self):
5292 ("erste", Boolean()),
5294 int_encoded = Integer(123).encode()
5295 bool_encoded = Boolean(False).encode()
5297 obj.decode(bool_encoded)
5298 with self.assertRaises(TagMismatch):
5299 obj.decode(int_encoded)
5301 def test_tag_mismatch_underlying(self):
5302 class SeqOfBoolean(SequenceOf):
5305 class SeqOfInteger(SequenceOf):
5310 ("erste", SeqOfBoolean()),
5313 int_encoded = SeqOfInteger((Integer(123),)).encode()
5314 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5316 obj.decode(bool_encoded)
5317 with self.assertRaises(TagMismatch) as err:
5318 obj.decode(int_encoded)
5319 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5323 def seq_values_strategy(draw, seq_klass, do_expl=False):
5325 if draw(booleans()):
5327 value._value = draw(dictionaries(
5330 booleans().map(Boolean),
5331 integers().map(Integer),
5335 if draw(booleans()):
5336 schema = list(draw(dictionaries(
5339 booleans().map(Boolean),
5340 integers().map(Integer),
5346 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5348 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5350 if draw(booleans()):
5351 default = seq_klass()
5352 default._value = draw(dictionaries(
5355 booleans().map(Boolean),
5356 integers().map(Integer),
5359 optional = draw(one_of(none(), booleans()))
5361 draw(integers(min_value=0)),
5362 draw(integers(min_value=0)),
5363 draw(integers(min_value=0)),
5365 return (value, schema, impl, expl, default, optional, _decoded)
5369 def sequence_strategy(draw, seq_klass):
5370 inputs = draw(lists(
5372 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5373 tuples(just(Integer), integers(), one_of(none(), integers())),
5378 integers(min_value=1),
5379 min_size=len(inputs),
5380 max_size=len(inputs),
5383 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5384 for tag, expled in zip(tags, draw(lists(
5386 min_size=len(inputs),
5387 max_size=len(inputs),
5391 for i, optional in enumerate(draw(lists(
5392 sampled_from(("required", "optional", "empty")),
5393 min_size=len(inputs),
5394 max_size=len(inputs),
5396 if optional in ("optional", "empty"):
5397 inits[i]["optional"] = True
5398 if optional == "empty":
5400 empties = set(empties)
5401 names = list(draw(sets(
5403 min_size=len(inputs),
5404 max_size=len(inputs),
5407 for i, (klass, value, default) in enumerate(inputs):
5408 schema.append((names[i], klass(default=default, **inits[i])))
5409 seq_name = draw(text_letters())
5410 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5413 for i, (klass, value, default) in enumerate(inputs):
5420 "default_value": None if spec.default is None else default,
5424 expect["optional"] = True
5426 expect["presented"] = True
5427 expect["value"] = value
5429 expect["optional"] = True
5430 if default is not None and default == value:
5431 expect["presented"] = False
5432 seq[name] = klass(value)
5433 expects.append(expect)
5438 def sequences_strategy(draw, seq_klass):
5439 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5441 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5442 for tag, expled in zip(tags, draw(lists(
5449 i for i, is_default in enumerate(draw(lists(
5455 names = list(draw(sets(
5460 seq_expectses = draw(lists(
5461 sequence_strategy(seq_klass=seq_klass),
5465 seqs = [seq for seq, _ in seq_expectses]
5467 for i, (name, seq) in enumerate(zip(names, seqs)):
5470 seq(default=(seq if i in defaulted else None), **inits[i]),
5472 seq_name = draw(text_letters())
5473 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5476 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5479 "expects": expects_inner,
5482 seq_outer[name] = seq_inner
5483 if seq_outer.specs[name].default is None:
5484 expect["presented"] = True
5485 expect_outers.append(expect)
5486 return seq_outer, expect_outers
5489 class SeqMixing(object):
5490 def test_invalid_value_type(self):
5491 with self.assertRaises(InvalidValueType) as err:
5492 self.base_klass(123)
5495 def test_invalid_value_type_set(self):
5496 class Seq(self.base_klass):
5497 schema = (("whatever", Boolean()),)
5499 with self.assertRaises(InvalidValueType) as err:
5500 seq["whatever"] = Integer(123)
5504 def test_optional(self, optional):
5505 obj = self.base_klass(default=self.base_klass(), optional=optional)
5506 self.assertTrue(obj.optional)
5508 @given(data_strategy())
5509 def test_ready(self, d):
5511 str(i): v for i, v in enumerate(d.draw(lists(
5518 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5525 for name in d.draw(permutations(
5526 list(ready.keys()) + list(non_ready.keys()),
5528 schema_input.append((name, Boolean()))
5530 class Seq(self.base_klass):
5531 schema = tuple(schema_input)
5533 for name in ready.keys():
5535 seq[name] = Boolean()
5536 self.assertFalse(seq.ready)
5539 pprint(seq, big_blobs=True, with_decode_path=True)
5540 for name, value in ready.items():
5541 seq[name] = Boolean(value)
5542 self.assertFalse(seq.ready)
5545 pprint(seq, big_blobs=True, with_decode_path=True)
5546 with self.assertRaises(ObjNotReady) as err:
5549 for name, value in non_ready.items():
5550 seq[name] = Boolean(value)
5551 self.assertTrue(seq.ready)
5554 pprint(seq, big_blobs=True, with_decode_path=True)
5556 @given(data_strategy())
5557 def test_call(self, d):
5558 class SeqInherited(self.base_klass):
5560 for klass in (self.base_klass, SeqInherited):
5569 ) = d.draw(seq_values_strategy(seq_klass=klass))
5570 obj_initial = klass(
5576 optional_initial or False,
5587 ) = d.draw(seq_values_strategy(
5589 do_expl=impl_initial is None,
5591 obj = obj_initial(value, impl, expl, default, optional)
5592 value_expected = default if value is None else value
5594 default_initial if value_expected is None
5597 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5598 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5599 self.assertEqual(obj.expl_tag, expl or expl_initial)
5601 {} if obj.default is None else obj.default._value,
5602 getattr(default_initial if default is None else default, "_value", {}),
5604 if obj.default is None:
5605 optional = optional_initial if optional is None else optional
5606 optional = False if optional is None else optional
5609 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5610 self.assertEqual(obj.optional, optional)
5612 @given(data_strategy())
5613 def test_copy(self, d):
5614 class SeqInherited(self.base_klass):
5616 register_class(SeqInherited)
5617 for klass in (self.base_klass, SeqInherited):
5618 values = d.draw(seq_values_strategy(seq_klass=klass))
5619 obj = klass(*values)
5620 for copy_func in copy_funcs:
5621 obj_copied = copy_func(obj)
5622 self.assert_copied_basic_fields(obj, obj_copied)
5623 self.assertEqual(obj.specs, obj_copied.specs)
5624 self.assertEqual(obj._value, obj_copied._value)
5626 @given(data_strategy())
5627 def test_stripped(self, d):
5628 value = d.draw(integers())
5629 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5631 class Seq(self.base_klass):
5633 schema = (("whatever", Integer()),)
5635 seq["whatever"] = Integer(value)
5636 with self.assertRaises(NotEnoughData):
5637 seq.decode(seq.encode()[:-1])
5639 @given(data_strategy())
5640 def test_stripped_expl(self, d):
5641 value = d.draw(integers())
5642 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5644 class Seq(self.base_klass):
5646 schema = (("whatever", Integer()),)
5648 seq["whatever"] = Integer(value)
5649 with self.assertRaises(NotEnoughData):
5650 seq.decode(seq.encode()[:-1])
5652 @given(binary(min_size=2))
5653 def test_non_tag_mismatch_raised(self, junk):
5655 _, _, len_encoded = tag_strip(memoryview(junk))
5656 len_decode(len_encoded)
5662 class Seq(self.base_klass):
5664 ("whatever", Integer()),
5666 ("whenever", Integer()),
5669 seq["whatever"] = Integer(123)
5670 seq["junk"] = Any(junk)
5671 seq["whenever"] = Integer(123)
5672 with self.assertRaises(DecodeError):
5673 seq.decode(seq.encode())
5676 integers(min_value=31),
5677 integers(min_value=0),
5680 def test_bad_tag(self, tag, offset, decode_path):
5681 with self.assertRaises(DecodeError) as err:
5682 self.base_klass().decode(
5683 tag_encode(tag)[:-1],
5685 decode_path=decode_path,
5688 self.assertEqual(err.exception.offset, offset)
5689 self.assertEqual(err.exception.decode_path, decode_path)
5692 integers(min_value=128),
5693 integers(min_value=0),
5696 def test_bad_len(self, l, offset, decode_path):
5697 with self.assertRaises(DecodeError) as err:
5698 self.base_klass().decode(
5699 self.base_klass.tag_default + len_encode(l)[:-1],
5701 decode_path=decode_path,
5704 self.assertEqual(err.exception.offset, offset)
5705 self.assertEqual(err.exception.decode_path, decode_path)
5707 def _assert_expects(self, seq, expects):
5708 for expect in expects:
5710 seq.specs[expect["name"]].optional,
5713 if expect["default_value"] is not None:
5715 seq.specs[expect["name"]].default,
5716 expect["default_value"],
5718 if expect["presented"]:
5719 self.assertIn(expect["name"], seq)
5720 self.assertEqual(seq[expect["name"]], expect["value"])
5722 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5723 @given(data_strategy())
5724 def test_symmetric(self, d):
5725 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5726 tail_junk = d.draw(binary(max_size=5))
5727 self.assertTrue(seq.ready)
5728 self.assertFalse(seq.decoded)
5729 self._assert_expects(seq, expects)
5732 pprint(seq, big_blobs=True, with_decode_path=True)
5733 self.assertTrue(seq.ready)
5734 seq_encoded = seq.encode()
5735 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5736 self.assertFalse(seq_decoded.lenindef)
5737 self.assertFalse(seq_decoded.ber_encoded)
5738 self.assertFalse(seq_decoded.bered)
5740 t, _, lv = tag_strip(seq_encoded)
5741 _, _, v = len_decode(lv)
5742 seq_encoded_lenindef = t + LENINDEF + v + EOC
5743 with self.assertRaises(DecodeError):
5744 seq.decode(seq_encoded_lenindef)
5745 ctx_copied = deepcopy(ctx_dummy)
5746 ctx_copied["bered"] = True
5747 seq_decoded_lenindef, tail_lenindef = seq.decode(
5748 seq_encoded_lenindef + tail_junk,
5751 del ctx_copied["bered"]
5752 self.assertDictEqual(ctx_copied, ctx_dummy)
5753 self.assertTrue(seq_decoded_lenindef.lenindef)
5754 self.assertTrue(seq_decoded_lenindef.bered)
5755 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5756 self.assertTrue(seq_decoded_lenindef.lenindef)
5757 self.assertTrue(seq_decoded_lenindef.bered)
5758 with self.assertRaises(DecodeError):
5759 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5760 with self.assertRaises(DecodeError):
5761 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5762 repr(seq_decoded_lenindef)
5763 list(seq_decoded_lenindef.pps())
5764 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5765 self.assertTrue(seq_decoded_lenindef.ready)
5767 for decoded, decoded_tail, encoded in (
5768 (seq_decoded, tail, seq_encoded),
5769 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5771 self.assertEqual(decoded_tail, tail_junk)
5772 self._assert_expects(decoded, expects)
5773 self.assertEqual(seq, decoded)
5774 self.assertEqual(decoded.encode(), seq_encoded)
5775 self.assertEqual(decoded.tlvlen, len(encoded))
5776 for expect in expects:
5777 if not expect["presented"]:
5778 self.assertNotIn(expect["name"], decoded)
5780 self.assertIn(expect["name"], decoded)
5781 obj = decoded[expect["name"]]
5782 self.assertTrue(obj.decoded)
5783 offset = obj.expl_offset if obj.expled else obj.offset
5784 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5785 self.assertSequenceEqual(
5786 seq_encoded[offset:offset + tlvlen],
5790 assert_exceeding_data(
5792 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5796 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5797 @given(data_strategy())
5798 def test_symmetric_with_seq(self, d):
5799 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5800 self.assertTrue(seq.ready)
5801 seq_encoded = seq.encode()
5802 seq_decoded, tail = seq.decode(seq_encoded)
5803 self.assertEqual(tail, b"")
5804 self.assertTrue(seq.ready)
5805 self.assertEqual(seq, seq_decoded)
5806 self.assertEqual(seq_decoded.encode(), seq_encoded)
5807 for expect_outer in expect_outers:
5808 if not expect_outer["presented"]:
5809 self.assertNotIn(expect_outer["name"], seq_decoded)
5811 self.assertIn(expect_outer["name"], seq_decoded)
5812 obj = seq_decoded[expect_outer["name"]]
5813 self.assertTrue(obj.decoded)
5814 offset = obj.expl_offset if obj.expled else obj.offset
5815 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5816 self.assertSequenceEqual(
5817 seq_encoded[offset:offset + tlvlen],
5820 self._assert_expects(obj, expect_outer["expects"])
5822 @given(data_strategy())
5823 def test_default_disappears(self, d):
5824 _schema = list(d.draw(dictionaries(
5826 sets(integers(), min_size=2, max_size=2),
5830 class Seq(self.base_klass):
5832 (n, Integer(default=d))
5833 for n, (_, d) in _schema
5836 for name, (value, _) in _schema:
5837 seq[name] = Integer(value)
5838 self.assertEqual(len(seq._value), len(_schema))
5839 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5840 self.assertGreater(len(seq.encode()), len(empty_seq))
5841 for name, (_, default) in _schema:
5842 seq[name] = Integer(default)
5843 self.assertEqual(len(seq._value), 0)
5844 self.assertSequenceEqual(seq.encode(), empty_seq)
5846 @given(data_strategy())
5847 def test_encoded_default_not_accepted(self, d):
5848 _schema = list(d.draw(dictionaries(
5853 tags = [tag_encode(tag) for tag in d.draw(sets(
5854 integers(min_value=0),
5855 min_size=len(_schema),
5856 max_size=len(_schema),
5859 class SeqWithoutDefault(self.base_klass):
5861 (n, Integer(impl=t))
5862 for (n, _), t in zip(_schema, tags)
5864 seq_without_default = SeqWithoutDefault()
5865 for name, value in _schema:
5866 seq_without_default[name] = Integer(value)
5867 seq_encoded = seq_without_default.encode()
5869 class SeqWithDefault(self.base_klass):
5871 (n, Integer(default=v, impl=t))
5872 for (n, v), t in zip(_schema, tags)
5874 seq_with_default = SeqWithDefault()
5875 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5876 seq_with_default.decode(seq_encoded)
5877 for ctx in ({"bered": True}, {"allow_default_values": True}):
5878 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5879 self.assertTrue(seq_decoded.ber_encoded)
5880 self.assertTrue(seq_decoded.bered)
5881 seq_decoded = copy(seq_decoded)
5882 self.assertTrue(seq_decoded.ber_encoded)
5883 self.assertTrue(seq_decoded.bered)
5884 for name, value in _schema:
5885 self.assertEqual(seq_decoded[name], seq_with_default[name])
5886 self.assertEqual(seq_decoded[name], value)
5888 @given(data_strategy())
5889 def test_missing_from_spec(self, d):
5890 names = list(d.draw(sets(text_letters(), min_size=2)))
5891 tags = [tag_encode(tag) for tag in d.draw(sets(
5892 integers(min_value=0),
5893 min_size=len(names),
5894 max_size=len(names),
5896 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5898 class SeqFull(self.base_klass):
5899 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5900 seq_full = SeqFull()
5901 for i, name in enumerate(names):
5902 seq_full[name] = Integer(i)
5903 seq_encoded = seq_full.encode()
5904 altered = names_tags[:-2] + names_tags[-1:]
5906 class SeqMissing(self.base_klass):
5907 schema = [(n, Integer(impl=t)) for n, t in altered]
5908 seq_missing = SeqMissing()
5909 with self.assertRaises(TagMismatch):
5910 seq_missing.decode(seq_encoded)
5912 def test_bered(self):
5913 class Seq(self.base_klass):
5914 schema = (("underlying", Boolean()),)
5915 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5916 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5917 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5918 self.assertFalse(decoded.ber_encoded)
5919 self.assertFalse(decoded.lenindef)
5920 self.assertTrue(decoded.bered)
5921 decoded = copy(decoded)
5922 self.assertFalse(decoded.ber_encoded)
5923 self.assertFalse(decoded.lenindef)
5924 self.assertTrue(decoded.bered)
5926 class Seq(self.base_klass):
5927 schema = (("underlying", OctetString()),)
5929 tag_encode(form=TagFormConstructed, num=4) +
5931 OctetString(b"whatever").encode() +
5934 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5935 with self.assertRaises(DecodeError):
5936 Seq().decode(encoded)
5937 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5938 self.assertFalse(decoded.ber_encoded)
5939 self.assertFalse(decoded.lenindef)
5940 self.assertTrue(decoded.bered)
5941 decoded = copy(decoded)
5942 self.assertFalse(decoded.ber_encoded)
5943 self.assertFalse(decoded.lenindef)
5944 self.assertTrue(decoded.bered)
5947 class TestSequence(SeqMixing, CommonMixin, TestCase):
5948 base_klass = Sequence
5954 def test_remaining(self, value, junk):
5955 class Seq(Sequence):
5957 ("whatever", Integer()),
5959 int_encoded = Integer(value).encode()
5961 Sequence.tag_default,
5962 len_encode(len(int_encoded + junk)),
5965 with assertRaisesRegex(self, DecodeError, "remaining"):
5966 Seq().decode(junked)
5968 @given(sets(text_letters(), min_size=2))
5969 def test_obj_unknown(self, names):
5970 missing = names.pop()
5972 class Seq(Sequence):
5973 schema = [(n, Boolean()) for n in names]
5975 with self.assertRaises(ObjUnknown) as err:
5978 with self.assertRaises(ObjUnknown) as err:
5979 seq[missing] = Boolean()
5982 def test_x690_vector(self):
5983 class Seq(Sequence):
5985 ("name", IA5String()),
5988 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
5989 self.assertEqual(seq["name"], "Smith")
5990 self.assertEqual(seq["ok"], True)
5993 class TestSet(SeqMixing, CommonMixin, TestCase):
5996 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5997 @given(data_strategy())
5998 def test_sorted(self, d):
6000 tag_encode(tag) for tag in
6001 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
6005 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
6007 for name, _ in Seq.schema:
6008 seq[name] = OctetString(b"")
6009 seq_encoded = seq.encode()
6010 seq_decoded, _ = seq.decode(seq_encoded)
6011 self.assertSequenceEqual(
6012 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6013 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
6016 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6017 @given(data_strategy())
6018 def test_unsorted(self, d):
6020 tag_encode(tag) for tag in
6021 d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
6023 tags = d.draw(permutations(tags))
6024 assume(tags != sorted(tags))
6025 encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
6026 seq_encoded = b"".join((
6028 len_encode(len(encoded)),
6033 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
6035 with assertRaisesRegex(self, DecodeError, "unordered SET"):
6036 seq.decode(seq_encoded)
6037 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6038 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6039 self.assertTrue(seq_decoded.ber_encoded)
6040 self.assertTrue(seq_decoded.bered)
6041 seq_decoded = copy(seq_decoded)
6042 self.assertTrue(seq_decoded.ber_encoded)
6043 self.assertTrue(seq_decoded.bered)
6044 self.assertSequenceEqual(
6045 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
6051 def seqof_values_strategy(draw, schema=None, do_expl=False):
6053 schema = draw(sampled_from((Boolean(), Integer())))
6054 bound_min, bound_max = sorted(draw(sets(
6055 integers(min_value=0, max_value=10),
6059 if isinstance(schema, Boolean):
6060 values_generator = booleans().map(Boolean)
6061 elif isinstance(schema, Integer):
6062 values_generator = integers().map(Integer)
6063 values_generator = lists(
6068 values = draw(one_of(none(), values_generator))
6072 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6074 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6075 default = draw(one_of(none(), values_generator))
6076 optional = draw(one_of(none(), booleans()))
6078 draw(integers(min_value=0)),
6079 draw(integers(min_value=0)),
6080 draw(integers(min_value=0)),
6085 (bound_min, bound_max),
6094 class SeqOfMixing(object):
6095 def test_invalid_value_type(self):
6096 with self.assertRaises(InvalidValueType) as err:
6097 self.base_klass(123)
6100 def test_invalid_values_type(self):
6101 class SeqOf(self.base_klass):
6103 with self.assertRaises(InvalidValueType) as err:
6104 SeqOf([Integer(123), Boolean(False), Integer(234)])
6107 def test_schema_required(self):
6108 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6109 self.base_klass.__mro__[1]()
6111 @given(booleans(), booleans(), binary(), binary())
6112 def test_comparison(self, value1, value2, tag1, tag2):
6113 class SeqOf(self.base_klass):
6115 obj1 = SeqOf([Boolean(value1)])
6116 obj2 = SeqOf([Boolean(value2)])
6117 self.assertEqual(obj1 == obj2, value1 == value2)
6118 self.assertEqual(obj1 != obj2, value1 != value2)
6119 self.assertEqual(obj1 == list(obj2), value1 == value2)
6120 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6121 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6122 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6123 self.assertEqual(obj1 == obj2, tag1 == tag2)
6124 self.assertEqual(obj1 != obj2, tag1 != tag2)
6126 @given(lists(booleans()))
6127 def test_iter(self, values):
6128 class SeqOf(self.base_klass):
6130 obj = SeqOf([Boolean(value) for value in values])
6131 self.assertEqual(len(obj), len(values))
6132 for i, value in enumerate(obj):
6133 self.assertEqual(value, values[i])
6135 @given(data_strategy())
6136 def test_ready(self, d):
6137 ready = [Integer(v) for v in d.draw(lists(
6144 range(d.draw(integers(min_value=1, max_value=5)))
6147 class SeqOf(self.base_klass):
6149 values = d.draw(permutations(ready + non_ready))
6151 for value in values:
6153 self.assertFalse(seqof.ready)
6156 pprint(seqof, big_blobs=True, with_decode_path=True)
6157 with self.assertRaises(ObjNotReady) as err:
6160 for i, value in enumerate(values):
6161 self.assertEqual(seqof[i], value)
6162 if not seqof[i].ready:
6163 seqof[i] = Integer(i)
6164 self.assertTrue(seqof.ready)
6167 pprint(seqof, big_blobs=True, with_decode_path=True)
6169 def test_spec_mismatch(self):
6170 class SeqOf(self.base_klass):
6173 seqof.append(Integer(123))
6174 with self.assertRaises(ValueError):
6175 seqof.append(Boolean(False))
6176 with self.assertRaises(ValueError):
6177 seqof[0] = Boolean(False)
6179 @given(data_strategy())
6180 def test_bounds_satisfied(self, d):
6181 class SeqOf(self.base_klass):
6183 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6184 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6185 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6186 SeqOf(value=value, bounds=(bound_min, bound_max))
6188 @given(data_strategy())
6189 def test_bounds_unsatisfied(self, d):
6190 class SeqOf(self.base_klass):
6192 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6193 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6194 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6195 with self.assertRaises(BoundsError) as err:
6196 SeqOf(value=value, bounds=(bound_min, bound_max))
6198 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6199 SeqOf(bounds=(bound_min, bound_max)).decode(
6200 SeqOf(value).encode()
6203 value = [Boolean(True)] * d.draw(integers(
6204 min_value=bound_max + 1,
6205 max_value=bound_max + 10,
6207 with self.assertRaises(BoundsError) as err:
6208 SeqOf(value=value, bounds=(bound_min, bound_max))
6210 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6211 SeqOf(bounds=(bound_min, bound_max)).decode(
6212 SeqOf(value).encode()
6216 @given(integers(min_value=1, max_value=10))
6217 def test_out_of_bounds(self, bound_max):
6218 class SeqOf(self.base_klass):
6220 bounds = (0, bound_max)
6222 for _ in range(bound_max):
6223 seqof.append(Integer(123))
6224 with self.assertRaises(BoundsError):
6225 seqof.append(Integer(123))
6227 @given(data_strategy())
6228 def test_call(self, d):
6238 ) = d.draw(seqof_values_strategy())
6240 class SeqOf(self.base_klass):
6241 schema = schema_initial
6242 obj_initial = SeqOf(
6243 value=value_initial,
6244 bounds=bounds_initial,
6247 default=default_initial,
6248 optional=optional_initial or False,
6249 _decoded=_decoded_initial,
6260 ) = d.draw(seqof_values_strategy(
6261 schema=schema_initial,
6262 do_expl=impl_initial is None,
6264 if (default is None) and (obj_initial.default is not None):
6267 (bounds is None) and
6268 (value is not None) and
6269 (bounds_initial is not None) and
6270 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6274 (bounds is None) and
6275 (default is not None) and
6276 (bounds_initial is not None) and
6277 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6289 value_expected = default if value is None else value
6291 default_initial if value_expected is None
6294 value_expected = () if value_expected is None else value_expected
6295 self.assertEqual(obj, value_expected)
6296 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6297 self.assertEqual(obj.expl_tag, expl or expl_initial)
6300 default_initial if default is None else default,
6302 if obj.default is None:
6303 optional = optional_initial if optional is None else optional
6304 optional = False if optional is None else optional
6307 self.assertEqual(obj.optional, optional)
6309 (obj._bound_min, obj._bound_max),
6310 bounds or bounds_initial or (0, float("+inf")),
6313 @given(seqof_values_strategy())
6314 def test_copy(self, values):
6315 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6317 class SeqOf(self.base_klass):
6319 register_class(SeqOf)
6326 optional=optional or False,
6329 for copy_func in copy_funcs:
6330 obj_copied = copy_func(obj)
6331 self.assert_copied_basic_fields(obj, obj_copied)
6332 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6333 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6334 self.assertEqual(obj._value, obj_copied._value)
6338 integers(min_value=1).map(tag_encode),
6340 def test_stripped(self, values, tag_impl):
6341 class SeqOf(self.base_klass):
6342 schema = OctetString()
6343 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6344 with self.assertRaises(NotEnoughData):
6345 obj.decode(obj.encode()[:-1])
6349 integers(min_value=1).map(tag_ctxc),
6351 def test_stripped_expl(self, values, tag_expl):
6352 class SeqOf(self.base_klass):
6353 schema = OctetString()
6354 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6355 with self.assertRaises(NotEnoughData):
6356 obj.decode(obj.encode()[:-1])
6359 integers(min_value=31),
6360 integers(min_value=0),
6363 def test_bad_tag(self, tag, offset, decode_path):
6364 with self.assertRaises(DecodeError) as err:
6365 self.base_klass().decode(
6366 tag_encode(tag)[:-1],
6368 decode_path=decode_path,
6371 self.assertEqual(err.exception.offset, offset)
6372 self.assertEqual(err.exception.decode_path, decode_path)
6375 integers(min_value=128),
6376 integers(min_value=0),
6379 def test_bad_len(self, l, offset, decode_path):
6380 with self.assertRaises(DecodeError) as err:
6381 self.base_klass().decode(
6382 self.base_klass.tag_default + len_encode(l)[:-1],
6384 decode_path=decode_path,
6387 self.assertEqual(err.exception.offset, offset)
6388 self.assertEqual(err.exception.decode_path, decode_path)
6390 @given(binary(min_size=1))
6391 def test_tag_mismatch(self, impl):
6392 assume(impl != self.base_klass.tag_default)
6393 with self.assertRaises(TagMismatch):
6394 self.base_klass(impl=impl).decode(self.base_klass().encode())
6396 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6398 seqof_values_strategy(schema=Integer()),
6399 lists(integers().map(Integer)),
6400 integers(min_value=1).map(tag_ctxc),
6401 integers(min_value=0),
6404 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
6405 _, _, _, _, _, default, optional, _decoded = values
6407 class SeqOf(self.base_klass):
6417 pprint(obj, big_blobs=True, with_decode_path=True)
6418 self.assertFalse(obj.expled)
6419 obj_encoded = obj.encode()
6420 obj_expled = obj(value, expl=tag_expl)
6421 self.assertTrue(obj_expled.expled)
6423 list(obj_expled.pps())
6424 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6425 obj_expled_encoded = obj_expled.encode()
6426 ctx_copied = deepcopy(ctx_dummy)
6427 obj_decoded, tail = obj_expled.decode(
6428 obj_expled_encoded + tail_junk,
6432 self.assertDictEqual(ctx_copied, ctx_dummy)
6434 list(obj_decoded.pps())
6435 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6436 self.assertEqual(tail, tail_junk)
6437 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6438 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6439 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6440 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6442 obj_decoded.expl_llen,
6443 len(len_encode(len(obj_encoded))),
6445 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6446 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6449 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6451 self.assertEqual(obj_decoded.expl_offset, offset)
6452 for obj_inner in obj_decoded:
6453 self.assertIn(obj_inner, obj_decoded)
6454 self.assertSequenceEqual(
6457 obj_inner.offset - offset:
6458 obj_inner.offset + obj_inner.tlvlen - offset
6462 t, _, lv = tag_strip(obj_encoded)
6463 _, _, v = len_decode(lv)
6464 obj_encoded_lenindef = t + LENINDEF + v + EOC
6465 with self.assertRaises(DecodeError):
6466 obj.decode(obj_encoded_lenindef)
6467 obj_decoded_lenindef, tail_lenindef = obj.decode(
6468 obj_encoded_lenindef + tail_junk,
6469 ctx={"bered": True},
6471 self.assertTrue(obj_decoded_lenindef.lenindef)
6472 self.assertTrue(obj_decoded_lenindef.bered)
6473 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6474 self.assertTrue(obj_decoded_lenindef.lenindef)
6475 self.assertTrue(obj_decoded_lenindef.bered)
6476 repr(obj_decoded_lenindef)
6477 list(obj_decoded_lenindef.pps())
6478 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6479 self.assertEqual(tail_lenindef, tail_junk)
6480 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6481 with self.assertRaises(DecodeError):
6482 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6483 with self.assertRaises(DecodeError):
6484 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6486 assert_exceeding_data(
6488 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6492 def test_bered(self):
6493 class SeqOf(self.base_klass):
6495 encoded = Boolean(False).encode()
6496 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6497 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6498 with self.assertRaises(DecodeError):
6499 SeqOf().decode(encoded)
6500 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6501 self.assertFalse(decoded.ber_encoded)
6502 self.assertFalse(decoded.lenindef)
6503 self.assertTrue(decoded.bered)
6504 decoded = copy(decoded)
6505 self.assertFalse(decoded.ber_encoded)
6506 self.assertFalse(decoded.lenindef)
6507 self.assertTrue(decoded.bered)
6509 class SeqOf(self.base_klass):
6510 schema = OctetString()
6511 encoded = OctetString(b"whatever").encode()
6513 tag_encode(form=TagFormConstructed, num=4) +
6515 OctetString(b"whatever").encode() +
6518 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6519 with self.assertRaises(DecodeError):
6520 SeqOf().decode(encoded)
6521 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6522 self.assertFalse(decoded.ber_encoded)
6523 self.assertFalse(decoded.lenindef)
6524 self.assertTrue(decoded.bered)
6525 decoded = copy(decoded)
6526 self.assertFalse(decoded.ber_encoded)
6527 self.assertFalse(decoded.lenindef)
6528 self.assertTrue(decoded.bered)
6531 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6532 class SeqOf(SequenceOf):
6536 def _test_symmetric_compare_objs(self, obj1, obj2):
6537 self.assertEqual(obj1, obj2)
6538 self.assertSequenceEqual(list(obj1), list(obj2))
6541 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6546 def _test_symmetric_compare_objs(self, obj1, obj2):
6547 self.assertSetEqual(
6548 set(int(v) for v in obj1),
6549 set(int(v) for v in obj2),
6552 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6553 @given(data_strategy())
6554 def test_sorted(self, d):
6555 values = [OctetString(v) for v in d.draw(lists(binary()))]
6558 schema = OctetString()
6560 seq_encoded = seq.encode()
6561 seq_decoded, _ = seq.decode(seq_encoded)
6562 self.assertSequenceEqual(
6563 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6564 b"".join(sorted([v.encode() for v in values])),
6567 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6568 @given(data_strategy())
6569 def test_unsorted(self, d):
6570 values = [OctetString(v).encode() for v in d.draw(sets(
6571 binary(min_size=1, max_size=5),
6575 values = d.draw(permutations(values))
6576 assume(values != sorted(values))
6577 encoded = b"".join(values)
6578 seq_encoded = b"".join((
6580 len_encode(len(encoded)),
6585 schema = OctetString()
6587 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6588 seq.decode(seq_encoded)
6590 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6591 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6592 self.assertTrue(seq_decoded.ber_encoded)
6593 self.assertTrue(seq_decoded.bered)
6594 seq_decoded = copy(seq_decoded)
6595 self.assertTrue(seq_decoded.ber_encoded)
6596 self.assertTrue(seq_decoded.bered)
6597 self.assertSequenceEqual(
6598 [obj.encode() for obj in seq_decoded],
6603 class TestGoMarshalVectors(TestCase):
6605 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6606 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6607 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6608 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6609 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6611 class Seq(Sequence):
6613 ("erste", Integer()),
6614 ("zweite", Integer(optional=True))
6617 seq["erste"] = Integer(64)
6618 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6619 seq["erste"] = Integer(0x123456)
6620 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6621 seq["erste"] = Integer(64)
6622 seq["zweite"] = Integer(65)
6623 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6625 class NestedSeq(Sequence):
6629 seq["erste"] = Integer(127)
6630 seq["zweite"] = None
6631 nested = NestedSeq()
6632 nested["nest"] = seq
6633 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6635 self.assertSequenceEqual(
6636 OctetString(b"\x01\x02\x03").encode(),
6637 hexdec("0403010203"),
6640 class Seq(Sequence):
6642 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6645 seq["erste"] = Integer(64)
6646 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6648 class Seq(Sequence):
6650 ("erste", Integer(expl=tag_ctxc(5))),
6653 seq["erste"] = Integer(64)
6654 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6656 class Seq(Sequence):
6659 impl=tag_encode(0, klass=TagClassContext),
6664 seq["erste"] = Null()
6665 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6667 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6669 self.assertSequenceEqual(
6670 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6671 hexdec("170d3730303130313030303030305a"),
6673 self.assertSequenceEqual(
6674 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6675 hexdec("170d3039313131353232353631365a"),
6677 self.assertSequenceEqual(
6678 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6679 hexdec("180f32313030303430353132303130315a"),
6682 class Seq(Sequence):
6684 ("erste", GeneralizedTime()),
6687 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6688 self.assertSequenceEqual(
6690 hexdec("3011180f32303039313131353232353631365a"),
6693 self.assertSequenceEqual(
6694 BitString((1, b"\x80")).encode(),
6697 self.assertSequenceEqual(
6698 BitString((12, b"\x81\xF0")).encode(),
6699 hexdec("03030481f0"),
6702 self.assertSequenceEqual(
6703 ObjectIdentifier("1.2.3.4").encode(),
6704 hexdec("06032a0304"),
6706 self.assertSequenceEqual(
6707 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6708 hexdec("06092a864888932d010105"),
6710 self.assertSequenceEqual(
6711 ObjectIdentifier("2.100.3").encode(),
6712 hexdec("0603813403"),
6715 self.assertSequenceEqual(
6716 PrintableString("test").encode(),
6717 hexdec("130474657374"),
6719 self.assertSequenceEqual(
6720 PrintableString("x" * 127).encode(),
6721 hexdec("137F" + "78" * 127),
6723 self.assertSequenceEqual(
6724 PrintableString("x" * 128).encode(),
6725 hexdec("138180" + "78" * 128),
6727 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6729 class Seq(Sequence):
6731 ("erste", IA5String()),
6734 seq["erste"] = IA5String("test")
6735 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6737 class Seq(Sequence):
6739 ("erste", PrintableString()),
6742 seq["erste"] = PrintableString("test")
6743 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6744 # Asterisk is actually not allowable
6745 PrintableString._allowable_chars |= set(b"*")
6746 seq["erste"] = PrintableString("test*")
6747 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6748 PrintableString._allowable_chars -= set(b"*")
6750 class Seq(Sequence):
6752 ("erste", Any(optional=True)),
6753 ("zweite", Integer()),
6756 seq["zweite"] = Integer(64)
6757 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6762 seq.append(Integer(10))
6763 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6765 class _SeqOf(SequenceOf):
6766 schema = PrintableString()
6768 class SeqOf(SequenceOf):
6771 _seqof.append(PrintableString("1"))
6773 seqof.append(_seqof)
6774 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6776 class Seq(Sequence):
6778 ("erste", Integer(default=1)),
6781 seq["erste"] = Integer(0)
6782 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6783 seq["erste"] = Integer(1)
6784 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6785 seq["erste"] = Integer(2)
6786 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6789 class TestPP(TestCase):
6790 @given(data_strategy())
6791 def test_oid_printing(self, d):
6793 str(ObjectIdentifier(k)): v * 2
6794 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6796 chosen = d.draw(sampled_from(sorted(oids)))
6797 chosen_id = oids[chosen]
6798 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6799 self.assertNotIn(chosen_id, pp_console_row(pp))
6802 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6806 class TestAutoAddSlots(TestCase):
6808 class Inher(Integer):
6811 with self.assertRaises(AttributeError):
6813 inher.unexistent = "whatever"
6816 class TestOIDDefines(TestCase):
6817 @given(data_strategy())
6818 def runTest(self, d):
6819 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6820 value_name_chosen = d.draw(sampled_from(value_names))
6822 ObjectIdentifier(oid)
6823 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6825 oid_chosen = d.draw(sampled_from(oids))
6826 values = d.draw(lists(
6828 min_size=len(value_names),
6829 max_size=len(value_names),
6831 for definable_class in (Any, OctetString, BitString):
6833 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6834 oid: Integer() for oid in oids[:-1]
6837 for i, value_name in enumerate(value_names):
6838 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
6840 class Seq(Sequence):
6843 for value_name, value in zip(value_names, values):
6844 seq[value_name] = definable_class(Integer(value).encode())
6845 seq["type"] = oid_chosen
6846 seq, _ = Seq().decode(seq.encode())
6847 for value_name in value_names:
6848 if value_name == value_name_chosen:
6850 self.assertIsNone(seq[value_name].defined)
6851 if value_name_chosen in oids[:-1]:
6852 self.assertIsNotNone(seq[value_name_chosen].defined)
6853 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6854 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6857 pprint(seq, big_blobs=True, with_decode_path=True)
6860 class TestDefinesByPath(TestCase):
6861 def test_generated(self):
6862 class Seq(Sequence):
6864 ("type", ObjectIdentifier()),
6865 ("value", OctetString(expl=tag_ctxc(123))),
6868 class SeqInner(Sequence):
6870 ("typeInner", ObjectIdentifier()),
6871 ("valueInner", Any()),
6874 class PairValue(SetOf):
6877 class Pair(Sequence):
6879 ("type", ObjectIdentifier()),
6880 ("value", PairValue()),
6883 class Pairs(SequenceOf):
6890 type_octet_stringed,
6892 ObjectIdentifier(oid)
6893 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6895 seq_integered = Seq()
6896 seq_integered["type"] = type_integered
6897 seq_integered["value"] = OctetString(Integer(123).encode())
6898 seq_integered_raw = seq_integered.encode()
6902 (type_octet_stringed, OctetString(b"whatever")),
6903 (type_integered, Integer(123)),
6904 (type_octet_stringed, OctetString(b"whenever")),
6905 (type_integered, Integer(234)),
6907 for t, v in pairs_input:
6910 ("value", PairValue((Any(v),))),
6912 seq_inner = SeqInner()
6913 seq_inner["typeInner"] = type_innered
6914 seq_inner["valueInner"] = Any(pairs)
6915 seq_sequenced = Seq()
6916 seq_sequenced["type"] = type_sequenced
6917 seq_sequenced["value"] = OctetString(seq_inner.encode())
6918 seq_sequenced_raw = seq_sequenced.encode()
6920 list(seq_sequenced.pps())
6921 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6923 defines_by_path = []
6924 ctx_copied = deepcopy(ctx_dummy)
6925 seq_integered, _ = Seq().decode(
6929 self.assertDictEqual(ctx_copied, ctx_dummy)
6930 self.assertIsNone(seq_integered["value"].defined)
6931 defines_by_path.append(
6932 (("type",), ((("value",), {
6933 type_integered: Integer(),
6934 type_sequenced: SeqInner(),
6937 ctx_copied["defines_by_path"] = defines_by_path
6938 seq_integered, _ = Seq().decode(
6942 del ctx_copied["defines_by_path"]
6943 self.assertDictEqual(ctx_copied, ctx_dummy)
6944 self.assertIsNotNone(seq_integered["value"].defined)
6945 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6946 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6947 self.assertTrue(seq_integered_raw[
6948 seq_integered["value"].defined[1].offset:
6949 ].startswith(Integer(123).encode()))
6951 list(seq_integered.pps())
6952 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6954 ctx_copied["defines_by_path"] = defines_by_path
6955 seq_sequenced, _ = Seq().decode(
6959 del ctx_copied["defines_by_path"]
6960 self.assertDictEqual(ctx_copied, ctx_dummy)
6961 self.assertIsNotNone(seq_sequenced["value"].defined)
6962 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6963 seq_inner = seq_sequenced["value"].defined[1]
6964 self.assertIsNone(seq_inner["valueInner"].defined)
6966 list(seq_sequenced.pps())
6967 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6969 defines_by_path.append((
6970 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
6971 ((("valueInner",), {type_innered: Pairs()}),),
6973 ctx_copied["defines_by_path"] = defines_by_path
6974 seq_sequenced, _ = Seq().decode(
6978 del ctx_copied["defines_by_path"]
6979 self.assertDictEqual(ctx_copied, ctx_dummy)
6980 self.assertIsNotNone(seq_sequenced["value"].defined)
6981 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
6982 seq_inner = seq_sequenced["value"].defined[1]
6983 self.assertIsNotNone(seq_inner["valueInner"].defined)
6984 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
6985 pairs = seq_inner["valueInner"].defined[1]
6987 self.assertIsNone(pair["value"][0].defined)
6989 list(seq_sequenced.pps())
6990 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6992 defines_by_path.append((
6995 DecodePathDefBy(type_sequenced),
6997 DecodePathDefBy(type_innered),
7002 type_integered: Integer(),
7003 type_octet_stringed: OctetString(),
7006 ctx_copied["defines_by_path"] = defines_by_path
7007 seq_sequenced, _ = Seq().decode(
7011 del ctx_copied["defines_by_path"]
7012 self.assertDictEqual(ctx_copied, ctx_dummy)
7013 self.assertIsNotNone(seq_sequenced["value"].defined)
7014 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7015 seq_inner = seq_sequenced["value"].defined[1]
7016 self.assertIsNotNone(seq_inner["valueInner"].defined)
7017 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7018 pairs_got = seq_inner["valueInner"].defined[1]
7019 for pair_input, pair_got in zip(pairs_input, pairs_got):
7020 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7021 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7023 list(seq_sequenced.pps())
7024 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7026 @given(oid_strategy(), integers())
7027 def test_simple(self, oid, tgt):
7028 class Inner(Sequence):
7030 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7031 ObjectIdentifier(oid): Integer(),
7035 class Outer(Sequence):
7038 ("tgt", OctetString()),
7042 inner["oid"] = ObjectIdentifier(oid)
7044 outer["inner"] = inner
7045 outer["tgt"] = OctetString(Integer(tgt).encode())
7046 decoded, _ = Outer().decode(outer.encode())
7047 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7049 def test_remaining_data(self):
7050 oid = ObjectIdentifier("1.2.3")
7051 class Seq(Sequence):
7053 ("oid", ObjectIdentifier(defines=((("tgt",), {
7056 ("tgt", OctetString()),
7061 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7063 with assertRaisesRegex(self, DecodeError, "remaining data"):
7064 Seq().decode(seq.encode())
7066 def test_remaining_data_seqof(self):
7067 oid = ObjectIdentifier("1.2.3")
7069 schema = OctetString()
7071 class Seq(Sequence):
7073 ("oid", ObjectIdentifier(defines=((("tgt",), {
7081 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7083 with assertRaisesRegex(self, DecodeError, "remaining data"):
7084 Seq().decode(seq.encode())
7087 class TestAbsDecodePath(TestCase):
7089 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7090 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7092 def test_concat(self, decode_path, rel_path):
7093 dp = abs_decode_path(decode_path, rel_path)
7094 self.assertSequenceEqual(dp, decode_path + rel_path)
7098 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7099 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7101 def test_abs(self, decode_path, rel_path):
7102 self.assertSequenceEqual(
7103 abs_decode_path(decode_path, ("/",) + rel_path),
7108 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7109 integers(min_value=1, max_value=3),
7110 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7112 def test_dots(self, decode_path, number_of_dots, rel_path):
7113 self.assertSequenceEqual(
7114 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7115 decode_path[:-number_of_dots] + rel_path,
7119 class TestStrictDefaultExistence(TestCase):
7120 @given(data_strategy())
7121 def runTest(self, d):
7122 count = d.draw(integers(min_value=1, max_value=10))
7123 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7125 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7126 for i in range(count)
7128 for klass in (Sequence, Set):
7132 for i in range(count):
7133 seq["int%d" % i] = Integer(123)
7135 chosen_choice = "int%d" % chosen
7136 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7137 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7139 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7140 self.assertTrue(decoded.ber_encoded)
7141 self.assertTrue(decoded.bered)
7142 decoded = copy(decoded)
7143 self.assertTrue(decoded.ber_encoded)
7144 self.assertTrue(decoded.bered)
7145 decoded, _ = seq.decode(raw, ctx={"bered": True})
7146 self.assertTrue(decoded.ber_encoded)
7147 self.assertTrue(decoded.bered)
7148 decoded = copy(decoded)
7149 self.assertTrue(decoded.ber_encoded)
7150 self.assertTrue(decoded.bered)
7153 class TestX690PrefixedType(TestCase):
7155 self.assertSequenceEqual(
7156 VisibleString("Jones").encode(),
7157 hexdec("1A054A6F6E6573"),
7159 self.assertSequenceEqual(
7162 impl=tag_encode(3, klass=TagClassApplication),
7164 hexdec("43054A6F6E6573"),
7166 self.assertSequenceEqual(
7170 impl=tag_encode(3, klass=TagClassApplication),
7174 hexdec("A20743054A6F6E6573"),
7176 self.assertSequenceEqual(
7180 impl=tag_encode(3, klass=TagClassApplication),
7182 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7184 hexdec("670743054A6F6E6573"),
7186 self.assertSequenceEqual(
7187 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7188 hexdec("82054A6F6E6573"),
7192 class TestExplOOB(TestCase):
7194 expl = tag_ctxc(123)
7195 raw = Integer(123).encode() + Integer(234).encode()
7196 raw = b"".join((expl, len_encode(len(raw)), raw))
7197 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7198 Integer(expl=expl).decode(raw)
7199 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7202 class TestPickleDifferentVersion(TestCase):
7204 pickled = pickle_dumps(Integer(123), pickle_proto)
7206 version_orig = pyderasn.__version__
7207 pyderasn.__version__ += "different"
7208 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7209 pickle_loads(pickled)
7210 pyderasn.__version__ = version_orig
7211 pickle_loads(pickled)