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 os import environ
24 from random import random
25 from string import ascii_letters
26 from string import digits
27 from string import printable
28 from string import whitespace
29 from time import mktime
31 from unittest import TestCase
33 from hypothesis import assume
34 from hypothesis import given
35 from hypothesis import settings
36 from hypothesis.strategies import binary
37 from hypothesis.strategies import booleans
38 from hypothesis.strategies import composite
39 from hypothesis.strategies import data as data_strategy
40 from hypothesis.strategies import datetimes
41 from hypothesis.strategies import dictionaries
42 from hypothesis.strategies import integers
43 from hypothesis.strategies import just
44 from hypothesis.strategies import lists
45 from hypothesis.strategies import none
46 from hypothesis.strategies import one_of
47 from hypothesis.strategies import permutations
48 from hypothesis.strategies import sampled_from
49 from hypothesis.strategies import sets
50 from hypothesis.strategies import text
51 from hypothesis.strategies import tuples
52 from six import assertRaisesRegex
53 from six import binary_type
54 from six import byte2int
55 from six import indexbytes
56 from six import int2byte
57 from six import iterbytes
59 from six import text_type
60 from six import unichr as six_unichr
61 from six.moves.cPickle import dumps as pickle_dumps
62 from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto
63 from six.moves.cPickle import loads as pickle_loads
65 from pyderasn import _pp
66 from pyderasn import abs_decode_path
67 from pyderasn import Any
68 from pyderasn import BitString
69 from pyderasn import BMPString
70 from pyderasn import Boolean
71 from pyderasn import BoundsError
72 from pyderasn import Choice
73 from pyderasn import DecodeError
74 from pyderasn import DecodePathDefBy
75 from pyderasn import Enumerated
76 from pyderasn import EOC
77 from pyderasn import EOC_LEN
78 from pyderasn import ExceedingData
79 from pyderasn import GeneralizedTime
80 from pyderasn import GeneralString
81 from pyderasn import GraphicString
82 from pyderasn import hexdec
83 from pyderasn import hexenc
84 from pyderasn import IA5String
85 from pyderasn import Integer
86 from pyderasn import InvalidLength
87 from pyderasn import InvalidOID
88 from pyderasn import InvalidValueType
89 from pyderasn import len_decode
90 from pyderasn import len_encode
91 from pyderasn import LEN_YYMMDDHHMMSSZ
92 from pyderasn import LEN_YYYYMMDDHHMMSSDMZ
93 from pyderasn import LEN_YYYYMMDDHHMMSSZ
94 from pyderasn import LENINDEF
95 from pyderasn import LenIndefForm
96 from pyderasn import NotEnoughData
97 from pyderasn import Null
98 from pyderasn import NumericString
99 from pyderasn import ObjectIdentifier
100 from pyderasn import ObjNotReady
101 from pyderasn import ObjUnknown
102 from pyderasn import OctetString
103 from pyderasn import pp_console_row
104 from pyderasn import pprint
105 from pyderasn import PrintableString
106 from pyderasn import Sequence
107 from pyderasn import SequenceOf
108 from pyderasn import Set
109 from pyderasn import SetOf
110 from pyderasn import tag_ctxc
111 from pyderasn import tag_ctxp
112 from pyderasn import tag_decode
113 from pyderasn import tag_encode
114 from pyderasn import tag_strip
115 from pyderasn import TagClassApplication
116 from pyderasn import TagClassContext
117 from pyderasn import TagClassPrivate
118 from pyderasn import TagClassUniversal
119 from pyderasn import TagFormConstructed
120 from pyderasn import TagFormPrimitive
121 from pyderasn import TagMismatch
122 from pyderasn import TeletexString
123 from pyderasn import UniversalString
124 from pyderasn import UTCTime
125 from pyderasn import UTF8String
126 from pyderasn import VideotexString
127 from pyderasn import VisibleString
130 max_examples = environ.get("MAX_EXAMPLES")
131 settings.register_profile("local", settings(
133 **({"max_examples": int(max_examples)} if max_examples else {})
135 settings.load_profile("local")
136 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
138 tag_classes = sampled_from((
144 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
145 decode_path_strat = lists(integers(), max_size=3).map(
146 lambda decode_path: tuple(str(dp) for dp in decode_path)
148 ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
151 lambda obj: pickle_loads(pickle_dumps(obj, pickle_proto)),
153 self_module = import_module(__name__)
156 def register_class(klass):
157 klassname = klass.__name__ + str(time()).replace(".", "")
158 klass.__name__ = klassname
159 klass.__qualname__ = klassname
160 setattr(self_module, klassname, klass)
163 def assert_exceeding_data(self, call, junk):
166 with assertRaisesRegex(self, ExceedingData, "%d trailing bytes" % len(junk)) as err:
171 class TestHex(TestCase):
173 def test_symmetric(self, data):
174 self.assertEqual(hexdec(hexenc(data)), data)
177 class TestTagCoder(TestCase):
178 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
182 integers(min_value=0, max_value=30),
185 def test_short(self, klass, form, num, junk):
186 raw = tag_encode(klass=klass, form=form, num=num)
187 self.assertEqual(tag_decode(raw), (klass, form, num))
188 self.assertEqual(len(raw), 1)
190 byte2int(tag_encode(klass=klass, form=form, num=0)),
191 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
193 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
194 self.assertSequenceEqual(stripped.tobytes(), raw)
195 self.assertEqual(tlen, len(raw))
196 self.assertSequenceEqual(tail, junk)
198 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
202 integers(min_value=31),
205 def test_long(self, klass, form, num, junk):
206 raw = tag_encode(klass=klass, form=form, num=num)
207 self.assertEqual(tag_decode(raw), (klass, form, num))
208 self.assertGreater(len(raw), 1)
210 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
213 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
214 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
215 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
216 self.assertSequenceEqual(stripped.tobytes(), raw)
217 self.assertEqual(tlen, len(raw))
218 self.assertSequenceEqual(tail, junk)
220 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
221 @given(integers(min_value=31))
222 def test_unfinished_tag(self, num):
223 raw = bytearray(tag_encode(num=num))
224 for i in range(1, len(raw)):
226 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
227 tag_strip(bytes(raw))
229 def test_go_vectors_valid(self):
230 for data, (eklass, etag, elen, eform) in (
231 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
232 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
233 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
234 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
235 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
236 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
237 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
238 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
239 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
240 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
242 tag, _, len_encoded = tag_strip(memoryview(data))
243 klass, form, num = tag_decode(tag)
244 _len, _, tail = len_decode(len_encoded)
245 self.assertSequenceEqual(tail, b"")
246 self.assertEqual(klass, eklass)
247 self.assertEqual(num, etag)
248 self.assertEqual(_len, elen)
249 self.assertEqual(form, eform)
251 def test_go_vectors_invalid(self):
259 with self.assertRaises(DecodeError):
260 _, _, len_encoded = tag_strip(memoryview(data))
261 len_decode(len_encoded)
264 integers(min_value=0, max_value=127),
265 integers(min_value=0, max_value=2),
267 def test_long_instead_of_short(self, l, dummy_num):
268 octets = (b"\x00" * dummy_num) + int2byte(l)
269 octets = int2byte((dummy_num + 1) | 0x80) + octets
270 with self.assertRaises(DecodeError):
274 class TestLenCoder(TestCase):
275 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
277 integers(min_value=0, max_value=127),
280 def test_short(self, l, junk):
281 raw = len_encode(l) + junk
282 decoded, llen, tail = len_decode(memoryview(raw))
283 self.assertEqual(decoded, l)
284 self.assertEqual(llen, 1)
285 self.assertEqual(len(raw), 1 + len(junk))
286 self.assertEqual(tail.tobytes(), junk)
288 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
290 integers(min_value=128),
293 def test_long(self, l, junk):
294 raw = len_encode(l) + junk
295 decoded, llen, tail = len_decode(memoryview(raw))
296 self.assertEqual(decoded, l)
297 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
298 self.assertEqual(llen, len(raw) - len(junk))
299 self.assertNotEqual(indexbytes(raw, 1), 0)
300 self.assertSequenceEqual(tail.tobytes(), junk)
302 def test_empty(self):
303 with self.assertRaises(NotEnoughData):
306 @given(integers(min_value=128))
307 def test_stripped(self, _len):
308 with self.assertRaises(NotEnoughData):
309 len_decode(len_encode(_len)[:-1])
312 text_printable = text(alphabet=printable, min_size=1)
316 def text_letters(draw):
317 result = draw(text(alphabet=ascii_letters, min_size=1))
319 result = result.encode("ascii")
323 class CommonMixin(object):
324 def test_tag_default(self):
325 obj = self.base_klass()
326 self.assertEqual(obj.tag, obj.tag_default)
328 def test_simultaneous_impl_expl(self):
329 with self.assertRaises(ValueError):
330 self.base_klass(impl=b"whatever", expl=b"whenever")
332 @given(binary(min_size=1), integers(), integers(), integers())
333 def test_decoded(self, impl, offset, llen, vlen):
334 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
335 self.assertEqual(obj.offset, offset)
336 self.assertEqual(obj.llen, llen)
337 self.assertEqual(obj.vlen, vlen)
338 self.assertEqual(obj.tlen, len(impl))
339 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
341 @given(binary(min_size=1))
342 def test_impl_inherited(self, impl_tag):
343 class Inherited(self.base_klass):
346 self.assertSequenceEqual(obj.impl, impl_tag)
347 self.assertFalse(obj.expled)
349 tag_class, _, tag_num = tag_decode(impl_tag)
350 self.assertEqual(obj.tag_order, (tag_class, tag_num))
352 @given(binary(min_size=1))
353 def test_expl_inherited(self, expl_tag):
354 class Inherited(self.base_klass):
357 self.assertSequenceEqual(obj.expl, expl_tag)
358 self.assertTrue(obj.expled)
360 tag_class, _, tag_num = tag_decode(expl_tag)
361 self.assertEqual(obj.tag_order, (tag_class, tag_num))
363 def assert_copied_basic_fields(self, obj, obj_copied):
364 self.assertEqual(obj, obj_copied)
365 self.assertSequenceEqual(obj.tag, obj_copied.tag)
366 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
367 self.assertEqual(obj.default, obj_copied.default)
368 self.assertEqual(obj.optional, obj_copied.optional)
369 self.assertEqual(obj.offset, obj_copied.offset)
370 self.assertEqual(obj.llen, obj_copied.llen)
371 self.assertEqual(obj.vlen, obj_copied.vlen)
373 self.assertEqual(obj.tag_order, obj_copied.tag_order)
377 def boolean_values_strategy(draw, do_expl=False):
378 value = draw(one_of(none(), booleans()))
382 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
384 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
385 default = draw(one_of(none(), booleans()))
386 optional = draw(one_of(none(), booleans()))
388 draw(integers(min_value=0)),
389 draw(integers(min_value=0)),
390 draw(integers(min_value=0)),
392 return (value, impl, expl, default, optional, _decoded)
395 class BooleanInherited(Boolean):
399 class TestBoolean(CommonMixin, TestCase):
402 def test_invalid_value_type(self):
403 with self.assertRaises(InvalidValueType) as err:
408 def test_optional(self, optional):
409 obj = Boolean(default=Boolean(False), optional=optional)
410 self.assertTrue(obj.optional)
413 def test_ready(self, value):
415 self.assertFalse(obj.ready)
418 pprint(obj, big_blobs=True, with_decode_path=True)
419 with self.assertRaises(ObjNotReady) as err:
423 self.assertTrue(obj.ready)
426 pprint(obj, big_blobs=True, with_decode_path=True)
428 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
429 def test_comparison(self, value1, value2, tag1, tag2):
430 for klass in (Boolean, BooleanInherited):
433 self.assertEqual(obj1 == obj2, value1 == value2)
434 self.assertEqual(obj1 != obj2, value1 != value2)
435 self.assertEqual(obj1 == bool(obj2), value1 == value2)
436 obj1 = klass(value1, impl=tag1)
437 obj2 = klass(value1, impl=tag2)
438 self.assertEqual(obj1 == obj2, tag1 == tag2)
439 self.assertEqual(obj1 != obj2, tag1 != tag2)
441 @given(data_strategy())
442 def test_call(self, d):
443 for klass in (Boolean, BooleanInherited):
451 ) = d.draw(boolean_values_strategy())
457 optional_initial or False,
467 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
468 obj = obj_initial(value, impl, expl, default, optional)
470 value_expected = default if value is None else value
472 default_initial if value_expected is None
475 self.assertEqual(obj, value_expected)
476 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
477 self.assertEqual(obj.expl_tag, expl or expl_initial)
480 default_initial if default is None else default,
482 if obj.default is None:
483 optional = optional_initial if optional is None else optional
484 optional = False if optional is None else optional
487 self.assertEqual(obj.optional, optional)
489 @given(boolean_values_strategy())
490 def test_copy(self, values):
491 for klass in (Boolean, BooleanInherited):
493 for copy_func in copy_funcs:
494 obj_copied = copy_func(obj)
495 self.assert_copied_basic_fields(obj, obj_copied)
499 integers(min_value=1).map(tag_encode),
501 def test_stripped(self, value, tag_impl):
502 obj = Boolean(value, impl=tag_impl)
503 with self.assertRaises(NotEnoughData):
504 obj.decode(obj.encode()[:-1])
508 integers(min_value=1).map(tag_ctxc),
510 def test_stripped_expl(self, value, tag_expl):
511 obj = Boolean(value, expl=tag_expl)
512 with self.assertRaises(NotEnoughData):
513 obj.decode(obj.encode()[:-1])
516 integers(min_value=31),
517 integers(min_value=0),
520 def test_bad_tag(self, tag, offset, decode_path):
521 with self.assertRaises(DecodeError) as err:
523 tag_encode(tag)[:-1],
525 decode_path=decode_path,
528 self.assertEqual(err.exception.offset, offset)
529 self.assertEqual(err.exception.decode_path, decode_path)
532 integers(min_value=31),
533 integers(min_value=0),
536 def test_bad_expl_tag(self, tag, offset, decode_path):
537 with self.assertRaises(DecodeError) as err:
538 Boolean(expl=Boolean.tag_default).decode(
539 tag_encode(tag)[:-1],
541 decode_path=decode_path,
544 self.assertEqual(err.exception.offset, offset)
545 self.assertEqual(err.exception.decode_path, decode_path)
548 integers(min_value=128),
549 integers(min_value=0),
552 def test_bad_len(self, l, offset, decode_path):
553 with self.assertRaises(DecodeError) as err:
555 Boolean.tag_default + len_encode(l)[:-1],
557 decode_path=decode_path,
560 self.assertEqual(err.exception.offset, offset)
561 self.assertEqual(err.exception.decode_path, decode_path)
564 integers(min_value=128),
565 integers(min_value=0),
568 def test_bad_expl_len(self, l, offset, decode_path):
569 with self.assertRaises(DecodeError) as err:
570 Boolean(expl=Boolean.tag_default).decode(
571 Boolean.tag_default + len_encode(l)[:-1],
573 decode_path=decode_path,
576 self.assertEqual(err.exception.offset, offset)
577 self.assertEqual(err.exception.decode_path, decode_path)
579 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
581 boolean_values_strategy(),
583 integers(min_value=1).map(tag_ctxc),
584 integers(min_value=0),
587 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
588 for klass in (Boolean, BooleanInherited):
589 _, _, _, default, optional, _decoded = values
598 pprint(obj, big_blobs=True, with_decode_path=True)
599 self.assertFalse(obj.expled)
600 obj_encoded = obj.encode()
601 obj_expled = obj(value, expl=tag_expl)
602 self.assertTrue(obj_expled.expled)
604 list(obj_expled.pps())
605 pprint(obj_expled, big_blobs=True, with_decode_path=True)
606 obj_expled_hex_encoded = obj_expled.hexencode()
607 ctx_copied = deepcopy(ctx_dummy)
608 obj_decoded, tail = obj_expled.hexdecode(
609 obj_expled_hex_encoded + hexenc(tail_junk),
613 self.assertDictEqual(ctx_copied, ctx_dummy)
615 list(obj_decoded.pps())
616 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
617 self.assertEqual(tail, tail_junk)
618 self.assertEqual(obj_decoded, obj_expled)
619 self.assertNotEqual(obj_decoded, obj)
620 self.assertEqual(bool(obj_decoded), bool(obj_expled))
621 self.assertEqual(bool(obj_decoded), bool(obj))
622 self.assertSequenceEqual(obj_decoded.hexencode(), obj_expled_hex_encoded)
623 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
624 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
626 obj_decoded.expl_llen,
627 len(len_encode(len(obj_encoded))),
629 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
630 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
633 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
635 self.assertEqual(obj_decoded.expl_offset, offset)
636 assert_exceeding_data(
638 lambda: obj_expled.hexdecod(obj_expled_hex_encoded + hexenc(tail_junk)),
642 @given(integers(min_value=2))
643 def test_invalid_len(self, l):
644 with self.assertRaises(InvalidLength):
645 Boolean().decode(b"".join((
651 @given(integers(min_value=0 + 1, max_value=255 - 1))
652 def test_ber_value(self, value):
653 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
654 Boolean().decode(b"".join((
659 obj, _ = Boolean().decode(
667 self.assertTrue(bool(obj))
668 self.assertTrue(obj.ber_encoded)
669 self.assertFalse(obj.lenindef)
670 self.assertTrue(obj.bered)
672 self.assertTrue(obj.ber_encoded)
673 self.assertFalse(obj.lenindef)
674 self.assertTrue(obj.bered)
677 integers(min_value=1).map(tag_ctxc),
678 binary().filter(lambda x: not x.startswith(EOC)),
680 def test_ber_expl_no_eoc(self, expl, junk):
681 encoded = expl + LENINDEF + Boolean(False).encode()
682 with self.assertRaises(LenIndefForm):
683 Boolean(expl=expl).decode(encoded + junk)
684 with assertRaisesRegex(self, DecodeError, "no EOC"):
685 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
686 obj, tail = Boolean(expl=expl).decode(
687 encoded + EOC + junk,
690 self.assertTrue(obj.expl_lenindef)
691 self.assertFalse(obj.lenindef)
692 self.assertFalse(obj.ber_encoded)
693 self.assertTrue(obj.bered)
695 self.assertTrue(obj.expl_lenindef)
696 self.assertFalse(obj.lenindef)
697 self.assertFalse(obj.ber_encoded)
698 self.assertTrue(obj.bered)
699 self.assertSequenceEqual(tail, junk)
702 pprint(obj, big_blobs=True, with_decode_path=True)
705 integers(min_value=1).map(tag_ctxc),
712 def test_ber_expl(self, expl, values):
718 Boolean(value).encode() +
721 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
723 class SeqOf(SequenceOf):
724 schema = Boolean(expl=expl)
725 with self.assertRaises(LenIndefForm):
726 SeqOf().decode(encoded)
727 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
728 self.assertSequenceEqual(tail, b"")
729 self.assertSequenceEqual([bool(v) for v in seqof], values)
745 len(expl) + 1 + 3 + EOC_LEN,
756 pprint(seqof, big_blobs=True, with_decode_path=True)
760 def integer_values_strategy(draw, do_expl=False):
761 bound_min, value, default, bound_max = sorted(draw(sets(
770 _specs = draw(sets(text_letters()))
773 min_size=len(_specs),
774 max_size=len(_specs),
776 _specs = list(zip(_specs, values))
779 bounds = (bound_min, bound_max)
783 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
785 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
788 optional = draw(one_of(none(), booleans()))
790 draw(integers(min_value=0)),
791 draw(integers(min_value=0)),
792 draw(integers(min_value=0)),
794 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
797 class IntegerInherited(Integer):
801 class TestInteger(CommonMixin, TestCase):
804 def test_invalid_value_type(self):
805 with self.assertRaises(InvalidValueType) as err:
809 @given(sets(text_letters(), min_size=2))
810 def test_unknown_name(self, names_input):
811 missing = names_input.pop()
814 schema = [(n, 123) for n in names_input]
815 with self.assertRaises(ObjUnknown) as err:
819 @given(sets(text_letters(), min_size=2))
820 def test_known_name(self, names_input):
822 schema = [(n, 123) for n in names_input]
823 Int(names_input.pop())
826 def test_optional(self, optional):
827 obj = Integer(default=Integer(0), optional=optional)
828 self.assertTrue(obj.optional)
831 def test_ready(self, value):
833 self.assertFalse(obj.ready)
836 pprint(obj, big_blobs=True, with_decode_path=True)
837 with self.assertRaises(ObjNotReady) as err:
841 self.assertTrue(obj.ready)
844 pprint(obj, big_blobs=True, with_decode_path=True)
847 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
848 def test_comparison(self, value1, value2, tag1, tag2):
849 for klass in (Integer, IntegerInherited):
852 self.assertEqual(obj1 == obj2, value1 == value2)
853 self.assertEqual(obj1 != obj2, value1 != value2)
854 self.assertEqual(obj1 == int(obj2), value1 == value2)
855 obj1 = klass(value1, impl=tag1)
856 obj2 = klass(value1, impl=tag2)
857 self.assertEqual(obj1 == obj2, tag1 == tag2)
858 self.assertEqual(obj1 != obj2, tag1 != tag2)
860 @given(lists(integers()))
861 def test_sorted_works(self, values):
862 self.assertSequenceEqual(
863 [int(v) for v in sorted(Integer(v) for v in values)],
867 @given(data_strategy())
868 def test_named(self, d):
869 names_input = list(d.draw(sets(text_letters(), min_size=1)))
870 values_input = list(d.draw(sets(
872 min_size=len(names_input),
873 max_size=len(names_input),
875 chosen_name = d.draw(sampled_from(names_input))
876 names_input = dict(zip(names_input, values_input))
880 _int = Int(chosen_name)
881 self.assertEqual(_int.named, chosen_name)
882 self.assertEqual(int(_int), names_input[chosen_name])
884 @given(integers(), integers(min_value=0), integers(min_value=0))
885 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
886 value = bound_min + value_delta
887 bound_max = value + bound_delta
888 Integer(value=value, bounds=(bound_min, bound_max))
890 @given(sets(integers(), min_size=3, max_size=3))
891 def test_bounds_unsatisfied(self, values):
892 values = sorted(values)
893 with self.assertRaises(BoundsError) as err:
894 Integer(value=values[0], bounds=(values[1], values[2]))
896 with assertRaisesRegex(self, DecodeError, "bounds") as err:
897 Integer(bounds=(values[1], values[2])).decode(
898 Integer(values[0]).encode()
901 with self.assertRaises(BoundsError) as err:
902 Integer(value=values[2], bounds=(values[0], values[1]))
904 with assertRaisesRegex(self, DecodeError, "bounds") as err:
905 Integer(bounds=(values[0], values[1])).decode(
906 Integer(values[2]).encode()
910 @given(data_strategy())
911 def test_call(self, d):
912 for klass in (Integer, IntegerInherited):
922 ) = d.draw(integer_values_strategy())
929 optional_initial or False,
942 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
943 if (default is None) and (obj_initial.default is not None):
947 (value is not None) and
948 (bounds_initial is not None) and
949 not (bounds_initial[0] <= value <= bounds_initial[1])
954 (default is not None) and
955 (bounds_initial is not None) and
956 not (bounds_initial[0] <= default <= bounds_initial[1])
959 obj = obj_initial(value, bounds, impl, expl, default, optional)
961 value_expected = default if value is None else value
963 default_initial if value_expected is None
966 self.assertEqual(obj, value_expected)
967 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
968 self.assertEqual(obj.expl_tag, expl or expl_initial)
971 default_initial if default is None else default,
973 if obj.default is None:
974 optional = optional_initial if optional is None else optional
975 optional = False if optional is None else optional
978 self.assertEqual(obj.optional, optional)
980 (obj._bound_min, obj._bound_max),
981 bounds or bounds_initial or (float("-inf"), float("+inf")),
985 {} if _specs_initial is None else dict(_specs_initial),
988 @given(integer_values_strategy())
989 def test_copy(self, values):
990 for klass in (Integer, IntegerInherited):
992 for copy_func in copy_funcs:
993 obj_copied = copy_func(obj)
994 self.assert_copied_basic_fields(obj, obj_copied)
995 self.assertEqual(obj.specs, obj_copied.specs)
996 self.assertEqual(obj._bound_min, obj_copied._bound_min)
997 self.assertEqual(obj._bound_max, obj_copied._bound_max)
998 self.assertEqual(obj._value, obj_copied._value)
1002 integers(min_value=1).map(tag_encode),
1004 def test_stripped(self, value, tag_impl):
1005 obj = Integer(value, impl=tag_impl)
1006 with self.assertRaises(NotEnoughData):
1007 obj.decode(obj.encode()[:-1])
1011 integers(min_value=1).map(tag_ctxc),
1013 def test_stripped_expl(self, value, tag_expl):
1014 obj = Integer(value, expl=tag_expl)
1015 with self.assertRaises(NotEnoughData):
1016 obj.decode(obj.encode()[:-1])
1018 def test_zero_len(self):
1019 with self.assertRaises(NotEnoughData):
1020 Integer().decode(b"".join((
1021 Integer.tag_default,
1026 integers(min_value=31),
1027 integers(min_value=0),
1030 def test_bad_tag(self, tag, offset, decode_path):
1031 with self.assertRaises(DecodeError) as err:
1033 tag_encode(tag)[:-1],
1035 decode_path=decode_path,
1038 self.assertEqual(err.exception.offset, offset)
1039 self.assertEqual(err.exception.decode_path, decode_path)
1042 integers(min_value=128),
1043 integers(min_value=0),
1046 def test_bad_len(self, l, offset, decode_path):
1047 with self.assertRaises(DecodeError) as err:
1049 Integer.tag_default + len_encode(l)[:-1],
1051 decode_path=decode_path,
1054 self.assertEqual(err.exception.offset, offset)
1055 self.assertEqual(err.exception.decode_path, decode_path)
1058 sets(integers(), min_size=2, max_size=2),
1059 integers(min_value=0),
1062 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1063 value, bound_min = list(sorted(ints))
1066 bounds = (bound_min, bound_min)
1067 with self.assertRaises(DecodeError) as err:
1069 Integer(value).encode(),
1071 decode_path=decode_path,
1074 self.assertEqual(err.exception.offset, offset)
1075 self.assertEqual(err.exception.decode_path, decode_path)
1077 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1079 integer_values_strategy(),
1081 integers(min_value=1).map(tag_ctxc),
1082 integers(min_value=0),
1085 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1086 for klass in (Integer, IntegerInherited):
1087 _, _, _, _, default, optional, _, _decoded = values
1096 pprint(obj, big_blobs=True, with_decode_path=True)
1097 self.assertFalse(obj.expled)
1098 obj_encoded = obj.encode()
1099 obj_expled = obj(value, expl=tag_expl)
1100 self.assertTrue(obj_expled.expled)
1102 list(obj_expled.pps())
1103 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1104 obj_expled_encoded = obj_expled.encode()
1105 ctx_copied = deepcopy(ctx_dummy)
1106 obj_decoded, tail = obj_expled.decode(
1107 obj_expled_encoded + tail_junk,
1111 self.assertDictEqual(ctx_copied, ctx_dummy)
1113 list(obj_decoded.pps())
1114 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1115 self.assertEqual(tail, tail_junk)
1116 self.assertEqual(obj_decoded, obj_expled)
1117 self.assertNotEqual(obj_decoded, obj)
1118 self.assertEqual(int(obj_decoded), int(obj_expled))
1119 self.assertEqual(int(obj_decoded), int(obj))
1120 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1121 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1122 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1124 obj_decoded.expl_llen,
1125 len(len_encode(len(obj_encoded))),
1127 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1128 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1131 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1133 self.assertEqual(obj_decoded.expl_offset, offset)
1134 assert_exceeding_data(
1136 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1140 def test_go_vectors_valid(self):
1141 for data, expect in ((
1145 (b"\xff\x7f", -129),
1149 (b"\xff\x00", -256),
1153 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1154 (b"\x80\x00\x00\x00", -2147483648),
1157 Integer().decode(b"".join((
1158 Integer.tag_default,
1159 len_encode(len(data)),
1165 def test_go_vectors_invalid(self):
1170 with self.assertRaises(DecodeError):
1171 Integer().decode(b"".join((
1172 Integer.tag_default,
1173 len_encode(len(data)),
1179 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1182 if draw(booleans()):
1183 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1185 integers(min_value=0, max_value=255),
1186 min_size=len(schema),
1187 max_size=len(schema),
1189 schema = list(zip(schema, bits))
1191 def _value(value_required):
1192 if not value_required and draw(booleans()):
1194 generation_choice = 0
1196 generation_choice = draw(sampled_from((1, 2, 3)))
1197 if generation_choice == 1 or draw(booleans()):
1198 return "'%s'B" % "".join(draw(lists(
1199 sampled_from(("0", "1")),
1200 max_size=len(schema),
1202 if generation_choice == 2 or draw(booleans()):
1203 return draw(binary(max_size=len(schema) // 8))
1204 if generation_choice == 3 or draw(booleans()):
1205 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1207 value = _value(value_required)
1208 default = _value(value_required=False)
1212 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1214 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1215 optional = draw(one_of(none(), booleans()))
1217 draw(integers(min_value=0)),
1218 draw(integers(min_value=0)),
1219 draw(integers(min_value=0)),
1221 return (schema, value, impl, expl, default, optional, _decoded)
1224 class BitStringInherited(BitString):
1228 class TestBitString(CommonMixin, TestCase):
1229 base_klass = BitString
1231 @given(lists(booleans()))
1232 def test_b_encoding(self, bits):
1233 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1234 self.assertEqual(obj.bit_len, len(bits))
1235 self.assertSequenceEqual(list(obj), bits)
1236 for i, bit in enumerate(bits):
1237 self.assertEqual(obj[i], bit)
1239 @given(lists(booleans()))
1240 def test_out_of_bounds_bits(self, bits):
1241 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1242 for i in range(len(bits), len(bits) * 2):
1243 self.assertFalse(obj[i])
1245 def test_bad_b_encoding(self):
1246 with self.assertRaises(ValueError):
1247 BitString("'010120101'B")
1250 integers(min_value=1, max_value=255),
1251 integers(min_value=1, max_value=255),
1253 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1254 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1255 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1256 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1258 class BS(BitString):
1259 schema = (("whatever", 0),)
1260 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1261 self.assertEqual(obj.bit_len, leading_zeros + 1)
1262 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1264 def test_zero_len(self):
1265 with self.assertRaises(NotEnoughData):
1266 BitString().decode(b"".join((
1267 BitString.tag_default,
1271 def test_invalid_value_type(self):
1272 with self.assertRaises(InvalidValueType) as err:
1275 with self.assertRaises(InvalidValueType) as err:
1279 def test_obj_unknown(self):
1280 with self.assertRaises(ObjUnknown) as err:
1281 BitString(b"whatever")["whenever"]
1284 def test_get_invalid_type(self):
1285 with self.assertRaises(InvalidValueType) as err:
1286 BitString(b"whatever")[(1, 2, 3)]
1289 @given(data_strategy())
1290 def test_unknown_name(self, d):
1291 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1292 missing = _schema.pop()
1294 class BS(BitString):
1295 schema = [(n, i) for i, n in enumerate(_schema)]
1296 with self.assertRaises(ObjUnknown) as err:
1301 def test_optional(self, optional):
1302 obj = BitString(default=BitString(b""), optional=optional)
1303 self.assertTrue(obj.optional)
1306 def test_ready(self, value):
1308 self.assertFalse(obj.ready)
1311 pprint(obj, big_blobs=True, with_decode_path=True)
1312 with self.assertRaises(ObjNotReady) as err:
1315 obj = BitString(value)
1316 self.assertTrue(obj.ready)
1319 pprint(obj, big_blobs=True, with_decode_path=True)
1322 tuples(integers(min_value=0), binary()),
1323 tuples(integers(min_value=0), binary()),
1327 def test_comparison(self, value1, value2, tag1, tag2):
1328 for klass in (BitString, BitStringInherited):
1329 obj1 = klass(value1)
1330 obj2 = klass(value2)
1331 self.assertEqual(obj1 == obj2, value1 == value2)
1332 self.assertEqual(obj1 != obj2, value1 != value2)
1333 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1334 obj1 = klass(value1, impl=tag1)
1335 obj2 = klass(value1, impl=tag2)
1336 self.assertEqual(obj1 == obj2, tag1 == tag2)
1337 self.assertEqual(obj1 != obj2, tag1 != tag2)
1339 @given(data_strategy())
1340 def test_call(self, d):
1341 for klass in (BitString, BitStringInherited):
1350 ) = d.draw(bit_string_values_strategy())
1353 schema = schema_initial
1355 value=value_initial,
1358 default=default_initial,
1359 optional=optional_initial or False,
1360 _decoded=_decoded_initial,
1370 ) = d.draw(bit_string_values_strategy(
1371 schema=schema_initial,
1372 do_expl=impl_initial is None,
1381 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1382 self.assertEqual(obj.expl_tag, expl or expl_initial)
1383 if obj.default is None:
1384 optional = optional_initial if optional is None else optional
1385 optional = False if optional is None else optional
1388 self.assertEqual(obj.optional, optional)
1389 self.assertEqual(obj.specs, obj_initial.specs)
1391 @given(bit_string_values_strategy())
1392 def test_copy(self, values):
1393 for klass in (BitString, BitStringInherited):
1394 _schema, value, impl, expl, default, optional, _decoded = values
1404 optional=optional or False,
1407 for copy_func in copy_funcs:
1408 obj_copied = copy_func(obj)
1409 self.assert_copied_basic_fields(obj, obj_copied)
1410 self.assertEqual(obj.specs, obj_copied.specs)
1411 self.assertEqual(obj._value, obj_copied._value)
1415 integers(min_value=1).map(tag_encode),
1417 def test_stripped(self, value, tag_impl):
1418 obj = BitString(value, impl=tag_impl)
1419 with self.assertRaises(NotEnoughData):
1420 obj.decode(obj.encode()[:-1])
1424 integers(min_value=1).map(tag_ctxc),
1426 def test_stripped_expl(self, value, tag_expl):
1427 obj = BitString(value, expl=tag_expl)
1428 with self.assertRaises(NotEnoughData):
1429 obj.decode(obj.encode()[:-1])
1432 integers(min_value=31),
1433 integers(min_value=0),
1436 def test_bad_tag(self, tag, offset, decode_path):
1437 with self.assertRaises(DecodeError) as err:
1439 tag_encode(tag)[:-1],
1441 decode_path=decode_path,
1444 self.assertEqual(err.exception.offset, offset)
1445 self.assertEqual(err.exception.decode_path, decode_path)
1448 integers(min_value=128),
1449 integers(min_value=0),
1452 def test_bad_len(self, l, offset, decode_path):
1453 with self.assertRaises(DecodeError) as err:
1455 BitString.tag_default + len_encode(l)[:-1],
1457 decode_path=decode_path,
1460 self.assertEqual(err.exception.offset, offset)
1461 self.assertEqual(err.exception.decode_path, decode_path)
1463 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1464 @given(data_strategy())
1465 def test_symmetric(self, d):
1474 ) = d.draw(bit_string_values_strategy(value_required=True))
1475 tail_junk = d.draw(binary(max_size=5))
1476 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1477 offset = d.draw(integers(min_value=0))
1478 for klass in (BitString, BitStringInherited):
1489 pprint(obj, big_blobs=True, with_decode_path=True)
1490 self.assertFalse(obj.expled)
1491 obj_encoded = obj.encode()
1492 obj_expled = obj(value, expl=tag_expl)
1493 self.assertTrue(obj_expled.expled)
1495 list(obj_expled.pps())
1496 pprint(obj_expled, big_blobs=True, with_decode_path=True)
1497 obj_expled_encoded = obj_expled.encode()
1498 ctx_copied = deepcopy(ctx_dummy)
1499 obj_decoded, tail = obj_expled.decode(
1500 obj_expled_encoded + tail_junk,
1504 self.assertDictEqual(ctx_copied, ctx_dummy)
1506 list(obj_decoded.pps())
1507 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
1508 self.assertEqual(tail, tail_junk)
1509 self.assertEqual(obj_decoded, obj_expled)
1510 self.assertNotEqual(obj_decoded, obj)
1511 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1512 self.assertEqual(bytes(obj_decoded), bytes(obj))
1513 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1514 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1515 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1517 obj_decoded.expl_llen,
1518 len(len_encode(len(obj_encoded))),
1520 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1521 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1524 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1526 self.assertEqual(obj_decoded.expl_offset, offset)
1527 if isinstance(value, tuple):
1528 self.assertSetEqual(set(value), set(obj_decoded.named))
1531 assert_exceeding_data(
1533 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
1537 @given(integers(min_value=1, max_value=255))
1538 def test_bad_zero_value(self, pad_size):
1539 with self.assertRaises(DecodeError):
1540 BitString().decode(b"".join((
1541 BitString.tag_default,
1546 def test_go_vectors_invalid(self):
1552 with self.assertRaises(DecodeError):
1553 BitString().decode(b"".join((
1554 BitString.tag_default,
1559 def test_go_vectors_valid(self):
1560 obj, _ = BitString().decode(b"".join((
1561 BitString.tag_default,
1565 self.assertEqual(bytes(obj), b"")
1566 self.assertEqual(obj.bit_len, 0)
1568 obj, _ = BitString().decode(b"".join((
1569 BitString.tag_default,
1573 self.assertEqual(bytes(obj), b"\x00")
1574 self.assertEqual(obj.bit_len, 1)
1576 obj = BitString((16, b"\x82\x40"))
1577 self.assertTrue(obj[0])
1578 self.assertFalse(obj[1])
1579 self.assertTrue(obj[6])
1580 self.assertTrue(obj[9])
1581 self.assertFalse(obj[17])
1584 integers(min_value=1, max_value=30),
1587 binary(min_size=1, max_size=5),
1589 binary(min_size=1, max_size=5),
1597 lists(booleans(), min_size=1),
1600 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1601 def chunk_constructed(contents):
1603 tag_encode(form=TagFormConstructed, num=3) +
1605 b"".join(BitString(content).encode() for content in contents) +
1609 payload_expected = b""
1610 bit_len_expected = 0
1611 for chunk_input in chunk_inputs:
1612 if isinstance(chunk_input, binary_type):
1613 chunks.append(BitString(chunk_input).encode())
1614 payload_expected += chunk_input
1615 bit_len_expected += len(chunk_input) * 8
1617 chunks.append(chunk_constructed(chunk_input))
1618 payload = b"".join(chunk_input)
1619 payload_expected += payload
1620 bit_len_expected += len(payload) * 8
1621 chunk_last = BitString("'%s'B" % "".join(
1622 "1" if bit else "0" for bit in chunk_last_bits
1624 payload_expected += bytes(chunk_last)
1625 bit_len_expected += chunk_last.bit_len
1626 encoded_indefinite = (
1627 tag_encode(form=TagFormConstructed, num=impl) +
1630 chunk_last.encode() +
1633 encoded_definite = (
1634 tag_encode(form=TagFormConstructed, num=impl) +
1635 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1639 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1640 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1641 for lenindef_expected, encoded in (
1642 (True, encoded_indefinite),
1643 (False, encoded_definite),
1645 obj, tail = BitString(impl=tag_encode(impl)).decode(
1647 ctx={"bered": True},
1649 self.assertSequenceEqual(tail, junk)
1650 self.assertEqual(obj.bit_len, bit_len_expected)
1651 self.assertSequenceEqual(bytes(obj), payload_expected)
1652 self.assertTrue(obj.ber_encoded)
1653 self.assertEqual(obj.lenindef, lenindef_expected)
1654 self.assertTrue(obj.bered)
1656 self.assertTrue(obj.ber_encoded)
1657 self.assertEqual(obj.lenindef, lenindef_expected)
1658 self.assertTrue(obj.bered)
1659 self.assertEqual(len(encoded), obj.tlvlen)
1662 pprint(obj, big_blobs=True, with_decode_path=True)
1665 integers(min_value=0),
1668 def test_ber_definite_too_short(self, offset, decode_path):
1669 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1671 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1673 decode_path=decode_path,
1674 ctx={"bered": True},
1676 self.assertEqual(err.exception.decode_path, decode_path)
1677 self.assertEqual(err.exception.offset, offset)
1680 integers(min_value=0),
1683 def test_ber_definite_no_data(self, offset, decode_path):
1684 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1686 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1688 decode_path=decode_path,
1689 ctx={"bered": True},
1691 self.assertEqual(err.exception.decode_path, decode_path)
1692 self.assertEqual(err.exception.offset, offset)
1695 integers(min_value=0),
1697 integers(min_value=1, max_value=3),
1699 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1700 bs = BitString(b"data").encode()
1701 with self.assertRaises(NotEnoughData) as err:
1703 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1705 decode_path=decode_path,
1706 ctx={"bered": True},
1708 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1709 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1712 integers(min_value=0),
1714 integers(min_value=1, max_value=3),
1716 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1717 bs = BitString(b"data").encode()
1718 bs_longer = BitString(b"data-longer").encode()
1719 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1722 tag_encode(3, form=TagFormConstructed) +
1723 len_encode((chunks + 1) * len(bs)) +
1728 decode_path=decode_path,
1729 ctx={"bered": True},
1731 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1732 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1735 integers(min_value=0),
1738 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1739 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1741 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1743 decode_path=decode_path,
1744 ctx={"bered": True},
1746 self.assertEqual(err.exception.decode_path, decode_path)
1747 self.assertEqual(err.exception.offset, offset)
1749 @given(data_strategy())
1750 def test_ber_indefinite_not_multiple(self, d):
1751 bs_short = BitString("'A'H").encode()
1752 bs_full = BitString("'AA'H").encode()
1753 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1754 chunks.append(bs_short)
1755 d.draw(permutations(chunks))
1756 chunks.append(bs_short)
1757 offset = d.draw(integers(min_value=0))
1758 decode_path = d.draw(decode_path_strat)
1759 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1762 tag_encode(3, form=TagFormConstructed) +
1768 decode_path=decode_path,
1769 ctx={"bered": True},
1772 err.exception.decode_path,
1773 decode_path + (str(chunks.index(bs_short)),),
1776 err.exception.offset,
1777 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1780 def test_x690_vector(self):
1781 vector = BitString("'0A3B5F291CD'H")
1782 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1783 self.assertSequenceEqual(tail, b"")
1784 self.assertEqual(obj, vector)
1785 obj, tail = BitString().decode(
1786 hexdec("23800303000A3B0305045F291CD00000"),
1787 ctx={"bered": True},
1789 self.assertSequenceEqual(tail, b"")
1790 self.assertEqual(obj, vector)
1791 self.assertTrue(obj.ber_encoded)
1792 self.assertTrue(obj.lenindef)
1793 self.assertTrue(obj.bered)
1795 self.assertTrue(obj.ber_encoded)
1796 self.assertTrue(obj.lenindef)
1797 self.assertTrue(obj.bered)
1801 def octet_string_values_strategy(draw, do_expl=False):
1802 bound_min, bound_max = sorted(draw(sets(
1803 integers(min_value=0, max_value=1 << 7),
1807 value = draw(one_of(
1809 binary(min_size=bound_min, max_size=bound_max),
1811 default = draw(one_of(
1813 binary(min_size=bound_min, max_size=bound_max),
1816 if draw(booleans()):
1817 bounds = (bound_min, bound_max)
1821 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1823 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1824 optional = draw(one_of(none(), booleans()))
1826 draw(integers(min_value=0)),
1827 draw(integers(min_value=0)),
1828 draw(integers(min_value=0)),
1830 return (value, bounds, impl, expl, default, optional, _decoded)
1833 class OctetStringInherited(OctetString):
1837 class TestOctetString(CommonMixin, TestCase):
1838 base_klass = OctetString
1840 def test_invalid_value_type(self):
1841 with self.assertRaises(InvalidValueType) as err:
1842 OctetString(text_type(123))
1846 def test_optional(self, optional):
1847 obj = OctetString(default=OctetString(b""), optional=optional)
1848 self.assertTrue(obj.optional)
1851 def test_ready(self, value):
1853 self.assertFalse(obj.ready)
1856 pprint(obj, big_blobs=True, with_decode_path=True)
1857 with self.assertRaises(ObjNotReady) as err:
1860 obj = OctetString(value)
1861 self.assertTrue(obj.ready)
1864 pprint(obj, big_blobs=True, with_decode_path=True)
1866 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1867 def test_comparison(self, value1, value2, tag1, tag2):
1868 for klass in (OctetString, OctetStringInherited):
1869 obj1 = klass(value1)
1870 obj2 = klass(value2)
1871 self.assertEqual(obj1 == obj2, value1 == value2)
1872 self.assertEqual(obj1 != obj2, value1 != value2)
1873 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1874 obj1 = klass(value1, impl=tag1)
1875 obj2 = klass(value1, impl=tag2)
1876 self.assertEqual(obj1 == obj2, tag1 == tag2)
1877 self.assertEqual(obj1 != obj2, tag1 != tag2)
1879 @given(lists(binary()))
1880 def test_sorted_works(self, values):
1881 self.assertSequenceEqual(
1882 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1886 @given(data_strategy())
1887 def test_bounds_satisfied(self, d):
1888 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1889 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1890 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1891 OctetString(value=value, bounds=(bound_min, bound_max))
1893 @given(data_strategy())
1894 def test_bounds_unsatisfied(self, d):
1895 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1896 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1897 value = d.draw(binary(max_size=bound_min - 1))
1898 with self.assertRaises(BoundsError) as err:
1899 OctetString(value=value, bounds=(bound_min, bound_max))
1901 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1902 OctetString(bounds=(bound_min, bound_max)).decode(
1903 OctetString(value).encode()
1906 value = d.draw(binary(min_size=bound_max + 1))
1907 with self.assertRaises(BoundsError) as err:
1908 OctetString(value=value, bounds=(bound_min, bound_max))
1910 with assertRaisesRegex(self, DecodeError, "bounds") as err:
1911 OctetString(bounds=(bound_min, bound_max)).decode(
1912 OctetString(value).encode()
1916 @given(data_strategy())
1917 def test_call(self, d):
1918 for klass in (OctetString, OctetStringInherited):
1927 ) = d.draw(octet_string_values_strategy())
1928 obj_initial = klass(
1934 optional_initial or False,
1945 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1946 if (default is None) and (obj_initial.default is not None):
1949 (bounds is None) and
1950 (value is not None) and
1951 (bounds_initial is not None) and
1952 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1956 (bounds is None) and
1957 (default is not None) and
1958 (bounds_initial is not None) and
1959 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1962 obj = obj_initial(value, bounds, impl, expl, default, optional)
1964 value_expected = default if value is None else value
1966 default_initial if value_expected is None
1969 self.assertEqual(obj, value_expected)
1970 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1971 self.assertEqual(obj.expl_tag, expl or expl_initial)
1974 default_initial if default is None else default,
1976 if obj.default is None:
1977 optional = optional_initial if optional is None else optional
1978 optional = False if optional is None else optional
1981 self.assertEqual(obj.optional, optional)
1983 (obj._bound_min, obj._bound_max),
1984 bounds or bounds_initial or (0, float("+inf")),
1987 @given(octet_string_values_strategy())
1988 def test_copy(self, values):
1989 for klass in (OctetString, OctetStringInherited):
1990 obj = klass(*values)
1991 for copy_func in copy_funcs:
1992 obj_copied = copy_func(obj)
1993 self.assert_copied_basic_fields(obj, obj_copied)
1994 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1995 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1996 self.assertEqual(obj._value, obj_copied._value)
2000 integers(min_value=1).map(tag_encode),
2002 def test_stripped(self, value, tag_impl):
2003 obj = OctetString(value, impl=tag_impl)
2004 with self.assertRaises(NotEnoughData):
2005 obj.decode(obj.encode()[:-1])
2009 integers(min_value=1).map(tag_ctxc),
2011 def test_stripped_expl(self, value, tag_expl):
2012 obj = OctetString(value, expl=tag_expl)
2013 with self.assertRaises(NotEnoughData):
2014 obj.decode(obj.encode()[:-1])
2017 integers(min_value=31),
2018 integers(min_value=0),
2021 def test_bad_tag(self, tag, offset, decode_path):
2022 with self.assertRaises(DecodeError) as err:
2023 OctetString().decode(
2024 tag_encode(tag)[:-1],
2026 decode_path=decode_path,
2029 self.assertEqual(err.exception.offset, offset)
2030 self.assertEqual(err.exception.decode_path, decode_path)
2033 integers(min_value=128),
2034 integers(min_value=0),
2037 def test_bad_len(self, l, offset, decode_path):
2038 with self.assertRaises(DecodeError) as err:
2039 OctetString().decode(
2040 OctetString.tag_default + len_encode(l)[:-1],
2042 decode_path=decode_path,
2045 self.assertEqual(err.exception.offset, offset)
2046 self.assertEqual(err.exception.decode_path, decode_path)
2049 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2050 integers(min_value=0),
2053 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2054 value, bound_min = list(sorted(ints))
2056 class String(OctetString):
2057 bounds = (bound_min, bound_min)
2058 with self.assertRaises(DecodeError) as err:
2060 OctetString(b"\x00" * value).encode(),
2062 decode_path=decode_path,
2065 self.assertEqual(err.exception.offset, offset)
2066 self.assertEqual(err.exception.decode_path, decode_path)
2068 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2070 octet_string_values_strategy(),
2072 integers(min_value=1).map(tag_ctxc),
2073 integers(min_value=0),
2076 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2077 for klass in (OctetString, OctetStringInherited):
2078 _, _, _, _, default, optional, _decoded = values
2087 pprint(obj, big_blobs=True, with_decode_path=True)
2088 self.assertFalse(obj.expled)
2089 obj_encoded = obj.encode()
2090 obj_expled = obj(value, expl=tag_expl)
2091 self.assertTrue(obj_expled.expled)
2093 list(obj_expled.pps())
2094 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2095 obj_expled_encoded = obj_expled.encode()
2096 ctx_copied = deepcopy(ctx_dummy)
2097 obj_decoded, tail = obj_expled.decode(
2098 obj_expled_encoded + tail_junk,
2102 self.assertDictEqual(ctx_copied, ctx_dummy)
2104 list(obj_decoded.pps())
2105 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2106 self.assertEqual(tail, tail_junk)
2107 self.assertEqual(obj_decoded, obj_expled)
2108 self.assertNotEqual(obj_decoded, obj)
2109 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2110 self.assertEqual(bytes(obj_decoded), bytes(obj))
2111 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2112 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2113 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2115 obj_decoded.expl_llen,
2116 len(len_encode(len(obj_encoded))),
2118 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2119 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2122 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2124 self.assertEqual(obj_decoded.expl_offset, offset)
2125 assert_exceeding_data(
2127 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2132 integers(min_value=1, max_value=30),
2135 binary(min_size=1, max_size=5),
2137 binary(min_size=1, max_size=5),
2147 def test_constructed(self, impl, chunk_inputs, junk):
2148 def chunk_constructed(contents):
2150 tag_encode(form=TagFormConstructed, num=4) +
2152 b"".join(OctetString(content).encode() for content in contents) +
2156 payload_expected = b""
2157 for chunk_input in chunk_inputs:
2158 if isinstance(chunk_input, binary_type):
2159 chunks.append(OctetString(chunk_input).encode())
2160 payload_expected += chunk_input
2162 chunks.append(chunk_constructed(chunk_input))
2163 payload = b"".join(chunk_input)
2164 payload_expected += payload
2165 encoded_indefinite = (
2166 tag_encode(form=TagFormConstructed, num=impl) +
2171 encoded_definite = (
2172 tag_encode(form=TagFormConstructed, num=impl) +
2173 len_encode(len(b"".join(chunks))) +
2176 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2177 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2178 for lenindef_expected, encoded in (
2179 (True, encoded_indefinite),
2180 (False, encoded_definite),
2182 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2184 ctx={"bered": True},
2186 self.assertSequenceEqual(tail, junk)
2187 self.assertSequenceEqual(bytes(obj), payload_expected)
2188 self.assertTrue(obj.ber_encoded)
2189 self.assertEqual(obj.lenindef, lenindef_expected)
2190 self.assertTrue(obj.bered)
2192 self.assertTrue(obj.ber_encoded)
2193 self.assertEqual(obj.lenindef, lenindef_expected)
2194 self.assertTrue(obj.bered)
2195 self.assertEqual(len(encoded), obj.tlvlen)
2198 pprint(obj, big_blobs=True, with_decode_path=True)
2201 integers(min_value=0),
2204 def test_ber_definite_too_short(self, offset, decode_path):
2205 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2206 OctetString().decode(
2207 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2209 decode_path=decode_path,
2210 ctx={"bered": True},
2212 self.assertEqual(err.exception.decode_path, decode_path)
2213 self.assertEqual(err.exception.offset, offset)
2216 integers(min_value=0),
2218 integers(min_value=1, max_value=3),
2220 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2221 bs = OctetString(b"data").encode()
2222 with self.assertRaises(NotEnoughData) as err:
2223 OctetString().decode(
2224 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2226 decode_path=decode_path,
2227 ctx={"bered": True},
2229 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2230 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2233 integers(min_value=0),
2235 integers(min_value=1, max_value=3),
2237 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2238 bs = OctetString(b"data").encode()
2239 bs_longer = OctetString(b"data-longer").encode()
2240 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2241 OctetString().decode(
2243 tag_encode(4, form=TagFormConstructed) +
2244 len_encode((chunks + 1) * len(bs)) +
2249 decode_path=decode_path,
2250 ctx={"bered": True},
2252 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2253 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2257 def null_values_strategy(draw, do_expl=False):
2261 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2263 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2264 optional = draw(one_of(none(), booleans()))
2266 draw(integers(min_value=0)),
2267 draw(integers(min_value=0)),
2268 draw(integers(min_value=0)),
2270 return (impl, expl, optional, _decoded)
2273 class NullInherited(Null):
2277 class TestNull(CommonMixin, TestCase):
2280 def test_ready(self):
2282 self.assertTrue(obj.ready)
2285 pprint(obj, big_blobs=True, with_decode_path=True)
2287 @given(binary(min_size=1), binary(min_size=1))
2288 def test_comparison(self, tag1, tag2):
2289 for klass in (Null, NullInherited):
2290 obj1 = klass(impl=tag1)
2291 obj2 = klass(impl=tag2)
2292 self.assertEqual(obj1 == obj2, tag1 == tag2)
2293 self.assertEqual(obj1 != obj2, tag1 != tag2)
2294 self.assertNotEqual(obj1, tag2)
2296 @given(data_strategy())
2297 def test_call(self, d):
2298 for klass in (Null, NullInherited):
2304 ) = d.draw(null_values_strategy())
2305 obj_initial = klass(
2308 optional=optional_initial or False,
2309 _decoded=_decoded_initial,
2316 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2317 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2318 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2319 self.assertEqual(obj.expl_tag, expl or expl_initial)
2320 optional = optional_initial if optional is None else optional
2321 optional = False if optional is None else optional
2322 self.assertEqual(obj.optional, optional)
2324 @given(null_values_strategy())
2325 def test_copy(self, values):
2326 for klass in (Null, NullInherited):
2327 impl, expl, optional, _decoded = values
2331 optional=optional or False,
2334 for copy_func in copy_funcs:
2335 obj_copied = copy_func(obj)
2336 self.assert_copied_basic_fields(obj, obj_copied)
2338 @given(integers(min_value=1).map(tag_encode))
2339 def test_stripped(self, tag_impl):
2340 obj = Null(impl=tag_impl)
2341 with self.assertRaises(NotEnoughData):
2342 obj.decode(obj.encode()[:-1])
2344 @given(integers(min_value=1).map(tag_ctxc))
2345 def test_stripped_expl(self, tag_expl):
2346 obj = Null(expl=tag_expl)
2347 with self.assertRaises(NotEnoughData):
2348 obj.decode(obj.encode()[:-1])
2351 integers(min_value=31),
2352 integers(min_value=0),
2355 def test_bad_tag(self, tag, offset, decode_path):
2356 with self.assertRaises(DecodeError) as err:
2358 tag_encode(tag)[:-1],
2360 decode_path=decode_path,
2363 self.assertEqual(err.exception.offset, offset)
2364 self.assertEqual(err.exception.decode_path, decode_path)
2367 integers(min_value=128),
2368 integers(min_value=0),
2371 def test_bad_len(self, l, offset, decode_path):
2372 with self.assertRaises(DecodeError) as err:
2374 Null.tag_default + len_encode(l)[:-1],
2376 decode_path=decode_path,
2379 self.assertEqual(err.exception.offset, offset)
2380 self.assertEqual(err.exception.decode_path, decode_path)
2382 @given(binary(min_size=1))
2383 def test_tag_mismatch(self, impl):
2384 assume(impl != Null.tag_default)
2385 with self.assertRaises(TagMismatch):
2386 Null(impl=impl).decode(Null().encode())
2389 null_values_strategy(),
2390 integers(min_value=1).map(tag_ctxc),
2391 integers(min_value=0),
2394 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2395 for klass in (Null, NullInherited):
2396 _, _, optional, _decoded = values
2397 obj = klass(optional=optional, _decoded=_decoded)
2400 pprint(obj, big_blobs=True, with_decode_path=True)
2401 self.assertFalse(obj.expled)
2402 obj_encoded = obj.encode()
2403 obj_expled = obj(expl=tag_expl)
2404 self.assertTrue(obj_expled.expled)
2406 list(obj_expled.pps())
2407 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2408 obj_expled_encoded = obj_expled.encode()
2409 ctx_copied = deepcopy(ctx_dummy)
2410 obj_decoded, tail = obj_expled.decode(
2411 obj_expled_encoded + tail_junk,
2415 self.assertDictEqual(ctx_copied, ctx_dummy)
2417 list(obj_decoded.pps())
2418 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2419 self.assertEqual(tail, tail_junk)
2420 self.assertEqual(obj_decoded, obj_expled)
2421 self.assertNotEqual(obj_decoded, obj)
2422 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2423 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2424 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2426 obj_decoded.expl_llen,
2427 len(len_encode(len(obj_encoded))),
2429 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2430 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2433 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2435 self.assertEqual(obj_decoded.expl_offset, offset)
2436 assert_exceeding_data(
2438 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2442 @given(integers(min_value=1))
2443 def test_invalid_len(self, l):
2444 with self.assertRaises(InvalidLength):
2445 Null().decode(b"".join((
2452 def oid_strategy(draw):
2453 first_arc = draw(integers(min_value=0, max_value=2))
2455 if first_arc in (0, 1):
2456 second_arc = draw(integers(min_value=0, max_value=39))
2458 second_arc = draw(integers(min_value=0))
2459 other_arcs = draw(lists(integers(min_value=0)))
2460 return tuple([first_arc, second_arc] + other_arcs)
2464 def oid_values_strategy(draw, do_expl=False):
2465 value = draw(one_of(none(), oid_strategy()))
2469 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2471 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2472 default = draw(one_of(none(), oid_strategy()))
2473 optional = draw(one_of(none(), booleans()))
2475 draw(integers(min_value=0)),
2476 draw(integers(min_value=0)),
2477 draw(integers(min_value=0)),
2479 return (value, impl, expl, default, optional, _decoded)
2482 class ObjectIdentifierInherited(ObjectIdentifier):
2486 class TestObjectIdentifier(CommonMixin, TestCase):
2487 base_klass = ObjectIdentifier
2489 def test_invalid_value_type(self):
2490 with self.assertRaises(InvalidValueType) as err:
2491 ObjectIdentifier(123)
2495 def test_optional(self, optional):
2496 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2497 self.assertTrue(obj.optional)
2499 @given(oid_strategy())
2500 def test_ready(self, value):
2501 obj = ObjectIdentifier()
2502 self.assertFalse(obj.ready)
2505 pprint(obj, big_blobs=True, with_decode_path=True)
2506 with self.assertRaises(ObjNotReady) as err:
2509 obj = ObjectIdentifier(value)
2510 self.assertTrue(obj.ready)
2511 self.assertFalse(obj.ber_encoded)
2514 pprint(obj, big_blobs=True, with_decode_path=True)
2517 @given(oid_strategy(), oid_strategy(), binary(min_size=1), binary(min_size=1))
2518 def test_comparison(self, value1, value2, tag1, tag2):
2519 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2520 obj1 = klass(value1)
2521 obj2 = klass(value2)
2522 self.assertEqual(obj1 == obj2, value1 == value2)
2523 self.assertEqual(obj1 != obj2, value1 != value2)
2524 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2525 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2526 obj1 = klass(value1, impl=tag1)
2527 obj2 = klass(value1, impl=tag2)
2528 self.assertEqual(obj1 == obj2, tag1 == tag2)
2529 self.assertEqual(obj1 != obj2, tag1 != tag2)
2531 @given(lists(oid_strategy()))
2532 def test_sorted_works(self, values):
2533 self.assertSequenceEqual(
2534 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2538 @given(data_strategy())
2539 def test_call(self, d):
2540 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2548 ) = d.draw(oid_values_strategy())
2549 obj_initial = klass(
2550 value=value_initial,
2553 default=default_initial,
2554 optional=optional_initial or False,
2555 _decoded=_decoded_initial,
2564 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2573 value_expected = default if value is None else value
2575 default_initial if value_expected is None
2578 self.assertEqual(obj, value_expected)
2579 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2580 self.assertEqual(obj.expl_tag, expl or expl_initial)
2583 default_initial if default is None else default,
2585 if obj.default is None:
2586 optional = optional_initial if optional is None else optional
2587 optional = False if optional is None else optional
2590 self.assertEqual(obj.optional, optional)
2592 @given(oid_values_strategy())
2593 def test_copy(self, values):
2594 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2611 for copy_func in copy_funcs:
2612 obj_copied = copy_func(obj)
2613 self.assert_copied_basic_fields(obj, obj_copied)
2614 self.assertEqual(obj._value, obj_copied._value)
2616 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2619 integers(min_value=1).map(tag_encode),
2621 def test_stripped(self, value, tag_impl):
2622 obj = ObjectIdentifier(value, impl=tag_impl)
2623 with self.assertRaises(NotEnoughData):
2624 obj.decode(obj.encode()[:-1])
2628 integers(min_value=1).map(tag_ctxc),
2630 def test_stripped_expl(self, value, tag_expl):
2631 obj = ObjectIdentifier(value, expl=tag_expl)
2632 with self.assertRaises(NotEnoughData):
2633 obj.decode(obj.encode()[:-1])
2636 integers(min_value=31),
2637 integers(min_value=0),
2640 def test_bad_tag(self, tag, offset, decode_path):
2641 with self.assertRaises(DecodeError) as err:
2642 ObjectIdentifier().decode(
2643 tag_encode(tag)[:-1],
2645 decode_path=decode_path,
2648 self.assertEqual(err.exception.offset, offset)
2649 self.assertEqual(err.exception.decode_path, decode_path)
2652 integers(min_value=128),
2653 integers(min_value=0),
2656 def test_bad_len(self, l, offset, decode_path):
2657 with self.assertRaises(DecodeError) as err:
2658 ObjectIdentifier().decode(
2659 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2661 decode_path=decode_path,
2664 self.assertEqual(err.exception.offset, offset)
2665 self.assertEqual(err.exception.decode_path, decode_path)
2667 def test_zero_oid(self):
2668 with self.assertRaises(NotEnoughData):
2669 ObjectIdentifier().decode(
2670 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2673 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2674 @given(oid_strategy())
2675 def test_unfinished_oid(self, value):
2676 assume(list(value)[-1] > 255)
2677 obj_encoded = ObjectIdentifier(value).encode()
2678 obj, _ = ObjectIdentifier().decode(obj_encoded)
2679 data = obj_encoded[obj.tlen + obj.llen:-1]
2681 ObjectIdentifier.tag_default,
2682 len_encode(len(data)),
2685 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2688 @given(integers(min_value=0))
2689 def test_invalid_short(self, value):
2690 with self.assertRaises(InvalidOID):
2691 ObjectIdentifier((value,))
2692 with self.assertRaises(InvalidOID):
2693 ObjectIdentifier("%d" % value)
2695 @given(integers(min_value=3), integers(min_value=0))
2696 def test_invalid_first_arc(self, first_arc, second_arc):
2697 with self.assertRaises(InvalidOID):
2698 ObjectIdentifier((first_arc, second_arc))
2699 with self.assertRaises(InvalidOID):
2700 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2702 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2703 def test_invalid_second_arc(self, first_arc, second_arc):
2704 with self.assertRaises(InvalidOID):
2705 ObjectIdentifier((first_arc, second_arc))
2706 with self.assertRaises(InvalidOID):
2707 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2709 @given(text(alphabet=ascii_letters + ".", min_size=1))
2710 def test_junk(self, oid):
2711 with self.assertRaises(InvalidOID):
2712 ObjectIdentifier(oid)
2714 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2715 @given(oid_strategy())
2716 def test_validness(self, oid):
2717 obj = ObjectIdentifier(oid)
2718 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2721 pprint(obj, big_blobs=True, with_decode_path=True)
2723 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2725 oid_values_strategy(),
2727 integers(min_value=1).map(tag_ctxc),
2728 integers(min_value=0),
2731 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2732 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2733 _, _, _, default, optional, _decoded = values
2742 pprint(obj, big_blobs=True, with_decode_path=True)
2743 self.assertFalse(obj.expled)
2744 obj_encoded = obj.encode()
2745 obj_expled = obj(value, expl=tag_expl)
2746 self.assertTrue(obj_expled.expled)
2748 list(obj_expled.pps())
2749 pprint(obj_expled, big_blobs=True, with_decode_path=True)
2750 obj_expled_encoded = obj_expled.encode()
2751 ctx_copied = deepcopy(ctx_dummy)
2752 obj_decoded, tail = obj_expled.decode(
2753 obj_expled_encoded + tail_junk,
2757 self.assertDictEqual(ctx_copied, ctx_dummy)
2759 list(obj_decoded.pps())
2760 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
2761 self.assertEqual(tail, tail_junk)
2762 self.assertEqual(obj_decoded, obj_expled)
2763 self.assertNotEqual(obj_decoded, obj)
2764 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2765 self.assertEqual(tuple(obj_decoded), tuple(obj))
2766 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2767 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2768 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2770 obj_decoded.expl_llen,
2771 len(len_encode(len(obj_encoded))),
2773 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2774 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2777 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2779 self.assertEqual(obj_decoded.expl_offset, offset)
2780 assert_exceeding_data(
2782 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
2787 oid_strategy().map(ObjectIdentifier),
2788 oid_strategy().map(ObjectIdentifier),
2790 def test_add(self, oid1, oid2):
2791 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2792 for oid_to_add in (oid2, tuple(oid2)):
2793 self.assertEqual(oid1 + oid_to_add, oid_expect)
2794 with self.assertRaises(InvalidValueType):
2797 def test_go_vectors_valid(self):
2798 for data, expect in (
2800 (b"\x55\x02", (2, 5, 2)),
2801 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2802 (b"\x81\x34\x03", (2, 100, 3)),
2805 ObjectIdentifier().decode(b"".join((
2806 ObjectIdentifier.tag_default,
2807 len_encode(len(data)),
2813 def test_go_vectors_invalid(self):
2814 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2815 with self.assertRaises(DecodeError):
2816 ObjectIdentifier().decode(b"".join((
2817 Integer.tag_default,
2818 len_encode(len(data)),
2822 def test_x690_vector(self):
2824 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2825 ObjectIdentifier((2, 999, 3)),
2828 def test_nonnormalized_first_arc(self):
2830 ObjectIdentifier.tag_default +
2833 ObjectIdentifier((1, 0)).encode()[-1:]
2835 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2836 self.assertTrue(obj.ber_encoded)
2837 self.assertTrue(obj.bered)
2839 self.assertTrue(obj.ber_encoded)
2840 self.assertTrue(obj.bered)
2841 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2842 ObjectIdentifier().decode(tampered)
2844 @given(data_strategy())
2845 def test_negative_arcs(self, d):
2846 oid = list(d.draw(oid_strategy()))
2849 idx = d.draw(integers(min_value=3, max_value=len(oid)))
2851 if oid[idx - 1] == 0:
2853 with self.assertRaises(InvalidOID):
2854 ObjectIdentifier(tuple(oid))
2855 with self.assertRaises(InvalidOID):
2856 ObjectIdentifier(".".join(str(i) for i in oid))
2858 @given(data_strategy())
2859 def test_plused_arcs(self, d):
2860 oid = [str(arc) for arc in d.draw(oid_strategy())]
2861 idx = d.draw(integers(min_value=0, max_value=len(oid)))
2862 oid[idx - 1] = "+" + oid[idx - 1]
2863 with self.assertRaises(InvalidOID):
2864 ObjectIdentifier(".".join(str(i) for i in oid))
2866 @given(data_strategy())
2867 def test_nonnormalized_arcs(self, d):
2868 arcs = d.draw(lists(
2869 integers(min_value=0, max_value=100),
2873 dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode()
2874 _, _, lv = tag_strip(dered)
2875 _, _, v = len_decode(lv)
2876 v_no_first_arc = v[1:]
2877 idx_for_tamper = d.draw(integers(
2879 max_value=len(v_no_first_arc) - 1,
2881 tampered = list(bytearray(v_no_first_arc))
2882 for _ in range(d.draw(integers(min_value=1, max_value=3))):
2883 tampered.insert(idx_for_tamper, 0x80)
2884 tampered = bytes(bytearray(tampered))
2886 ObjectIdentifier.tag_default +
2887 len_encode(len(tampered)) +
2890 obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
2891 self.assertTrue(obj.ber_encoded)
2892 self.assertTrue(obj.bered)
2894 self.assertTrue(obj.ber_encoded)
2895 self.assertTrue(obj.bered)
2896 with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
2897 ObjectIdentifier().decode(tampered)
2901 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2903 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2904 values = list(draw(sets(
2906 min_size=len(schema),
2907 max_size=len(schema),
2909 schema = list(zip(schema, values))
2910 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2914 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2916 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2917 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2918 optional = draw(one_of(none(), booleans()))
2920 draw(integers(min_value=0)),
2921 draw(integers(min_value=0)),
2922 draw(integers(min_value=0)),
2924 return (schema, value, impl, expl, default, optional, _decoded)
2927 class TestEnumerated(CommonMixin, TestCase):
2928 class EWhatever(Enumerated):
2929 schema = (("whatever", 0),)
2931 base_klass = EWhatever
2933 def test_schema_required(self):
2934 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2937 def test_invalid_value_type(self):
2938 with self.assertRaises(InvalidValueType) as err:
2939 self.base_klass((1, 2))
2942 @given(sets(text_letters(), min_size=2))
2943 def test_unknown_name(self, schema_input):
2944 missing = schema_input.pop()
2946 class E(Enumerated):
2947 schema = [(n, 123) for n in schema_input]
2948 with self.assertRaises(ObjUnknown) as err:
2953 sets(text_letters(), min_size=2),
2954 sets(integers(), min_size=2),
2956 def test_unknown_value(self, schema_input, values_input):
2958 missing_value = values_input.pop()
2959 _input = list(zip(schema_input, values_input))
2961 class E(Enumerated):
2963 with self.assertRaises(DecodeError) as err:
2968 def test_optional(self, optional):
2969 obj = self.base_klass(default="whatever", optional=optional)
2970 self.assertTrue(obj.optional)
2972 def test_ready(self):
2973 obj = self.base_klass()
2974 self.assertFalse(obj.ready)
2977 pprint(obj, big_blobs=True, with_decode_path=True)
2978 with self.assertRaises(ObjNotReady) as err:
2981 obj = self.base_klass("whatever")
2982 self.assertTrue(obj.ready)
2985 pprint(obj, big_blobs=True, with_decode_path=True)
2987 @given(integers(), integers(), binary(min_size=1), binary(min_size=1))
2988 def test_comparison(self, value1, value2, tag1, tag2):
2989 class E(Enumerated):
2991 ("whatever0", value1),
2992 ("whatever1", value2),
2995 class EInherited(E):
2997 for klass in (E, EInherited):
2998 obj1 = klass(value1)
2999 obj2 = klass(value2)
3000 self.assertEqual(obj1 == obj2, value1 == value2)
3001 self.assertEqual(obj1 != obj2, value1 != value2)
3002 self.assertEqual(obj1 == int(obj2), value1 == value2)
3003 obj1 = klass(value1, impl=tag1)
3004 obj2 = klass(value1, impl=tag2)
3005 self.assertEqual(obj1 == obj2, tag1 == tag2)
3006 self.assertEqual(obj1 != obj2, tag1 != tag2)
3008 @given(data_strategy())
3009 def test_call(self, d):
3018 ) = d.draw(enumerated_values_strategy())
3020 class E(Enumerated):
3021 schema = schema_initial
3023 value=value_initial,
3026 default=default_initial,
3027 optional=optional_initial or False,
3028 _decoded=_decoded_initial,
3038 ) = d.draw(enumerated_values_strategy(
3039 schema=schema_initial,
3040 do_expl=impl_initial is None,
3050 value_expected = default if value is None else value
3052 default_initial if value_expected is None
3057 dict(schema_initial).get(value_expected, value_expected),
3059 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3060 self.assertEqual(obj.expl_tag, expl or expl_initial)
3063 default_initial if default is None else default,
3065 if obj.default is None:
3066 optional = optional_initial if optional is None else optional
3067 optional = False if optional is None else optional
3070 self.assertEqual(obj.optional, optional)
3071 self.assertEqual(obj.specs, dict(schema_initial))
3073 @given(enumerated_values_strategy())
3074 def test_copy(self, values):
3075 schema_input, value, impl, expl, default, optional, _decoded = values
3077 class E(Enumerated):
3078 schema = schema_input
3088 for copy_func in copy_funcs:
3089 obj_copied = copy_func(obj)
3090 self.assert_copied_basic_fields(obj, obj_copied)
3091 self.assertEqual(obj.specs, obj_copied.specs)
3093 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3094 @given(data_strategy())
3095 def test_symmetric(self, d):
3096 schema_input, _, _, _, default, optional, _decoded = d.draw(
3097 enumerated_values_strategy(),
3099 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
3100 offset = d.draw(integers(min_value=0))
3101 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
3102 tail_junk = d.draw(binary(max_size=5))
3104 class E(Enumerated):
3105 schema = schema_input
3114 pprint(obj, big_blobs=True, with_decode_path=True)
3115 self.assertFalse(obj.expled)
3116 obj_encoded = obj.encode()
3117 obj_expled = obj(value, expl=tag_expl)
3118 self.assertTrue(obj_expled.expled)
3120 list(obj_expled.pps())
3121 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3122 obj_expled_encoded = obj_expled.encode()
3123 ctx_copied = deepcopy(ctx_dummy)
3124 obj_decoded, tail = obj_expled.decode(
3125 obj_expled_encoded + tail_junk,
3129 self.assertDictEqual(ctx_copied, ctx_dummy)
3131 list(obj_decoded.pps())
3132 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3133 self.assertEqual(tail, tail_junk)
3134 self.assertEqual(obj_decoded, obj_expled)
3135 self.assertNotEqual(obj_decoded, obj)
3136 self.assertEqual(int(obj_decoded), int(obj_expled))
3137 self.assertEqual(int(obj_decoded), int(obj))
3138 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3139 self.assertEqual(obj_decoded.expl_tag, tag_expl)
3140 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3142 obj_decoded.expl_llen,
3143 len(len_encode(len(obj_encoded))),
3145 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3146 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3149 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3151 self.assertEqual(obj_decoded.expl_offset, offset)
3152 assert_exceeding_data(
3154 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3160 def string_values_strategy(draw, alphabet, do_expl=False):
3161 bound_min, bound_max = sorted(draw(sets(
3162 integers(min_value=0, max_value=1 << 7),
3166 value = draw(one_of(
3168 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3170 default = draw(one_of(
3172 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
3175 if draw(booleans()):
3176 bounds = (bound_min, bound_max)
3180 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3182 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3183 optional = draw(one_of(none(), booleans()))
3185 draw(integers(min_value=0)),
3186 draw(integers(min_value=0)),
3187 draw(integers(min_value=0)),
3189 return (value, bounds, impl, expl, default, optional, _decoded)
3192 class StringMixin(object):
3193 def test_invalid_value_type(self):
3194 with self.assertRaises(InvalidValueType) as err:
3195 self.base_klass((1, 2))
3198 def text_alphabet(self):
3199 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
3200 return printable + whitespace
3204 def test_optional(self, optional):
3205 obj = self.base_klass(default=self.base_klass(""), optional=optional)
3206 self.assertTrue(obj.optional)
3208 @given(data_strategy())
3209 def test_ready(self, d):
3210 obj = self.base_klass()
3211 self.assertFalse(obj.ready)
3214 pprint(obj, big_blobs=True, with_decode_path=True)
3216 with self.assertRaises(ObjNotReady) as err:
3219 value = d.draw(text(alphabet=self.text_alphabet()))
3220 obj = self.base_klass(value)
3221 self.assertTrue(obj.ready)
3224 pprint(obj, big_blobs=True, with_decode_path=True)
3227 @given(data_strategy())
3228 def test_comparison(self, d):
3229 value1 = d.draw(text(alphabet=self.text_alphabet()))
3230 value2 = d.draw(text(alphabet=self.text_alphabet()))
3231 tag1 = d.draw(binary(min_size=1))
3232 tag2 = d.draw(binary(min_size=1))
3233 obj1 = self.base_klass(value1)
3234 obj2 = self.base_klass(value2)
3235 self.assertEqual(obj1 == obj2, value1 == value2)
3236 self.assertEqual(obj1 != obj2, value1 != value2)
3237 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3238 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
3239 obj1 = self.base_klass(value1, impl=tag1)
3240 obj2 = self.base_klass(value1, impl=tag2)
3241 self.assertEqual(obj1 == obj2, tag1 == tag2)
3242 self.assertEqual(obj1 != obj2, tag1 != tag2)
3244 @given(data_strategy())
3245 def test_bounds_satisfied(self, d):
3246 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
3247 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3248 value = d.draw(text(
3249 alphabet=self.text_alphabet(),
3253 self.base_klass(value=value, bounds=(bound_min, bound_max))
3255 @given(data_strategy())
3256 def test_bounds_unsatisfied(self, d):
3257 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
3258 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
3259 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
3260 with self.assertRaises(BoundsError) as err:
3261 self.base_klass(value=value, bounds=(bound_min, bound_max))
3263 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3264 self.base_klass(bounds=(bound_min, bound_max)).decode(
3265 self.base_klass(value).encode()
3268 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
3269 with self.assertRaises(BoundsError) as err:
3270 self.base_klass(value=value, bounds=(bound_min, bound_max))
3272 with assertRaisesRegex(self, DecodeError, "bounds") as err:
3273 self.base_klass(bounds=(bound_min, bound_max)).decode(
3274 self.base_klass(value).encode()
3278 @given(data_strategy())
3279 def test_call(self, d):
3288 ) = d.draw(string_values_strategy(self.text_alphabet()))
3289 obj_initial = self.base_klass(
3295 optional_initial or False,
3306 ) = d.draw(string_values_strategy(
3307 self.text_alphabet(),
3308 do_expl=impl_initial is None,
3310 if (default is None) and (obj_initial.default is not None):
3313 (bounds is None) and
3314 (value is not None) and
3315 (bounds_initial is not None) and
3316 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3320 (bounds is None) and
3321 (default is not None) and
3322 (bounds_initial is not None) and
3323 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3326 obj = obj_initial(value, bounds, impl, expl, default, optional)
3328 value_expected = default if value is None else value
3330 default_initial if value_expected is None
3333 self.assertEqual(obj, value_expected)
3334 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3335 self.assertEqual(obj.expl_tag, expl or expl_initial)
3338 default_initial if default is None else default,
3340 if obj.default is None:
3341 optional = optional_initial if optional is None else optional
3342 optional = False if optional is None else optional
3345 self.assertEqual(obj.optional, optional)
3347 (obj._bound_min, obj._bound_max),
3348 bounds or bounds_initial or (0, float("+inf")),
3351 @given(data_strategy())
3352 def test_copy(self, d):
3353 values = d.draw(string_values_strategy(self.text_alphabet()))
3354 obj = self.base_klass(*values)
3355 for copy_func in copy_funcs:
3356 obj_copied = copy_func(obj)
3357 self.assert_copied_basic_fields(obj, obj_copied)
3358 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3359 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3360 self.assertEqual(obj._value, obj_copied._value)
3362 @given(data_strategy())
3363 def test_stripped(self, d):
3364 value = d.draw(text(alphabet=self.text_alphabet()))
3365 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3366 obj = self.base_klass(value, impl=tag_impl)
3367 with self.assertRaises(NotEnoughData):
3368 obj.decode(obj.encode()[:-1])
3370 @given(data_strategy())
3371 def test_stripped_expl(self, d):
3372 value = d.draw(text(alphabet=self.text_alphabet()))
3373 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3374 obj = self.base_klass(value, expl=tag_expl)
3375 with self.assertRaises(NotEnoughData):
3376 obj.decode(obj.encode()[:-1])
3379 integers(min_value=31),
3380 integers(min_value=0),
3383 def test_bad_tag(self, tag, offset, decode_path):
3384 with self.assertRaises(DecodeError) as err:
3385 self.base_klass().decode(
3386 tag_encode(tag)[:-1],
3388 decode_path=decode_path,
3391 self.assertEqual(err.exception.offset, offset)
3392 self.assertEqual(err.exception.decode_path, decode_path)
3395 integers(min_value=128),
3396 integers(min_value=0),
3399 def test_bad_len(self, l, offset, decode_path):
3400 with self.assertRaises(DecodeError) as err:
3401 self.base_klass().decode(
3402 self.base_klass.tag_default + len_encode(l)[:-1],
3404 decode_path=decode_path,
3407 self.assertEqual(err.exception.offset, offset)
3408 self.assertEqual(err.exception.decode_path, decode_path)
3411 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3412 integers(min_value=0),
3415 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3416 value, bound_min = list(sorted(ints))
3418 class String(self.base_klass):
3419 # Multiply this value by four, to satisfy UTF-32 bounds
3420 # (4 bytes per character) validation
3421 bounds = (bound_min * 4, bound_min * 4)
3422 with self.assertRaises(DecodeError) as err:
3424 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3426 decode_path=decode_path,
3429 self.assertEqual(err.exception.offset, offset)
3430 self.assertEqual(err.exception.decode_path, decode_path)
3432 @given(data_strategy())
3433 def test_symmetric(self, d):
3434 values = d.draw(string_values_strategy(self.text_alphabet()))
3435 value = d.draw(text(alphabet=self.text_alphabet()))
3436 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3437 offset = d.draw(integers(min_value=0))
3438 tail_junk = d.draw(binary(max_size=5))
3439 _, _, _, _, default, optional, _decoded = values
3440 obj = self.base_klass(
3448 pprint(obj, big_blobs=True, with_decode_path=True)
3449 self.assertFalse(obj.expled)
3450 obj_encoded = obj.encode()
3451 obj_expled = obj(value, expl=tag_expl)
3452 self.assertTrue(obj_expled.expled)
3454 list(obj_expled.pps())
3455 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3456 obj_expled_encoded = obj_expled.encode()
3457 ctx_copied = deepcopy(ctx_dummy)
3458 obj_decoded, tail = obj_expled.decode(
3459 obj_expled_encoded + tail_junk,
3463 self.assertDictEqual(ctx_copied, ctx_dummy)
3465 list(obj_decoded.pps())
3466 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3467 self.assertEqual(tail, tail_junk)
3468 self.assertEqual(obj_decoded, obj_expled)
3469 self.assertNotEqual(obj_decoded, obj)
3470 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3471 self.assertEqual(bytes(obj_decoded), bytes(obj))
3472 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3473 self.assertEqual(text_type(obj_decoded), text_type(obj))
3474 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3475 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3476 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3478 obj_decoded.expl_llen,
3479 len(len_encode(len(obj_encoded))),
3481 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3482 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3485 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3487 self.assertEqual(obj_decoded.expl_offset, offset)
3488 assert_exceeding_data(
3490 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3495 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3496 base_klass = UTF8String
3499 cyrillic_letters = text(
3500 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3506 class UnicodeDecodeErrorMixin(object):
3507 @given(cyrillic_letters)
3508 def test_unicode_decode_error(self, cyrillic_text):
3509 with self.assertRaises(DecodeError):
3510 self.base_klass(cyrillic_text)
3513 class TestNumericString(StringMixin, CommonMixin, TestCase):
3514 base_klass = NumericString
3516 def text_alphabet(self):
3519 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3520 def test_non_numeric(self, non_numeric_text):
3521 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3522 self.base_klass(non_numeric_text)
3525 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3526 integers(min_value=0),
3529 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3530 value, bound_min = list(sorted(ints))
3532 class String(self.base_klass):
3533 bounds = (bound_min, bound_min)
3534 with self.assertRaises(DecodeError) as err:
3536 self.base_klass(b"1" * value).encode(),
3538 decode_path=decode_path,
3541 self.assertEqual(err.exception.offset, offset)
3542 self.assertEqual(err.exception.decode_path, decode_path)
3545 class TestPrintableString(
3546 UnicodeDecodeErrorMixin,
3551 base_klass = PrintableString
3553 def text_alphabet(self):
3554 return ascii_letters + digits + " '()+,-./:=?"
3556 @given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
3557 def test_non_printable(self, non_printable_text):
3558 with assertRaisesRegex(self, DecodeError, "non-printable"):
3559 self.base_klass(non_printable_text)
3562 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3563 integers(min_value=0),
3566 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3567 value, bound_min = list(sorted(ints))
3569 class String(self.base_klass):
3570 bounds = (bound_min, bound_min)
3571 with self.assertRaises(DecodeError) as err:
3573 self.base_klass(b"1" * value).encode(),
3575 decode_path=decode_path,
3578 self.assertEqual(err.exception.offset, offset)
3579 self.assertEqual(err.exception.decode_path, decode_path)
3581 def test_allowable_invalid_chars(self):
3583 ("*", {"allow_asterisk": True}),
3584 ("&", {"allow_ampersand": True}),
3585 ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
3588 obj = self.base_klass(s)
3589 for prop in kwargs.keys():
3590 self.assertFalse(getattr(obj, prop))
3592 with assertRaisesRegex(self, DecodeError, "non-printable"):
3594 self.base_klass(s, **kwargs)
3595 klass = self.base_klass(**kwargs)
3597 for prop in kwargs.keys():
3598 self.assertTrue(getattr(obj, prop))
3601 for prop in kwargs.keys():
3602 self.assertTrue(getattr(obj, prop))
3605 class TestTeletexString(
3606 UnicodeDecodeErrorMixin,
3611 base_klass = TeletexString
3614 class TestVideotexString(
3615 UnicodeDecodeErrorMixin,
3620 base_klass = VideotexString
3623 class TestIA5String(
3624 UnicodeDecodeErrorMixin,
3629 base_klass = IA5String
3632 class TestGraphicString(
3633 UnicodeDecodeErrorMixin,
3638 base_klass = GraphicString
3641 class TestVisibleString(
3642 UnicodeDecodeErrorMixin,
3647 base_klass = VisibleString
3649 def test_x690_vector(self):
3650 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3651 self.assertSequenceEqual(tail, b"")
3652 self.assertEqual(str(obj), "Jones")
3653 self.assertFalse(obj.ber_encoded)
3654 self.assertFalse(obj.lenindef)
3655 self.assertFalse(obj.bered)
3657 obj, tail = VisibleString().decode(
3658 hexdec("3A0904034A6F6E04026573"),
3659 ctx={"bered": True},
3661 self.assertSequenceEqual(tail, b"")
3662 self.assertEqual(str(obj), "Jones")
3663 self.assertTrue(obj.ber_encoded)
3664 self.assertFalse(obj.lenindef)
3665 self.assertTrue(obj.bered)
3667 self.assertTrue(obj.ber_encoded)
3668 self.assertFalse(obj.lenindef)
3669 self.assertTrue(obj.bered)
3671 obj, tail = VisibleString().decode(
3672 hexdec("3A8004034A6F6E040265730000"),
3673 ctx={"bered": True},
3675 self.assertSequenceEqual(tail, b"")
3676 self.assertEqual(str(obj), "Jones")
3677 self.assertTrue(obj.ber_encoded)
3678 self.assertTrue(obj.lenindef)
3679 self.assertTrue(obj.bered)
3681 self.assertTrue(obj.ber_encoded)
3682 self.assertTrue(obj.lenindef)
3683 self.assertTrue(obj.bered)
3686 class TestGeneralString(
3687 UnicodeDecodeErrorMixin,
3692 base_klass = GeneralString
3695 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3696 base_klass = UniversalString
3699 class TestBMPString(StringMixin, CommonMixin, TestCase):
3700 base_klass = BMPString
3704 def generalized_time_values_strategy(
3712 if draw(booleans()):
3713 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3715 value = value.replace(microsecond=0)
3717 if draw(booleans()):
3718 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3720 default = default.replace(microsecond=0)
3724 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3726 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3727 optional = draw(one_of(none(), booleans()))
3729 draw(integers(min_value=0)),
3730 draw(integers(min_value=0)),
3731 draw(integers(min_value=0)),
3733 return (value, impl, expl, default, optional, _decoded)
3736 class TimeMixin(object):
3737 def test_invalid_value_type(self):
3738 with self.assertRaises(InvalidValueType) as err:
3739 self.base_klass(datetime.now().timetuple())
3742 @given(data_strategy())
3743 def test_optional(self, d):
3744 default = d.draw(datetimes(
3745 min_value=self.min_datetime,
3746 max_value=self.max_datetime,
3748 optional = d.draw(booleans())
3749 obj = self.base_klass(default=default, optional=optional)
3750 self.assertTrue(obj.optional)
3752 @given(data_strategy())
3753 def test_ready(self, d):
3754 obj = self.base_klass()
3755 self.assertFalse(obj.ready)
3758 pprint(obj, big_blobs=True, with_decode_path=True)
3759 with self.assertRaises(ObjNotReady) as err:
3762 value = d.draw(datetimes(
3763 min_value=self.min_datetime,
3764 max_value=self.max_datetime,
3766 obj = self.base_klass(value)
3767 self.assertTrue(obj.ready)
3770 pprint(obj, big_blobs=True, with_decode_path=True)
3772 @given(data_strategy())
3773 def test_comparison(self, d):
3774 value1 = d.draw(datetimes(
3775 min_value=self.min_datetime,
3776 max_value=self.max_datetime,
3778 value2 = d.draw(datetimes(
3779 min_value=self.min_datetime,
3780 max_value=self.max_datetime,
3782 tag1 = d.draw(binary(min_size=1))
3783 tag2 = d.draw(binary(min_size=1))
3785 value1 = value1.replace(microsecond=0)
3786 value2 = value2.replace(microsecond=0)
3787 obj1 = self.base_klass(value1)
3788 obj2 = self.base_klass(value2)
3789 self.assertEqual(obj1 == obj2, value1 == value2)
3790 self.assertEqual(obj1 != obj2, value1 != value2)
3791 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3792 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3793 obj1 = self.base_klass(value1, impl=tag1)
3794 obj2 = self.base_klass(value1, impl=tag2)
3795 self.assertEqual(obj1 == obj2, tag1 == tag2)
3796 self.assertEqual(obj1 != obj2, tag1 != tag2)
3798 @given(data_strategy())
3799 def test_call(self, d):
3807 ) = d.draw(generalized_time_values_strategy(
3808 min_datetime=self.min_datetime,
3809 max_datetime=self.max_datetime,
3810 omit_ms=self.omit_ms,
3812 obj_initial = self.base_klass(
3813 value=value_initial,
3816 default=default_initial,
3817 optional=optional_initial or False,
3818 _decoded=_decoded_initial,
3827 ) = d.draw(generalized_time_values_strategy(
3828 min_datetime=self.min_datetime,
3829 max_datetime=self.max_datetime,
3830 omit_ms=self.omit_ms,
3831 do_expl=impl_initial is None,
3841 value_expected = default if value is None else value
3843 default_initial if value_expected is None
3846 self.assertEqual(obj, value_expected)
3847 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3848 self.assertEqual(obj.expl_tag, expl or expl_initial)
3851 default_initial if default is None else default,
3853 if obj.default is None:
3854 optional = optional_initial if optional is None else optional
3855 optional = False if optional is None else optional
3858 self.assertEqual(obj.optional, optional)
3860 @given(data_strategy())
3861 def test_copy(self, d):
3862 values = d.draw(generalized_time_values_strategy(
3863 min_datetime=self.min_datetime,
3864 max_datetime=self.max_datetime,
3866 obj = self.base_klass(*values)
3867 for copy_func in copy_funcs:
3868 obj_copied = copy_func(obj)
3869 self.assert_copied_basic_fields(obj, obj_copied)
3870 self.assertEqual(obj._value, obj_copied._value)
3872 @given(data_strategy())
3873 def test_stripped(self, d):
3874 value = d.draw(datetimes(
3875 min_value=self.min_datetime,
3876 max_value=self.max_datetime,
3878 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3879 obj = self.base_klass(value, impl=tag_impl)
3880 with self.assertRaises(NotEnoughData):
3881 obj.decode(obj.encode()[:-1])
3883 @given(data_strategy())
3884 def test_stripped_expl(self, d):
3885 value = d.draw(datetimes(
3886 min_value=self.min_datetime,
3887 max_value=self.max_datetime,
3889 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3890 obj = self.base_klass(value, expl=tag_expl)
3891 with self.assertRaises(NotEnoughData):
3892 obj.decode(obj.encode()[:-1])
3894 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3895 @given(data_strategy())
3896 def test_symmetric(self, d):
3897 values = d.draw(generalized_time_values_strategy(
3898 min_datetime=self.min_datetime,
3899 max_datetime=self.max_datetime,
3901 value = d.draw(datetimes(
3902 min_value=self.min_datetime,
3903 max_value=self.max_datetime,
3905 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3906 offset = d.draw(integers(min_value=0))
3907 tail_junk = d.draw(binary(max_size=5))
3908 _, _, _, default, optional, _decoded = values
3909 obj = self.base_klass(
3917 pprint(obj, big_blobs=True, with_decode_path=True)
3918 self.assertFalse(obj.expled)
3919 obj_encoded = obj.encode()
3920 self.additional_symmetric_check(value, obj_encoded)
3921 obj_expled = obj(value, expl=tag_expl)
3922 self.assertTrue(obj_expled.expled)
3924 list(obj_expled.pps())
3925 pprint(obj_expled, big_blobs=True, with_decode_path=True)
3926 obj_expled_encoded = obj_expled.encode()
3927 ctx_copied = deepcopy(ctx_dummy)
3928 obj_decoded, tail = obj_expled.decode(
3929 obj_expled_encoded + tail_junk,
3933 self.assertDictEqual(ctx_copied, ctx_dummy)
3935 list(obj_decoded.pps())
3936 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
3937 self.assertEqual(tail, tail_junk)
3938 self.assertEqual(obj_decoded, obj_expled)
3939 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3940 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3941 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3942 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3943 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3945 obj_decoded.expl_llen,
3946 len(len_encode(len(obj_encoded))),
3948 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3949 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3952 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3954 self.assertEqual(obj_decoded.expl_offset, offset)
3955 assert_exceeding_data(
3957 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
3962 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3963 base_klass = GeneralizedTime
3965 min_datetime = datetime(1900, 1, 1)
3966 max_datetime = datetime(9999, 12, 31)
3968 def additional_symmetric_check(self, value, obj_encoded):
3969 if value.microsecond > 0:
3970 self.assertFalse(obj_encoded.endswith(b"0Z"))
3972 def test_repr_not_ready(self):
3973 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
3974 repr(GeneralizedTime())
3976 def test_x690_vector_valid(self):
3980 b"19920722132100.3Z",
3982 GeneralizedTime(data)
3984 def test_x690_vector_invalid(self):
3987 b"19920622123421.0Z",
3988 b"19920722132100.30Z",
3990 with self.assertRaises(DecodeError) as err:
3991 GeneralizedTime(data)
3994 def test_go_vectors_invalid(self):
4006 b"-20100102030410Z",
4007 b"2010-0102030410Z",
4008 b"2010-0002030410Z",
4009 b"201001-02030410Z",
4010 b"20100102-030410Z",
4011 b"2010010203-0410Z",
4012 b"201001020304-10Z",
4013 # These ones are INVALID in *DER*, but accepted
4014 # by Go's encoding/asn1
4015 b"20100102030405+0607",
4016 b"20100102030405-0607",
4018 with self.assertRaises(DecodeError) as err:
4019 GeneralizedTime(data)
4022 def test_go_vectors_valid(self):
4024 GeneralizedTime(b"20100102030405Z").todatetime(),
4025 datetime(2010, 1, 2, 3, 4, 5, 0),
4028 def test_go_vectors_valid_ber(self):
4030 b"20100102030405+0607",
4031 b"20100102030405-0607",
4033 GeneralizedTime(data, ctx={"bered": True})
4035 def test_utc_offsets(self):
4036 """Some know equal UTC offsets
4039 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4043 "200101011130-0700",
4044 "200101011500-03:30",
4047 self.assertEqual(dts[0], dts[1])
4048 self.assertEqual(dts[0], dts[2])
4049 self.assertEqual(dts[0], dts[3])
4051 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4052 @given(data_strategy())
4053 def test_valid_ber(self, d):
4054 min_year = 1901 if PY2 else 2
4055 year = d.draw(integers(min_value=min_year, max_value=9999))
4056 month = d.draw(integers(min_value=1, max_value=12))
4057 day = d.draw(integers(min_value=1, max_value=28))
4058 hours = d.draw(integers(min_value=0, max_value=23))
4059 data = "%04d%02d%02d%02d" % (year, month, day, hours)
4060 dt = datetime(year, month, day, hours)
4061 fractions_sign = d.draw(sampled_from(" ,."))
4063 if fractions_sign != " ":
4064 fractions = random()
4065 if d.draw(booleans()):
4066 minutes = d.draw(integers(min_value=0, max_value=59))
4067 data += "%02d" % minutes
4068 dt += timedelta(seconds=60 * minutes)
4069 if d.draw(booleans()):
4070 seconds = d.draw(integers(min_value=0, max_value=59))
4071 data += "%02d" % seconds
4072 dt += timedelta(seconds=seconds)
4073 if fractions is not None:
4074 dt += timedelta(microseconds=10**6 * fractions)
4075 elif fractions is not None:
4076 dt += timedelta(seconds=60 * fractions)
4077 elif fractions is not None:
4078 dt += timedelta(seconds=3600 * fractions)
4079 if fractions is not None:
4080 data += fractions_sign + str(fractions)[2:]
4081 if d.draw(booleans()):
4083 elif d.draw(booleans()):
4084 offset_hour = d.draw(integers(min_value=0, max_value=13))
4086 if d.draw(booleans()):
4091 dt -= timedelta(seconds=sign * 3600 * offset_hour)
4092 data += "%02d" % offset_hour
4093 minutes_separator = d.draw(sampled_from((None, "", ":")))
4094 if minutes_separator is not None:
4095 offset_minute = d.draw(integers(min_value=0, max_value=59))
4096 dt -= timedelta(seconds=sign * 60 * offset_minute)
4097 data += "%s%02d" % (minutes_separator, offset_minute)
4098 data = data.encode("ascii")
4099 data_der = GeneralizedTime.tag_default + len_encode(len(data)) + data
4101 GeneralizedTime().decod(data_der)
4106 obj = GeneralizedTime().decod(data_der, ctx={"bered": True})
4109 mktime(obj.todatetime().timetuple()),
4110 mktime(dt.timetuple()),
4113 self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
4114 self.assertEqual(obj.ber_encoded, not dered)
4115 self.assertEqual(obj.bered, not dered)
4116 self.assertEqual(obj.ber_raw, None if dered else data)
4117 self.assertEqual(obj.encode() == data_der, dered)
4122 def test_invalid_ber(self):
4124 # "00010203040506.07",
4125 "-0010203040506.07",
4126 "0001-203040506.07",
4127 "000102-3040506.07",
4128 "00010203-40506.07",
4129 "0001020304-506.07",
4130 "000102030405-6.07",
4131 "00010203040506.-7",
4132 "+0010203040506.07",
4133 "0001+203040506.07",
4134 "000102+3040506.07",
4135 "00010203+40506.07",
4136 "0001020304+506.07",
4137 "000102030405+6.07",
4138 "00010203040506.+7",
4139 " 0010203040506.07",
4140 "0001 203040506.07",
4141 "000102 3040506.07",
4142 "00010203 40506.07",
4143 "0001020304 506.07",
4144 "000102030405 6.07",
4145 "00010203040506. 7",
4146 "001 0203040506.07",
4147 "00012 03040506.07",
4148 "0001023 040506.07",
4149 "000102034 0506.07",
4150 "00010203045 06.07",
4151 "0001020304056 .07",
4152 "00010203040506.7 ",
4232 "00010203040506.07+15",
4233 "00010203040506.07-15",
4234 "00010203040506.07+14:60",
4235 "00010203040506.07+1460",
4236 "00010203040506.07-1460",
4237 "00010203040506.07+00:60",
4238 "00010203040506.07-00:60",
4240 "00010203040506+15",
4241 "00010203040506-15",
4242 "00010203040506+14:60",
4243 "00010203040506+1460",
4244 "00010203040506-1460",
4245 "00010203040506+00:60",
4246 "00010203040506-00:60",
4255 with self.assertRaises(DecodeError):
4256 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4257 data = data.replace(".", ",")
4258 with self.assertRaises(DecodeError):
4259 GeneralizedTime(data.encode("ascii"), ctx={"bered": True})
4263 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4264 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4266 binary(min_size=1, max_size=1),
4268 min_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4269 max_size=(LEN_YYYYMMDDHHMMSSZ - 1) // 2,
4272 def test_junk(self, part0, part1, part2):
4273 junk = part0 + part1 + part2
4274 assume(not (set(junk) <= set(digits.encode("ascii"))))
4275 with self.assertRaises(DecodeError):
4276 GeneralizedTime().decode(
4277 GeneralizedTime.tag_default +
4278 len_encode(len(junk)) +
4284 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4285 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4287 binary(min_size=1, max_size=1),
4289 min_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4290 max_size=(LEN_YYYYMMDDHHMMSSDMZ - 1) // 2,
4293 def test_junk_dm(self, part0, part1, part2):
4294 junk = part0 + part1 + part2
4295 assume(not (set(junk) <= set(digits.encode("ascii"))))
4296 with self.assertRaises(DecodeError):
4297 GeneralizedTime().decode(
4298 GeneralizedTime.tag_default +
4299 len_encode(len(junk)) +
4303 def test_ns_fractions(self):
4304 GeneralizedTime(b"20010101000000.000001Z")
4305 with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
4306 GeneralizedTime(b"20010101000000.0000001Z")
4308 def test_non_pure_integers(self):
4310 # b"20000102030405Z,
4317 b"20000102030405.+6Z",
4318 b"20000102030405.-6Z",
4325 b"20000102030405._6Z",
4326 b"20000102030405.6_Z",
4333 b"20000102030405. 6Z",
4340 b"20000102030405.6 Z",
4342 with self.assertRaises(DecodeError):
4343 GeneralizedTime(data)
4346 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
4347 base_klass = UTCTime
4349 min_datetime = datetime(2000, 1, 1)
4350 max_datetime = datetime(2049, 12, 31)
4352 def additional_symmetric_check(self, value, obj_encoded):
4355 def test_repr_not_ready(self):
4356 unicode(GeneralizedTime()) if PY2 else str(GeneralizedTime())
4359 def test_x690_vector_valid(self):
4367 def test_x690_vector_invalid(self):
4372 with self.assertRaises(DecodeError) as err:
4376 def test_go_vectors_invalid(self):
4402 # These ones are INVALID in *DER*, but accepted
4403 # by Go's encoding/asn1
4404 b"910506164540-0700",
4405 b"910506164540+0730",
4409 with self.assertRaises(DecodeError) as err:
4413 def test_go_vectors_valid(self):
4415 UTCTime(b"910506234540Z").todatetime(),
4416 datetime(1991, 5, 6, 23, 45, 40, 0),
4419 def test_non_pure_integers(self):
4448 with self.assertRaises(DecodeError):
4451 def test_x680_vector_valid_ber(self):
4453 (b"8201021200Z", datetime(1982, 1, 2, 12)),
4454 (b"8201020700-0500", datetime(1982, 1, 2, 12)),
4455 (b"0101021200Z", datetime(2001, 1, 2, 12)),
4456 (b"0101020700-0500", datetime(2001, 1, 2, 12)),
4458 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4459 obj = UTCTime().decod(data_der, ctx={"bered": True})
4460 self.assertEqual(obj, dt)
4461 self.assertEqual(obj.todatetime(), dt)
4462 self.assertTrue(obj.ber_encoded)
4463 self.assertTrue(obj.bered)
4464 self.assertEqual(obj.ber_raw, data)
4465 self.assertNotEqual(obj.encode(), data_der)
4468 def test_go_vectors_valid_ber(self):
4470 b"910506164540-0700",
4471 b"910506164540+0730",
4475 data = UTCTime.tag_default + len_encode(len(data)) + data
4476 obj = UTCTime().decod(data, ctx={"bered": True})
4477 self.assertTrue(obj.ber_encoded)
4478 self.assertTrue(obj.bered)
4479 self.assertNotEqual(obj.encode(), data)
4482 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4483 @given(data_strategy())
4484 def test_valid_ber(self, d):
4485 year = d.draw(integers(min_value=0, max_value=99))
4486 month = d.draw(integers(min_value=1, max_value=12))
4487 day = d.draw(integers(min_value=1, max_value=28))
4488 hours = d.draw(integers(min_value=0, max_value=23))
4489 minute = d.draw(integers(min_value=0, max_value=59))
4490 data = "%02d%02d%02d%02d%02d" % (year, month, day, hours, minute)
4492 year + (2000 if year < 50 else 1900),
4499 if d.draw(booleans()):
4501 seconds = d.draw(integers(min_value=0, max_value=59))
4502 data += "%02d" % seconds
4503 dt += timedelta(seconds=seconds)
4504 if d.draw(booleans()):
4508 offset_hour = d.draw(integers(min_value=0, max_value=13))
4509 offset_minute = d.draw(integers(min_value=0, max_value=59))
4510 offset = timedelta(seconds=offset_hour * 3600 + offset_minute * 60)
4511 if d.draw(booleans()):
4517 data += "%02d%02d" % (offset_hour, offset_minute)
4518 data = data.encode("ascii")
4519 data_der = UTCTime.tag_default + len_encode(len(data)) + data
4520 obj = UTCTime().decod(data_der, ctx={"bered": True})
4521 self.assertEqual(obj, dt)
4522 self.assertEqual(obj.todatetime(), dt)
4523 self.assertEqual(obj.ber_encoded, not dered)
4524 self.assertEqual(obj.bered, not dered)
4525 self.assertEqual(obj.ber_raw, None if dered else data)
4526 self.assertEqual(obj.encode() == data_der, dered)
4531 def test_invalid_ber(self):
4572 b"0001020304+0000Z",
4581 with self.assertRaises(DecodeError):
4582 UTCTime(data, ctx={"bered": True})
4583 data = data[:8] + data[8+2:]
4584 with self.assertRaises(DecodeError):
4585 UTCTime(data, ctx={"bered": True})
4630 b"000102030405+000",
4631 b"000102030405+000Z",
4632 b"000102030405+0000Z",
4633 b"000102030405+-101",
4634 b"000102030405+01-1",
4635 b"000102030405+0060",
4636 b"000102030405+1401",
4637 b"500101000002+0003",
4639 with self.assertRaises(DecodeError):
4640 UTCTime(data, ctx={"bered": True})
4642 @given(integers(min_value=0, max_value=49))
4643 def test_pre50(self, year):
4645 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4649 @given(integers(min_value=50, max_value=99))
4650 def test_post50(self, year):
4652 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
4658 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4659 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4661 binary(min_size=1, max_size=1),
4663 min_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4664 max_size=(LEN_YYMMDDHHMMSSZ - 1) // 2,
4667 def test_junk(self, part0, part1, part2):
4668 junk = part0 + part1 + part2
4669 assume(not (set(junk) <= set(digits.encode("ascii"))))
4670 with self.assertRaises(DecodeError):
4672 UTCTime.tag_default +
4673 len_encode(len(junk)) +
4679 def tlv_value_strategy(draw):
4680 tag_num = draw(integers(min_value=1))
4681 data = draw(binary())
4682 return b"".join((tag_encode(tag_num), len_encode(len(data)), data))
4686 def any_values_strategy(draw, do_expl=False):
4687 value = draw(one_of(none(), tlv_value_strategy()))
4690 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4691 optional = draw(one_of(none(), booleans()))
4693 draw(integers(min_value=0)),
4694 draw(integers(min_value=0)),
4695 draw(integers(min_value=0)),
4697 return (value, expl, optional, _decoded)
4700 class AnyInherited(Any):
4704 class TestAny(CommonMixin, TestCase):
4707 def test_invalid_value_type(self):
4708 with self.assertRaises(InvalidValueType) as err:
4713 def test_optional(self, optional):
4714 obj = Any(optional=optional)
4715 self.assertEqual(obj.optional, optional)
4717 @given(tlv_value_strategy())
4718 def test_ready(self, value):
4720 self.assertFalse(obj.ready)
4723 pprint(obj, big_blobs=True, with_decode_path=True)
4724 with self.assertRaises(ObjNotReady) as err:
4728 self.assertTrue(obj.ready)
4731 pprint(obj, big_blobs=True, with_decode_path=True)
4734 def test_basic(self, value):
4735 integer_encoded = Integer(value).encode()
4737 Any(integer_encoded),
4738 Any(Integer(value)),
4739 Any(Any(Integer(value))),
4741 self.assertSequenceEqual(bytes(obj), integer_encoded)
4743 obj.decode(obj.encode())[0].vlen,
4744 len(integer_encoded),
4748 pprint(obj, big_blobs=True, with_decode_path=True)
4749 self.assertSequenceEqual(obj.encode(), integer_encoded)
4751 @given(tlv_value_strategy(), tlv_value_strategy())
4752 def test_comparison(self, value1, value2):
4753 for klass in (Any, AnyInherited):
4754 obj1 = klass(value1)
4755 obj2 = klass(value2)
4756 self.assertEqual(obj1 == obj2, value1 == value2)
4757 self.assertEqual(obj1 != obj2, value1 != value2)
4758 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
4760 @given(data_strategy())
4761 def test_call(self, d):
4762 for klass in (Any, AnyInherited):
4768 ) = d.draw(any_values_strategy())
4769 obj_initial = klass(
4772 optional_initial or False,
4780 ) = d.draw(any_values_strategy(do_expl=True))
4781 obj = obj_initial(value, expl, optional)
4783 value_expected = None if value is None else value
4784 self.assertEqual(obj, value_expected)
4785 self.assertEqual(obj.expl_tag, expl or expl_initial)
4786 if obj.default is None:
4787 optional = optional_initial if optional is None else optional
4788 optional = False if optional is None else optional
4789 self.assertEqual(obj.optional, optional)
4791 def test_simultaneous_impl_expl(self):
4792 # override it, as Any does not have implicit tag
4795 def test_decoded(self):
4796 # override it, as Any does not have implicit tag
4799 @given(any_values_strategy())
4800 def test_copy(self, values):
4801 for klass in (Any, AnyInherited):
4802 obj = klass(*values)
4803 for copy_func in copy_funcs:
4804 obj_copied = copy_func(obj)
4805 self.assert_copied_basic_fields(obj, obj_copied)
4806 self.assertEqual(obj._value, obj_copied._value)
4808 @given(binary().map(OctetString))
4809 def test_stripped(self, value):
4811 with self.assertRaises(NotEnoughData):
4812 obj.decode(obj.encode()[:-1])
4815 tlv_value_strategy(),
4816 integers(min_value=1).map(tag_ctxc),
4818 def test_stripped_expl(self, value, tag_expl):
4819 obj = Any(value, expl=tag_expl)
4820 with self.assertRaises(NotEnoughData):
4821 obj.decode(obj.encode()[:-1])
4824 integers(min_value=31),
4825 integers(min_value=0),
4828 def test_bad_tag(self, tag, offset, decode_path):
4829 with self.assertRaises(DecodeError) as err:
4831 tag_encode(tag)[:-1],
4833 decode_path=decode_path,
4836 self.assertEqual(err.exception.offset, offset)
4837 self.assertEqual(err.exception.decode_path, decode_path)
4840 integers(min_value=128),
4841 integers(min_value=0),
4844 def test_bad_len(self, l, offset, decode_path):
4845 with self.assertRaises(DecodeError) as err:
4847 Any.tag_default + len_encode(l)[:-1],
4849 decode_path=decode_path,
4852 self.assertEqual(err.exception.offset, offset)
4853 self.assertEqual(err.exception.decode_path, decode_path)
4855 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4857 any_values_strategy(),
4858 integers().map(lambda x: Integer(x).encode()),
4859 integers(min_value=1).map(tag_ctxc),
4860 integers(min_value=0),
4863 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
4864 for klass in (Any, AnyInherited):
4865 _, _, optional, _decoded = values
4866 obj = klass(value=value, optional=optional, _decoded=_decoded)
4869 pprint(obj, big_blobs=True, with_decode_path=True)
4870 self.assertFalse(obj.expled)
4871 tag_class, _, tag_num = tag_decode(tag_strip(value)[0])
4872 self.assertEqual(obj.tag_order, (tag_class, tag_num))
4873 obj_encoded = obj.encode()
4874 obj_expled = obj(value, expl=tag_expl)
4875 self.assertTrue(obj_expled.expled)
4876 tag_class, _, tag_num = tag_decode(tag_expl)
4877 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
4879 list(obj_expled.pps())
4880 pprint(obj_expled, big_blobs=True, with_decode_path=True)
4881 obj_expled_encoded = obj_expled.encode()
4882 ctx_copied = deepcopy(ctx_dummy)
4883 obj_decoded, tail = obj_expled.decode(
4884 obj_expled_encoded + tail_junk,
4888 self.assertDictEqual(ctx_copied, ctx_dummy)
4890 list(obj_decoded.pps())
4891 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
4892 self.assertEqual(tail, tail_junk)
4893 self.assertEqual(obj_decoded, obj_expled)
4894 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
4895 self.assertEqual(bytes(obj_decoded), bytes(obj))
4896 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4897 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4898 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4900 obj_decoded.expl_llen,
4901 len(len_encode(len(obj_encoded))),
4903 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4904 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4907 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4909 self.assertEqual(obj_decoded.expl_offset, offset)
4910 self.assertEqual(obj_decoded.tlen, 0)
4911 self.assertEqual(obj_decoded.llen, 0)
4912 self.assertEqual(obj_decoded.vlen, len(value))
4913 assert_exceeding_data(
4915 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
4920 integers(min_value=1).map(tag_ctxc),
4921 integers(min_value=0, max_value=3),
4922 integers(min_value=0),
4926 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
4927 chunk = Boolean(False, expl=expl).encode()
4929 OctetString.tag_default +
4931 b"".join([chunk] * chunks) +
4934 with self.assertRaises(LenIndefForm):
4938 decode_path=decode_path,
4940 obj, tail = Any().decode(
4943 decode_path=decode_path,
4944 ctx={"bered": True},
4946 self.assertSequenceEqual(tail, junk)
4947 self.assertEqual(obj.offset, offset)
4948 self.assertEqual(obj.tlvlen, len(encoded))
4949 self.assertTrue(obj.lenindef)
4950 self.assertFalse(obj.ber_encoded)
4951 self.assertTrue(obj.bered)
4953 self.assertTrue(obj.lenindef)
4954 self.assertFalse(obj.ber_encoded)
4955 self.assertTrue(obj.bered)
4958 pprint(obj, big_blobs=True, with_decode_path=True)
4959 with self.assertRaises(NotEnoughData) as err:
4963 decode_path=decode_path,
4964 ctx={"bered": True},
4966 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
4967 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
4969 class SeqOf(SequenceOf):
4970 schema = Boolean(expl=expl)
4972 class Seq(Sequence):
4974 ("type", ObjectIdentifier(defines=((("value",), {
4975 ObjectIdentifier("1.2.3"): SeqOf(impl=OctetString.tag_default),
4980 ("type", ObjectIdentifier("1.2.3")),
4981 ("value", Any(encoded)),
4983 seq_encoded = seq.encode()
4984 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
4985 self.assertIsNotNone(seq_decoded["value"].defined)
4987 list(seq_decoded.pps())
4988 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
4989 self.assertTrue(seq_decoded.bered)
4990 self.assertFalse(seq_decoded["type"].bered)
4991 self.assertTrue(seq_decoded["value"].bered)
4993 chunk = chunk[:-1] + b"\x01"
4994 chunks = b"".join([chunk] * (chunks + 1))
4995 encoded = OctetString.tag_default + len_encode(len(chunks)) + chunks
4997 ("type", ObjectIdentifier("1.2.3")),
4998 ("value", Any(encoded)),
5000 seq_encoded = seq.encode()
5001 seq_decoded, _ = Seq().decode(seq_encoded, ctx={"bered": True})
5002 self.assertIsNotNone(seq_decoded["value"].defined)
5004 list(seq_decoded.pps())
5005 pprint(seq_decoded, big_blobs=True, with_decode_path=True)
5006 self.assertTrue(seq_decoded.bered)
5007 self.assertFalse(seq_decoded["type"].bered)
5008 self.assertTrue(seq_decoded["value"].bered)
5012 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
5014 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
5015 tags = [{tag_type: tag_value} for tag_type, tag_value in draw(sets(
5017 tuples(just("impl"), integers(min_value=0).map(tag_encode)),
5018 tuples(just("expl"), integers(min_value=0).map(tag_ctxp)),
5020 min_size=len(names),
5021 max_size=len(names),
5024 (name, Integer(**tag_kwargs))
5025 for name, tag_kwargs in zip(names, tags)
5028 if value_required or draw(booleans()):
5029 value = draw(tuples(
5030 sampled_from([name for name, _ in schema]),
5031 integers().map(Integer),
5035 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5036 default = draw(one_of(
5038 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
5040 optional = draw(one_of(none(), booleans()))
5042 draw(integers(min_value=0)),
5043 draw(integers(min_value=0)),
5044 draw(integers(min_value=0)),
5046 return (schema, value, expl, default, optional, _decoded)
5049 class ChoiceInherited(Choice):
5053 class TestChoice(CommonMixin, TestCase):
5055 schema = (("whatever", Boolean()),)
5058 def test_schema_required(self):
5059 with assertRaisesRegex(self, ValueError, "schema must be specified"):
5062 def test_impl_forbidden(self):
5063 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
5064 Choice(impl=b"whatever")
5066 def test_invalid_value_type(self):
5067 with self.assertRaises(InvalidValueType) as err:
5068 self.base_klass(123)
5070 with self.assertRaises(ObjUnknown) as err:
5071 self.base_klass(("whenever", Boolean(False)))
5073 with self.assertRaises(InvalidValueType) as err:
5074 self.base_klass(("whatever", Integer(123)))
5078 def test_optional(self, optional):
5079 obj = self.base_klass(
5080 default=self.base_klass(("whatever", Boolean(False))),
5083 self.assertTrue(obj.optional)
5086 def test_ready(self, value):
5087 obj = self.base_klass()
5088 self.assertFalse(obj.ready)
5091 pprint(obj, big_blobs=True, with_decode_path=True)
5092 self.assertIsNone(obj["whatever"])
5093 with self.assertRaises(ObjNotReady) as err:
5096 obj["whatever"] = Boolean()
5097 self.assertFalse(obj.ready)
5100 pprint(obj, big_blobs=True, with_decode_path=True)
5101 obj["whatever"] = Boolean(value)
5102 self.assertTrue(obj.ready)
5105 pprint(obj, big_blobs=True, with_decode_path=True)
5107 @given(booleans(), booleans())
5108 def test_comparison(self, value1, value2):
5109 class WahlInherited(self.base_klass):
5111 for klass in (self.base_klass, WahlInherited):
5112 obj1 = klass(("whatever", Boolean(value1)))
5113 obj2 = klass(("whatever", Boolean(value2)))
5114 self.assertEqual(obj1 == obj2, value1 == value2)
5115 self.assertEqual(obj1 != obj2, value1 != value2)
5116 self.assertEqual(obj1 == obj2._value, value1 == value2)
5117 self.assertFalse(obj1 == obj2._value[1])
5119 @given(data_strategy())
5120 def test_call(self, d):
5121 for klass in (Choice, ChoiceInherited):
5129 ) = d.draw(choice_values_strategy())
5132 schema = schema_initial
5134 value=value_initial,
5136 default=default_initial,
5137 optional=optional_initial or False,
5138 _decoded=_decoded_initial,
5147 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
5148 obj = obj_initial(value, expl, default, optional)
5150 value_expected = default if value is None else value
5152 default_initial if value_expected is None
5155 self.assertEqual(obj.choice, value_expected[0])
5156 self.assertEqual(obj.value, int(value_expected[1]))
5157 self.assertEqual(obj.expl_tag, expl or expl_initial)
5158 default_expect = default_initial if default is None else default
5159 if default_expect is not None:
5160 self.assertEqual(obj.default.choice, default_expect[0])
5161 self.assertEqual(obj.default.value, int(default_expect[1]))
5162 if obj.default is None:
5163 optional = optional_initial if optional is None else optional
5164 optional = False if optional is None else optional
5167 self.assertEqual(obj.optional, optional)
5168 self.assertEqual(obj.specs, obj_initial.specs)
5170 def test_simultaneous_impl_expl(self):
5171 # override it, as Any does not have implicit tag
5174 def test_decoded(self):
5175 # override it, as Any does not have implicit tag
5178 @given(choice_values_strategy())
5179 def test_copy(self, values):
5180 _schema, value, expl, default, optional, _decoded = values
5182 class Wahl(self.base_klass):
5184 register_class(Wahl)
5189 optional=optional or False,
5192 for copy_func in copy_funcs:
5193 obj_copied = copy_func(obj)
5194 self.assertIsNone(obj.tag)
5195 self.assertIsNone(obj_copied.tag)
5196 # hack for assert_copied_basic_fields
5197 obj.tag = "whatever"
5198 obj_copied.tag = "whatever"
5199 self.assert_copied_basic_fields(obj, obj_copied)
5201 self.assertEqual(obj._value, obj_copied._value)
5202 self.assertEqual(obj.specs, obj_copied.specs)
5205 def test_stripped(self, value):
5206 obj = self.base_klass(("whatever", Boolean(value)))
5207 with self.assertRaises(NotEnoughData):
5208 obj.decode(obj.encode()[:-1])
5212 integers(min_value=1).map(tag_ctxc),
5214 def test_stripped_expl(self, value, tag_expl):
5215 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
5216 with self.assertRaises(NotEnoughData):
5217 obj.decode(obj.encode()[:-1])
5219 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5220 @given(data_strategy())
5221 def test_symmetric(self, d):
5222 _schema, value, _, default, optional, _decoded = d.draw(
5223 choice_values_strategy(value_required=True)
5225 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5226 offset = d.draw(integers(min_value=0))
5227 tail_junk = d.draw(binary(max_size=5))
5229 class Wahl(self.base_klass):
5239 pprint(obj, big_blobs=True, with_decode_path=True)
5240 self.assertFalse(obj.expled)
5241 self.assertEqual(obj.tag_order, obj.value.tag_order)
5242 obj_encoded = obj.encode()
5243 obj_expled = obj(value, expl=tag_expl)
5244 self.assertTrue(obj_expled.expled)
5245 tag_class, _, tag_num = tag_decode(tag_expl)
5246 self.assertEqual(obj_expled.tag_order, (tag_class, tag_num))
5248 list(obj_expled.pps())
5249 pprint(obj_expled, big_blobs=True, with_decode_path=True)
5250 obj_expled_encoded = obj_expled.encode()
5251 ctx_copied = deepcopy(ctx_dummy)
5252 obj_decoded, tail = obj_expled.decode(
5253 obj_expled_encoded + tail_junk,
5257 self.assertDictEqual(ctx_copied, ctx_dummy)
5259 list(obj_decoded.pps())
5260 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
5261 self.assertEqual(tail, tail_junk)
5262 self.assertEqual(obj_decoded, obj_expled)
5263 self.assertEqual(obj_decoded.choice, obj_expled.choice)
5264 self.assertEqual(obj_decoded.value, obj_expled.value)
5265 self.assertEqual(obj_decoded.choice, obj.choice)
5266 self.assertEqual(obj_decoded.value, obj.value)
5267 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5268 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5269 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5271 obj_decoded.expl_llen,
5272 len(len_encode(len(obj_encoded))),
5274 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5275 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5278 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5280 self.assertEqual(obj_decoded.expl_offset, offset)
5281 self.assertSequenceEqual(
5283 obj_decoded.value.fulloffset - offset:
5284 obj_decoded.value.fulloffset + obj_decoded.value.fulllen - offset
5288 assert_exceeding_data(
5290 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
5295 def test_set_get(self, value):
5298 ("erste", Boolean()),
5299 ("zweite", Integer()),
5302 with self.assertRaises(ObjUnknown) as err:
5303 obj["whatever"] = "whenever"
5304 with self.assertRaises(InvalidValueType) as err:
5305 obj["zweite"] = Boolean(False)
5306 obj["zweite"] = Integer(value)
5308 with self.assertRaises(ObjUnknown) as err:
5311 self.assertIsNone(obj["erste"])
5312 self.assertEqual(obj["zweite"], Integer(value))
5314 def test_tag_mismatch(self):
5317 ("erste", Boolean()),
5319 int_encoded = Integer(123).encode()
5320 bool_encoded = Boolean(False).encode()
5322 obj.decode(bool_encoded)
5323 with self.assertRaises(TagMismatch):
5324 obj.decode(int_encoded)
5326 def test_tag_mismatch_underlying(self):
5327 class SeqOfBoolean(SequenceOf):
5330 class SeqOfInteger(SequenceOf):
5335 ("erste", SeqOfBoolean()),
5338 int_encoded = SeqOfInteger((Integer(123),)).encode()
5339 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
5341 obj.decode(bool_encoded)
5342 with self.assertRaises(TagMismatch) as err:
5343 obj.decode(int_encoded)
5344 self.assertEqual(err.exception.decode_path, ("erste", "0"))
5348 def seq_values_strategy(draw, seq_klass, do_expl=False):
5350 if draw(booleans()):
5352 value._value = draw(dictionaries(
5355 booleans().map(Boolean),
5356 integers().map(Integer),
5360 if draw(booleans()):
5361 schema = list(draw(dictionaries(
5364 booleans().map(Boolean),
5365 integers().map(Integer),
5371 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5373 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
5375 if draw(booleans()):
5376 default = seq_klass()
5377 default._value = draw(dictionaries(
5380 booleans().map(Boolean),
5381 integers().map(Integer),
5384 optional = draw(one_of(none(), booleans()))
5386 draw(integers(min_value=0)),
5387 draw(integers(min_value=0)),
5388 draw(integers(min_value=0)),
5390 return (value, schema, impl, expl, default, optional, _decoded)
5394 def sequence_strategy(draw, seq_klass):
5395 inputs = draw(lists(
5397 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
5398 tuples(just(Integer), integers(), one_of(none(), integers())),
5403 integers(min_value=1),
5404 min_size=len(inputs),
5405 max_size=len(inputs),
5408 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5409 for tag, expled in zip(tags, draw(lists(
5411 min_size=len(inputs),
5412 max_size=len(inputs),
5416 for i, optional in enumerate(draw(lists(
5417 sampled_from(("required", "optional", "empty")),
5418 min_size=len(inputs),
5419 max_size=len(inputs),
5421 if optional in ("optional", "empty"):
5422 inits[i]["optional"] = True
5423 if optional == "empty":
5425 empties = set(empties)
5426 names = list(draw(sets(
5428 min_size=len(inputs),
5429 max_size=len(inputs),
5432 for i, (klass, value, default) in enumerate(inputs):
5433 schema.append((names[i], klass(default=default, **inits[i])))
5434 seq_name = draw(text_letters())
5435 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5438 for i, (klass, value, default) in enumerate(inputs):
5445 "default_value": None if spec.default is None else default,
5449 expect["optional"] = True
5451 expect["presented"] = True
5452 expect["value"] = value
5454 expect["optional"] = True
5455 if default is not None and default == value:
5456 expect["presented"] = False
5457 seq[name] = klass(value)
5458 expects.append(expect)
5463 def sequences_strategy(draw, seq_klass):
5464 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
5466 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
5467 for tag, expled in zip(tags, draw(lists(
5474 i for i, is_default in enumerate(draw(lists(
5480 names = list(draw(sets(
5485 seq_expectses = draw(lists(
5486 sequence_strategy(seq_klass=seq_klass),
5490 seqs = [seq for seq, _ in seq_expectses]
5492 for i, (name, seq) in enumerate(zip(names, seqs)):
5495 seq(default=(seq if i in defaulted else None), **inits[i]),
5497 seq_name = draw(text_letters())
5498 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
5501 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
5504 "expects": expects_inner,
5507 seq_outer[name] = seq_inner
5508 if seq_outer.specs[name].default is None:
5509 expect["presented"] = True
5510 expect_outers.append(expect)
5511 return seq_outer, expect_outers
5514 class SeqMixing(object):
5515 def test_invalid_value_type(self):
5516 with self.assertRaises(InvalidValueType) as err:
5517 self.base_klass(123)
5520 def test_invalid_value_type_set(self):
5521 class Seq(self.base_klass):
5522 schema = (("whatever", Boolean()),)
5524 with self.assertRaises(InvalidValueType) as err:
5525 seq["whatever"] = Integer(123)
5529 def test_optional(self, optional):
5530 obj = self.base_klass(default=self.base_klass(), optional=optional)
5531 self.assertTrue(obj.optional)
5533 @given(data_strategy())
5534 def test_ready(self, d):
5536 str(i): v for i, v in enumerate(d.draw(lists(
5543 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
5550 for name in d.draw(permutations(
5551 list(ready.keys()) + list(non_ready.keys()),
5553 schema_input.append((name, Boolean()))
5555 class Seq(self.base_klass):
5556 schema = tuple(schema_input)
5558 for name in ready.keys():
5560 seq[name] = Boolean()
5561 self.assertFalse(seq.ready)
5564 pprint(seq, big_blobs=True, with_decode_path=True)
5565 for name, value in ready.items():
5566 seq[name] = Boolean(value)
5567 self.assertFalse(seq.ready)
5570 pprint(seq, big_blobs=True, with_decode_path=True)
5571 with self.assertRaises(ObjNotReady) as err:
5574 for name, value in non_ready.items():
5575 seq[name] = Boolean(value)
5576 self.assertTrue(seq.ready)
5579 pprint(seq, big_blobs=True, with_decode_path=True)
5581 @given(data_strategy())
5582 def test_call(self, d):
5583 class SeqInherited(self.base_klass):
5585 for klass in (self.base_klass, SeqInherited):
5594 ) = d.draw(seq_values_strategy(seq_klass=klass))
5595 obj_initial = klass(
5601 optional_initial or False,
5612 ) = d.draw(seq_values_strategy(
5614 do_expl=impl_initial is None,
5616 obj = obj_initial(value, impl, expl, default, optional)
5617 value_expected = default if value is None else value
5619 default_initial if value_expected is None
5622 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
5623 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5624 self.assertEqual(obj.expl_tag, expl or expl_initial)
5626 {} if obj.default is None else obj.default._value,
5627 getattr(default_initial if default is None else default, "_value", {}),
5629 if obj.default is None:
5630 optional = optional_initial if optional is None else optional
5631 optional = False if optional is None else optional
5634 self.assertEqual(list(obj.specs.items()), schema_initial or [])
5635 self.assertEqual(obj.optional, optional)
5637 @given(data_strategy())
5638 def test_copy(self, d):
5639 class SeqInherited(self.base_klass):
5641 register_class(SeqInherited)
5642 for klass in (self.base_klass, SeqInherited):
5643 values = d.draw(seq_values_strategy(seq_klass=klass))
5644 obj = klass(*values)
5645 for copy_func in copy_funcs:
5646 obj_copied = copy_func(obj)
5647 self.assert_copied_basic_fields(obj, obj_copied)
5648 self.assertEqual(obj.specs, obj_copied.specs)
5649 self.assertEqual(obj._value, obj_copied._value)
5651 @given(data_strategy())
5652 def test_stripped(self, d):
5653 value = d.draw(integers())
5654 tag_impl = tag_encode(d.draw(integers(min_value=1)))
5656 class Seq(self.base_klass):
5658 schema = (("whatever", Integer()),)
5660 seq["whatever"] = Integer(value)
5661 with self.assertRaises(NotEnoughData):
5662 seq.decode(seq.encode()[:-1])
5664 @given(data_strategy())
5665 def test_stripped_expl(self, d):
5666 value = d.draw(integers())
5667 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
5669 class Seq(self.base_klass):
5671 schema = (("whatever", Integer()),)
5673 seq["whatever"] = Integer(value)
5674 with self.assertRaises(NotEnoughData):
5675 seq.decode(seq.encode()[:-1])
5677 @given(integers(min_value=3), binary(min_size=2))
5678 def test_non_tag_mismatch_raised(self, junk_tag_num, junk):
5679 junk = tag_encode(junk_tag_num) + junk
5681 _, _, len_encoded = tag_strip(memoryview(junk))
5682 len_decode(len_encoded)
5688 class Seq(self.base_klass):
5690 ("whatever", Integer()),
5692 ("whenever", Integer()),
5695 seq["whatever"] = Integer(123)
5696 seq["junk"] = Any(junk)
5697 seq["whenever"] = Integer(123)
5698 with self.assertRaises(DecodeError):
5699 seq.decode(seq.encode())
5702 integers(min_value=31),
5703 integers(min_value=0),
5706 def test_bad_tag(self, tag, offset, decode_path):
5707 with self.assertRaises(DecodeError) as err:
5708 self.base_klass().decode(
5709 tag_encode(tag)[:-1],
5711 decode_path=decode_path,
5714 self.assertEqual(err.exception.offset, offset)
5715 self.assertEqual(err.exception.decode_path, decode_path)
5718 integers(min_value=128),
5719 integers(min_value=0),
5722 def test_bad_len(self, l, offset, decode_path):
5723 with self.assertRaises(DecodeError) as err:
5724 self.base_klass().decode(
5725 self.base_klass.tag_default + len_encode(l)[:-1],
5727 decode_path=decode_path,
5730 self.assertEqual(err.exception.offset, offset)
5731 self.assertEqual(err.exception.decode_path, decode_path)
5733 def _assert_expects(self, seq, expects):
5734 for expect in expects:
5736 seq.specs[expect["name"]].optional,
5739 if expect["default_value"] is not None:
5741 seq.specs[expect["name"]].default,
5742 expect["default_value"],
5744 if expect["presented"]:
5745 self.assertIn(expect["name"], seq)
5746 self.assertEqual(seq[expect["name"]], expect["value"])
5748 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5749 @given(data_strategy())
5750 def test_symmetric(self, d):
5751 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
5752 tail_junk = d.draw(binary(max_size=5))
5753 self.assertTrue(seq.ready)
5754 self.assertFalse(seq.decoded)
5755 self._assert_expects(seq, expects)
5758 pprint(seq, big_blobs=True, with_decode_path=True)
5759 self.assertTrue(seq.ready)
5760 seq_encoded = seq.encode()
5761 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
5762 self.assertFalse(seq_decoded.lenindef)
5763 self.assertFalse(seq_decoded.ber_encoded)
5764 self.assertFalse(seq_decoded.bered)
5766 t, _, lv = tag_strip(seq_encoded)
5767 _, _, v = len_decode(lv)
5768 seq_encoded_lenindef = t + LENINDEF + v + EOC
5769 with self.assertRaises(DecodeError):
5770 seq.decode(seq_encoded_lenindef)
5771 ctx_copied = deepcopy(ctx_dummy)
5772 ctx_copied["bered"] = True
5773 seq_decoded_lenindef, tail_lenindef = seq.decode(
5774 seq_encoded_lenindef + tail_junk,
5777 del ctx_copied["bered"]
5778 self.assertDictEqual(ctx_copied, ctx_dummy)
5779 self.assertTrue(seq_decoded_lenindef.lenindef)
5780 self.assertTrue(seq_decoded_lenindef.bered)
5781 seq_decoded_lenindef = copy(seq_decoded_lenindef)
5782 self.assertTrue(seq_decoded_lenindef.lenindef)
5783 self.assertTrue(seq_decoded_lenindef.bered)
5784 with self.assertRaises(DecodeError):
5785 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
5786 with self.assertRaises(DecodeError):
5787 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
5788 repr(seq_decoded_lenindef)
5789 list(seq_decoded_lenindef.pps())
5790 pprint(seq_decoded_lenindef, big_blobs=True, with_decode_path=True)
5791 self.assertTrue(seq_decoded_lenindef.ready)
5793 for decoded, decoded_tail, encoded in (
5794 (seq_decoded, tail, seq_encoded),
5795 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
5797 self.assertEqual(decoded_tail, tail_junk)
5798 self._assert_expects(decoded, expects)
5799 self.assertEqual(seq, decoded)
5800 self.assertEqual(decoded.encode(), seq_encoded)
5801 self.assertEqual(decoded.tlvlen, len(encoded))
5802 for expect in expects:
5803 if not expect["presented"]:
5804 self.assertNotIn(expect["name"], decoded)
5806 self.assertIn(expect["name"], decoded)
5807 obj = decoded[expect["name"]]
5808 self.assertTrue(obj.decoded)
5809 offset = obj.expl_offset if obj.expled else obj.offset
5810 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5811 self.assertSequenceEqual(
5812 seq_encoded[offset:offset + tlvlen],
5816 assert_exceeding_data(
5818 lambda: seq.decod(seq_encoded_lenindef + tail_junk, ctx={"bered": True}),
5822 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5823 @given(data_strategy())
5824 def test_symmetric_with_seq(self, d):
5825 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
5826 self.assertTrue(seq.ready)
5827 seq_encoded = seq.encode()
5828 seq_decoded, tail = seq.decode(seq_encoded)
5829 self.assertEqual(tail, b"")
5830 self.assertTrue(seq.ready)
5831 self.assertEqual(seq, seq_decoded)
5832 self.assertEqual(seq_decoded.encode(), seq_encoded)
5833 for expect_outer in expect_outers:
5834 if not expect_outer["presented"]:
5835 self.assertNotIn(expect_outer["name"], seq_decoded)
5837 self.assertIn(expect_outer["name"], seq_decoded)
5838 obj = seq_decoded[expect_outer["name"]]
5839 self.assertTrue(obj.decoded)
5840 offset = obj.expl_offset if obj.expled else obj.offset
5841 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
5842 self.assertSequenceEqual(
5843 seq_encoded[offset:offset + tlvlen],
5846 self._assert_expects(obj, expect_outer["expects"])
5848 @given(data_strategy())
5849 def test_default_disappears(self, d):
5850 _schema = list(d.draw(dictionaries(
5852 sets(integers(), min_size=2, max_size=2),
5856 class Seq(self.base_klass):
5858 (n, Integer(default=d))
5859 for n, (_, d) in _schema
5862 for name, (value, _) in _schema:
5863 seq[name] = Integer(value)
5864 self.assertEqual(len(seq._value), len(_schema))
5865 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
5866 self.assertGreater(len(seq.encode()), len(empty_seq))
5867 for name, (_, default) in _schema:
5868 seq[name] = Integer(default)
5869 self.assertEqual(len(seq._value), 0)
5870 self.assertSequenceEqual(seq.encode(), empty_seq)
5872 @given(data_strategy())
5873 def test_encoded_default_not_accepted(self, d):
5874 _schema = list(d.draw(dictionaries(
5879 tags = [tag_encode(tag) for tag in d.draw(sets(
5880 integers(min_value=1),
5881 min_size=len(_schema),
5882 max_size=len(_schema),
5885 class SeqWithoutDefault(self.base_klass):
5887 (n, Integer(impl=t))
5888 for (n, _), t in zip(_schema, tags)
5890 seq_without_default = SeqWithoutDefault()
5891 for name, value in _schema:
5892 seq_without_default[name] = Integer(value)
5893 seq_encoded = seq_without_default.encode()
5895 class SeqWithDefault(self.base_klass):
5897 (n, Integer(default=v, impl=t))
5898 for (n, v), t in zip(_schema, tags)
5900 seq_with_default = SeqWithDefault()
5901 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5902 seq_with_default.decode(seq_encoded)
5903 for ctx in ({"bered": True}, {"allow_default_values": True}):
5904 seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
5905 self.assertTrue(seq_decoded.ber_encoded)
5906 self.assertTrue(seq_decoded.bered)
5907 seq_decoded = copy(seq_decoded)
5908 self.assertTrue(seq_decoded.ber_encoded)
5909 self.assertTrue(seq_decoded.bered)
5910 for name, value in _schema:
5911 self.assertEqual(seq_decoded[name], seq_with_default[name])
5912 self.assertEqual(seq_decoded[name], value)
5914 @given(data_strategy())
5915 def test_missing_from_spec(self, d):
5916 names = list(d.draw(sets(text_letters(), min_size=2)))
5917 tags = [tag_encode(tag) for tag in d.draw(sets(
5918 integers(min_value=1),
5919 min_size=len(names),
5920 max_size=len(names),
5922 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
5924 class SeqFull(self.base_klass):
5925 schema = [(n, Integer(impl=t)) for n, t in names_tags]
5926 seq_full = SeqFull()
5927 for i, name in enumerate(names):
5928 seq_full[name] = Integer(i)
5929 seq_encoded = seq_full.encode()
5930 altered = names_tags[:-2] + names_tags[-1:]
5932 class SeqMissing(self.base_klass):
5933 schema = [(n, Integer(impl=t)) for n, t in altered]
5934 seq_missing = SeqMissing()
5935 with self.assertRaises(TagMismatch):
5936 seq_missing.decode(seq_encoded)
5938 def test_bered(self):
5939 class Seq(self.base_klass):
5940 schema = (("underlying", Boolean()),)
5941 encoded = Boolean.tag_default + len_encode(1) + b"\x01"
5942 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5943 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5944 self.assertFalse(decoded.ber_encoded)
5945 self.assertFalse(decoded.lenindef)
5946 self.assertTrue(decoded.bered)
5947 decoded = copy(decoded)
5948 self.assertFalse(decoded.ber_encoded)
5949 self.assertFalse(decoded.lenindef)
5950 self.assertTrue(decoded.bered)
5952 class Seq(self.base_klass):
5953 schema = (("underlying", OctetString()),)
5955 tag_encode(form=TagFormConstructed, num=4) +
5957 OctetString(b"whatever").encode() +
5960 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
5961 with self.assertRaises(DecodeError):
5962 Seq().decode(encoded)
5963 decoded, _ = Seq().decode(encoded, ctx={"bered": True})
5964 self.assertFalse(decoded.ber_encoded)
5965 self.assertFalse(decoded.lenindef)
5966 self.assertTrue(decoded.bered)
5967 decoded = copy(decoded)
5968 self.assertFalse(decoded.ber_encoded)
5969 self.assertFalse(decoded.lenindef)
5970 self.assertTrue(decoded.bered)
5973 class TestSequence(SeqMixing, CommonMixin, TestCase):
5974 base_klass = Sequence
5980 def test_remaining(self, value, junk):
5981 class Seq(Sequence):
5983 ("whatever", Integer()),
5985 int_encoded = Integer(value).encode()
5987 Sequence.tag_default,
5988 len_encode(len(int_encoded + junk)),
5991 with assertRaisesRegex(self, DecodeError, "remaining"):
5992 Seq().decode(junked)
5994 @given(sets(text_letters(), min_size=2))
5995 def test_obj_unknown(self, names):
5996 missing = names.pop()
5998 class Seq(Sequence):
5999 schema = [(n, Boolean()) for n in names]
6001 with self.assertRaises(ObjUnknown) as err:
6004 with self.assertRaises(ObjUnknown) as err:
6005 seq[missing] = Boolean()
6008 def test_x690_vector(self):
6009 class Seq(Sequence):
6011 ("name", IA5String()),
6014 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
6015 self.assertEqual(seq["name"], "Smith")
6016 self.assertEqual(seq["ok"], True)
6019 class TestSet(SeqMixing, CommonMixin, TestCase):
6022 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6023 @given(data_strategy())
6024 def test_sorted(self, d):
6025 class DummySeq(Sequence):
6026 schema = (("null", Null()),)
6028 tag_nums = d.draw(sets(integers(min_value=1), min_size=1, max_size=50))
6029 _, _, dummy_seq_tag_num = tag_decode(DummySeq.tag_default)
6030 assume(any(i > dummy_seq_tag_num for i in tag_nums))
6031 tag_nums -= set([dummy_seq_tag_num])
6032 _schema = [(str(i), OctetString(impl=tag_encode(i))) for i in tag_nums]
6033 _schema.append(("seq", DummySeq()))
6036 schema = d.draw(permutations(_schema))
6038 for name, _ in _schema:
6040 seq[name] = OctetString(name.encode("ascii"))
6041 seq["seq"] = DummySeq((("null", Null()),))
6043 seq_encoded = seq.encode()
6044 seq_decoded, _ = seq.decode(seq_encoded)
6045 seq_encoded_expected = []
6046 for tag_num in sorted(tag_nums | set([dummy_seq_tag_num])):
6047 if tag_num == dummy_seq_tag_num:
6048 seq_encoded_expected.append(seq["seq"].encode())
6050 seq_encoded_expected.append(seq[str(tag_num)].encode())
6051 self.assertSequenceEqual(
6052 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6053 b"".join(seq_encoded_expected),
6056 encoded = b"".join(seq[str(i)].encode() for i in tag_nums)
6057 encoded += seq["seq"].encode()
6058 seq_encoded = b"".join((
6060 len_encode(len(encoded)),
6063 with assertRaisesRegex(self, DecodeError, "unordered SET"):
6064 seq.decode(seq_encoded)
6065 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6066 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6067 self.assertTrue(seq_decoded.ber_encoded)
6068 self.assertTrue(seq_decoded.bered)
6069 seq_decoded = copy(seq_decoded)
6070 self.assertTrue(seq_decoded.ber_encoded)
6071 self.assertTrue(seq_decoded.bered)
6073 def test_same_value_twice(self):
6076 ("bool", Boolean()),
6080 encoded = b"".join((
6081 Integer(123).encode(),
6082 Integer(234).encode(),
6083 Boolean(True).encode(),
6085 encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
6086 with self.assertRaises(TagMismatch):
6087 Seq().decod(encoded, ctx={"allow_unordered_set": True})
6091 def seqof_values_strategy(draw, schema=None, do_expl=False):
6093 schema = draw(sampled_from((Boolean(), Integer())))
6094 bound_min, bound_max = sorted(draw(sets(
6095 integers(min_value=0, max_value=10),
6099 if isinstance(schema, Boolean):
6100 values_generator = booleans().map(Boolean)
6101 elif isinstance(schema, Integer):
6102 values_generator = integers().map(Integer)
6103 values_generator = lists(
6108 values = draw(one_of(none(), values_generator))
6112 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6114 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
6115 default = draw(one_of(none(), values_generator))
6116 optional = draw(one_of(none(), booleans()))
6118 draw(integers(min_value=0)),
6119 draw(integers(min_value=0)),
6120 draw(integers(min_value=0)),
6125 (bound_min, bound_max),
6134 class SeqOfMixing(object):
6135 def test_invalid_value_type(self):
6136 with self.assertRaises(InvalidValueType) as err:
6137 self.base_klass(123)
6140 def test_invalid_values_type(self):
6141 class SeqOf(self.base_klass):
6143 with self.assertRaises(InvalidValueType) as err:
6144 SeqOf([Integer(123), Boolean(False), Integer(234)])
6147 def test_schema_required(self):
6148 with assertRaisesRegex(self, ValueError, "schema must be specified"):
6149 self.base_klass.__mro__[1]()
6151 @given(booleans(), booleans(), binary(min_size=1), binary(min_size=1))
6152 def test_comparison(self, value1, value2, tag1, tag2):
6153 class SeqOf(self.base_klass):
6155 obj1 = SeqOf([Boolean(value1)])
6156 obj2 = SeqOf([Boolean(value2)])
6157 self.assertEqual(obj1 == obj2, value1 == value2)
6158 self.assertEqual(obj1 != obj2, value1 != value2)
6159 self.assertEqual(obj1 == list(obj2), value1 == value2)
6160 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
6161 obj1 = SeqOf([Boolean(value1)], impl=tag1)
6162 obj2 = SeqOf([Boolean(value1)], impl=tag2)
6163 self.assertEqual(obj1 == obj2, tag1 == tag2)
6164 self.assertEqual(obj1 != obj2, tag1 != tag2)
6166 @given(lists(booleans()))
6167 def test_iter(self, values):
6168 class SeqOf(self.base_klass):
6170 obj = SeqOf([Boolean(value) for value in values])
6171 self.assertEqual(len(obj), len(values))
6172 for i, value in enumerate(obj):
6173 self.assertEqual(value, values[i])
6175 @given(data_strategy())
6176 def test_ready(self, d):
6177 ready = [Integer(v) for v in d.draw(lists(
6184 range(d.draw(integers(min_value=1, max_value=5)))
6187 class SeqOf(self.base_klass):
6189 values = d.draw(permutations(ready + non_ready))
6191 for value in values:
6193 self.assertFalse(seqof.ready)
6196 pprint(seqof, big_blobs=True, with_decode_path=True)
6197 with self.assertRaises(ObjNotReady) as err:
6200 for i, value in enumerate(values):
6201 self.assertEqual(seqof[i], value)
6202 if not seqof[i].ready:
6203 seqof[i] = Integer(i)
6204 self.assertTrue(seqof.ready)
6207 pprint(seqof, big_blobs=True, with_decode_path=True)
6209 def test_spec_mismatch(self):
6210 class SeqOf(self.base_klass):
6213 seqof.append(Integer(123))
6214 with self.assertRaises(ValueError):
6215 seqof.append(Boolean(False))
6216 with self.assertRaises(ValueError):
6217 seqof[0] = Boolean(False)
6219 @given(data_strategy())
6220 def test_bounds_satisfied(self, d):
6221 class SeqOf(self.base_klass):
6223 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
6224 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6225 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
6226 SeqOf(value=value, bounds=(bound_min, bound_max))
6228 @given(data_strategy())
6229 def test_bounds_unsatisfied(self, d):
6230 class SeqOf(self.base_klass):
6232 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
6233 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
6234 value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
6235 with self.assertRaises(BoundsError) as err:
6236 SeqOf(value=value, bounds=(bound_min, bound_max))
6238 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6239 SeqOf(bounds=(bound_min, bound_max)).decode(
6240 SeqOf(value).encode()
6243 value = [Boolean(True)] * d.draw(integers(
6244 min_value=bound_max + 1,
6245 max_value=bound_max + 10,
6247 with self.assertRaises(BoundsError) as err:
6248 SeqOf(value=value, bounds=(bound_min, bound_max))
6250 with assertRaisesRegex(self, DecodeError, "bounds") as err:
6251 SeqOf(bounds=(bound_min, bound_max)).decode(
6252 SeqOf(value).encode()
6256 @given(integers(min_value=1, max_value=10))
6257 def test_out_of_bounds(self, bound_max):
6258 class SeqOf(self.base_klass):
6260 bounds = (0, bound_max)
6262 for _ in range(bound_max):
6263 seqof.append(Integer(123))
6264 with self.assertRaises(BoundsError):
6265 seqof.append(Integer(123))
6267 @given(data_strategy())
6268 def test_call(self, d):
6278 ) = d.draw(seqof_values_strategy())
6280 class SeqOf(self.base_klass):
6281 schema = schema_initial
6282 obj_initial = SeqOf(
6283 value=value_initial,
6284 bounds=bounds_initial,
6287 default=default_initial,
6288 optional=optional_initial or False,
6289 _decoded=_decoded_initial,
6300 ) = d.draw(seqof_values_strategy(
6301 schema=schema_initial,
6302 do_expl=impl_initial is None,
6304 if (default is None) and (obj_initial.default is not None):
6307 (bounds is None) and
6308 (value is not None) and
6309 (bounds_initial is not None) and
6310 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
6314 (bounds is None) and
6315 (default is not None) and
6316 (bounds_initial is not None) and
6317 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
6329 value_expected = default if value is None else value
6331 default_initial if value_expected is None
6334 value_expected = () if value_expected is None else value_expected
6335 self.assertEqual(obj, value_expected)
6336 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
6337 self.assertEqual(obj.expl_tag, expl or expl_initial)
6340 default_initial if default is None else default,
6342 if obj.default is None:
6343 optional = optional_initial if optional is None else optional
6344 optional = False if optional is None else optional
6347 self.assertEqual(obj.optional, optional)
6349 (obj._bound_min, obj._bound_max),
6350 bounds or bounds_initial or (0, float("+inf")),
6353 @given(seqof_values_strategy())
6354 def test_copy(self, values):
6355 _schema, value, bounds, impl, expl, default, optional, _decoded = values
6357 class SeqOf(self.base_klass):
6359 register_class(SeqOf)
6366 optional=optional or False,
6369 for copy_func in copy_funcs:
6370 obj_copied = copy_func(obj)
6371 self.assert_copied_basic_fields(obj, obj_copied)
6372 self.assertEqual(obj._bound_min, obj_copied._bound_min)
6373 self.assertEqual(obj._bound_max, obj_copied._bound_max)
6374 self.assertEqual(obj._value, obj_copied._value)
6378 integers(min_value=1).map(tag_encode),
6380 def test_stripped(self, values, tag_impl):
6381 class SeqOf(self.base_klass):
6382 schema = OctetString()
6383 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
6384 with self.assertRaises(NotEnoughData):
6385 obj.decode(obj.encode()[:-1])
6389 integers(min_value=1).map(tag_ctxc),
6391 def test_stripped_expl(self, values, tag_expl):
6392 class SeqOf(self.base_klass):
6393 schema = OctetString()
6394 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
6395 with self.assertRaises(NotEnoughData):
6396 obj.decode(obj.encode()[:-1])
6399 integers(min_value=31),
6400 integers(min_value=0),
6403 def test_bad_tag(self, tag, offset, decode_path):
6404 with self.assertRaises(DecodeError) as err:
6405 self.base_klass().decode(
6406 tag_encode(tag)[:-1],
6408 decode_path=decode_path,
6411 self.assertEqual(err.exception.offset, offset)
6412 self.assertEqual(err.exception.decode_path, decode_path)
6415 integers(min_value=128),
6416 integers(min_value=0),
6419 def test_bad_len(self, l, offset, decode_path):
6420 with self.assertRaises(DecodeError) as err:
6421 self.base_klass().decode(
6422 self.base_klass.tag_default + len_encode(l)[:-1],
6424 decode_path=decode_path,
6427 self.assertEqual(err.exception.offset, offset)
6428 self.assertEqual(err.exception.decode_path, decode_path)
6430 @given(binary(min_size=1))
6431 def test_tag_mismatch(self, impl):
6432 assume(impl != self.base_klass.tag_default)
6433 with self.assertRaises(TagMismatch):
6434 self.base_klass(impl=impl).decode(self.base_klass().encode())
6436 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6438 seqof_values_strategy(schema=Integer()),
6439 lists(integers().map(Integer)),
6440 integers(min_value=1).map(tag_ctxc),
6441 integers(min_value=0),
6444 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
6445 _, _, _, _, _, default, optional, _decoded = values
6447 class SeqOf(self.base_klass):
6457 pprint(obj, big_blobs=True, with_decode_path=True)
6458 self.assertFalse(obj.expled)
6459 obj_encoded = obj.encode()
6460 obj_expled = obj(value, expl=tag_expl)
6461 self.assertTrue(obj_expled.expled)
6463 list(obj_expled.pps())
6464 pprint(obj_expled, big_blobs=True, with_decode_path=True)
6465 obj_expled_encoded = obj_expled.encode()
6466 ctx_copied = deepcopy(ctx_dummy)
6467 obj_decoded, tail = obj_expled.decode(
6468 obj_expled_encoded + tail_junk,
6472 self.assertDictEqual(ctx_copied, ctx_dummy)
6474 list(obj_decoded.pps())
6475 pprint(obj_decoded, big_blobs=True, with_decode_path=True)
6476 self.assertEqual(tail, tail_junk)
6477 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
6478 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
6479 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
6480 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
6482 obj_decoded.expl_llen,
6483 len(len_encode(len(obj_encoded))),
6485 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
6486 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
6489 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
6491 self.assertEqual(obj_decoded.expl_offset, offset)
6492 for obj_inner in obj_decoded:
6493 self.assertIn(obj_inner, obj_decoded)
6494 self.assertSequenceEqual(
6497 obj_inner.offset - offset:
6498 obj_inner.offset + obj_inner.tlvlen - offset
6502 t, _, lv = tag_strip(obj_encoded)
6503 _, _, v = len_decode(lv)
6504 obj_encoded_lenindef = t + LENINDEF + v + EOC
6505 with self.assertRaises(DecodeError):
6506 obj.decode(obj_encoded_lenindef)
6507 obj_decoded_lenindef, tail_lenindef = obj.decode(
6508 obj_encoded_lenindef + tail_junk,
6509 ctx={"bered": True},
6511 self.assertTrue(obj_decoded_lenindef.lenindef)
6512 self.assertTrue(obj_decoded_lenindef.bered)
6513 obj_decoded_lenindef = copy(obj_decoded_lenindef)
6514 self.assertTrue(obj_decoded_lenindef.lenindef)
6515 self.assertTrue(obj_decoded_lenindef.bered)
6516 repr(obj_decoded_lenindef)
6517 list(obj_decoded_lenindef.pps())
6518 pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
6519 self.assertEqual(tail_lenindef, tail_junk)
6520 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
6521 with self.assertRaises(DecodeError):
6522 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
6523 with self.assertRaises(DecodeError):
6524 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
6526 assert_exceeding_data(
6528 lambda: obj_expled.decod(obj_expled_encoded + tail_junk),
6532 def test_bered(self):
6533 class SeqOf(self.base_klass):
6535 encoded = Boolean(False).encode()
6536 encoded += Boolean.tag_default + len_encode(1) + b"\x01"
6537 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6538 with self.assertRaises(DecodeError):
6539 SeqOf().decode(encoded)
6540 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6541 self.assertFalse(decoded.ber_encoded)
6542 self.assertFalse(decoded.lenindef)
6543 self.assertTrue(decoded.bered)
6544 decoded = copy(decoded)
6545 self.assertFalse(decoded.ber_encoded)
6546 self.assertFalse(decoded.lenindef)
6547 self.assertTrue(decoded.bered)
6549 class SeqOf(self.base_klass):
6550 schema = OctetString()
6551 encoded = OctetString(b"whatever").encode()
6553 tag_encode(form=TagFormConstructed, num=4) +
6555 OctetString(b"whatever").encode() +
6558 encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
6559 with self.assertRaises(DecodeError):
6560 SeqOf().decode(encoded)
6561 decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
6562 self.assertFalse(decoded.ber_encoded)
6563 self.assertFalse(decoded.lenindef)
6564 self.assertTrue(decoded.bered)
6565 decoded = copy(decoded)
6566 self.assertFalse(decoded.ber_encoded)
6567 self.assertFalse(decoded.lenindef)
6568 self.assertTrue(decoded.bered)
6571 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
6572 class SeqOf(SequenceOf):
6576 def _test_symmetric_compare_objs(self, obj1, obj2):
6577 self.assertEqual(obj1, obj2)
6578 self.assertSequenceEqual(list(obj1), list(obj2))
6581 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
6586 def _test_symmetric_compare_objs(self, obj1, obj2):
6587 self.assertSetEqual(
6588 set(int(v) for v in obj1),
6589 set(int(v) for v in obj2),
6592 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6593 @given(data_strategy())
6594 def test_sorted(self, d):
6595 values = [OctetString(v) for v in d.draw(lists(binary()))]
6598 schema = OctetString()
6600 seq_encoded = seq.encode()
6601 seq_decoded, _ = seq.decode(seq_encoded)
6602 self.assertSequenceEqual(
6603 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
6604 b"".join(sorted([v.encode() for v in values])),
6607 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
6608 @given(data_strategy())
6609 def test_unsorted(self, d):
6610 values = [OctetString(v).encode() for v in d.draw(sets(
6611 binary(min_size=1, max_size=5),
6615 values = d.draw(permutations(values))
6616 assume(values != sorted(values))
6617 encoded = b"".join(values)
6618 seq_encoded = b"".join((
6620 len_encode(len(encoded)),
6625 schema = OctetString()
6627 with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
6628 seq.decode(seq_encoded)
6630 for ctx in ({"bered": True}, {"allow_unordered_set": True}):
6631 seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
6632 self.assertTrue(seq_decoded.ber_encoded)
6633 self.assertTrue(seq_decoded.bered)
6634 seq_decoded = copy(seq_decoded)
6635 self.assertTrue(seq_decoded.ber_encoded)
6636 self.assertTrue(seq_decoded.bered)
6637 self.assertSequenceEqual(
6638 [obj.encode() for obj in seq_decoded],
6643 class TestGoMarshalVectors(TestCase):
6645 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
6646 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
6647 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
6648 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
6649 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
6651 class Seq(Sequence):
6653 ("erste", Integer()),
6654 ("zweite", Integer(optional=True))
6657 seq["erste"] = Integer(64)
6658 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6659 seq["erste"] = Integer(0x123456)
6660 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
6661 seq["erste"] = Integer(64)
6662 seq["zweite"] = Integer(65)
6663 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
6665 class NestedSeq(Sequence):
6669 seq["erste"] = Integer(127)
6670 seq["zweite"] = None
6671 nested = NestedSeq()
6672 nested["nest"] = seq
6673 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
6675 self.assertSequenceEqual(
6676 OctetString(b"\x01\x02\x03").encode(),
6677 hexdec("0403010203"),
6680 class Seq(Sequence):
6682 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
6685 seq["erste"] = Integer(64)
6686 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
6688 class Seq(Sequence):
6690 ("erste", Integer(expl=tag_ctxc(5))),
6693 seq["erste"] = Integer(64)
6694 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
6696 class Seq(Sequence):
6699 impl=tag_encode(0, klass=TagClassContext),
6704 seq["erste"] = Null()
6705 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
6707 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6709 self.assertSequenceEqual(
6710 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
6711 hexdec("170d3730303130313030303030305a"),
6713 self.assertSequenceEqual(
6714 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
6715 hexdec("170d3039313131353232353631365a"),
6717 self.assertSequenceEqual(
6718 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
6719 hexdec("180f32313030303430353132303130315a"),
6722 class Seq(Sequence):
6724 ("erste", GeneralizedTime()),
6727 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
6728 self.assertSequenceEqual(
6730 hexdec("3011180f32303039313131353232353631365a"),
6733 self.assertSequenceEqual(
6734 BitString((1, b"\x80")).encode(),
6737 self.assertSequenceEqual(
6738 BitString((12, b"\x81\xF0")).encode(),
6739 hexdec("03030481f0"),
6742 self.assertSequenceEqual(
6743 ObjectIdentifier("1.2.3.4").encode(),
6744 hexdec("06032a0304"),
6746 self.assertSequenceEqual(
6747 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
6748 hexdec("06092a864888932d010105"),
6750 self.assertSequenceEqual(
6751 ObjectIdentifier("2.100.3").encode(),
6752 hexdec("0603813403"),
6755 self.assertSequenceEqual(
6756 PrintableString("test").encode(),
6757 hexdec("130474657374"),
6759 self.assertSequenceEqual(
6760 PrintableString("x" * 127).encode(),
6761 hexdec("137F" + "78" * 127),
6763 self.assertSequenceEqual(
6764 PrintableString("x" * 128).encode(),
6765 hexdec("138180" + "78" * 128),
6767 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
6769 class Seq(Sequence):
6771 ("erste", IA5String()),
6774 seq["erste"] = IA5String("test")
6775 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
6777 class Seq(Sequence):
6779 ("erste", PrintableString()),
6782 seq["erste"] = PrintableString("test")
6783 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
6784 # Asterisk is actually not allowable
6785 PrintableString._allowable_chars |= set(b"*")
6786 seq["erste"] = PrintableString("test*")
6787 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
6788 PrintableString._allowable_chars -= set(b"*")
6790 class Seq(Sequence):
6792 ("erste", Any(optional=True)),
6793 ("zweite", Integer()),
6796 seq["zweite"] = Integer(64)
6797 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
6802 seq.append(Integer(10))
6803 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
6805 class _SeqOf(SequenceOf):
6806 schema = PrintableString()
6808 class SeqOf(SequenceOf):
6811 _seqof.append(PrintableString("1"))
6813 seqof.append(_seqof)
6814 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
6816 class Seq(Sequence):
6818 ("erste", Integer(default=1)),
6821 seq["erste"] = Integer(0)
6822 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
6823 seq["erste"] = Integer(1)
6824 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
6825 seq["erste"] = Integer(2)
6826 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
6829 class TestPP(TestCase):
6830 @given(data_strategy())
6831 def test_oid_printing(self, d):
6833 str(ObjectIdentifier(k)): v * 2
6834 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
6836 chosen = d.draw(sampled_from(sorted(oids)))
6837 chosen_id = oids[chosen]
6838 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
6839 self.assertNotIn(chosen_id, pp_console_row(pp))
6842 pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
6846 class TestAutoAddSlots(TestCase):
6848 class Inher(Integer):
6851 with self.assertRaises(AttributeError):
6853 inher.unexistent = "whatever"
6856 class TestOIDDefines(TestCase):
6857 @given(data_strategy())
6858 def runTest(self, d):
6859 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
6860 value_name_chosen = d.draw(sampled_from(value_names))
6862 ObjectIdentifier(oid)
6863 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
6865 oid_chosen = d.draw(sampled_from(oids))
6866 values = d.draw(lists(
6868 min_size=len(value_names),
6869 max_size=len(value_names),
6871 for definable_class in (Any, OctetString, BitString):
6873 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
6874 oid: Integer() for oid in oids[:-1]
6877 for i, value_name in enumerate(value_names):
6878 _schema.append((value_name, definable_class(expl=tag_ctxp(i))))
6880 class Seq(Sequence):
6883 for value_name, value in zip(value_names, values):
6884 seq[value_name] = definable_class(Integer(value).encode())
6885 seq["type"] = oid_chosen
6886 seq, _ = Seq().decode(seq.encode())
6887 for value_name in value_names:
6888 if value_name == value_name_chosen:
6890 self.assertIsNone(seq[value_name].defined)
6891 if value_name_chosen in oids[:-1]:
6892 self.assertIsNotNone(seq[value_name_chosen].defined)
6893 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
6894 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
6897 pprint(seq, big_blobs=True, with_decode_path=True)
6900 class TestDefinesByPath(TestCase):
6901 def test_generated(self):
6902 class Seq(Sequence):
6904 ("type", ObjectIdentifier()),
6905 ("value", OctetString(expl=tag_ctxc(123))),
6908 class SeqInner(Sequence):
6910 ("typeInner", ObjectIdentifier()),
6911 ("valueInner", Any()),
6914 class PairValue(SetOf):
6917 class Pair(Sequence):
6919 ("type", ObjectIdentifier()),
6920 ("value", PairValue()),
6923 class Pairs(SequenceOf):
6930 type_octet_stringed,
6932 ObjectIdentifier(oid)
6933 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
6935 seq_integered = Seq()
6936 seq_integered["type"] = type_integered
6937 seq_integered["value"] = OctetString(Integer(123).encode())
6938 seq_integered_raw = seq_integered.encode()
6942 (type_octet_stringed, OctetString(b"whatever")),
6943 (type_integered, Integer(123)),
6944 (type_octet_stringed, OctetString(b"whenever")),
6945 (type_integered, Integer(234)),
6947 for t, v in pairs_input:
6950 ("value", PairValue((Any(v),))),
6952 seq_inner = SeqInner()
6953 seq_inner["typeInner"] = type_innered
6954 seq_inner["valueInner"] = Any(pairs)
6955 seq_sequenced = Seq()
6956 seq_sequenced["type"] = type_sequenced
6957 seq_sequenced["value"] = OctetString(seq_inner.encode())
6958 seq_sequenced_raw = seq_sequenced.encode()
6960 list(seq_sequenced.pps())
6961 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
6963 defines_by_path = []
6964 ctx_copied = deepcopy(ctx_dummy)
6965 seq_integered, _ = Seq().decode(
6969 self.assertDictEqual(ctx_copied, ctx_dummy)
6970 self.assertIsNone(seq_integered["value"].defined)
6971 defines_by_path.append(
6972 (("type",), ((("value",), {
6973 type_integered: Integer(),
6974 type_sequenced: SeqInner(),
6977 ctx_copied["defines_by_path"] = defines_by_path
6978 seq_integered, _ = Seq().decode(
6982 del ctx_copied["defines_by_path"]
6983 self.assertDictEqual(ctx_copied, ctx_dummy)
6984 self.assertIsNotNone(seq_integered["value"].defined)
6985 self.assertEqual(seq_integered["value"].defined[0], type_integered)
6986 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
6987 self.assertTrue(seq_integered_raw[
6988 seq_integered["value"].defined[1].offset:
6989 ].startswith(Integer(123).encode()))
6991 list(seq_integered.pps())
6992 pprint(seq_integered, big_blobs=True, with_decode_path=True)
6994 ctx_copied["defines_by_path"] = defines_by_path
6995 seq_sequenced, _ = Seq().decode(
6999 del ctx_copied["defines_by_path"]
7000 self.assertDictEqual(ctx_copied, ctx_dummy)
7001 self.assertIsNotNone(seq_sequenced["value"].defined)
7002 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7003 seq_inner = seq_sequenced["value"].defined[1]
7004 self.assertIsNone(seq_inner["valueInner"].defined)
7006 list(seq_sequenced.pps())
7007 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7009 defines_by_path.append((
7010 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
7011 ((("valueInner",), {type_innered: Pairs()}),),
7013 ctx_copied["defines_by_path"] = defines_by_path
7014 seq_sequenced, _ = Seq().decode(
7018 del ctx_copied["defines_by_path"]
7019 self.assertDictEqual(ctx_copied, ctx_dummy)
7020 self.assertIsNotNone(seq_sequenced["value"].defined)
7021 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7022 seq_inner = seq_sequenced["value"].defined[1]
7023 self.assertIsNotNone(seq_inner["valueInner"].defined)
7024 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7025 pairs = seq_inner["valueInner"].defined[1]
7027 self.assertIsNone(pair["value"][0].defined)
7029 list(seq_sequenced.pps())
7030 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7032 defines_by_path.append((
7035 DecodePathDefBy(type_sequenced),
7037 DecodePathDefBy(type_innered),
7042 type_integered: Integer(),
7043 type_octet_stringed: OctetString(),
7046 ctx_copied["defines_by_path"] = defines_by_path
7047 seq_sequenced, _ = Seq().decode(
7051 del ctx_copied["defines_by_path"]
7052 self.assertDictEqual(ctx_copied, ctx_dummy)
7053 self.assertIsNotNone(seq_sequenced["value"].defined)
7054 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
7055 seq_inner = seq_sequenced["value"].defined[1]
7056 self.assertIsNotNone(seq_inner["valueInner"].defined)
7057 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
7058 pairs_got = seq_inner["valueInner"].defined[1]
7059 for pair_input, pair_got in zip(pairs_input, pairs_got):
7060 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
7061 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
7063 list(seq_sequenced.pps())
7064 pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
7066 @given(oid_strategy(), integers())
7067 def test_simple(self, oid, tgt):
7068 class Inner(Sequence):
7070 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
7071 ObjectIdentifier(oid): Integer(),
7075 class Outer(Sequence):
7078 ("tgt", OctetString()),
7082 inner["oid"] = ObjectIdentifier(oid)
7084 outer["inner"] = inner
7085 outer["tgt"] = OctetString(Integer(tgt).encode())
7086 decoded, _ = Outer().decode(outer.encode())
7087 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
7089 def test_remaining_data(self):
7090 oid = ObjectIdentifier("1.2.3")
7091 class Seq(Sequence):
7093 ("oid", ObjectIdentifier(defines=((("tgt",), {
7096 ("tgt", OctetString()),
7101 ("tgt", OctetString(Integer(123).encode() + b"junk")),
7103 with assertRaisesRegex(self, DecodeError, "remaining data"):
7104 Seq().decode(seq.encode())
7106 def test_remaining_data_seqof(self):
7107 oid = ObjectIdentifier("1.2.3")
7109 schema = OctetString()
7111 class Seq(Sequence):
7113 ("oid", ObjectIdentifier(defines=((("tgt",), {
7121 ("tgt", SeqOf([OctetString(Integer(123).encode() + b"junk")])),
7123 with assertRaisesRegex(self, DecodeError, "remaining data"):
7124 Seq().decode(seq.encode())
7127 class TestAbsDecodePath(TestCase):
7129 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7130 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7132 def test_concat(self, decode_path, rel_path):
7133 dp = abs_decode_path(decode_path, rel_path)
7134 self.assertSequenceEqual(dp, decode_path + rel_path)
7138 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
7139 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7141 def test_abs(self, decode_path, rel_path):
7142 self.assertSequenceEqual(
7143 abs_decode_path(decode_path, ("/",) + rel_path),
7148 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
7149 integers(min_value=1, max_value=3),
7150 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
7152 def test_dots(self, decode_path, number_of_dots, rel_path):
7153 self.assertSequenceEqual(
7154 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
7155 decode_path[:-number_of_dots] + rel_path,
7159 class TestStrictDefaultExistence(TestCase):
7160 @given(data_strategy())
7161 def runTest(self, d):
7162 count = d.draw(integers(min_value=1, max_value=10))
7163 chosen = d.draw(integers(min_value=0, max_value=count - 1))
7165 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
7166 for i in range(count)
7168 for klass in (Sequence, Set):
7172 for i in range(count):
7173 seq["int%d" % i] = Integer(123)
7175 chosen_choice = "int%d" % chosen
7176 seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
7177 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
7179 decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
7180 self.assertTrue(decoded.ber_encoded)
7181 self.assertTrue(decoded.bered)
7182 decoded = copy(decoded)
7183 self.assertTrue(decoded.ber_encoded)
7184 self.assertTrue(decoded.bered)
7185 decoded, _ = seq.decode(raw, ctx={"bered": True})
7186 self.assertTrue(decoded.ber_encoded)
7187 self.assertTrue(decoded.bered)
7188 decoded = copy(decoded)
7189 self.assertTrue(decoded.ber_encoded)
7190 self.assertTrue(decoded.bered)
7193 class TestX690PrefixedType(TestCase):
7195 self.assertSequenceEqual(
7196 VisibleString("Jones").encode(),
7197 hexdec("1A054A6F6E6573"),
7199 self.assertSequenceEqual(
7202 impl=tag_encode(3, klass=TagClassApplication),
7204 hexdec("43054A6F6E6573"),
7206 self.assertSequenceEqual(
7210 impl=tag_encode(3, klass=TagClassApplication),
7214 hexdec("A20743054A6F6E6573"),
7216 self.assertSequenceEqual(
7220 impl=tag_encode(3, klass=TagClassApplication),
7222 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
7224 hexdec("670743054A6F6E6573"),
7226 self.assertSequenceEqual(
7227 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
7228 hexdec("82054A6F6E6573"),
7232 class TestExplOOB(TestCase):
7234 expl = tag_ctxc(123)
7235 raw = Integer(123).encode() + Integer(234).encode()
7236 raw = b"".join((expl, len_encode(len(raw)), raw))
7237 with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
7238 Integer(expl=expl).decode(raw)
7239 Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})
7242 class TestPickleDifferentVersion(TestCase):
7244 pickled = pickle_dumps(Integer(123), pickle_proto)
7246 version_orig = pyderasn.__version__
7247 pyderasn.__version__ += "different"
7248 with assertRaisesRegex(self, ValueError, "different PyDERASN version"):
7249 pickle_loads(pickled)
7250 pyderasn.__version__ = version_orig
7251 pickle_loads(pickled)