2 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
3 # Copyright (C) 2017-2018 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, either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
19 from datetime import datetime
20 from string import ascii_letters
21 from string import digits
22 from string import printable
23 from string import whitespace
24 from unittest import TestCase
26 from hypothesis import assume
27 from hypothesis import given
28 from hypothesis import settings
29 from hypothesis.strategies import binary
30 from hypothesis.strategies import booleans
31 from hypothesis.strategies import composite
32 from hypothesis.strategies import data as data_strategy
33 from hypothesis.strategies import datetimes
34 from hypothesis.strategies import dictionaries
35 from hypothesis.strategies import integers
36 from hypothesis.strategies import just
37 from hypothesis.strategies import lists
38 from hypothesis.strategies import none
39 from hypothesis.strategies import one_of
40 from hypothesis.strategies import permutations
41 from hypothesis.strategies import sampled_from
42 from hypothesis.strategies import sets
43 from hypothesis.strategies import text
44 from hypothesis.strategies import tuples
45 from six import assertRaisesRegex
46 from six import binary_type
47 from six import byte2int
48 from six import indexbytes
49 from six import int2byte
50 from six import iterbytes
52 from six import text_type
53 from six import unichr as six_unichr
55 from pyderasn import _pp
56 from pyderasn import abs_decode_path
57 from pyderasn import Any
58 from pyderasn import BitString
59 from pyderasn import BMPString
60 from pyderasn import Boolean
61 from pyderasn import BoundsError
62 from pyderasn import Choice
63 from pyderasn import DecodeError
64 from pyderasn import DecodePathDefBy
65 from pyderasn import Enumerated
66 from pyderasn import EOC
67 from pyderasn import EOC_LEN
68 from pyderasn import GeneralizedTime
69 from pyderasn import GeneralString
70 from pyderasn import GraphicString
71 from pyderasn import hexdec
72 from pyderasn import hexenc
73 from pyderasn import IA5String
74 from pyderasn import Integer
75 from pyderasn import InvalidLength
76 from pyderasn import InvalidOID
77 from pyderasn import InvalidValueType
78 from pyderasn import len_decode
79 from pyderasn import len_encode
80 from pyderasn import LENINDEF
81 from pyderasn import NotEnoughData
82 from pyderasn import Null
83 from pyderasn import NumericString
84 from pyderasn import ObjectIdentifier
85 from pyderasn import ObjNotReady
86 from pyderasn import ObjUnknown
87 from pyderasn import OctetString
88 from pyderasn import pp_console_row
89 from pyderasn import pprint
90 from pyderasn import PrintableString
91 from pyderasn import Sequence
92 from pyderasn import SequenceOf
93 from pyderasn import Set
94 from pyderasn import SetOf
95 from pyderasn import tag_ctxc
96 from pyderasn import tag_ctxp
97 from pyderasn import tag_decode
98 from pyderasn import tag_encode
99 from pyderasn import tag_strip
100 from pyderasn import TagClassApplication
101 from pyderasn import TagClassContext
102 from pyderasn import TagClassPrivate
103 from pyderasn import TagClassUniversal
104 from pyderasn import TagFormConstructed
105 from pyderasn import TagFormPrimitive
106 from pyderasn import TagMismatch
107 from pyderasn import TeletexString
108 from pyderasn import UniversalString
109 from pyderasn import UTCTime
110 from pyderasn import UTF8String
111 from pyderasn import VideotexString
112 from pyderasn import VisibleString
115 settings.register_profile("local", settings(
118 settings.load_profile("local")
119 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
121 tag_classes = sampled_from((
127 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
128 decode_path_strat = lists(integers(), max_size=3).map(
129 lambda decode_path: tuple(str(dp) for dp in decode_path)
133 class TestHex(TestCase):
135 def test_symmetric(self, data):
136 self.assertEqual(hexdec(hexenc(data)), data)
139 class TestTagCoder(TestCase):
140 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
144 integers(min_value=0, max_value=30),
147 def test_short(self, klass, form, num, junk):
148 raw = tag_encode(klass=klass, form=form, num=num)
149 self.assertEqual(tag_decode(raw), (klass, form, num))
150 self.assertEqual(len(raw), 1)
152 byte2int(tag_encode(klass=klass, form=form, num=0)),
153 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
155 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
156 self.assertSequenceEqual(stripped.tobytes(), raw)
157 self.assertEqual(tlen, len(raw))
158 self.assertSequenceEqual(tail, junk)
160 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
164 integers(min_value=31),
167 def test_long(self, klass, form, num, junk):
168 raw = tag_encode(klass=klass, form=form, num=num)
169 self.assertEqual(tag_decode(raw), (klass, form, num))
170 self.assertGreater(len(raw), 1)
172 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
175 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
176 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
177 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
178 self.assertSequenceEqual(stripped.tobytes(), raw)
179 self.assertEqual(tlen, len(raw))
180 self.assertSequenceEqual(tail, junk)
182 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
183 @given(integers(min_value=31))
184 def test_unfinished_tag(self, num):
185 raw = bytearray(tag_encode(num=num))
186 for i in range(1, len(raw)):
188 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
189 tag_strip(bytes(raw))
191 def test_go_vectors_valid(self):
192 for data, (eklass, etag, elen, eform) in (
193 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
194 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
195 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
196 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
197 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
198 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
199 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
200 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
201 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
202 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
204 tag, _, len_encoded = tag_strip(memoryview(data))
205 klass, form, num = tag_decode(tag)
206 _len, _, tail = len_decode(len_encoded)
207 self.assertSequenceEqual(tail, b"")
208 self.assertEqual(klass, eklass)
209 self.assertEqual(num, etag)
210 self.assertEqual(_len, elen)
211 self.assertEqual(form, eform)
213 def test_go_vectors_invalid(self):
221 with self.assertRaises(DecodeError):
222 _, _, len_encoded = tag_strip(memoryview(data))
223 len_decode(len_encoded)
226 integers(min_value=0, max_value=127),
227 integers(min_value=0, max_value=2),
229 def test_long_instead_of_short(self, l, dummy_num):
230 octets = (b"\x00" * dummy_num) + int2byte(l)
231 octets = int2byte((dummy_num + 1) | 0x80) + octets
232 with self.assertRaises(DecodeError):
236 class TestLenCoder(TestCase):
237 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
239 integers(min_value=0, max_value=127),
242 def test_short(self, l, junk):
243 raw = len_encode(l) + junk
244 decoded, llen, tail = len_decode(memoryview(raw))
245 self.assertEqual(decoded, l)
246 self.assertEqual(llen, 1)
247 self.assertEqual(len(raw), 1 + len(junk))
248 self.assertEqual(tail.tobytes(), junk)
250 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
252 integers(min_value=128),
255 def test_long(self, l, junk):
256 raw = len_encode(l) + junk
257 decoded, llen, tail = len_decode(memoryview(raw))
258 self.assertEqual(decoded, l)
259 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
260 self.assertEqual(llen, len(raw) - len(junk))
261 self.assertNotEqual(indexbytes(raw, 1), 0)
262 self.assertSequenceEqual(tail.tobytes(), junk)
264 def test_empty(self):
265 with self.assertRaises(NotEnoughData):
268 @given(integers(min_value=128))
269 def test_stripped(self, _len):
270 with self.assertRaises(NotEnoughData):
271 len_decode(len_encode(_len)[:-1])
274 text_printable = text(alphabet=printable, min_size=1)
278 def text_letters(draw):
279 result = draw(text(alphabet=ascii_letters, min_size=1))
281 result = result.encode("ascii")
285 class CommonMixin(object):
286 def test_tag_default(self):
287 obj = self.base_klass()
288 self.assertEqual(obj.tag, obj.tag_default)
290 def test_simultaneous_impl_expl(self):
291 with self.assertRaises(ValueError):
292 self.base_klass(impl=b"whatever", expl=b"whenever")
294 @given(binary(min_size=1), integers(), integers(), integers())
295 def test_decoded(self, impl, offset, llen, vlen):
296 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
297 self.assertEqual(obj.offset, offset)
298 self.assertEqual(obj.llen, llen)
299 self.assertEqual(obj.vlen, vlen)
300 self.assertEqual(obj.tlen, len(impl))
301 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
303 @given(binary(min_size=1))
304 def test_impl_inherited(self, impl_tag):
305 class Inherited(self.base_klass):
308 self.assertSequenceEqual(obj.impl, impl_tag)
309 self.assertFalse(obj.expled)
312 def test_expl_inherited(self, expl_tag):
313 class Inherited(self.base_klass):
316 self.assertSequenceEqual(obj.expl, expl_tag)
317 self.assertTrue(obj.expled)
319 def assert_copied_basic_fields(self, obj, obj_copied):
320 self.assertEqual(obj, obj_copied)
321 self.assertSequenceEqual(obj.tag, obj_copied.tag)
322 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
323 self.assertEqual(obj.default, obj_copied.default)
324 self.assertEqual(obj.optional, obj_copied.optional)
325 self.assertEqual(obj.offset, obj_copied.offset)
326 self.assertEqual(obj.llen, obj_copied.llen)
327 self.assertEqual(obj.vlen, obj_copied.vlen)
331 def boolean_values_strategy(draw, do_expl=False):
332 value = draw(one_of(none(), booleans()))
336 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
338 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
339 default = draw(one_of(none(), booleans()))
340 optional = draw(one_of(none(), booleans()))
342 draw(integers(min_value=0)),
343 draw(integers(min_value=0)),
344 draw(integers(min_value=0)),
346 return (value, impl, expl, default, optional, _decoded)
349 class BooleanInherited(Boolean):
353 class TestBoolean(CommonMixin, TestCase):
356 def test_invalid_value_type(self):
357 with self.assertRaises(InvalidValueType) as err:
362 def test_optional(self, optional):
363 obj = Boolean(default=Boolean(False), optional=optional)
364 self.assertTrue(obj.optional)
367 def test_ready(self, value):
369 self.assertFalse(obj.ready)
372 with self.assertRaises(ObjNotReady) as err:
376 self.assertTrue(obj.ready)
380 @given(booleans(), booleans(), binary(), binary())
381 def test_comparison(self, value1, value2, tag1, tag2):
382 for klass in (Boolean, BooleanInherited):
385 self.assertEqual(obj1 == obj2, value1 == value2)
386 self.assertEqual(obj1 != obj2, value1 != value2)
387 self.assertEqual(obj1 == bool(obj2), value1 == value2)
388 obj1 = klass(value1, impl=tag1)
389 obj2 = klass(value1, impl=tag2)
390 self.assertEqual(obj1 == obj2, tag1 == tag2)
391 self.assertEqual(obj1 != obj2, tag1 != tag2)
393 @given(data_strategy())
394 def test_call(self, d):
395 for klass in (Boolean, BooleanInherited):
403 ) = d.draw(boolean_values_strategy())
409 optional_initial or False,
419 ) = d.draw(boolean_values_strategy(do_expl=impl_initial is None))
420 obj = obj_initial(value, impl, expl, default, optional)
422 value_expected = default if value is None else value
424 default_initial if value_expected is None
427 self.assertEqual(obj, value_expected)
428 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
429 self.assertEqual(obj.expl_tag, expl or expl_initial)
432 default_initial if default is None else default,
434 if obj.default is None:
435 optional = optional_initial if optional is None else optional
436 optional = False if optional is None else optional
439 self.assertEqual(obj.optional, optional)
441 @given(boolean_values_strategy())
442 def test_copy(self, values):
443 for klass in (Boolean, BooleanInherited):
445 obj_copied = obj.copy()
446 self.assert_copied_basic_fields(obj, obj_copied)
450 integers(min_value=1).map(tag_encode),
452 def test_stripped(self, value, tag_impl):
453 obj = Boolean(value, impl=tag_impl)
454 with self.assertRaises(NotEnoughData):
455 obj.decode(obj.encode()[:-1])
459 integers(min_value=1).map(tag_ctxc),
461 def test_stripped_expl(self, value, tag_expl):
462 obj = Boolean(value, expl=tag_expl)
463 with self.assertRaises(NotEnoughData):
464 obj.decode(obj.encode()[:-1])
467 integers(min_value=31),
468 integers(min_value=0),
471 def test_bad_tag(self, tag, offset, decode_path):
472 with self.assertRaises(DecodeError) as err:
474 tag_encode(tag)[:-1],
476 decode_path=decode_path,
479 self.assertEqual(err.exception.offset, offset)
480 self.assertEqual(err.exception.decode_path, decode_path)
483 integers(min_value=31),
484 integers(min_value=0),
487 def test_bad_expl_tag(self, tag, offset, decode_path):
488 with self.assertRaises(DecodeError) as err:
489 Boolean(expl=Boolean.tag_default).decode(
490 tag_encode(tag)[:-1],
492 decode_path=decode_path,
495 self.assertEqual(err.exception.offset, offset)
496 self.assertEqual(err.exception.decode_path, decode_path)
499 integers(min_value=128),
500 integers(min_value=0),
503 def test_bad_len(self, l, offset, decode_path):
504 with self.assertRaises(DecodeError) as err:
506 Boolean.tag_default + len_encode(l)[:-1],
508 decode_path=decode_path,
511 self.assertEqual(err.exception.offset, offset)
512 self.assertEqual(err.exception.decode_path, decode_path)
515 integers(min_value=128),
516 integers(min_value=0),
519 def test_bad_expl_len(self, l, offset, decode_path):
520 with self.assertRaises(DecodeError) as err:
521 Boolean(expl=Boolean.tag_default).decode(
522 Boolean.tag_default + len_encode(l)[:-1],
524 decode_path=decode_path,
527 self.assertEqual(err.exception.offset, offset)
528 self.assertEqual(err.exception.decode_path, decode_path)
530 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
532 boolean_values_strategy(),
534 integers(min_value=1).map(tag_ctxc),
535 integers(min_value=0),
538 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
539 for klass in (Boolean, BooleanInherited):
540 _, _, _, default, optional, _decoded = values
549 self.assertFalse(obj.expled)
550 obj_encoded = obj.encode()
551 obj_expled = obj(value, expl=tag_expl)
552 self.assertTrue(obj_expled.expled)
555 obj_expled_encoded = obj_expled.encode()
556 obj_decoded, tail = obj_expled.decode(
557 obj_expled_encoded + tail_junk,
562 self.assertEqual(tail, tail_junk)
563 self.assertEqual(obj_decoded, obj_expled)
564 self.assertNotEqual(obj_decoded, obj)
565 self.assertEqual(bool(obj_decoded), bool(obj_expled))
566 self.assertEqual(bool(obj_decoded), bool(obj))
567 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
568 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
569 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
571 obj_decoded.expl_llen,
572 len(len_encode(len(obj_encoded))),
574 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
575 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
578 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
580 self.assertEqual(obj_decoded.expl_offset, offset)
582 @given(integers(min_value=2))
583 def test_invalid_len(self, l):
584 with self.assertRaises(InvalidLength):
585 Boolean().decode(b"".join((
591 @given(integers(min_value=0 + 1, max_value=255 - 1))
592 def test_ber_value(self, value):
593 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
594 Boolean().decode(b"".join((
599 obj, _ = Boolean().decode(
607 self.assertTrue(bool(obj))
608 self.assertTrue(obj.bered)
609 self.assertFalse(obj.lenindef)
612 integers(min_value=1).map(tag_ctxc),
613 binary().filter(lambda x: not x.startswith(EOC)),
615 def test_ber_expl_no_eoc(self, expl, junk):
616 encoded = expl + LENINDEF + Boolean(False).encode()
617 with assertRaisesRegex(self, DecodeError, "no EOC"):
618 Boolean(expl=expl).decode(encoded + junk, ctx={"bered": True})
619 obj, tail = Boolean(expl=expl).decode(
620 encoded + EOC + junk,
623 self.assertTrue(obj.expl_lenindef)
624 self.assertSequenceEqual(tail, junk)
627 integers(min_value=1).map(tag_ctxc),
634 def test_ber_expl(self, expl, values):
640 Boolean(value).encode() +
643 encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
645 class SeqOf(SequenceOf):
646 schema = Boolean(expl=expl)
647 seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
648 self.assertSequenceEqual(tail, b"")
649 self.assertSequenceEqual([bool(v) for v in seqof], values)
664 len(expl) + 1 + 3 + EOC_LEN,
675 def integer_values_strategy(draw, do_expl=False):
676 bound_min, value, default, bound_max = sorted(draw(sets(
685 _specs = draw(sets(text_letters()))
688 min_size=len(_specs),
689 max_size=len(_specs),
691 _specs = list(zip(_specs, values))
694 bounds = (bound_min, bound_max)
698 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
700 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
703 optional = draw(one_of(none(), booleans()))
705 draw(integers(min_value=0)),
706 draw(integers(min_value=0)),
707 draw(integers(min_value=0)),
709 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
712 class IntegerInherited(Integer):
716 class TestInteger(CommonMixin, TestCase):
719 def test_invalid_value_type(self):
720 with self.assertRaises(InvalidValueType) as err:
724 @given(sets(text_letters(), min_size=2))
725 def test_unknown_name(self, names_input):
726 missing = names_input.pop()
729 schema = [(n, 123) for n in names_input]
730 with self.assertRaises(ObjUnknown) as err:
734 @given(sets(text_letters(), min_size=2))
735 def test_known_name(self, names_input):
737 schema = [(n, 123) for n in names_input]
738 Int(names_input.pop())
741 def test_optional(self, optional):
742 obj = Integer(default=Integer(0), optional=optional)
743 self.assertTrue(obj.optional)
746 def test_ready(self, value):
748 self.assertFalse(obj.ready)
751 with self.assertRaises(ObjNotReady) as err:
755 self.assertTrue(obj.ready)
760 @given(integers(), integers(), binary(), binary())
761 def test_comparison(self, value1, value2, tag1, tag2):
762 for klass in (Integer, IntegerInherited):
765 self.assertEqual(obj1 == obj2, value1 == value2)
766 self.assertEqual(obj1 != obj2, value1 != value2)
767 self.assertEqual(obj1 == int(obj2), value1 == value2)
768 obj1 = klass(value1, impl=tag1)
769 obj2 = klass(value1, impl=tag2)
770 self.assertEqual(obj1 == obj2, tag1 == tag2)
771 self.assertEqual(obj1 != obj2, tag1 != tag2)
773 @given(lists(integers()))
774 def test_sorted_works(self, values):
775 self.assertSequenceEqual(
776 [int(v) for v in sorted(Integer(v) for v in values)],
780 @given(data_strategy())
781 def test_named(self, d):
782 names_input = list(d.draw(sets(text_letters(), min_size=1)))
783 values_input = list(d.draw(sets(
785 min_size=len(names_input),
786 max_size=len(names_input),
788 chosen_name = d.draw(sampled_from(names_input))
789 names_input = dict(zip(names_input, values_input))
793 _int = Int(chosen_name)
794 self.assertEqual(_int.named, chosen_name)
795 self.assertEqual(int(_int), names_input[chosen_name])
797 @given(integers(), integers(min_value=0), integers(min_value=0))
798 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
799 value = bound_min + value_delta
800 bound_max = value + bound_delta
801 Integer(value=value, bounds=(bound_min, bound_max))
803 @given(sets(integers(), min_size=3, max_size=3))
804 def test_bounds_unsatisfied(self, values):
805 values = sorted(values)
806 with self.assertRaises(BoundsError) as err:
807 Integer(value=values[0], bounds=(values[1], values[2]))
809 with self.assertRaises(BoundsError) as err:
810 Integer(value=values[2], bounds=(values[0], values[1]))
813 @given(data_strategy())
814 def test_call(self, d):
815 for klass in (Integer, IntegerInherited):
825 ) = d.draw(integer_values_strategy())
832 optional_initial or False,
845 ) = d.draw(integer_values_strategy(do_expl=impl_initial is None))
846 if (default is None) and (obj_initial.default is not None):
850 (value is not None) and
851 (bounds_initial is not None) and
852 not (bounds_initial[0] <= value <= bounds_initial[1])
857 (default is not None) and
858 (bounds_initial is not None) and
859 not (bounds_initial[0] <= default <= bounds_initial[1])
862 obj = obj_initial(value, bounds, impl, expl, default, optional)
864 value_expected = default if value is None else value
866 default_initial if value_expected is None
869 self.assertEqual(obj, value_expected)
870 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
871 self.assertEqual(obj.expl_tag, expl or expl_initial)
874 default_initial if default is None else default,
876 if obj.default is None:
877 optional = optional_initial if optional is None else optional
878 optional = False if optional is None else optional
881 self.assertEqual(obj.optional, optional)
883 (obj._bound_min, obj._bound_max),
884 bounds or bounds_initial or (float("-inf"), float("+inf")),
888 {} if _specs_initial is None else dict(_specs_initial),
891 @given(integer_values_strategy())
892 def test_copy(self, values):
893 for klass in (Integer, IntegerInherited):
895 obj_copied = obj.copy()
896 self.assert_copied_basic_fields(obj, obj_copied)
897 self.assertEqual(obj.specs, obj_copied.specs)
898 self.assertEqual(obj._bound_min, obj_copied._bound_min)
899 self.assertEqual(obj._bound_max, obj_copied._bound_max)
900 self.assertEqual(obj._value, obj_copied._value)
904 integers(min_value=1).map(tag_encode),
906 def test_stripped(self, value, tag_impl):
907 obj = Integer(value, impl=tag_impl)
908 with self.assertRaises(NotEnoughData):
909 obj.decode(obj.encode()[:-1])
913 integers(min_value=1).map(tag_ctxc),
915 def test_stripped_expl(self, value, tag_expl):
916 obj = Integer(value, expl=tag_expl)
917 with self.assertRaises(NotEnoughData):
918 obj.decode(obj.encode()[:-1])
920 def test_zero_len(self):
921 with self.assertRaises(NotEnoughData):
922 Integer().decode(b"".join((
928 integers(min_value=31),
929 integers(min_value=0),
932 def test_bad_tag(self, tag, offset, decode_path):
933 with self.assertRaises(DecodeError) as err:
935 tag_encode(tag)[:-1],
937 decode_path=decode_path,
940 self.assertEqual(err.exception.offset, offset)
941 self.assertEqual(err.exception.decode_path, decode_path)
944 integers(min_value=128),
945 integers(min_value=0),
948 def test_bad_len(self, l, offset, decode_path):
949 with self.assertRaises(DecodeError) as err:
951 Integer.tag_default + len_encode(l)[:-1],
953 decode_path=decode_path,
956 self.assertEqual(err.exception.offset, offset)
957 self.assertEqual(err.exception.decode_path, decode_path)
960 sets(integers(), min_size=2, max_size=2),
961 integers(min_value=0),
964 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
965 value, bound_min = list(sorted(ints))
968 bounds = (bound_min, bound_min)
969 with self.assertRaises(DecodeError) as err:
971 Integer(value).encode(),
973 decode_path=decode_path,
976 self.assertEqual(err.exception.offset, offset)
977 self.assertEqual(err.exception.decode_path, decode_path)
979 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
981 integer_values_strategy(),
983 integers(min_value=1).map(tag_ctxc),
984 integers(min_value=0),
987 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
988 for klass in (Integer, IntegerInherited):
989 _, _, _, _, default, optional, _, _decoded = values
998 self.assertFalse(obj.expled)
999 obj_encoded = obj.encode()
1000 obj_expled = obj(value, expl=tag_expl)
1001 self.assertTrue(obj_expled.expled)
1004 obj_expled_encoded = obj_expled.encode()
1005 obj_decoded, tail = obj_expled.decode(
1006 obj_expled_encoded + tail_junk,
1011 self.assertEqual(tail, tail_junk)
1012 self.assertEqual(obj_decoded, obj_expled)
1013 self.assertNotEqual(obj_decoded, obj)
1014 self.assertEqual(int(obj_decoded), int(obj_expled))
1015 self.assertEqual(int(obj_decoded), int(obj))
1016 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1017 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1018 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1020 obj_decoded.expl_llen,
1021 len(len_encode(len(obj_encoded))),
1023 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1024 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1027 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1029 self.assertEqual(obj_decoded.expl_offset, offset)
1031 def test_go_vectors_valid(self):
1032 for data, expect in ((
1036 (b"\xff\x7f", -129),
1040 (b"\xff\x00", -256),
1044 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
1045 (b"\x80\x00\x00\x00", -2147483648),
1048 Integer().decode(b"".join((
1049 Integer.tag_default,
1050 len_encode(len(data)),
1056 def test_go_vectors_invalid(self):
1061 with self.assertRaises(DecodeError):
1062 Integer().decode(b"".join((
1063 Integer.tag_default,
1064 len_encode(len(data)),
1070 def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=False):
1073 if draw(booleans()):
1074 schema = draw(sets(text_letters(), min_size=1, max_size=256))
1076 integers(min_value=0, max_value=255),
1077 min_size=len(schema),
1078 max_size=len(schema),
1080 schema = list(zip(schema, bits))
1082 def _value(value_required):
1083 if not value_required and draw(booleans()):
1085 generation_choice = 0
1087 generation_choice = draw(sampled_from((1, 2, 3)))
1088 if generation_choice == 1 or draw(booleans()):
1089 return "'%s'B" % "".join(draw(lists(
1090 sampled_from(("0", "1")),
1091 max_size=len(schema),
1093 elif generation_choice == 2 or draw(booleans()):
1094 return draw(binary(max_size=len(schema) // 8))
1095 elif generation_choice == 3 or draw(booleans()):
1096 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1098 value = _value(value_required)
1099 default = _value(value_required=False)
1103 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1105 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1106 optional = draw(one_of(none(), booleans()))
1108 draw(integers(min_value=0)),
1109 draw(integers(min_value=0)),
1110 draw(integers(min_value=0)),
1112 return (schema, value, impl, expl, default, optional, _decoded)
1115 class BitStringInherited(BitString):
1119 class TestBitString(CommonMixin, TestCase):
1120 base_klass = BitString
1122 @given(lists(booleans()))
1123 def test_b_encoding(self, bits):
1124 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1125 self.assertEqual(obj.bit_len, len(bits))
1126 self.assertSequenceEqual(list(obj), bits)
1127 for i, bit in enumerate(bits):
1128 self.assertEqual(obj[i], bit)
1130 @given(lists(booleans()))
1131 def test_out_of_bounds_bits(self, bits):
1132 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1133 for i in range(len(bits), len(bits) * 2):
1134 self.assertFalse(obj[i])
1136 def test_bad_b_encoding(self):
1137 with self.assertRaises(ValueError):
1138 BitString("'010120101'B")
1141 integers(min_value=1, max_value=255),
1142 integers(min_value=1, max_value=255),
1144 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1145 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1146 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1147 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1149 class BS(BitString):
1150 schema = (("whatever", 0),)
1151 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1152 self.assertEqual(obj.bit_len, leading_zeros + 1)
1153 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1155 def test_zero_len(self):
1156 with self.assertRaises(NotEnoughData):
1157 BitString().decode(b"".join((
1158 BitString.tag_default,
1162 def test_invalid_value_type(self):
1163 with self.assertRaises(InvalidValueType) as err:
1166 with self.assertRaises(InvalidValueType) as err:
1170 def test_obj_unknown(self):
1171 with self.assertRaises(ObjUnknown) as err:
1172 BitString(b"whatever")["whenever"]
1175 def test_get_invalid_type(self):
1176 with self.assertRaises(InvalidValueType) as err:
1177 BitString(b"whatever")[(1, 2, 3)]
1180 @given(data_strategy())
1181 def test_unknown_name(self, d):
1182 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1183 missing = _schema.pop()
1185 class BS(BitString):
1186 schema = [(n, i) for i, n in enumerate(_schema)]
1187 with self.assertRaises(ObjUnknown) as err:
1192 def test_optional(self, optional):
1193 obj = BitString(default=BitString(b""), optional=optional)
1194 self.assertTrue(obj.optional)
1197 def test_ready(self, value):
1199 self.assertFalse(obj.ready)
1202 with self.assertRaises(ObjNotReady) as err:
1205 obj = BitString(value)
1206 self.assertTrue(obj.ready)
1211 tuples(integers(min_value=0), binary()),
1212 tuples(integers(min_value=0), binary()),
1216 def test_comparison(self, value1, value2, tag1, tag2):
1217 for klass in (BitString, BitStringInherited):
1218 obj1 = klass(value1)
1219 obj2 = klass(value2)
1220 self.assertEqual(obj1 == obj2, value1 == value2)
1221 self.assertEqual(obj1 != obj2, value1 != value2)
1222 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1223 obj1 = klass(value1, impl=tag1)
1224 obj2 = klass(value1, impl=tag2)
1225 self.assertEqual(obj1 == obj2, tag1 == tag2)
1226 self.assertEqual(obj1 != obj2, tag1 != tag2)
1228 @given(data_strategy())
1229 def test_call(self, d):
1230 for klass in (BitString, BitStringInherited):
1239 ) = d.draw(bit_string_values_strategy())
1242 schema = schema_initial
1244 value=value_initial,
1247 default=default_initial,
1248 optional=optional_initial or False,
1249 _decoded=_decoded_initial,
1259 ) = d.draw(bit_string_values_strategy(
1260 schema=schema_initial,
1261 do_expl=impl_initial is None,
1270 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1271 self.assertEqual(obj.expl_tag, expl or expl_initial)
1272 if obj.default is None:
1273 optional = optional_initial if optional is None else optional
1274 optional = False if optional is None else optional
1277 self.assertEqual(obj.optional, optional)
1278 self.assertEqual(obj.specs, obj_initial.specs)
1280 @given(bit_string_values_strategy())
1281 def test_copy(self, values):
1282 for klass in (BitString, BitStringInherited):
1283 _schema, value, impl, expl, default, optional, _decoded = values
1292 optional=optional or False,
1295 obj_copied = obj.copy()
1296 self.assert_copied_basic_fields(obj, obj_copied)
1297 self.assertEqual(obj.specs, obj_copied.specs)
1298 self.assertEqual(obj._value, obj_copied._value)
1302 integers(min_value=1).map(tag_encode),
1304 def test_stripped(self, value, tag_impl):
1305 obj = BitString(value, impl=tag_impl)
1306 with self.assertRaises(NotEnoughData):
1307 obj.decode(obj.encode()[:-1])
1311 integers(min_value=1).map(tag_ctxc),
1313 def test_stripped_expl(self, value, tag_expl):
1314 obj = BitString(value, expl=tag_expl)
1315 with self.assertRaises(NotEnoughData):
1316 obj.decode(obj.encode()[:-1])
1319 integers(min_value=31),
1320 integers(min_value=0),
1323 def test_bad_tag(self, tag, offset, decode_path):
1324 with self.assertRaises(DecodeError) as err:
1326 tag_encode(tag)[:-1],
1328 decode_path=decode_path,
1331 self.assertEqual(err.exception.offset, offset)
1332 self.assertEqual(err.exception.decode_path, decode_path)
1335 integers(min_value=128),
1336 integers(min_value=0),
1339 def test_bad_len(self, l, offset, decode_path):
1340 with self.assertRaises(DecodeError) as err:
1342 BitString.tag_default + len_encode(l)[:-1],
1344 decode_path=decode_path,
1347 self.assertEqual(err.exception.offset, offset)
1348 self.assertEqual(err.exception.decode_path, decode_path)
1350 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1351 @given(data_strategy())
1352 def test_symmetric(self, d):
1361 ) = d.draw(bit_string_values_strategy(value_required=True))
1362 tail_junk = d.draw(binary(max_size=5))
1363 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1364 offset = d.draw(integers(min_value=0))
1365 for klass in (BitString, BitStringInherited):
1376 self.assertFalse(obj.expled)
1377 obj_encoded = obj.encode()
1378 obj_expled = obj(value, expl=tag_expl)
1379 self.assertTrue(obj_expled.expled)
1382 obj_expled_encoded = obj_expled.encode()
1383 obj_decoded, tail = obj_expled.decode(
1384 obj_expled_encoded + tail_junk,
1389 self.assertEqual(tail, tail_junk)
1390 self.assertEqual(obj_decoded, obj_expled)
1391 self.assertNotEqual(obj_decoded, obj)
1392 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1393 self.assertEqual(bytes(obj_decoded), bytes(obj))
1394 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1395 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1396 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1398 obj_decoded.expl_llen,
1399 len(len_encode(len(obj_encoded))),
1401 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1402 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1405 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1407 self.assertEqual(obj_decoded.expl_offset, offset)
1408 if isinstance(value, tuple):
1409 self.assertSetEqual(set(value), set(obj_decoded.named))
1413 @given(integers(min_value=1, max_value=255))
1414 def test_bad_zero_value(self, pad_size):
1415 with self.assertRaises(DecodeError):
1416 BitString().decode(b"".join((
1417 BitString.tag_default,
1422 def test_go_vectors_invalid(self):
1428 with self.assertRaises(DecodeError):
1429 BitString().decode(b"".join((
1430 BitString.tag_default,
1435 def test_go_vectors_valid(self):
1436 obj, _ = BitString().decode(b"".join((
1437 BitString.tag_default,
1441 self.assertEqual(bytes(obj), b"")
1442 self.assertEqual(obj.bit_len, 0)
1444 obj, _ = BitString().decode(b"".join((
1445 BitString.tag_default,
1449 self.assertEqual(bytes(obj), b"\x00")
1450 self.assertEqual(obj.bit_len, 1)
1452 obj = BitString((16, b"\x82\x40"))
1453 self.assertTrue(obj[0])
1454 self.assertFalse(obj[1])
1455 self.assertTrue(obj[6])
1456 self.assertTrue(obj[9])
1457 self.assertFalse(obj[17])
1460 integers(min_value=1, max_value=30),
1463 binary(min_size=1, max_size=5),
1465 binary(min_size=1, max_size=5),
1473 lists(booleans(), min_size=1),
1476 def test_constructed(self, impl, chunk_inputs, chunk_last_bits, junk):
1477 def chunk_constructed(contents):
1479 tag_encode(form=TagFormConstructed, num=3) +
1481 b"".join(BitString(content).encode() for content in contents) +
1485 payload_expected = b""
1486 bit_len_expected = 0
1487 for chunk_input in chunk_inputs:
1488 if isinstance(chunk_input, binary_type):
1489 chunks.append(BitString(chunk_input).encode())
1490 payload_expected += chunk_input
1491 bit_len_expected += len(chunk_input) * 8
1493 chunks.append(chunk_constructed(chunk_input))
1494 payload = b"".join(chunk_input)
1495 payload_expected += payload
1496 bit_len_expected += len(payload) * 8
1497 chunk_last = BitString("'%s'B" % "".join(
1498 "1" if bit else "0" for bit in chunk_last_bits
1500 payload_expected += bytes(chunk_last)
1501 bit_len_expected += chunk_last.bit_len
1502 encoded_indefinite = (
1503 tag_encode(form=TagFormConstructed, num=impl) +
1506 chunk_last.encode() +
1509 encoded_definite = (
1510 tag_encode(form=TagFormConstructed, num=impl) +
1511 len_encode(len(b"".join(chunks) + chunk_last.encode())) +
1515 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
1516 BitString(impl=tag_encode(impl)).decode(encoded_indefinite)
1517 for lenindef_expected, encoded in (
1518 (True, encoded_indefinite),
1519 (False, encoded_definite),
1521 obj, tail = BitString(impl=tag_encode(impl)).decode(
1523 ctx={"bered": True},
1525 self.assertSequenceEqual(tail, junk)
1526 self.assertEqual(obj.bit_len, bit_len_expected)
1527 self.assertSequenceEqual(bytes(obj), payload_expected)
1528 self.assertTrue(obj.bered)
1529 self.assertEqual(obj.lenindef, lenindef_expected)
1530 self.assertEqual(len(encoded), obj.tlvlen)
1533 integers(min_value=0),
1536 def test_ber_definite_too_short(self, offset, decode_path):
1537 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
1539 tag_encode(3, form=TagFormConstructed) + len_encode(1),
1541 decode_path=decode_path,
1542 ctx={"bered": True},
1544 self.assertEqual(err.exception.decode_path, decode_path)
1545 self.assertEqual(err.exception.offset, offset)
1548 integers(min_value=0),
1551 def test_ber_definite_no_data(self, offset, decode_path):
1552 with assertRaisesRegex(self, DecodeError, "zero length") as err:
1554 tag_encode(3, form=TagFormConstructed) + len_encode(0),
1556 decode_path=decode_path,
1557 ctx={"bered": True},
1559 self.assertEqual(err.exception.decode_path, decode_path)
1560 self.assertEqual(err.exception.offset, offset)
1563 integers(min_value=0),
1565 integers(min_value=1, max_value=3),
1567 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
1568 bs = BitString(b"data").encode()
1569 with self.assertRaises(NotEnoughData) as err:
1571 tag_encode(3, form=TagFormConstructed) + LENINDEF + chunks * bs,
1573 decode_path=decode_path,
1574 ctx={"bered": True},
1576 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1577 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1580 integers(min_value=0),
1582 integers(min_value=1, max_value=3),
1584 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
1585 bs = BitString(b"data").encode()
1586 bs_longer = BitString(b"data-longer").encode()
1587 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
1590 tag_encode(3, form=TagFormConstructed) +
1591 len_encode((chunks + 1) * len(bs)) +
1596 decode_path=decode_path,
1597 ctx={"bered": True},
1599 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
1600 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
1603 integers(min_value=0),
1606 def test_ber_indefinite_no_chunks(self, offset, decode_path):
1607 with assertRaisesRegex(self, DecodeError, "no chunks") as err:
1609 tag_encode(3, form=TagFormConstructed) + LENINDEF + EOC,
1611 decode_path=decode_path,
1612 ctx={"bered": True},
1614 self.assertEqual(err.exception.decode_path, decode_path)
1615 self.assertEqual(err.exception.offset, offset)
1617 @given(data_strategy())
1618 def test_ber_indefinite_not_multiple(self, d):
1619 bs_short = BitString("'A'H").encode()
1620 bs_full = BitString("'AA'H").encode()
1621 chunks = [bs_full for _ in range(d.draw(integers(min_value=0, max_value=3)))]
1622 chunks.append(bs_short)
1623 d.draw(permutations(chunks))
1624 chunks.append(bs_short)
1625 offset = d.draw(integers(min_value=0))
1626 decode_path = d.draw(decode_path_strat)
1627 with assertRaisesRegex(self, DecodeError, "multiple of 8 bits") as err:
1630 tag_encode(3, form=TagFormConstructed) +
1636 decode_path=decode_path,
1637 ctx={"bered": True},
1640 err.exception.decode_path,
1641 decode_path + (str(chunks.index(bs_short)),),
1644 err.exception.offset,
1645 offset + 1 + 1 + chunks.index(bs_short) * len(bs_full),
1648 def test_x690_vector(self):
1649 vector = BitString("'0A3B5F291CD'H")
1650 obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0"))
1651 self.assertSequenceEqual(tail, b"")
1652 self.assertEqual(obj, vector)
1653 obj, tail = BitString().decode(
1654 hexdec("23800303000A3B0305045F291CD00000"),
1655 ctx={"bered": True},
1657 self.assertSequenceEqual(tail, b"")
1658 self.assertEqual(obj, vector)
1659 self.assertTrue(obj.bered)
1660 self.assertTrue(obj.lenindef)
1664 def octet_string_values_strategy(draw, do_expl=False):
1665 bound_min, bound_max = sorted(draw(sets(
1666 integers(min_value=0, max_value=1 << 7),
1670 value = draw(one_of(
1672 binary(min_size=bound_min, max_size=bound_max),
1674 default = draw(one_of(
1676 binary(min_size=bound_min, max_size=bound_max),
1679 if draw(booleans()):
1680 bounds = (bound_min, bound_max)
1684 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1686 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1687 optional = draw(one_of(none(), booleans()))
1689 draw(integers(min_value=0)),
1690 draw(integers(min_value=0)),
1691 draw(integers(min_value=0)),
1693 return (value, bounds, impl, expl, default, optional, _decoded)
1696 class OctetStringInherited(OctetString):
1700 class TestOctetString(CommonMixin, TestCase):
1701 base_klass = OctetString
1703 def test_invalid_value_type(self):
1704 with self.assertRaises(InvalidValueType) as err:
1705 OctetString(text_type(123))
1709 def test_optional(self, optional):
1710 obj = OctetString(default=OctetString(b""), optional=optional)
1711 self.assertTrue(obj.optional)
1714 def test_ready(self, value):
1716 self.assertFalse(obj.ready)
1719 with self.assertRaises(ObjNotReady) as err:
1722 obj = OctetString(value)
1723 self.assertTrue(obj.ready)
1727 @given(binary(), binary(), binary(min_size=1), binary(min_size=1))
1728 def test_comparison(self, value1, value2, tag1, tag2):
1729 for klass in (OctetString, OctetStringInherited):
1730 obj1 = klass(value1)
1731 obj2 = klass(value2)
1732 self.assertEqual(obj1 == obj2, value1 == value2)
1733 self.assertEqual(obj1 != obj2, value1 != value2)
1734 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1735 obj1 = klass(value1, impl=tag1)
1736 obj2 = klass(value1, impl=tag2)
1737 self.assertEqual(obj1 == obj2, tag1 == tag2)
1738 self.assertEqual(obj1 != obj2, tag1 != tag2)
1740 @given(lists(binary()))
1741 def test_sorted_works(self, values):
1742 self.assertSequenceEqual(
1743 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1747 @given(data_strategy())
1748 def test_bounds_satisfied(self, d):
1749 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1750 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1751 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1752 OctetString(value=value, bounds=(bound_min, bound_max))
1754 @given(data_strategy())
1755 def test_bounds_unsatisfied(self, d):
1756 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1757 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1758 value = d.draw(binary(max_size=bound_min - 1))
1759 with self.assertRaises(BoundsError) as err:
1760 OctetString(value=value, bounds=(bound_min, bound_max))
1762 value = d.draw(binary(min_size=bound_max + 1))
1763 with self.assertRaises(BoundsError) as err:
1764 OctetString(value=value, bounds=(bound_min, bound_max))
1767 @given(data_strategy())
1768 def test_call(self, d):
1769 for klass in (OctetString, OctetStringInherited):
1778 ) = d.draw(octet_string_values_strategy())
1779 obj_initial = klass(
1785 optional_initial or False,
1796 ) = d.draw(octet_string_values_strategy(do_expl=impl_initial is None))
1797 if (default is None) and (obj_initial.default is not None):
1800 (bounds is None) and
1801 (value is not None) and
1802 (bounds_initial is not None) and
1803 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1807 (bounds is None) and
1808 (default is not None) and
1809 (bounds_initial is not None) and
1810 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1813 obj = obj_initial(value, bounds, impl, expl, default, optional)
1815 value_expected = default if value is None else value
1817 default_initial if value_expected is None
1820 self.assertEqual(obj, value_expected)
1821 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1822 self.assertEqual(obj.expl_tag, expl or expl_initial)
1825 default_initial if default is None else default,
1827 if obj.default is None:
1828 optional = optional_initial if optional is None else optional
1829 optional = False if optional is None else optional
1832 self.assertEqual(obj.optional, optional)
1834 (obj._bound_min, obj._bound_max),
1835 bounds or bounds_initial or (0, float("+inf")),
1838 @given(octet_string_values_strategy())
1839 def test_copy(self, values):
1840 for klass in (OctetString, OctetStringInherited):
1841 obj = klass(*values)
1842 obj_copied = obj.copy()
1843 self.assert_copied_basic_fields(obj, obj_copied)
1844 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1845 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1846 self.assertEqual(obj._value, obj_copied._value)
1850 integers(min_value=1).map(tag_encode),
1852 def test_stripped(self, value, tag_impl):
1853 obj = OctetString(value, impl=tag_impl)
1854 with self.assertRaises(NotEnoughData):
1855 obj.decode(obj.encode()[:-1])
1859 integers(min_value=1).map(tag_ctxc),
1861 def test_stripped_expl(self, value, tag_expl):
1862 obj = OctetString(value, expl=tag_expl)
1863 with self.assertRaises(NotEnoughData):
1864 obj.decode(obj.encode()[:-1])
1867 integers(min_value=31),
1868 integers(min_value=0),
1871 def test_bad_tag(self, tag, offset, decode_path):
1872 with self.assertRaises(DecodeError) as err:
1873 OctetString().decode(
1874 tag_encode(tag)[:-1],
1876 decode_path=decode_path,
1879 self.assertEqual(err.exception.offset, offset)
1880 self.assertEqual(err.exception.decode_path, decode_path)
1883 integers(min_value=128),
1884 integers(min_value=0),
1887 def test_bad_len(self, l, offset, decode_path):
1888 with self.assertRaises(DecodeError) as err:
1889 OctetString().decode(
1890 OctetString.tag_default + len_encode(l)[:-1],
1892 decode_path=decode_path,
1895 self.assertEqual(err.exception.offset, offset)
1896 self.assertEqual(err.exception.decode_path, decode_path)
1899 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1900 integers(min_value=0),
1903 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1904 value, bound_min = list(sorted(ints))
1906 class String(OctetString):
1907 bounds = (bound_min, bound_min)
1908 with self.assertRaises(DecodeError) as err:
1910 OctetString(b"\x00" * value).encode(),
1912 decode_path=decode_path,
1915 self.assertEqual(err.exception.offset, offset)
1916 self.assertEqual(err.exception.decode_path, decode_path)
1918 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1920 octet_string_values_strategy(),
1922 integers(min_value=1).map(tag_ctxc),
1923 integers(min_value=0),
1926 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
1927 for klass in (OctetString, OctetStringInherited):
1928 _, _, _, _, default, optional, _decoded = values
1937 self.assertFalse(obj.expled)
1938 obj_encoded = obj.encode()
1939 obj_expled = obj(value, expl=tag_expl)
1940 self.assertTrue(obj_expled.expled)
1943 obj_expled_encoded = obj_expled.encode()
1944 obj_decoded, tail = obj_expled.decode(
1945 obj_expled_encoded + tail_junk,
1950 self.assertEqual(tail, tail_junk)
1951 self.assertEqual(obj_decoded, obj_expled)
1952 self.assertNotEqual(obj_decoded, obj)
1953 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1954 self.assertEqual(bytes(obj_decoded), bytes(obj))
1955 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1956 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1957 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1959 obj_decoded.expl_llen,
1960 len(len_encode(len(obj_encoded))),
1962 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1963 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1966 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1968 self.assertEqual(obj_decoded.expl_offset, offset)
1971 integers(min_value=1, max_value=30),
1974 binary(min_size=1, max_size=5),
1976 binary(min_size=1, max_size=5),
1986 def test_constructed(self, impl, chunk_inputs, junk):
1987 def chunk_constructed(contents):
1989 tag_encode(form=TagFormConstructed, num=4) +
1991 b"".join(OctetString(content).encode() for content in contents) +
1995 payload_expected = b""
1996 for chunk_input in chunk_inputs:
1997 if isinstance(chunk_input, binary_type):
1998 chunks.append(OctetString(chunk_input).encode())
1999 payload_expected += chunk_input
2001 chunks.append(chunk_constructed(chunk_input))
2002 payload = b"".join(chunk_input)
2003 payload_expected += payload
2004 encoded_indefinite = (
2005 tag_encode(form=TagFormConstructed, num=impl) +
2010 encoded_definite = (
2011 tag_encode(form=TagFormConstructed, num=impl) +
2012 len_encode(len(b"".join(chunks))) +
2015 with assertRaisesRegex(self, DecodeError, "unallowed BER"):
2016 OctetString(impl=tag_encode(impl)).decode(encoded_indefinite)
2017 for lenindef_expected, encoded in (
2018 (True, encoded_indefinite),
2019 (False, encoded_definite),
2021 obj, tail = OctetString(impl=tag_encode(impl)).decode(
2023 ctx={"bered": True},
2025 self.assertSequenceEqual(tail, junk)
2026 self.assertSequenceEqual(bytes(obj), payload_expected)
2027 self.assertTrue(obj.bered)
2028 self.assertEqual(obj.lenindef, lenindef_expected)
2029 self.assertEqual(len(encoded), obj.tlvlen)
2032 integers(min_value=0),
2035 def test_ber_definite_too_short(self, offset, decode_path):
2036 with assertRaisesRegex(self, DecodeError, "longer than data") as err:
2037 OctetString().decode(
2038 tag_encode(4, form=TagFormConstructed) + len_encode(1),
2040 decode_path=decode_path,
2041 ctx={"bered": True},
2043 self.assertEqual(err.exception.decode_path, decode_path)
2044 self.assertEqual(err.exception.offset, offset)
2047 integers(min_value=0),
2049 integers(min_value=1, max_value=3),
2051 def test_ber_indefinite_no_eoc(self, offset, decode_path, chunks):
2052 bs = OctetString(b"data").encode()
2053 with self.assertRaises(NotEnoughData) as err:
2054 OctetString().decode(
2055 tag_encode(4, form=TagFormConstructed) + LENINDEF + chunks * bs,
2057 decode_path=decode_path,
2058 ctx={"bered": True},
2060 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2061 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2064 integers(min_value=0),
2066 integers(min_value=1, max_value=3),
2068 def test_ber_definite_chunk_out_of_bounds(self, offset, decode_path, chunks):
2069 bs = OctetString(b"data").encode()
2070 bs_longer = OctetString(b"data-longer").encode()
2071 with assertRaisesRegex(self, DecodeError, "chunk out of bounds") as err:
2072 OctetString().decode(
2074 tag_encode(4, form=TagFormConstructed) +
2075 len_encode((chunks + 1) * len(bs)) +
2080 decode_path=decode_path,
2081 ctx={"bered": True},
2083 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
2084 self.assertEqual(err.exception.offset, offset + 1 + 1 + chunks * len(bs))
2088 def null_values_strategy(draw, do_expl=False):
2092 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2094 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2095 optional = draw(one_of(none(), booleans()))
2097 draw(integers(min_value=0)),
2098 draw(integers(min_value=0)),
2099 draw(integers(min_value=0)),
2101 return (impl, expl, optional, _decoded)
2104 class NullInherited(Null):
2108 class TestNull(CommonMixin, TestCase):
2111 def test_ready(self):
2113 self.assertTrue(obj.ready)
2117 @given(binary(), binary())
2118 def test_comparison(self, tag1, tag2):
2119 for klass in (Null, NullInherited):
2120 obj1 = klass(impl=tag1)
2121 obj2 = klass(impl=tag2)
2122 self.assertEqual(obj1 == obj2, tag1 == tag2)
2123 self.assertEqual(obj1 != obj2, tag1 != tag2)
2124 self.assertNotEqual(obj1, tag2)
2126 @given(data_strategy())
2127 def test_call(self, d):
2128 for klass in (Null, NullInherited):
2134 ) = d.draw(null_values_strategy())
2135 obj_initial = klass(
2138 optional=optional_initial or False,
2139 _decoded=_decoded_initial,
2146 ) = d.draw(null_values_strategy(do_expl=impl_initial is None))
2147 obj = obj_initial(impl=impl, expl=expl, optional=optional)
2148 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2149 self.assertEqual(obj.expl_tag, expl or expl_initial)
2150 optional = optional_initial if optional is None else optional
2151 optional = False if optional is None else optional
2152 self.assertEqual(obj.optional, optional)
2154 @given(null_values_strategy())
2155 def test_copy(self, values):
2156 for klass in (Null, NullInherited):
2157 impl, expl, optional, _decoded = values
2161 optional=optional or False,
2164 obj_copied = obj.copy()
2165 self.assert_copied_basic_fields(obj, obj_copied)
2167 @given(integers(min_value=1).map(tag_encode))
2168 def test_stripped(self, tag_impl):
2169 obj = Null(impl=tag_impl)
2170 with self.assertRaises(NotEnoughData):
2171 obj.decode(obj.encode()[:-1])
2173 @given(integers(min_value=1).map(tag_ctxc))
2174 def test_stripped_expl(self, tag_expl):
2175 obj = Null(expl=tag_expl)
2176 with self.assertRaises(NotEnoughData):
2177 obj.decode(obj.encode()[:-1])
2180 integers(min_value=31),
2181 integers(min_value=0),
2184 def test_bad_tag(self, tag, offset, decode_path):
2185 with self.assertRaises(DecodeError) as err:
2187 tag_encode(tag)[:-1],
2189 decode_path=decode_path,
2192 self.assertEqual(err.exception.offset, offset)
2193 self.assertEqual(err.exception.decode_path, decode_path)
2196 integers(min_value=128),
2197 integers(min_value=0),
2200 def test_bad_len(self, l, offset, decode_path):
2201 with self.assertRaises(DecodeError) as err:
2203 Null.tag_default + len_encode(l)[:-1],
2205 decode_path=decode_path,
2208 self.assertEqual(err.exception.offset, offset)
2209 self.assertEqual(err.exception.decode_path, decode_path)
2211 @given(binary(min_size=1))
2212 def test_tag_mismatch(self, impl):
2213 assume(impl != Null.tag_default)
2214 with self.assertRaises(TagMismatch):
2215 Null(impl=impl).decode(Null().encode())
2218 null_values_strategy(),
2219 integers(min_value=1).map(tag_ctxc),
2220 integers(min_value=0),
2223 def test_symmetric(self, values, tag_expl, offset, tail_junk):
2224 for klass in (Null, NullInherited):
2225 _, _, optional, _decoded = values
2226 obj = klass(optional=optional, _decoded=_decoded)
2229 self.assertFalse(obj.expled)
2230 obj_encoded = obj.encode()
2231 obj_expled = obj(expl=tag_expl)
2232 self.assertTrue(obj_expled.expled)
2235 obj_expled_encoded = obj_expled.encode()
2236 obj_decoded, tail = obj_expled.decode(
2237 obj_expled_encoded + tail_junk,
2242 self.assertEqual(tail, tail_junk)
2243 self.assertEqual(obj_decoded, obj_expled)
2244 self.assertNotEqual(obj_decoded, obj)
2245 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2246 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2247 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2249 obj_decoded.expl_llen,
2250 len(len_encode(len(obj_encoded))),
2252 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2253 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2256 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2258 self.assertEqual(obj_decoded.expl_offset, offset)
2260 @given(integers(min_value=1))
2261 def test_invalid_len(self, l):
2262 with self.assertRaises(InvalidLength):
2263 Null().decode(b"".join((
2270 def oid_strategy(draw):
2271 first_arc = draw(integers(min_value=0, max_value=2))
2273 if first_arc in (0, 1):
2274 second_arc = draw(integers(min_value=0, max_value=39))
2276 second_arc = draw(integers(min_value=0))
2277 other_arcs = draw(lists(integers(min_value=0)))
2278 return tuple([first_arc, second_arc] + other_arcs)
2282 def oid_values_strategy(draw, do_expl=False):
2283 value = draw(one_of(none(), oid_strategy()))
2287 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2289 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2290 default = draw(one_of(none(), oid_strategy()))
2291 optional = draw(one_of(none(), booleans()))
2293 draw(integers(min_value=0)),
2294 draw(integers(min_value=0)),
2295 draw(integers(min_value=0)),
2297 return (value, impl, expl, default, optional, _decoded)
2300 class ObjectIdentifierInherited(ObjectIdentifier):
2304 class TestObjectIdentifier(CommonMixin, TestCase):
2305 base_klass = ObjectIdentifier
2307 def test_invalid_value_type(self):
2308 with self.assertRaises(InvalidValueType) as err:
2309 ObjectIdentifier(123)
2313 def test_optional(self, optional):
2314 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
2315 self.assertTrue(obj.optional)
2317 @given(oid_strategy())
2318 def test_ready(self, value):
2319 obj = ObjectIdentifier()
2320 self.assertFalse(obj.ready)
2323 with self.assertRaises(ObjNotReady) as err:
2326 obj = ObjectIdentifier(value)
2327 self.assertTrue(obj.ready)
2332 @given(oid_strategy(), oid_strategy(), binary(), binary())
2333 def test_comparison(self, value1, value2, tag1, tag2):
2334 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2335 obj1 = klass(value1)
2336 obj2 = klass(value2)
2337 self.assertEqual(obj1 == obj2, value1 == value2)
2338 self.assertEqual(obj1 != obj2, value1 != value2)
2339 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
2340 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
2341 obj1 = klass(value1, impl=tag1)
2342 obj2 = klass(value1, impl=tag2)
2343 self.assertEqual(obj1 == obj2, tag1 == tag2)
2344 self.assertEqual(obj1 != obj2, tag1 != tag2)
2346 @given(lists(oid_strategy()))
2347 def test_sorted_works(self, values):
2348 self.assertSequenceEqual(
2349 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
2353 @given(data_strategy())
2354 def test_call(self, d):
2355 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2363 ) = d.draw(oid_values_strategy())
2364 obj_initial = klass(
2365 value=value_initial,
2368 default=default_initial,
2369 optional=optional_initial or False,
2370 _decoded=_decoded_initial,
2379 ) = d.draw(oid_values_strategy(do_expl=impl_initial is None))
2388 value_expected = default if value is None else value
2390 default_initial if value_expected is None
2393 self.assertEqual(obj, value_expected)
2394 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2395 self.assertEqual(obj.expl_tag, expl or expl_initial)
2398 default_initial if default is None else default,
2400 if obj.default is None:
2401 optional = optional_initial if optional is None else optional
2402 optional = False if optional is None else optional
2405 self.assertEqual(obj.optional, optional)
2407 @given(oid_values_strategy())
2408 def test_copy(self, values):
2409 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2426 obj_copied = obj.copy()
2427 self.assert_copied_basic_fields(obj, obj_copied)
2428 self.assertEqual(obj._value, obj_copied._value)
2430 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2433 integers(min_value=1).map(tag_encode),
2435 def test_stripped(self, value, tag_impl):
2436 obj = ObjectIdentifier(value, impl=tag_impl)
2437 with self.assertRaises(NotEnoughData):
2438 obj.decode(obj.encode()[:-1])
2442 integers(min_value=1).map(tag_ctxc),
2444 def test_stripped_expl(self, value, tag_expl):
2445 obj = ObjectIdentifier(value, expl=tag_expl)
2446 with self.assertRaises(NotEnoughData):
2447 obj.decode(obj.encode()[:-1])
2450 integers(min_value=31),
2451 integers(min_value=0),
2454 def test_bad_tag(self, tag, offset, decode_path):
2455 with self.assertRaises(DecodeError) as err:
2456 ObjectIdentifier().decode(
2457 tag_encode(tag)[:-1],
2459 decode_path=decode_path,
2462 self.assertEqual(err.exception.offset, offset)
2463 self.assertEqual(err.exception.decode_path, decode_path)
2466 integers(min_value=128),
2467 integers(min_value=0),
2470 def test_bad_len(self, l, offset, decode_path):
2471 with self.assertRaises(DecodeError) as err:
2472 ObjectIdentifier().decode(
2473 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2475 decode_path=decode_path,
2478 self.assertEqual(err.exception.offset, offset)
2479 self.assertEqual(err.exception.decode_path, decode_path)
2481 def test_zero_oid(self):
2482 with self.assertRaises(NotEnoughData):
2483 ObjectIdentifier().decode(
2484 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2487 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2488 @given(oid_strategy())
2489 def test_unfinished_oid(self, value):
2490 assume(list(value)[-1] > 255)
2491 obj_encoded = ObjectIdentifier(value).encode()
2492 obj, _ = ObjectIdentifier().decode(obj_encoded)
2493 data = obj_encoded[obj.tlen + obj.llen:-1]
2495 ObjectIdentifier.tag_default,
2496 len_encode(len(data)),
2499 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2502 @given(integers(min_value=0))
2503 def test_invalid_short(self, value):
2504 with self.assertRaises(InvalidOID):
2505 ObjectIdentifier((value,))
2506 with self.assertRaises(InvalidOID):
2507 ObjectIdentifier("%d" % value)
2509 @given(integers(min_value=3), integers(min_value=0))
2510 def test_invalid_first_arc(self, first_arc, second_arc):
2511 with self.assertRaises(InvalidOID):
2512 ObjectIdentifier((first_arc, second_arc))
2513 with self.assertRaises(InvalidOID):
2514 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2516 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2517 def test_invalid_second_arc(self, first_arc, second_arc):
2518 with self.assertRaises(InvalidOID):
2519 ObjectIdentifier((first_arc, second_arc))
2520 with self.assertRaises(InvalidOID):
2521 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2523 @given(text(alphabet=ascii_letters + ".", min_size=1))
2524 def test_junk(self, oid):
2525 with self.assertRaises(InvalidOID):
2526 ObjectIdentifier(oid)
2528 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2529 @given(oid_strategy())
2530 def test_validness(self, oid):
2531 obj = ObjectIdentifier(oid)
2532 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2537 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2539 oid_values_strategy(),
2541 integers(min_value=1).map(tag_ctxc),
2542 integers(min_value=0),
2545 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
2546 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2547 _, _, _, default, optional, _decoded = values
2556 self.assertFalse(obj.expled)
2557 obj_encoded = obj.encode()
2558 obj_expled = obj(value, expl=tag_expl)
2559 self.assertTrue(obj_expled.expled)
2562 obj_expled_encoded = obj_expled.encode()
2563 obj_decoded, tail = obj_expled.decode(
2564 obj_expled_encoded + tail_junk,
2569 self.assertEqual(tail, tail_junk)
2570 self.assertEqual(obj_decoded, obj_expled)
2571 self.assertNotEqual(obj_decoded, obj)
2572 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2573 self.assertEqual(tuple(obj_decoded), tuple(obj))
2574 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2575 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2576 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2578 obj_decoded.expl_llen,
2579 len(len_encode(len(obj_encoded))),
2581 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2582 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2585 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2587 self.assertEqual(obj_decoded.expl_offset, offset)
2590 oid_strategy().map(ObjectIdentifier),
2591 oid_strategy().map(ObjectIdentifier),
2593 def test_add(self, oid1, oid2):
2594 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2595 for oid_to_add in (oid2, tuple(oid2)):
2596 self.assertEqual(oid1 + oid_to_add, oid_expect)
2597 with self.assertRaises(InvalidValueType):
2600 def test_go_vectors_valid(self):
2601 for data, expect in (
2603 (b"\x55\x02", (2, 5, 2)),
2604 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2605 (b"\x81\x34\x03", (2, 100, 3)),
2608 ObjectIdentifier().decode(b"".join((
2609 ObjectIdentifier.tag_default,
2610 len_encode(len(data)),
2616 def test_go_vectors_invalid(self):
2617 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2618 with self.assertRaises(DecodeError):
2619 ObjectIdentifier().decode(b"".join((
2620 Integer.tag_default,
2621 len_encode(len(data)),
2625 def test_x690_vector(self):
2627 ObjectIdentifier().decode(hexdec("0603883703"))[0],
2628 ObjectIdentifier((2, 999, 3)),
2633 def enumerated_values_strategy(draw, schema=None, do_expl=False):
2635 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2636 values = list(draw(sets(
2638 min_size=len(schema),
2639 max_size=len(schema),
2641 schema = list(zip(schema, values))
2642 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2646 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2648 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2649 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2650 optional = draw(one_of(none(), booleans()))
2652 draw(integers(min_value=0)),
2653 draw(integers(min_value=0)),
2654 draw(integers(min_value=0)),
2656 return (schema, value, impl, expl, default, optional, _decoded)
2659 class TestEnumerated(CommonMixin, TestCase):
2660 class EWhatever(Enumerated):
2661 schema = (("whatever", 0),)
2663 base_klass = EWhatever
2665 def test_schema_required(self):
2666 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2669 def test_invalid_value_type(self):
2670 with self.assertRaises(InvalidValueType) as err:
2671 self.base_klass((1, 2))
2674 @given(sets(text_letters(), min_size=2))
2675 def test_unknown_name(self, schema_input):
2676 missing = schema_input.pop()
2678 class E(Enumerated):
2679 schema = [(n, 123) for n in schema_input]
2680 with self.assertRaises(ObjUnknown) as err:
2685 sets(text_letters(), min_size=2),
2686 sets(integers(), min_size=2),
2688 def test_unknown_value(self, schema_input, values_input):
2690 missing_value = values_input.pop()
2691 _input = list(zip(schema_input, values_input))
2693 class E(Enumerated):
2695 with self.assertRaises(DecodeError) as err:
2700 def test_optional(self, optional):
2701 obj = self.base_klass(default="whatever", optional=optional)
2702 self.assertTrue(obj.optional)
2704 def test_ready(self):
2705 obj = self.base_klass()
2706 self.assertFalse(obj.ready)
2709 with self.assertRaises(ObjNotReady) as err:
2712 obj = self.base_klass("whatever")
2713 self.assertTrue(obj.ready)
2717 @given(integers(), integers(), binary(), binary())
2718 def test_comparison(self, value1, value2, tag1, tag2):
2719 class E(Enumerated):
2721 ("whatever0", value1),
2722 ("whatever1", value2),
2725 class EInherited(E):
2727 for klass in (E, EInherited):
2728 obj1 = klass(value1)
2729 obj2 = klass(value2)
2730 self.assertEqual(obj1 == obj2, value1 == value2)
2731 self.assertEqual(obj1 != obj2, value1 != value2)
2732 self.assertEqual(obj1 == int(obj2), value1 == value2)
2733 obj1 = klass(value1, impl=tag1)
2734 obj2 = klass(value1, impl=tag2)
2735 self.assertEqual(obj1 == obj2, tag1 == tag2)
2736 self.assertEqual(obj1 != obj2, tag1 != tag2)
2738 @given(data_strategy())
2739 def test_call(self, d):
2748 ) = d.draw(enumerated_values_strategy())
2750 class E(Enumerated):
2751 schema = schema_initial
2753 value=value_initial,
2756 default=default_initial,
2757 optional=optional_initial or False,
2758 _decoded=_decoded_initial,
2768 ) = d.draw(enumerated_values_strategy(
2769 schema=schema_initial,
2770 do_expl=impl_initial is None,
2780 value_expected = default if value is None else value
2782 default_initial if value_expected is None
2787 dict(schema_initial).get(value_expected, value_expected),
2789 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2790 self.assertEqual(obj.expl_tag, expl or expl_initial)
2793 default_initial if default is None else default,
2795 if obj.default is None:
2796 optional = optional_initial if optional is None else optional
2797 optional = False if optional is None else optional
2800 self.assertEqual(obj.optional, optional)
2801 self.assertEqual(obj.specs, dict(schema_initial))
2803 @given(enumerated_values_strategy())
2804 def test_copy(self, values):
2805 schema_input, value, impl, expl, default, optional, _decoded = values
2807 class E(Enumerated):
2808 schema = schema_input
2817 obj_copied = obj.copy()
2818 self.assert_copied_basic_fields(obj, obj_copied)
2819 self.assertEqual(obj.specs, obj_copied.specs)
2821 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2822 @given(data_strategy())
2823 def test_symmetric(self, d):
2824 schema_input, _, _, _, default, optional, _decoded = d.draw(
2825 enumerated_values_strategy(),
2827 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2828 offset = d.draw(integers(min_value=0))
2829 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2830 tail_junk = d.draw(binary(max_size=5))
2832 class E(Enumerated):
2833 schema = schema_input
2842 self.assertFalse(obj.expled)
2843 obj_encoded = obj.encode()
2844 obj_expled = obj(value, expl=tag_expl)
2845 self.assertTrue(obj_expled.expled)
2848 obj_expled_encoded = obj_expled.encode()
2849 obj_decoded, tail = obj_expled.decode(
2850 obj_expled_encoded + tail_junk,
2855 self.assertEqual(tail, tail_junk)
2856 self.assertEqual(obj_decoded, obj_expled)
2857 self.assertNotEqual(obj_decoded, obj)
2858 self.assertEqual(int(obj_decoded), int(obj_expled))
2859 self.assertEqual(int(obj_decoded), int(obj))
2860 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2861 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2862 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2864 obj_decoded.expl_llen,
2865 len(len_encode(len(obj_encoded))),
2867 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2868 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2871 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2873 self.assertEqual(obj_decoded.expl_offset, offset)
2877 def string_values_strategy(draw, alphabet, do_expl=False):
2878 bound_min, bound_max = sorted(draw(sets(
2879 integers(min_value=0, max_value=1 << 7),
2883 value = draw(one_of(
2885 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2887 default = draw(one_of(
2889 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2892 if draw(booleans()):
2893 bounds = (bound_min, bound_max)
2897 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2899 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2900 optional = draw(one_of(none(), booleans()))
2902 draw(integers(min_value=0)),
2903 draw(integers(min_value=0)),
2904 draw(integers(min_value=0)),
2906 return (value, bounds, impl, expl, default, optional, _decoded)
2909 class StringMixin(object):
2910 def test_invalid_value_type(self):
2911 with self.assertRaises(InvalidValueType) as err:
2912 self.base_klass((1, 2))
2915 def text_alphabet(self):
2916 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2917 return printable + whitespace
2921 def test_optional(self, optional):
2922 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2923 self.assertTrue(obj.optional)
2925 @given(data_strategy())
2926 def test_ready(self, d):
2927 obj = self.base_klass()
2928 self.assertFalse(obj.ready)
2932 with self.assertRaises(ObjNotReady) as err:
2935 value = d.draw(text(alphabet=self.text_alphabet()))
2936 obj = self.base_klass(value)
2937 self.assertTrue(obj.ready)
2942 @given(data_strategy())
2943 def test_comparison(self, d):
2944 value1 = d.draw(text(alphabet=self.text_alphabet()))
2945 value2 = d.draw(text(alphabet=self.text_alphabet()))
2946 tag1 = d.draw(binary(min_size=1))
2947 tag2 = d.draw(binary(min_size=1))
2948 obj1 = self.base_klass(value1)
2949 obj2 = self.base_klass(value2)
2950 self.assertEqual(obj1 == obj2, value1 == value2)
2951 self.assertEqual(obj1 != obj2, value1 != value2)
2952 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2953 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2954 obj1 = self.base_klass(value1, impl=tag1)
2955 obj2 = self.base_klass(value1, impl=tag2)
2956 self.assertEqual(obj1 == obj2, tag1 == tag2)
2957 self.assertEqual(obj1 != obj2, tag1 != tag2)
2959 @given(data_strategy())
2960 def test_bounds_satisfied(self, d):
2961 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2962 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2963 value = d.draw(text(
2964 alphabet=self.text_alphabet(),
2968 self.base_klass(value=value, bounds=(bound_min, bound_max))
2970 @given(data_strategy())
2971 def test_bounds_unsatisfied(self, d):
2972 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2973 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2974 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2975 with self.assertRaises(BoundsError) as err:
2976 self.base_klass(value=value, bounds=(bound_min, bound_max))
2978 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2979 with self.assertRaises(BoundsError) as err:
2980 self.base_klass(value=value, bounds=(bound_min, bound_max))
2983 @given(data_strategy())
2984 def test_call(self, d):
2993 ) = d.draw(string_values_strategy(self.text_alphabet()))
2994 obj_initial = self.base_klass(
3000 optional_initial or False,
3011 ) = d.draw(string_values_strategy(
3012 self.text_alphabet(),
3013 do_expl=impl_initial is None,
3015 if (default is None) and (obj_initial.default is not None):
3018 (bounds is None) and
3019 (value is not None) and
3020 (bounds_initial is not None) and
3021 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
3025 (bounds is None) and
3026 (default is not None) and
3027 (bounds_initial is not None) and
3028 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
3031 obj = obj_initial(value, bounds, impl, expl, default, optional)
3033 value_expected = default if value is None else value
3035 default_initial if value_expected is None
3038 self.assertEqual(obj, value_expected)
3039 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3040 self.assertEqual(obj.expl_tag, expl or expl_initial)
3043 default_initial if default is None else default,
3045 if obj.default is None:
3046 optional = optional_initial if optional is None else optional
3047 optional = False if optional is None else optional
3050 self.assertEqual(obj.optional, optional)
3052 (obj._bound_min, obj._bound_max),
3053 bounds or bounds_initial or (0, float("+inf")),
3056 @given(data_strategy())
3057 def test_copy(self, d):
3058 values = d.draw(string_values_strategy(self.text_alphabet()))
3059 obj = self.base_klass(*values)
3060 obj_copied = obj.copy()
3061 self.assert_copied_basic_fields(obj, obj_copied)
3062 self.assertEqual(obj._bound_min, obj_copied._bound_min)
3063 self.assertEqual(obj._bound_max, obj_copied._bound_max)
3064 self.assertEqual(obj._value, obj_copied._value)
3066 @given(data_strategy())
3067 def test_stripped(self, d):
3068 value = d.draw(text(alphabet=self.text_alphabet()))
3069 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3070 obj = self.base_klass(value, impl=tag_impl)
3071 with self.assertRaises(NotEnoughData):
3072 obj.decode(obj.encode()[:-1])
3074 @given(data_strategy())
3075 def test_stripped_expl(self, d):
3076 value = d.draw(text(alphabet=self.text_alphabet()))
3077 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3078 obj = self.base_klass(value, expl=tag_expl)
3079 with self.assertRaises(NotEnoughData):
3080 obj.decode(obj.encode()[:-1])
3083 integers(min_value=31),
3084 integers(min_value=0),
3087 def test_bad_tag(self, tag, offset, decode_path):
3088 with self.assertRaises(DecodeError) as err:
3089 self.base_klass().decode(
3090 tag_encode(tag)[:-1],
3092 decode_path=decode_path,
3095 self.assertEqual(err.exception.offset, offset)
3096 self.assertEqual(err.exception.decode_path, decode_path)
3099 integers(min_value=128),
3100 integers(min_value=0),
3103 def test_bad_len(self, l, offset, decode_path):
3104 with self.assertRaises(DecodeError) as err:
3105 self.base_klass().decode(
3106 self.base_klass.tag_default + len_encode(l)[:-1],
3108 decode_path=decode_path,
3111 self.assertEqual(err.exception.offset, offset)
3112 self.assertEqual(err.exception.decode_path, decode_path)
3115 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3116 integers(min_value=0),
3119 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3120 value, bound_min = list(sorted(ints))
3122 class String(self.base_klass):
3123 # Multiply this value by four, to satisfy UTF-32 bounds
3124 # (4 bytes per character) validation
3125 bounds = (bound_min * 4, bound_min * 4)
3126 with self.assertRaises(DecodeError) as err:
3128 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
3130 decode_path=decode_path,
3133 self.assertEqual(err.exception.offset, offset)
3134 self.assertEqual(err.exception.decode_path, decode_path)
3136 @given(data_strategy())
3137 def test_symmetric(self, d):
3138 values = d.draw(string_values_strategy(self.text_alphabet()))
3139 value = d.draw(text(alphabet=self.text_alphabet()))
3140 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3141 offset = d.draw(integers(min_value=0))
3142 tail_junk = d.draw(binary(max_size=5))
3143 _, _, _, _, default, optional, _decoded = values
3144 obj = self.base_klass(
3152 self.assertFalse(obj.expled)
3153 obj_encoded = obj.encode()
3154 obj_expled = obj(value, expl=tag_expl)
3155 self.assertTrue(obj_expled.expled)
3158 obj_expled_encoded = obj_expled.encode()
3159 obj_decoded, tail = obj_expled.decode(
3160 obj_expled_encoded + tail_junk,
3165 self.assertEqual(tail, tail_junk)
3166 self.assertEqual(obj_decoded, obj_expled)
3167 self.assertNotEqual(obj_decoded, obj)
3168 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3169 self.assertEqual(bytes(obj_decoded), bytes(obj))
3170 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
3171 self.assertEqual(text_type(obj_decoded), text_type(obj))
3172 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3173 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3174 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3176 obj_decoded.expl_llen,
3177 len(len_encode(len(obj_encoded))),
3179 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3180 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3183 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3185 self.assertEqual(obj_decoded.expl_offset, offset)
3188 class TestUTF8String(StringMixin, CommonMixin, TestCase):
3189 base_klass = UTF8String
3192 class UnicodeDecodeErrorMixin(object):
3194 alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))),
3198 def test_unicode_decode_error(self, cyrillic_text):
3199 with self.assertRaises(DecodeError):
3200 self.base_klass(cyrillic_text)
3203 class TestNumericString(StringMixin, CommonMixin, TestCase):
3204 base_klass = NumericString
3206 def text_alphabet(self):
3209 @given(text(alphabet=ascii_letters, min_size=1, max_size=5))
3210 def test_non_numeric(self, cyrillic_text):
3211 with assertRaisesRegex(self, DecodeError, "non-numeric"):
3212 self.base_klass(cyrillic_text)
3215 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
3216 integers(min_value=0),
3219 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
3220 value, bound_min = list(sorted(ints))
3222 class String(self.base_klass):
3223 bounds = (bound_min, bound_min)
3224 with self.assertRaises(DecodeError) as err:
3226 self.base_klass(b"1" * value).encode(),
3228 decode_path=decode_path,
3231 self.assertEqual(err.exception.offset, offset)
3232 self.assertEqual(err.exception.decode_path, decode_path)
3235 class TestPrintableString(
3236 UnicodeDecodeErrorMixin,
3241 base_klass = PrintableString
3244 class TestTeletexString(
3245 UnicodeDecodeErrorMixin,
3250 base_klass = TeletexString
3253 class TestVideotexString(
3254 UnicodeDecodeErrorMixin,
3259 base_klass = VideotexString
3262 class TestIA5String(
3263 UnicodeDecodeErrorMixin,
3268 base_klass = IA5String
3271 class TestGraphicString(
3272 UnicodeDecodeErrorMixin,
3277 base_klass = GraphicString
3280 class TestVisibleString(
3281 UnicodeDecodeErrorMixin,
3286 base_klass = VisibleString
3288 def test_x690_vector(self):
3289 obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
3290 self.assertSequenceEqual(tail, b"")
3291 self.assertEqual(str(obj), "Jones")
3292 self.assertFalse(obj.bered)
3293 self.assertFalse(obj.lenindef)
3295 obj, tail = VisibleString().decode(
3296 hexdec("3A0904034A6F6E04026573"),
3297 ctx={"bered": True},
3299 self.assertSequenceEqual(tail, b"")
3300 self.assertEqual(str(obj), "Jones")
3301 self.assertTrue(obj.bered)
3302 self.assertFalse(obj.lenindef)
3304 obj, tail = VisibleString().decode(
3305 hexdec("3A8004034A6F6E040265730000"),
3306 ctx={"bered": True},
3308 self.assertSequenceEqual(tail, b"")
3309 self.assertEqual(str(obj), "Jones")
3310 self.assertTrue(obj.bered)
3311 self.assertTrue(obj.lenindef)
3314 class TestGeneralString(
3315 UnicodeDecodeErrorMixin,
3320 base_klass = GeneralString
3323 class TestUniversalString(StringMixin, CommonMixin, TestCase):
3324 base_klass = UniversalString
3327 class TestBMPString(StringMixin, CommonMixin, TestCase):
3328 base_klass = BMPString
3332 def generalized_time_values_strategy(
3340 if draw(booleans()):
3341 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3343 value = value.replace(microsecond=0)
3345 if draw(booleans()):
3346 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
3348 default = default.replace(microsecond=0)
3352 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3354 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3355 optional = draw(one_of(none(), booleans()))
3357 draw(integers(min_value=0)),
3358 draw(integers(min_value=0)),
3359 draw(integers(min_value=0)),
3361 return (value, impl, expl, default, optional, _decoded)
3364 class TimeMixin(object):
3365 def test_invalid_value_type(self):
3366 with self.assertRaises(InvalidValueType) as err:
3367 self.base_klass(datetime.now().timetuple())
3370 @given(data_strategy())
3371 def test_optional(self, d):
3372 default = d.draw(datetimes(
3373 min_value=self.min_datetime,
3374 max_value=self.max_datetime,
3376 optional = d.draw(booleans())
3377 obj = self.base_klass(default=default, optional=optional)
3378 self.assertTrue(obj.optional)
3380 @given(data_strategy())
3381 def test_ready(self, d):
3382 obj = self.base_klass()
3383 self.assertFalse(obj.ready)
3386 with self.assertRaises(ObjNotReady) as err:
3389 value = d.draw(datetimes(min_value=self.min_datetime))
3390 obj = self.base_klass(value)
3391 self.assertTrue(obj.ready)
3395 @given(data_strategy())
3396 def test_comparison(self, d):
3397 value1 = d.draw(datetimes(
3398 min_value=self.min_datetime,
3399 max_value=self.max_datetime,
3401 value2 = d.draw(datetimes(
3402 min_value=self.min_datetime,
3403 max_value=self.max_datetime,
3405 tag1 = d.draw(binary(min_size=1))
3406 tag2 = d.draw(binary(min_size=1))
3408 value1 = value1.replace(microsecond=0)
3409 value2 = value2.replace(microsecond=0)
3410 obj1 = self.base_klass(value1)
3411 obj2 = self.base_klass(value2)
3412 self.assertEqual(obj1 == obj2, value1 == value2)
3413 self.assertEqual(obj1 != obj2, value1 != value2)
3414 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
3415 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3416 obj1 = self.base_klass(value1, impl=tag1)
3417 obj2 = self.base_klass(value1, impl=tag2)
3418 self.assertEqual(obj1 == obj2, tag1 == tag2)
3419 self.assertEqual(obj1 != obj2, tag1 != tag2)
3421 @given(data_strategy())
3422 def test_call(self, d):
3430 ) = d.draw(generalized_time_values_strategy(
3431 min_datetime=self.min_datetime,
3432 max_datetime=self.max_datetime,
3433 omit_ms=self.omit_ms,
3435 obj_initial = self.base_klass(
3436 value=value_initial,
3439 default=default_initial,
3440 optional=optional_initial or False,
3441 _decoded=_decoded_initial,
3450 ) = d.draw(generalized_time_values_strategy(
3451 min_datetime=self.min_datetime,
3452 max_datetime=self.max_datetime,
3453 omit_ms=self.omit_ms,
3454 do_expl=impl_initial is None,
3464 value_expected = default if value is None else value
3466 default_initial if value_expected is None
3469 self.assertEqual(obj, value_expected)
3470 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
3471 self.assertEqual(obj.expl_tag, expl or expl_initial)
3474 default_initial if default is None else default,
3476 if obj.default is None:
3477 optional = optional_initial if optional is None else optional
3478 optional = False if optional is None else optional
3481 self.assertEqual(obj.optional, optional)
3483 @given(data_strategy())
3484 def test_copy(self, d):
3485 values = d.draw(generalized_time_values_strategy(
3486 min_datetime=self.min_datetime,
3487 max_datetime=self.max_datetime,
3489 obj = self.base_klass(*values)
3490 obj_copied = obj.copy()
3491 self.assert_copied_basic_fields(obj, obj_copied)
3492 self.assertEqual(obj._value, obj_copied._value)
3494 @given(data_strategy())
3495 def test_stripped(self, d):
3496 value = d.draw(datetimes(
3497 min_value=self.min_datetime,
3498 max_value=self.max_datetime,
3500 tag_impl = tag_encode(d.draw(integers(min_value=1)))
3501 obj = self.base_klass(value, impl=tag_impl)
3502 with self.assertRaises(NotEnoughData):
3503 obj.decode(obj.encode()[:-1])
3505 @given(data_strategy())
3506 def test_stripped_expl(self, d):
3507 value = d.draw(datetimes(
3508 min_value=self.min_datetime,
3509 max_value=self.max_datetime,
3511 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3512 obj = self.base_klass(value, expl=tag_expl)
3513 with self.assertRaises(NotEnoughData):
3514 obj.decode(obj.encode()[:-1])
3516 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3517 @given(data_strategy())
3518 def test_symmetric(self, d):
3519 values = d.draw(generalized_time_values_strategy(
3520 min_datetime=self.min_datetime,
3521 max_datetime=self.max_datetime,
3523 value = d.draw(datetimes(
3524 min_value=self.min_datetime,
3525 max_value=self.max_datetime,
3527 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3528 offset = d.draw(integers(min_value=0))
3529 tail_junk = d.draw(binary(max_size=5))
3530 _, _, _, default, optional, _decoded = values
3531 obj = self.base_klass(
3539 self.assertFalse(obj.expled)
3540 obj_encoded = obj.encode()
3541 obj_expled = obj(value, expl=tag_expl)
3542 self.assertTrue(obj_expled.expled)
3545 obj_expled_encoded = obj_expled.encode()
3546 obj_decoded, tail = obj_expled.decode(
3547 obj_expled_encoded + tail_junk,
3552 self.assertEqual(tail, tail_junk)
3553 self.assertEqual(obj_decoded, obj_expled)
3554 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3555 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3556 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3557 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3558 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3560 obj_decoded.expl_llen,
3561 len(len_encode(len(obj_encoded))),
3563 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3564 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3567 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3569 self.assertEqual(obj_decoded.expl_offset, offset)
3572 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3573 base_klass = GeneralizedTime
3575 min_datetime = datetime(1900, 1, 1)
3576 max_datetime = datetime(9999, 12, 31)
3578 def test_go_vectors_invalid(self):
3590 b"-20100102030410Z",
3591 b"2010-0102030410Z",
3592 b"2010-0002030410Z",
3593 b"201001-02030410Z",
3594 b"20100102-030410Z",
3595 b"2010010203-0410Z",
3596 b"201001020304-10Z",
3597 # These ones are INVALID in *DER*, but accepted
3598 # by Go's encoding/asn1
3599 b"20100102030405+0607",
3600 b"20100102030405-0607",
3602 with self.assertRaises(DecodeError) as err:
3603 GeneralizedTime(data)
3606 def test_go_vectors_valid(self):
3608 GeneralizedTime(b"20100102030405Z").todatetime(),
3609 datetime(2010, 1, 2, 3, 4, 5, 0),
3613 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3614 base_klass = UTCTime
3616 min_datetime = datetime(2000, 1, 1)
3617 max_datetime = datetime(2049, 12, 31)
3619 def test_go_vectors_invalid(self):
3645 # These ones are INVALID in *DER*, but accepted
3646 # by Go's encoding/asn1
3647 b"910506164540-0700",
3648 b"910506164540+0730",
3652 with self.assertRaises(DecodeError) as err:
3656 def test_go_vectors_valid(self):
3658 UTCTime(b"910506234540Z").todatetime(),
3659 datetime(1991, 5, 6, 23, 45, 40, 0),
3662 @given(integers(min_value=0, max_value=49))
3663 def test_pre50(self, year):
3665 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3669 @given(integers(min_value=50, max_value=99))
3670 def test_post50(self, year):
3672 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3678 def any_values_strategy(draw, do_expl=False):
3679 value = draw(one_of(none(), binary()))
3682 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3683 optional = draw(one_of(none(), booleans()))
3685 draw(integers(min_value=0)),
3686 draw(integers(min_value=0)),
3687 draw(integers(min_value=0)),
3689 return (value, expl, optional, _decoded)
3692 class AnyInherited(Any):
3696 class TestAny(CommonMixin, TestCase):
3699 def test_invalid_value_type(self):
3700 with self.assertRaises(InvalidValueType) as err:
3705 def test_optional(self, optional):
3706 obj = Any(optional=optional)
3707 self.assertEqual(obj.optional, optional)
3710 def test_ready(self, value):
3712 self.assertFalse(obj.ready)
3715 with self.assertRaises(ObjNotReady) as err:
3719 self.assertTrue(obj.ready)
3724 def test_basic(self, value):
3725 integer_encoded = Integer(value).encode()
3727 Any(integer_encoded),
3728 Any(Integer(value)),
3729 Any(Any(Integer(value))),
3731 self.assertSequenceEqual(bytes(obj), integer_encoded)
3733 obj.decode(obj.encode())[0].vlen,
3734 len(integer_encoded),
3738 self.assertSequenceEqual(obj.encode(), integer_encoded)
3740 @given(binary(), binary())
3741 def test_comparison(self, value1, value2):
3742 for klass in (Any, AnyInherited):
3743 obj1 = klass(value1)
3744 obj2 = klass(value2)
3745 self.assertEqual(obj1 == obj2, value1 == value2)
3746 self.assertEqual(obj1 != obj2, value1 != value2)
3747 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3749 @given(data_strategy())
3750 def test_call(self, d):
3751 for klass in (Any, AnyInherited):
3757 ) = d.draw(any_values_strategy())
3758 obj_initial = klass(
3761 optional_initial or False,
3769 ) = d.draw(any_values_strategy(do_expl=True))
3770 obj = obj_initial(value, expl, optional)
3772 value_expected = None if value is None else value
3773 self.assertEqual(obj, value_expected)
3774 self.assertEqual(obj.expl_tag, expl or expl_initial)
3775 if obj.default is None:
3776 optional = optional_initial if optional is None else optional
3777 optional = False if optional is None else optional
3778 self.assertEqual(obj.optional, optional)
3780 def test_simultaneous_impl_expl(self):
3781 # override it, as Any does not have implicit tag
3784 def test_decoded(self):
3785 # override it, as Any does not have implicit tag
3788 @given(any_values_strategy())
3789 def test_copy(self, values):
3790 for klass in (Any, AnyInherited):
3791 obj = klass(*values)
3792 obj_copied = obj.copy()
3793 self.assert_copied_basic_fields(obj, obj_copied)
3794 self.assertEqual(obj._value, obj_copied._value)
3796 @given(binary().map(OctetString))
3797 def test_stripped(self, value):
3799 with self.assertRaises(NotEnoughData):
3800 obj.decode(obj.encode()[:-1])
3804 integers(min_value=1).map(tag_ctxc),
3806 def test_stripped_expl(self, value, tag_expl):
3807 obj = Any(value, expl=tag_expl)
3808 with self.assertRaises(NotEnoughData):
3809 obj.decode(obj.encode()[:-1])
3812 integers(min_value=31),
3813 integers(min_value=0),
3816 def test_bad_tag(self, tag, offset, decode_path):
3817 with self.assertRaises(DecodeError) as err:
3819 tag_encode(tag)[:-1],
3821 decode_path=decode_path,
3824 self.assertEqual(err.exception.offset, offset)
3825 self.assertEqual(err.exception.decode_path, decode_path)
3828 integers(min_value=128),
3829 integers(min_value=0),
3832 def test_bad_len(self, l, offset, decode_path):
3833 with self.assertRaises(DecodeError) as err:
3835 Any.tag_default + len_encode(l)[:-1],
3837 decode_path=decode_path,
3840 self.assertEqual(err.exception.offset, offset)
3841 self.assertEqual(err.exception.decode_path, decode_path)
3843 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3845 any_values_strategy(),
3846 integers().map(lambda x: Integer(x).encode()),
3847 integers(min_value=1).map(tag_ctxc),
3848 integers(min_value=0),
3851 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
3852 for klass in (Any, AnyInherited):
3853 _, _, optional, _decoded = values
3854 obj = klass(value=value, optional=optional, _decoded=_decoded)
3857 self.assertFalse(obj.expled)
3858 obj_encoded = obj.encode()
3859 obj_expled = obj(value, expl=tag_expl)
3860 self.assertTrue(obj_expled.expled)
3863 obj_expled_encoded = obj_expled.encode()
3864 obj_decoded, tail = obj_expled.decode(
3865 obj_expled_encoded + tail_junk,
3870 self.assertEqual(tail, tail_junk)
3871 self.assertEqual(obj_decoded, obj_expled)
3872 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3873 self.assertEqual(bytes(obj_decoded), bytes(obj))
3874 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3875 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3876 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3878 obj_decoded.expl_llen,
3879 len(len_encode(len(obj_encoded))),
3881 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3882 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3885 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3887 self.assertEqual(obj_decoded.expl_offset, offset)
3888 self.assertEqual(obj_decoded.tlen, 0)
3889 self.assertEqual(obj_decoded.llen, 0)
3890 self.assertEqual(obj_decoded.vlen, len(value))
3893 integers(min_value=1).map(tag_ctxc),
3894 integers(min_value=0, max_value=3),
3895 integers(min_value=0),
3899 def test_indefinite(self, expl, chunks, offset, decode_path, junk):
3900 chunk = Boolean(False, expl=expl).encode()
3902 OctetString.tag_default +
3904 b"".join([chunk] * chunks) +
3907 obj, tail = Any().decode(
3910 decode_path=decode_path,
3911 ctx={"bered": True},
3913 self.assertSequenceEqual(tail, junk)
3914 self.assertEqual(obj.offset, offset)
3915 self.assertEqual(obj.tlvlen, len(encoded))
3916 with self.assertRaises(NotEnoughData) as err:
3920 decode_path=decode_path,
3921 ctx={"bered": True},
3923 self.assertEqual(err.exception.offset, offset + 1 + 1 + len(chunk) * chunks)
3924 self.assertEqual(err.exception.decode_path, decode_path + (str(chunks),))
3928 def choice_values_strategy(draw, value_required=False, schema=None, do_expl=False):
3930 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3931 tags = [tag_encode(tag) for tag in draw(sets(
3932 integers(min_value=0),
3933 min_size=len(names),
3934 max_size=len(names),
3936 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3938 if value_required or draw(booleans()):
3939 value = draw(tuples(
3940 sampled_from([name for name, _ in schema]),
3941 integers().map(Integer),
3945 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3946 default = draw(one_of(
3948 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3950 optional = draw(one_of(none(), booleans()))
3952 draw(integers(min_value=0)),
3953 draw(integers(min_value=0)),
3954 draw(integers(min_value=0)),
3956 return (schema, value, expl, default, optional, _decoded)
3959 class ChoiceInherited(Choice):
3963 class TestChoice(CommonMixin, TestCase):
3965 schema = (("whatever", Boolean()),)
3968 def test_schema_required(self):
3969 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3972 def test_impl_forbidden(self):
3973 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3974 Choice(impl=b"whatever")
3976 def test_invalid_value_type(self):
3977 with self.assertRaises(InvalidValueType) as err:
3978 self.base_klass(123)
3980 with self.assertRaises(ObjUnknown) as err:
3981 self.base_klass(("whenever", Boolean(False)))
3983 with self.assertRaises(InvalidValueType) as err:
3984 self.base_klass(("whatever", Integer(123)))
3988 def test_optional(self, optional):
3989 obj = self.base_klass(
3990 default=self.base_klass(("whatever", Boolean(False))),
3993 self.assertTrue(obj.optional)
3996 def test_ready(self, value):
3997 obj = self.base_klass()
3998 self.assertFalse(obj.ready)
4001 self.assertIsNone(obj["whatever"])
4002 with self.assertRaises(ObjNotReady) as err:
4005 obj["whatever"] = Boolean()
4006 self.assertFalse(obj.ready)
4009 obj["whatever"] = Boolean(value)
4010 self.assertTrue(obj.ready)
4014 @given(booleans(), booleans())
4015 def test_comparison(self, value1, value2):
4016 class WahlInherited(self.base_klass):
4018 for klass in (self.base_klass, WahlInherited):
4019 obj1 = klass(("whatever", Boolean(value1)))
4020 obj2 = klass(("whatever", Boolean(value2)))
4021 self.assertEqual(obj1 == obj2, value1 == value2)
4022 self.assertEqual(obj1 != obj2, value1 != value2)
4023 self.assertEqual(obj1 == obj2._value, value1 == value2)
4024 self.assertFalse(obj1 == obj2._value[1])
4026 @given(data_strategy())
4027 def test_call(self, d):
4028 for klass in (Choice, ChoiceInherited):
4036 ) = d.draw(choice_values_strategy())
4039 schema = schema_initial
4041 value=value_initial,
4043 default=default_initial,
4044 optional=optional_initial or False,
4045 _decoded=_decoded_initial,
4054 ) = d.draw(choice_values_strategy(schema=schema_initial, do_expl=True))
4055 obj = obj_initial(value, expl, default, optional)
4057 value_expected = default if value is None else value
4059 default_initial if value_expected is None
4062 self.assertEqual(obj.choice, value_expected[0])
4063 self.assertEqual(obj.value, int(value_expected[1]))
4064 self.assertEqual(obj.expl_tag, expl or expl_initial)
4065 default_expect = default_initial if default is None else default
4066 if default_expect is not None:
4067 self.assertEqual(obj.default.choice, default_expect[0])
4068 self.assertEqual(obj.default.value, int(default_expect[1]))
4069 if obj.default is None:
4070 optional = optional_initial if optional is None else optional
4071 optional = False if optional is None else optional
4074 self.assertEqual(obj.optional, optional)
4075 self.assertEqual(obj.specs, obj_initial.specs)
4077 def test_simultaneous_impl_expl(self):
4078 # override it, as Any does not have implicit tag
4081 def test_decoded(self):
4082 # override it, as Any does not have implicit tag
4085 @given(choice_values_strategy())
4086 def test_copy(self, values):
4087 _schema, value, expl, default, optional, _decoded = values
4089 class Wahl(self.base_klass):
4095 optional=optional or False,
4098 obj_copied = obj.copy()
4099 self.assertIsNone(obj.tag)
4100 self.assertIsNone(obj_copied.tag)
4101 # hack for assert_copied_basic_fields
4102 obj.tag = "whatever"
4103 obj_copied.tag = "whatever"
4104 self.assert_copied_basic_fields(obj, obj_copied)
4105 self.assertEqual(obj._value, obj_copied._value)
4106 self.assertEqual(obj.specs, obj_copied.specs)
4109 def test_stripped(self, value):
4110 obj = self.base_klass(("whatever", Boolean(value)))
4111 with self.assertRaises(NotEnoughData):
4112 obj.decode(obj.encode()[:-1])
4116 integers(min_value=1).map(tag_ctxc),
4118 def test_stripped_expl(self, value, tag_expl):
4119 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
4120 with self.assertRaises(NotEnoughData):
4121 obj.decode(obj.encode()[:-1])
4123 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4124 @given(data_strategy())
4125 def test_symmetric(self, d):
4126 _schema, value, _, default, optional, _decoded = d.draw(
4127 choice_values_strategy(value_required=True)
4129 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4130 offset = d.draw(integers(min_value=0))
4131 tail_junk = d.draw(binary(max_size=5))
4133 class Wahl(self.base_klass):
4143 self.assertFalse(obj.expled)
4144 obj_encoded = obj.encode()
4145 obj_expled = obj(value, expl=tag_expl)
4146 self.assertTrue(obj_expled.expled)
4149 obj_expled_encoded = obj_expled.encode()
4150 obj_decoded, tail = obj_expled.decode(
4151 obj_expled_encoded + tail_junk,
4156 self.assertEqual(tail, tail_junk)
4157 self.assertEqual(obj_decoded, obj_expled)
4158 self.assertEqual(obj_decoded.choice, obj_expled.choice)
4159 self.assertEqual(obj_decoded.value, obj_expled.value)
4160 self.assertEqual(obj_decoded.choice, obj.choice)
4161 self.assertEqual(obj_decoded.value, obj.value)
4162 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
4163 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
4164 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
4166 obj_decoded.expl_llen,
4167 len(len_encode(len(obj_encoded))),
4169 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
4170 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
4173 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
4175 self.assertEqual(obj_decoded.expl_offset, offset)
4176 self.assertSequenceEqual(
4178 obj_decoded.value.offset - offset:
4179 obj_decoded.value.offset + obj_decoded.value.tlvlen - offset
4185 def test_set_get(self, value):
4188 ("erste", Boolean()),
4189 ("zweite", Integer()),
4192 with self.assertRaises(ObjUnknown) as err:
4193 obj["whatever"] = "whenever"
4194 with self.assertRaises(InvalidValueType) as err:
4195 obj["zweite"] = Boolean(False)
4196 obj["zweite"] = Integer(value)
4198 with self.assertRaises(ObjUnknown) as err:
4201 self.assertIsNone(obj["erste"])
4202 self.assertEqual(obj["zweite"], Integer(value))
4204 def test_tag_mismatch(self):
4207 ("erste", Boolean()),
4209 int_encoded = Integer(123).encode()
4210 bool_encoded = Boolean(False).encode()
4212 obj.decode(bool_encoded)
4213 with self.assertRaises(TagMismatch):
4214 obj.decode(int_encoded)
4216 def test_tag_mismatch_underlying(self):
4217 class SeqOfBoolean(SequenceOf):
4220 class SeqOfInteger(SequenceOf):
4225 ("erste", SeqOfBoolean()),
4228 int_encoded = SeqOfInteger((Integer(123),)).encode()
4229 bool_encoded = SeqOfBoolean((Boolean(False),)).encode()
4231 obj.decode(bool_encoded)
4232 with self.assertRaises(TagMismatch) as err:
4233 obj.decode(int_encoded)
4234 self.assertEqual(err.exception.decode_path, ("erste", "0"))
4238 def seq_values_strategy(draw, seq_klass, do_expl=False):
4240 if draw(booleans()):
4243 k: v for k, v in draw(dictionaries(
4246 booleans().map(Boolean),
4247 integers().map(Integer),
4252 if draw(booleans()):
4253 schema = list(draw(dictionaries(
4256 booleans().map(Boolean),
4257 integers().map(Integer),
4263 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4265 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4267 if draw(booleans()):
4268 default = seq_klass()
4270 k: v for k, v in draw(dictionaries(
4273 booleans().map(Boolean),
4274 integers().map(Integer),
4278 optional = draw(one_of(none(), booleans()))
4280 draw(integers(min_value=0)),
4281 draw(integers(min_value=0)),
4282 draw(integers(min_value=0)),
4284 return (value, schema, impl, expl, default, optional, _decoded)
4288 def sequence_strategy(draw, seq_klass):
4289 inputs = draw(lists(
4291 tuples(just(Boolean), booleans(), one_of(none(), booleans())),
4292 tuples(just(Integer), integers(), one_of(none(), integers())),
4297 integers(min_value=1),
4298 min_size=len(inputs),
4299 max_size=len(inputs),
4302 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4303 for tag, expled in zip(tags, draw(lists(
4305 min_size=len(inputs),
4306 max_size=len(inputs),
4310 for i, optional in enumerate(draw(lists(
4311 sampled_from(("required", "optional", "empty")),
4312 min_size=len(inputs),
4313 max_size=len(inputs),
4315 if optional in ("optional", "empty"):
4316 inits[i]["optional"] = True
4317 if optional == "empty":
4319 empties = set(empties)
4320 names = list(draw(sets(
4322 min_size=len(inputs),
4323 max_size=len(inputs),
4326 for i, (klass, value, default) in enumerate(inputs):
4327 schema.append((names[i], klass(default=default, **inits[i])))
4328 seq_name = draw(text_letters())
4329 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4332 for i, (klass, value, default) in enumerate(inputs):
4339 "default_value": None if spec.default is None else default,
4343 expect["optional"] = True
4345 expect["presented"] = True
4346 expect["value"] = value
4348 expect["optional"] = True
4349 if default is not None and default == value:
4350 expect["presented"] = False
4351 seq[name] = klass(value)
4352 expects.append(expect)
4357 def sequences_strategy(draw, seq_klass):
4358 tags = draw(sets(integers(min_value=1), min_size=0, max_size=5))
4360 ({"expl": tag_ctxc(tag)} if expled else {"impl": tag_encode(tag)})
4361 for tag, expled in zip(tags, draw(lists(
4368 i for i, is_default in enumerate(draw(lists(
4374 names = list(draw(sets(
4379 seq_expectses = draw(lists(
4380 sequence_strategy(seq_klass=seq_klass),
4384 seqs = [seq for seq, _ in seq_expectses]
4386 for i, (name, seq) in enumerate(zip(names, seqs)):
4389 seq(default=(seq if i in defaulted else None), **inits[i]),
4391 seq_name = draw(text_letters())
4392 Seq = type(seq_name, (seq_klass,), {"schema": tuple(schema)})
4395 for name, (seq_inner, expects_inner) in zip(names, seq_expectses):
4398 "expects": expects_inner,
4401 seq_outer[name] = seq_inner
4402 if seq_outer.specs[name].default is None:
4403 expect["presented"] = True
4404 expect_outers.append(expect)
4405 return seq_outer, expect_outers
4408 class SeqMixing(object):
4409 def test_invalid_value_type(self):
4410 with self.assertRaises(InvalidValueType) as err:
4411 self.base_klass(123)
4414 def test_invalid_value_type_set(self):
4415 class Seq(self.base_klass):
4416 schema = (("whatever", Boolean()),)
4418 with self.assertRaises(InvalidValueType) as err:
4419 seq["whatever"] = Integer(123)
4423 def test_optional(self, optional):
4424 obj = self.base_klass(default=self.base_klass(), optional=optional)
4425 self.assertTrue(obj.optional)
4427 @given(data_strategy())
4428 def test_ready(self, d):
4430 str(i): v for i, v in enumerate(d.draw(lists(
4437 str(i + len(ready)): v for i, v in enumerate(d.draw(lists(
4444 for name in d.draw(permutations(
4445 list(ready.keys()) + list(non_ready.keys()),
4447 schema_input.append((name, Boolean()))
4449 class Seq(self.base_klass):
4450 schema = tuple(schema_input)
4452 for name in ready.keys():
4454 seq[name] = Boolean()
4455 self.assertFalse(seq.ready)
4458 for name, value in ready.items():
4459 seq[name] = Boolean(value)
4460 self.assertFalse(seq.ready)
4463 with self.assertRaises(ObjNotReady) as err:
4466 for name, value in non_ready.items():
4467 seq[name] = Boolean(value)
4468 self.assertTrue(seq.ready)
4472 @given(data_strategy())
4473 def test_call(self, d):
4474 class SeqInherited(self.base_klass):
4476 for klass in (self.base_klass, SeqInherited):
4485 ) = d.draw(seq_values_strategy(seq_klass=klass))
4486 obj_initial = klass(
4492 optional_initial or False,
4503 ) = d.draw(seq_values_strategy(
4505 do_expl=impl_initial is None,
4507 obj = obj_initial(value, impl, expl, default, optional)
4508 value_expected = default if value is None else value
4510 default_initial if value_expected is None
4513 self.assertEqual(obj._value, getattr(value_expected, "_value", {}))
4514 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
4515 self.assertEqual(obj.expl_tag, expl or expl_initial)
4517 {} if obj.default is None else obj.default._value,
4518 getattr(default_initial if default is None else default, "_value", {}),
4520 if obj.default is None:
4521 optional = optional_initial if optional is None else optional
4522 optional = False if optional is None else optional
4525 self.assertEqual(list(obj.specs.items()), schema_initial or [])
4526 self.assertEqual(obj.optional, optional)
4528 @given(data_strategy())
4529 def test_copy(self, d):
4530 class SeqInherited(self.base_klass):
4532 for klass in (self.base_klass, SeqInherited):
4533 values = d.draw(seq_values_strategy(seq_klass=klass))
4534 obj = klass(*values)
4535 obj_copied = obj.copy()
4536 self.assert_copied_basic_fields(obj, obj_copied)
4537 self.assertEqual(obj.specs, obj_copied.specs)
4538 self.assertEqual(obj._value, obj_copied._value)
4540 @given(data_strategy())
4541 def test_stripped(self, d):
4542 value = d.draw(integers())
4543 tag_impl = tag_encode(d.draw(integers(min_value=1)))
4545 class Seq(self.base_klass):
4547 schema = (("whatever", Integer()),)
4549 seq["whatever"] = Integer(value)
4550 with self.assertRaises(NotEnoughData):
4551 seq.decode(seq.encode()[:-1])
4553 @given(data_strategy())
4554 def test_stripped_expl(self, d):
4555 value = d.draw(integers())
4556 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
4558 class Seq(self.base_klass):
4560 schema = (("whatever", Integer()),)
4562 seq["whatever"] = Integer(value)
4563 with self.assertRaises(NotEnoughData):
4564 seq.decode(seq.encode()[:-1])
4566 @given(binary(min_size=2))
4567 def test_non_tag_mismatch_raised(self, junk):
4569 _, _, len_encoded = tag_strip(memoryview(junk))
4570 len_decode(len_encoded)
4576 class Seq(self.base_klass):
4578 ("whatever", Integer()),
4580 ("whenever", Integer()),
4583 seq["whatever"] = Integer(123)
4584 seq["junk"] = Any(junk)
4585 seq["whenever"] = Integer(123)
4586 with self.assertRaises(DecodeError):
4587 seq.decode(seq.encode())
4590 integers(min_value=31),
4591 integers(min_value=0),
4594 def test_bad_tag(self, tag, offset, decode_path):
4595 with self.assertRaises(DecodeError) as err:
4596 self.base_klass().decode(
4597 tag_encode(tag)[:-1],
4599 decode_path=decode_path,
4602 self.assertEqual(err.exception.offset, offset)
4603 self.assertEqual(err.exception.decode_path, decode_path)
4606 integers(min_value=128),
4607 integers(min_value=0),
4610 def test_bad_len(self, l, offset, decode_path):
4611 with self.assertRaises(DecodeError) as err:
4612 self.base_klass().decode(
4613 self.base_klass.tag_default + len_encode(l)[:-1],
4615 decode_path=decode_path,
4618 self.assertEqual(err.exception.offset, offset)
4619 self.assertEqual(err.exception.decode_path, decode_path)
4621 def _assert_expects(self, seq, expects):
4622 for expect in expects:
4624 seq.specs[expect["name"]].optional,
4627 if expect["default_value"] is not None:
4629 seq.specs[expect["name"]].default,
4630 expect["default_value"],
4632 if expect["presented"]:
4633 self.assertIn(expect["name"], seq)
4634 self.assertEqual(seq[expect["name"]], expect["value"])
4636 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4637 @given(data_strategy())
4638 def test_symmetric(self, d):
4639 seq, expects = d.draw(sequence_strategy(seq_klass=self.base_klass))
4640 tail_junk = d.draw(binary(max_size=5))
4641 self.assertTrue(seq.ready)
4642 self.assertFalse(seq.decoded)
4643 self._assert_expects(seq, expects)
4646 self.assertTrue(seq.ready)
4647 seq_encoded = seq.encode()
4648 seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
4649 self.assertFalse(seq_decoded.lenindef)
4651 t, _, lv = tag_strip(seq_encoded)
4652 _, _, v = len_decode(lv)
4653 seq_encoded_lenindef = t + LENINDEF + v + EOC
4654 seq_decoded_lenindef, tail_lenindef = seq.decode(
4655 seq_encoded_lenindef + tail_junk,
4656 ctx={"bered": True},
4658 self.assertTrue(seq_decoded_lenindef.lenindef)
4659 with self.assertRaises(DecodeError):
4660 seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
4661 with self.assertRaises(DecodeError):
4662 seq.decode(seq_encoded_lenindef[:-2], ctx={"bered": True})
4663 repr(seq_decoded_lenindef)
4664 pprint(seq_decoded_lenindef)
4665 self.assertTrue(seq_decoded_lenindef.ready)
4667 for decoded, decoded_tail, encoded in (
4668 (seq_decoded, tail, seq_encoded),
4669 (seq_decoded_lenindef, tail_lenindef, seq_encoded_lenindef),
4671 self.assertEqual(decoded_tail, tail_junk)
4672 self._assert_expects(decoded, expects)
4673 self.assertEqual(seq, decoded)
4674 self.assertEqual(decoded.encode(), seq_encoded)
4675 self.assertEqual(decoded.tlvlen, len(encoded))
4676 for expect in expects:
4677 if not expect["presented"]:
4678 self.assertNotIn(expect["name"], decoded)
4680 self.assertIn(expect["name"], decoded)
4681 obj = decoded[expect["name"]]
4682 self.assertTrue(obj.decoded)
4683 offset = obj.expl_offset if obj.expled else obj.offset
4684 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4685 self.assertSequenceEqual(
4686 seq_encoded[offset:offset + tlvlen],
4690 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4691 @given(data_strategy())
4692 def test_symmetric_with_seq(self, d):
4693 seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass))
4694 self.assertTrue(seq.ready)
4695 seq_encoded = seq.encode()
4696 seq_decoded, tail = seq.decode(seq_encoded)
4697 self.assertEqual(tail, b"")
4698 self.assertTrue(seq.ready)
4699 self.assertEqual(seq, seq_decoded)
4700 self.assertEqual(seq_decoded.encode(), seq_encoded)
4701 for expect_outer in expect_outers:
4702 if not expect_outer["presented"]:
4703 self.assertNotIn(expect_outer["name"], seq_decoded)
4705 self.assertIn(expect_outer["name"], seq_decoded)
4706 obj = seq_decoded[expect_outer["name"]]
4707 self.assertTrue(obj.decoded)
4708 offset = obj.expl_offset if obj.expled else obj.offset
4709 tlvlen = obj.expl_tlvlen if obj.expled else obj.tlvlen
4710 self.assertSequenceEqual(
4711 seq_encoded[offset:offset + tlvlen],
4714 self._assert_expects(obj, expect_outer["expects"])
4716 @given(data_strategy())
4717 def test_default_disappears(self, d):
4718 _schema = list(d.draw(dictionaries(
4720 sets(integers(), min_size=2, max_size=2),
4724 class Seq(self.base_klass):
4726 (n, Integer(default=d))
4727 for n, (_, d) in _schema
4730 for name, (value, _) in _schema:
4731 seq[name] = Integer(value)
4732 self.assertEqual(len(seq._value), len(_schema))
4733 empty_seq = b"".join((self.base_klass.tag_default, len_encode(0)))
4734 self.assertGreater(len(seq.encode()), len(empty_seq))
4735 for name, (_, default) in _schema:
4736 seq[name] = Integer(default)
4737 self.assertEqual(len(seq._value), 0)
4738 self.assertSequenceEqual(seq.encode(), empty_seq)
4740 @given(data_strategy())
4741 def test_encoded_default_accepted(self, d):
4742 _schema = list(d.draw(dictionaries(
4747 tags = [tag_encode(tag) for tag in d.draw(sets(
4748 integers(min_value=0),
4749 min_size=len(_schema),
4750 max_size=len(_schema),
4753 class SeqWithoutDefault(self.base_klass):
4755 (n, Integer(impl=t))
4756 for (n, _), t in zip(_schema, tags)
4758 seq_without_default = SeqWithoutDefault()
4759 for name, value in _schema:
4760 seq_without_default[name] = Integer(value)
4761 seq_encoded = seq_without_default.encode()
4763 class SeqWithDefault(self.base_klass):
4765 (n, Integer(default=v, impl=t))
4766 for (n, v), t in zip(_schema, tags)
4768 seq_with_default = SeqWithDefault()
4769 seq_decoded, _ = seq_with_default.decode(seq_encoded)
4770 for name, value in _schema:
4771 self.assertEqual(seq_decoded[name], seq_with_default[name])
4772 self.assertEqual(seq_decoded[name], value)
4774 @given(data_strategy())
4775 def test_missing_from_spec(self, d):
4776 names = list(d.draw(sets(text_letters(), min_size=2)))
4777 tags = [tag_encode(tag) for tag in d.draw(sets(
4778 integers(min_value=0),
4779 min_size=len(names),
4780 max_size=len(names),
4782 names_tags = [(name, tag) for tag, name in sorted(zip(tags, names))]
4784 class SeqFull(self.base_klass):
4785 schema = [(n, Integer(impl=t)) for n, t in names_tags]
4786 seq_full = SeqFull()
4787 for i, name in enumerate(names):
4788 seq_full[name] = Integer(i)
4789 seq_encoded = seq_full.encode()
4790 altered = names_tags[:-2] + names_tags[-1:]
4792 class SeqMissing(self.base_klass):
4793 schema = [(n, Integer(impl=t)) for n, t in altered]
4794 seq_missing = SeqMissing()
4795 with self.assertRaises(TagMismatch):
4796 seq_missing.decode(seq_encoded)
4799 class TestSequence(SeqMixing, CommonMixin, TestCase):
4800 base_klass = Sequence
4806 def test_remaining(self, value, junk):
4807 class Seq(Sequence):
4809 ("whatever", Integer()),
4811 int_encoded = Integer(value).encode()
4813 Sequence.tag_default,
4814 len_encode(len(int_encoded + junk)),
4817 with assertRaisesRegex(self, DecodeError, "remaining"):
4818 Seq().decode(junked)
4820 @given(sets(text_letters(), min_size=2))
4821 def test_obj_unknown(self, names):
4822 missing = names.pop()
4824 class Seq(Sequence):
4825 schema = [(n, Boolean()) for n in names]
4827 with self.assertRaises(ObjUnknown) as err:
4830 with self.assertRaises(ObjUnknown) as err:
4831 seq[missing] = Boolean()
4834 def test_x690_vector(self):
4835 class Seq(Sequence):
4837 ("name", IA5String()),
4840 seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0]
4841 self.assertEqual(seq["name"], "Smith")
4842 self.assertEqual(seq["ok"], True)
4845 class TestSet(SeqMixing, CommonMixin, TestCase):
4848 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
4849 @given(data_strategy())
4850 def test_sorted(self, d):
4852 tag_encode(tag) for tag in
4853 d.draw(sets(integers(min_value=1), min_size=1, max_size=10))
4857 schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
4859 for name, _ in Seq.schema:
4860 seq[name] = OctetString(b"")
4861 seq_encoded = seq.encode()
4862 seq_decoded, _ = seq.decode(seq_encoded)
4863 self.assertSequenceEqual(
4864 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
4865 b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
4870 def seqof_values_strategy(draw, schema=None, do_expl=False):
4872 schema = draw(sampled_from((Boolean(), Integer())))
4873 bound_min, bound_max = sorted(draw(sets(
4874 integers(min_value=0, max_value=10),
4878 if isinstance(schema, Boolean):
4879 values_generator = booleans().map(Boolean)
4880 elif isinstance(schema, Integer):
4881 values_generator = integers().map(Integer)
4882 values_generator = lists(
4887 values = draw(one_of(none(), values_generator))
4891 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4893 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
4894 default = draw(one_of(none(), values_generator))
4895 optional = draw(one_of(none(), booleans()))
4897 draw(integers(min_value=0)),
4898 draw(integers(min_value=0)),
4899 draw(integers(min_value=0)),
4904 (bound_min, bound_max),
4913 class SeqOfMixing(object):
4914 def test_invalid_value_type(self):
4915 with self.assertRaises(InvalidValueType) as err:
4916 self.base_klass(123)
4919 def test_invalid_values_type(self):
4920 class SeqOf(self.base_klass):
4922 with self.assertRaises(InvalidValueType) as err:
4923 SeqOf([Integer(123), Boolean(False), Integer(234)])
4926 def test_schema_required(self):
4927 with assertRaisesRegex(self, ValueError, "schema must be specified"):
4928 self.base_klass.__mro__[1]()
4930 @given(booleans(), booleans(), binary(), binary())
4931 def test_comparison(self, value1, value2, tag1, tag2):
4932 class SeqOf(self.base_klass):
4934 obj1 = SeqOf([Boolean(value1)])
4935 obj2 = SeqOf([Boolean(value2)])
4936 self.assertEqual(obj1 == obj2, value1 == value2)
4937 self.assertEqual(obj1 != obj2, value1 != value2)
4938 self.assertEqual(obj1 == list(obj2), value1 == value2)
4939 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
4940 obj1 = SeqOf([Boolean(value1)], impl=tag1)
4941 obj2 = SeqOf([Boolean(value1)], impl=tag2)
4942 self.assertEqual(obj1 == obj2, tag1 == tag2)
4943 self.assertEqual(obj1 != obj2, tag1 != tag2)
4945 @given(lists(booleans()))
4946 def test_iter(self, values):
4947 class SeqOf(self.base_klass):
4949 obj = SeqOf([Boolean(value) for value in values])
4950 self.assertEqual(len(obj), len(values))
4951 for i, value in enumerate(obj):
4952 self.assertEqual(value, values[i])
4954 @given(data_strategy())
4955 def test_ready(self, d):
4956 ready = [Integer(v) for v in d.draw(lists(
4963 range(d.draw(integers(min_value=1, max_value=5)))
4966 class SeqOf(self.base_klass):
4968 values = d.draw(permutations(ready + non_ready))
4970 for value in values:
4972 self.assertFalse(seqof.ready)
4975 with self.assertRaises(ObjNotReady) as err:
4978 for i, value in enumerate(values):
4979 self.assertEqual(seqof[i], value)
4980 if not seqof[i].ready:
4981 seqof[i] = Integer(i)
4982 self.assertTrue(seqof.ready)
4986 def test_spec_mismatch(self):
4987 class SeqOf(self.base_klass):
4990 seqof.append(Integer(123))
4991 with self.assertRaises(ValueError):
4992 seqof.append(Boolean(False))
4993 with self.assertRaises(ValueError):
4994 seqof[0] = Boolean(False)
4996 @given(data_strategy())
4997 def test_bounds_satisfied(self, d):
4998 class SeqOf(self.base_klass):
5000 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
5001 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5002 value = [Boolean()] * d.draw(integers(min_value=bound_min, max_value=bound_max))
5003 SeqOf(value=value, bounds=(bound_min, bound_max))
5005 @given(data_strategy())
5006 def test_bounds_unsatisfied(self, d):
5007 class SeqOf(self.base_klass):
5009 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
5010 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
5011 value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
5012 with self.assertRaises(BoundsError) as err:
5013 SeqOf(value=value, bounds=(bound_min, bound_max))
5015 value = [Boolean()] * d.draw(integers(
5016 min_value=bound_max + 1,
5017 max_value=bound_max + 10,
5019 with self.assertRaises(BoundsError) as err:
5020 SeqOf(value=value, bounds=(bound_min, bound_max))
5023 @given(integers(min_value=1, max_value=10))
5024 def test_out_of_bounds(self, bound_max):
5025 class SeqOf(self.base_klass):
5027 bounds = (0, bound_max)
5029 for _ in range(bound_max):
5030 seqof.append(Integer(123))
5031 with self.assertRaises(BoundsError):
5032 seqof.append(Integer(123))
5034 @given(data_strategy())
5035 def test_call(self, d):
5045 ) = d.draw(seqof_values_strategy())
5047 class SeqOf(self.base_klass):
5048 schema = schema_initial
5049 obj_initial = SeqOf(
5050 value=value_initial,
5051 bounds=bounds_initial,
5054 default=default_initial,
5055 optional=optional_initial or False,
5056 _decoded=_decoded_initial,
5067 ) = d.draw(seqof_values_strategy(
5068 schema=schema_initial,
5069 do_expl=impl_initial is None,
5071 if (default is None) and (obj_initial.default is not None):
5074 (bounds is None) and
5075 (value is not None) and
5076 (bounds_initial is not None) and
5077 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
5081 (bounds is None) and
5082 (default is not None) and
5083 (bounds_initial is not None) and
5084 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
5096 value_expected = default if value is None else value
5098 default_initial if value_expected is None
5101 value_expected = () if value_expected is None else value_expected
5102 self.assertEqual(obj, value_expected)
5103 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
5104 self.assertEqual(obj.expl_tag, expl or expl_initial)
5107 default_initial if default is None else default,
5109 if obj.default is None:
5110 optional = optional_initial if optional is None else optional
5111 optional = False if optional is None else optional
5114 self.assertEqual(obj.optional, optional)
5116 (obj._bound_min, obj._bound_max),
5117 bounds or bounds_initial or (0, float("+inf")),
5120 @given(seqof_values_strategy())
5121 def test_copy(self, values):
5122 _schema, value, bounds, impl, expl, default, optional, _decoded = values
5124 class SeqOf(self.base_klass):
5132 optional=optional or False,
5135 obj_copied = obj.copy()
5136 self.assert_copied_basic_fields(obj, obj_copied)
5137 self.assertEqual(obj._bound_min, obj_copied._bound_min)
5138 self.assertEqual(obj._bound_max, obj_copied._bound_max)
5139 self.assertEqual(obj._value, obj_copied._value)
5143 integers(min_value=1).map(tag_encode),
5145 def test_stripped(self, values, tag_impl):
5146 class SeqOf(self.base_klass):
5147 schema = OctetString()
5148 obj = SeqOf([OctetString(v) for v in values], impl=tag_impl)
5149 with self.assertRaises(NotEnoughData):
5150 obj.decode(obj.encode()[:-1])
5154 integers(min_value=1).map(tag_ctxc),
5156 def test_stripped_expl(self, values, tag_expl):
5157 class SeqOf(self.base_klass):
5158 schema = OctetString()
5159 obj = SeqOf([OctetString(v) for v in values], expl=tag_expl)
5160 with self.assertRaises(NotEnoughData):
5161 obj.decode(obj.encode()[:-1])
5164 integers(min_value=31),
5165 integers(min_value=0),
5168 def test_bad_tag(self, tag, offset, decode_path):
5169 with self.assertRaises(DecodeError) as err:
5170 self.base_klass().decode(
5171 tag_encode(tag)[:-1],
5173 decode_path=decode_path,
5176 self.assertEqual(err.exception.offset, offset)
5177 self.assertEqual(err.exception.decode_path, decode_path)
5180 integers(min_value=128),
5181 integers(min_value=0),
5184 def test_bad_len(self, l, offset, decode_path):
5185 with self.assertRaises(DecodeError) as err:
5186 self.base_klass().decode(
5187 self.base_klass.tag_default + len_encode(l)[:-1],
5189 decode_path=decode_path,
5192 self.assertEqual(err.exception.offset, offset)
5193 self.assertEqual(err.exception.decode_path, decode_path)
5195 @given(binary(min_size=1))
5196 def test_tag_mismatch(self, impl):
5197 assume(impl != self.base_klass.tag_default)
5198 with self.assertRaises(TagMismatch):
5199 self.base_klass(impl=impl).decode(self.base_klass().encode())
5201 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5203 seqof_values_strategy(schema=Integer()),
5204 lists(integers().map(Integer)),
5205 integers(min_value=1).map(tag_ctxc),
5206 integers(min_value=0),
5209 def test_symmetric(self, values, value, tag_expl, offset, tail_junk):
5210 _, _, _, _, _, default, optional, _decoded = values
5212 class SeqOf(self.base_klass):
5222 self.assertFalse(obj.expled)
5223 obj_encoded = obj.encode()
5224 obj_expled = obj(value, expl=tag_expl)
5225 self.assertTrue(obj_expled.expled)
5228 obj_expled_encoded = obj_expled.encode()
5229 obj_decoded, tail = obj_expled.decode(
5230 obj_expled_encoded + tail_junk,
5235 self.assertEqual(tail, tail_junk)
5236 self._test_symmetric_compare_objs(obj_decoded, obj_expled)
5237 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
5238 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
5239 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
5241 obj_decoded.expl_llen,
5242 len(len_encode(len(obj_encoded))),
5244 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
5245 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
5248 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
5250 self.assertEqual(obj_decoded.expl_offset, offset)
5251 for obj_inner in obj_decoded:
5252 self.assertIn(obj_inner, obj_decoded)
5253 self.assertSequenceEqual(
5256 obj_inner.offset - offset:
5257 obj_inner.offset + obj_inner.tlvlen - offset
5261 t, _, lv = tag_strip(obj_encoded)
5262 _, _, v = len_decode(lv)
5263 obj_encoded_lenindef = t + LENINDEF + v + EOC
5264 obj_decoded_lenindef, tail_lenindef = obj.decode(
5265 obj_encoded_lenindef + tail_junk,
5266 ctx={"bered": True},
5268 self.assertTrue(obj_decoded_lenindef.lenindef)
5269 repr(obj_decoded_lenindef)
5270 pprint(obj_decoded_lenindef)
5271 self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
5272 with self.assertRaises(DecodeError):
5273 obj.decode(obj_encoded_lenindef[:-1], ctx={"bered": True})
5274 with self.assertRaises(DecodeError):
5275 obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
5278 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
5279 class SeqOf(SequenceOf):
5283 def _test_symmetric_compare_objs(self, obj1, obj2):
5284 self.assertEqual(obj1, obj2)
5285 self.assertSequenceEqual(list(obj1), list(obj2))
5288 class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
5293 def _test_symmetric_compare_objs(self, obj1, obj2):
5294 self.assertSetEqual(
5295 set(int(v) for v in obj1),
5296 set(int(v) for v in obj2),
5299 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
5300 @given(data_strategy())
5301 def test_sorted(self, d):
5302 values = [OctetString(v) for v in d.draw(lists(binary()))]
5305 schema = OctetString()
5307 seq_encoded = seq.encode()
5308 seq_decoded, _ = seq.decode(seq_encoded)
5309 self.assertSequenceEqual(
5310 seq_encoded[seq_decoded.tlen + seq_decoded.llen:],
5311 b"".join(sorted([v.encode() for v in values])),
5315 class TestGoMarshalVectors(TestCase):
5317 self.assertSequenceEqual(Integer(10).encode(), hexdec("02010a"))
5318 self.assertSequenceEqual(Integer(127).encode(), hexdec("02017f"))
5319 self.assertSequenceEqual(Integer(128).encode(), hexdec("02020080"))
5320 self.assertSequenceEqual(Integer(-128).encode(), hexdec("020180"))
5321 self.assertSequenceEqual(Integer(-129).encode(), hexdec("0202ff7f"))
5323 class Seq(Sequence):
5325 ("erste", Integer()),
5326 ("zweite", Integer(optional=True))
5329 seq["erste"] = Integer(64)
5330 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5331 seq["erste"] = Integer(0x123456)
5332 self.assertSequenceEqual(seq.encode(), hexdec("30050203123456"))
5333 seq["erste"] = Integer(64)
5334 seq["zweite"] = Integer(65)
5335 self.assertSequenceEqual(seq.encode(), hexdec("3006020140020141"))
5337 class NestedSeq(Sequence):
5341 seq["erste"] = Integer(127)
5342 seq["zweite"] = None
5343 nested = NestedSeq()
5344 nested["nest"] = seq
5345 self.assertSequenceEqual(nested.encode(), hexdec("3005300302017f"))
5347 self.assertSequenceEqual(
5348 OctetString(b"\x01\x02\x03").encode(),
5349 hexdec("0403010203"),
5352 class Seq(Sequence):
5354 ("erste", Integer(impl=tag_encode(5, klass=TagClassContext))),
5357 seq["erste"] = Integer(64)
5358 self.assertSequenceEqual(seq.encode(), hexdec("3003850140"))
5360 class Seq(Sequence):
5362 ("erste", Integer(expl=tag_ctxc(5))),
5365 seq["erste"] = Integer(64)
5366 self.assertSequenceEqual(seq.encode(), hexdec("3005a503020140"))
5368 class Seq(Sequence):
5371 impl=tag_encode(0, klass=TagClassContext),
5376 seq["erste"] = Null()
5377 self.assertSequenceEqual(seq.encode(), hexdec("30028000"))
5379 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5381 self.assertSequenceEqual(
5382 UTCTime(datetime(1970, 1, 1, 0, 0)).encode(),
5383 hexdec("170d3730303130313030303030305a"),
5385 self.assertSequenceEqual(
5386 UTCTime(datetime(2009, 11, 15, 22, 56, 16)).encode(),
5387 hexdec("170d3039313131353232353631365a"),
5389 self.assertSequenceEqual(
5390 GeneralizedTime(datetime(2100, 4, 5, 12, 1, 1)).encode(),
5391 hexdec("180f32313030303430353132303130315a"),
5394 class Seq(Sequence):
5396 ("erste", GeneralizedTime()),
5399 seq["erste"] = GeneralizedTime(datetime(2009, 11, 15, 22, 56, 16))
5400 self.assertSequenceEqual(
5402 hexdec("3011180f32303039313131353232353631365a"),
5405 self.assertSequenceEqual(
5406 BitString((1, b"\x80")).encode(),
5409 self.assertSequenceEqual(
5410 BitString((12, b"\x81\xF0")).encode(),
5411 hexdec("03030481f0"),
5414 self.assertSequenceEqual(
5415 ObjectIdentifier("1.2.3.4").encode(),
5416 hexdec("06032a0304"),
5418 self.assertSequenceEqual(
5419 ObjectIdentifier("1.2.840.133549.1.1.5").encode(),
5420 hexdec("06092a864888932d010105"),
5422 self.assertSequenceEqual(
5423 ObjectIdentifier("2.100.3").encode(),
5424 hexdec("0603813403"),
5427 self.assertSequenceEqual(
5428 PrintableString("test").encode(),
5429 hexdec("130474657374"),
5431 self.assertSequenceEqual(
5432 PrintableString("x" * 127).encode(),
5433 hexdec("137F" + "78" * 127),
5435 self.assertSequenceEqual(
5436 PrintableString("x" * 128).encode(),
5437 hexdec("138180" + "78" * 128),
5439 self.assertSequenceEqual(UTF8String("Σ").encode(), hexdec("0c02cea3"))
5441 class Seq(Sequence):
5443 ("erste", IA5String()),
5446 seq["erste"] = IA5String("test")
5447 self.assertSequenceEqual(seq.encode(), hexdec("3006160474657374"))
5449 class Seq(Sequence):
5451 ("erste", PrintableString()),
5454 seq["erste"] = PrintableString("test")
5455 self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
5456 seq["erste"] = PrintableString("test*")
5457 self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
5459 class Seq(Sequence):
5461 ("erste", Any(optional=True)),
5462 ("zweite", Integer()),
5465 seq["zweite"] = Integer(64)
5466 self.assertSequenceEqual(seq.encode(), hexdec("3003020140"))
5471 seq.append(Integer(10))
5472 self.assertSequenceEqual(seq.encode(), hexdec("310302010a"))
5474 class _SeqOf(SequenceOf):
5475 schema = PrintableString()
5477 class SeqOf(SequenceOf):
5480 _seqof.append(PrintableString("1"))
5482 seqof.append(_seqof)
5483 self.assertSequenceEqual(seqof.encode(), hexdec("30053003130131"))
5485 class Seq(Sequence):
5487 ("erste", Integer(default=1)),
5490 seq["erste"] = Integer(0)
5491 self.assertSequenceEqual(seq.encode(), hexdec("3003020100"))
5492 seq["erste"] = Integer(1)
5493 self.assertSequenceEqual(seq.encode(), hexdec("3000"))
5494 seq["erste"] = Integer(2)
5495 self.assertSequenceEqual(seq.encode(), hexdec("3003020102"))
5498 class TestPP(TestCase):
5499 @given(data_strategy())
5500 def test_oid_printing(self, d):
5502 str(ObjectIdentifier(k)): v * 2
5503 for k, v in d.draw(dictionaries(oid_strategy(), text_letters())).items()
5505 chosen = d.draw(sampled_from(sorted(oids)))
5506 chosen_id = oids[chosen]
5507 pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
5508 self.assertNotIn(chosen_id, pp_console_row(pp))
5509 self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
5512 class TestAutoAddSlots(TestCase):
5514 class Inher(Integer):
5517 with self.assertRaises(AttributeError):
5519 inher.unexistent = "whatever"
5522 class TestOIDDefines(TestCase):
5523 @given(data_strategy())
5524 def runTest(self, d):
5525 value_names = list(d.draw(sets(text_letters(), min_size=1, max_size=10)))
5526 value_name_chosen = d.draw(sampled_from(value_names))
5528 ObjectIdentifier(oid)
5529 for oid in d.draw(sets(oid_strategy(), min_size=2, max_size=10))
5531 oid_chosen = d.draw(sampled_from(oids))
5532 values = d.draw(lists(
5534 min_size=len(value_names),
5535 max_size=len(value_names),
5538 ("type", ObjectIdentifier(defines=(((value_name_chosen,), {
5539 oid: Integer() for oid in oids[:-1]
5542 for i, value_name in enumerate(value_names):
5543 _schema.append((value_name, Any(expl=tag_ctxp(i))))
5545 class Seq(Sequence):
5548 for value_name, value in zip(value_names, values):
5549 seq[value_name] = Any(Integer(value).encode())
5550 seq["type"] = oid_chosen
5551 seq, _ = Seq().decode(seq.encode())
5552 for value_name in value_names:
5553 if value_name == value_name_chosen:
5555 self.assertIsNone(seq[value_name].defined)
5556 if value_name_chosen in oids[:-1]:
5557 self.assertIsNotNone(seq[value_name_chosen].defined)
5558 self.assertEqual(seq[value_name_chosen].defined[0], oid_chosen)
5559 self.assertIsInstance(seq[value_name_chosen].defined[1], Integer)
5562 class TestDefinesByPath(TestCase):
5563 def test_generated(self):
5564 class Seq(Sequence):
5566 ("type", ObjectIdentifier()),
5567 ("value", OctetString(expl=tag_ctxc(123))),
5570 class SeqInner(Sequence):
5572 ("typeInner", ObjectIdentifier()),
5573 ("valueInner", Any()),
5576 class PairValue(SetOf):
5579 class Pair(Sequence):
5581 ("type", ObjectIdentifier()),
5582 ("value", PairValue()),
5585 class Pairs(SequenceOf):
5592 type_octet_stringed,
5594 ObjectIdentifier(oid)
5595 for oid in sets(oid_strategy(), min_size=4, max_size=4).example()
5597 seq_integered = Seq()
5598 seq_integered["type"] = type_integered
5599 seq_integered["value"] = OctetString(Integer(123).encode())
5600 seq_integered_raw = seq_integered.encode()
5604 (type_octet_stringed, OctetString(b"whatever")),
5605 (type_integered, Integer(123)),
5606 (type_octet_stringed, OctetString(b"whenever")),
5607 (type_integered, Integer(234)),
5609 for t, v in pairs_input:
5612 pair["value"] = PairValue((Any(v),))
5614 seq_inner = SeqInner()
5615 seq_inner["typeInner"] = type_innered
5616 seq_inner["valueInner"] = Any(pairs)
5617 seq_sequenced = Seq()
5618 seq_sequenced["type"] = type_sequenced
5619 seq_sequenced["value"] = OctetString(seq_inner.encode())
5620 seq_sequenced_raw = seq_sequenced.encode()
5622 defines_by_path = []
5623 seq_integered, _ = Seq().decode(seq_integered_raw)
5624 self.assertIsNone(seq_integered["value"].defined)
5625 defines_by_path.append(
5626 (("type",), ((("value",), {
5627 type_integered: Integer(),
5628 type_sequenced: SeqInner(),
5631 seq_integered, _ = Seq().decode(
5633 ctx={"defines_by_path": defines_by_path},
5635 self.assertIsNotNone(seq_integered["value"].defined)
5636 self.assertEqual(seq_integered["value"].defined[0], type_integered)
5637 self.assertEqual(seq_integered["value"].defined[1], Integer(123))
5638 self.assertTrue(seq_integered_raw[
5639 seq_integered["value"].defined[1].offset:
5640 ].startswith(Integer(123).encode()))
5642 seq_sequenced, _ = Seq().decode(
5644 ctx={"defines_by_path": defines_by_path},
5646 self.assertIsNotNone(seq_sequenced["value"].defined)
5647 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5648 seq_inner = seq_sequenced["value"].defined[1]
5649 self.assertIsNone(seq_inner["valueInner"].defined)
5651 defines_by_path.append((
5652 ("value", DecodePathDefBy(type_sequenced), "typeInner"),
5653 ((("valueInner",), {type_innered: Pairs()}),),
5655 seq_sequenced, _ = Seq().decode(
5657 ctx={"defines_by_path": defines_by_path},
5659 self.assertIsNotNone(seq_sequenced["value"].defined)
5660 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5661 seq_inner = seq_sequenced["value"].defined[1]
5662 self.assertIsNotNone(seq_inner["valueInner"].defined)
5663 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5664 pairs = seq_inner["valueInner"].defined[1]
5666 self.assertIsNone(pair["value"][0].defined)
5668 defines_by_path.append((
5671 DecodePathDefBy(type_sequenced),
5673 DecodePathDefBy(type_innered),
5678 type_integered: Integer(),
5679 type_octet_stringed: OctetString(),
5682 seq_sequenced, _ = Seq().decode(
5684 ctx={"defines_by_path": defines_by_path},
5686 self.assertIsNotNone(seq_sequenced["value"].defined)
5687 self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
5688 seq_inner = seq_sequenced["value"].defined[1]
5689 self.assertIsNotNone(seq_inner["valueInner"].defined)
5690 self.assertEqual(seq_inner["valueInner"].defined[0], type_innered)
5691 pairs_got = seq_inner["valueInner"].defined[1]
5692 for pair_input, pair_got in zip(pairs_input, pairs_got):
5693 self.assertEqual(pair_got["value"][0].defined[0], pair_input[0])
5694 self.assertEqual(pair_got["value"][0].defined[1], pair_input[1])
5696 @given(oid_strategy(), integers())
5697 def test_simple(self, oid, tgt):
5698 class Inner(Sequence):
5700 ("oid", ObjectIdentifier(defines=((("..", "tgt"), {
5701 ObjectIdentifier(oid): Integer(),
5705 class Outer(Sequence):
5708 ("tgt", OctetString()),
5712 inner["oid"] = ObjectIdentifier(oid)
5714 outer["inner"] = inner
5715 outer["tgt"] = OctetString(Integer(tgt).encode())
5716 decoded, _ = Outer().decode(outer.encode())
5717 self.assertEqual(decoded["tgt"].defined[1], Integer(tgt))
5720 class TestAbsDecodePath(TestCase):
5722 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5723 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5725 def test_concat(self, decode_path, rel_path):
5726 self.assertSequenceEqual(
5727 abs_decode_path(decode_path, rel_path),
5728 decode_path + rel_path,
5732 lists(text(alphabet=ascii_letters, min_size=1)).map(tuple),
5733 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5735 def test_abs(self, decode_path, rel_path):
5736 self.assertSequenceEqual(
5737 abs_decode_path(decode_path, ("/",) + rel_path),
5742 lists(text(alphabet=ascii_letters, min_size=1), min_size=5).map(tuple),
5743 integers(min_value=1, max_value=3),
5744 lists(text(alphabet=ascii_letters, min_size=1), min_size=1).map(tuple),
5746 def test_dots(self, decode_path, number_of_dots, rel_path):
5747 self.assertSequenceEqual(
5748 abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path),
5749 decode_path[:-number_of_dots] + rel_path,
5753 class TestStrictDefaultExistence(TestCase):
5754 @given(data_strategy())
5755 def runTest(self, d):
5756 count = d.draw(integers(min_value=1, max_value=10))
5757 chosen = d.draw(integers(min_value=0, max_value=count - 1))
5759 ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
5760 for i in range(count)
5763 class Seq(Sequence):
5766 for i in range(count):
5767 seq["int%d" % i] = Integer(123)
5769 chosen = "int%d" % chosen
5770 seq.specs[chosen] = seq.specs[chosen](default=123)
5772 with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
5773 seq.decode(raw, ctx={"strict_default_existence": True})
5776 class TestX690PrefixedType(TestCase):
5778 self.assertSequenceEqual(
5779 VisibleString("Jones").encode(),
5780 hexdec("1A054A6F6E6573"),
5782 self.assertSequenceEqual(
5785 impl=tag_encode(3, klass=TagClassApplication),
5787 hexdec("43054A6F6E6573"),
5789 self.assertSequenceEqual(
5793 impl=tag_encode(3, klass=TagClassApplication),
5797 hexdec("A20743054A6F6E6573"),
5799 self.assertSequenceEqual(
5803 impl=tag_encode(3, klass=TagClassApplication),
5805 impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication),
5807 hexdec("670743054A6F6E6573"),
5809 self.assertSequenceEqual(
5810 VisibleString("Jones", impl=tag_ctxp(2)).encode(),
5811 hexdec("82054A6F6E6573"),