2 # PyDERASN -- Python ASN.1 DER codec with abstract structures
3 # Copyright (C) 2017 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 printable
22 from string import whitespace
23 from unittest import TestCase
25 from hypothesis import assume
26 from hypothesis import given
27 from hypothesis import settings
28 from hypothesis.strategies import binary
29 from hypothesis.strategies import booleans
30 from hypothesis.strategies import composite
31 from hypothesis.strategies import data as data_strategy
32 from hypothesis.strategies import datetimes
33 from hypothesis.strategies import dictionaries
34 from hypothesis.strategies import integers
35 from hypothesis.strategies import just
36 from hypothesis.strategies import lists
37 from hypothesis.strategies import none
38 from hypothesis.strategies import one_of
39 from hypothesis.strategies import permutations
40 from hypothesis.strategies import sampled_from
41 from hypothesis.strategies import sets
42 from hypothesis.strategies import text
43 from hypothesis.strategies import tuples
44 from six import assertRaisesRegex
45 from six import byte2int
46 from six import indexbytes
47 from six import int2byte
48 from six import iterbytes
50 from six import text_type
52 from pyderasn import _pp
53 from pyderasn import Any
54 from pyderasn import BitString
55 from pyderasn import BMPString
56 from pyderasn import Boolean
57 from pyderasn import BoundsError
58 from pyderasn import Choice
59 from pyderasn import DecodeError
60 from pyderasn import Enumerated
61 from pyderasn import GeneralizedTime
62 from pyderasn import GeneralString
63 from pyderasn import GraphicString
64 from pyderasn import hexdec
65 from pyderasn import hexenc
66 from pyderasn import IA5String
67 from pyderasn import Integer
68 from pyderasn import InvalidLength
69 from pyderasn import InvalidOID
70 from pyderasn import InvalidValueType
71 from pyderasn import len_decode
72 from pyderasn import len_encode
73 from pyderasn import NotEnoughData
74 from pyderasn import Null
75 from pyderasn import NumericString
76 from pyderasn import ObjectIdentifier
77 from pyderasn import ObjNotReady
78 from pyderasn import ObjUnknown
79 from pyderasn import OctetString
80 from pyderasn import pp_console_row
81 from pyderasn import pprint
82 from pyderasn import PrintableString
83 from pyderasn import Sequence
84 from pyderasn import SequenceOf
85 from pyderasn import Set
86 from pyderasn import SetOf
87 from pyderasn import tag_ctxc
88 from pyderasn import tag_decode
89 from pyderasn import tag_encode
90 from pyderasn import tag_strip
91 from pyderasn import TagClassApplication
92 from pyderasn import TagClassContext
93 from pyderasn import TagClassPrivate
94 from pyderasn import TagClassUniversal
95 from pyderasn import TagFormConstructed
96 from pyderasn import TagFormPrimitive
97 from pyderasn import TagMismatch
98 from pyderasn import TeletexString
99 from pyderasn import UniversalString
100 from pyderasn import UTCTime
101 from pyderasn import UTF8String
102 from pyderasn import VideotexString
103 from pyderasn import VisibleString
106 settings.register_profile('local', settings(
108 perform_health_check=False,
110 settings.load_profile('local')
111 LONG_TEST_MAX_EXAMPLES = settings().max_examples * 4
113 tag_classes = sampled_from((
119 tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
122 class TestHex(TestCase):
124 def test_symmetric(self, data):
125 self.assertEqual(hexdec(hexenc(data)), data)
128 class TestTagCoder(TestCase):
129 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
133 integers(min_value=0, max_value=30),
136 def test_short(self, klass, form, num, junk):
137 raw = tag_encode(klass=klass, form=form, num=num)
138 self.assertEqual(tag_decode(raw), (klass, form, num))
139 self.assertEqual(len(raw), 1)
141 byte2int(tag_encode(klass=klass, form=form, num=0)),
142 byte2int(raw) & (1 << 7 | 1 << 6 | 1 << 5),
144 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
145 self.assertSequenceEqual(stripped.tobytes(), raw)
146 self.assertEqual(tlen, len(raw))
147 self.assertSequenceEqual(tail, junk)
149 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
153 integers(min_value=31),
156 def test_long(self, klass, form, num, junk):
157 raw = tag_encode(klass=klass, form=form, num=num)
158 self.assertEqual(tag_decode(raw), (klass, form, num))
159 self.assertGreater(len(raw), 1)
161 byte2int(tag_encode(klass=klass, form=form, num=0)) | 31,
164 self.assertEqual(byte2int(raw[-1:]) & 0x80, 0)
165 self.assertTrue(all(b & 0x80 > 0 for b in iterbytes(raw[1:-1])))
166 stripped, tlen, tail = tag_strip(memoryview(raw + junk))
167 self.assertSequenceEqual(stripped.tobytes(), raw)
168 self.assertEqual(tlen, len(raw))
169 self.assertSequenceEqual(tail, junk)
171 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
172 @given(integers(min_value=31))
173 def test_unfinished_tag(self, num):
174 raw = bytearray(tag_encode(num=num))
175 for i in range(1, len(raw)):
177 with assertRaisesRegex(self, DecodeError, "unfinished tag"):
178 tag_strip(bytes(raw))
180 def test_go_vectors_valid(self):
181 for data, (eklass, etag, elen, eform) in (
182 (b"\x80\x01", (TagClassContext, 0, 1, TagFormPrimitive)),
183 (b"\xa0\x01", (TagClassContext, 0, 1, TagFormConstructed)),
184 (b"\x02\x00", (TagClassUniversal, 2, 0, TagFormPrimitive)),
185 (b"\xfe\x00", (TagClassPrivate, 30, 0, TagFormConstructed)),
186 (b"\x1f\x1f\x00", (TagClassUniversal, 31, 0, TagFormPrimitive)),
187 (b"\x1f\x81\x00\x00", (TagClassUniversal, 128, 0, TagFormPrimitive)),
188 (b"\x1f\x81\x80\x01\x00", (TagClassUniversal, 0x4001, 0, TagFormPrimitive)),
189 (b"\x00\x81\x80", (TagClassUniversal, 0, 128, TagFormPrimitive)),
190 (b"\x00\x82\x01\x00", (TagClassUniversal, 0, 256, TagFormPrimitive)),
191 (b"\xa0\x84\x7f\xff\xff\xff", (TagClassContext, 0, 0x7fffffff, TagFormConstructed)),
193 tag, _, len_encoded = tag_strip(memoryview(data))
194 klass, form, num = tag_decode(tag)
195 _len, _, tail = len_decode(len_encoded)
196 self.assertSequenceEqual(tail, b"")
197 self.assertEqual(klass, eklass)
198 self.assertEqual(num, etag)
199 self.assertEqual(_len, elen)
200 self.assertEqual(form, eform)
202 def test_go_vectors_invalid(self):
210 with self.assertRaises(DecodeError):
211 _, _, len_encoded = tag_strip(memoryview(data))
212 len_decode(len_encoded)
215 integers(min_value=0, max_value=127),
216 integers(min_value=0, max_value=2),
218 def test_long_instead_of_short(self, l, dummy_num):
219 octets = (b"\x00" * dummy_num) + int2byte(l)
220 octets = int2byte((dummy_num + 1) | 0x80) + octets
221 with self.assertRaises(DecodeError):
225 class TestLenCoder(TestCase):
226 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
228 integers(min_value=0, max_value=127),
231 def test_short(self, l, junk):
232 raw = len_encode(l) + junk
233 decoded, llen, tail = len_decode(memoryview(raw))
234 self.assertEqual(decoded, l)
235 self.assertEqual(llen, 1)
236 self.assertEqual(len(raw), 1 + len(junk))
237 self.assertEqual(tail.tobytes(), junk)
239 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
241 integers(min_value=128),
244 def test_long(self, l, junk):
245 raw = len_encode(l) + junk
246 decoded, llen, tail = len_decode(memoryview(raw))
247 self.assertEqual(decoded, l)
248 self.assertEqual((llen - 1) | 0x80, byte2int(raw))
249 self.assertEqual(llen, len(raw) - len(junk))
250 self.assertNotEqual(indexbytes(raw, 1), 0)
251 self.assertSequenceEqual(tail.tobytes(), junk)
253 def test_empty(self):
254 with self.assertRaises(NotEnoughData):
257 @given(integers(min_value=128))
258 def test_stripped(self, _len):
259 with self.assertRaises(NotEnoughData):
260 len_decode(len_encode(_len)[:-1])
263 text_printable = text(alphabet=printable, min_size=1)
267 def text_letters(draw):
268 result = draw(text(alphabet=ascii_letters, min_size=1))
270 result = result.encode("ascii")
274 class CommonMixin(object):
275 def test_tag_default(self):
276 obj = self.base_klass()
277 self.assertEqual(obj.tag, obj.tag_default)
279 def test_simultaneous_impl_expl(self):
280 with self.assertRaises(ValueError):
281 self.base_klass(impl=b"whatever", expl=b"whenever")
283 @given(binary(), integers(), integers(), integers())
284 def test_decoded(self, impl, offset, llen, vlen):
285 obj = self.base_klass(impl=impl, _decoded=(offset, llen, vlen))
286 self.assertEqual(obj.offset, offset)
287 self.assertEqual(obj.llen, llen)
288 self.assertEqual(obj.vlen, vlen)
289 self.assertEqual(obj.tlen, len(impl))
290 self.assertEqual(obj.tlvlen, obj.tlen + obj.llen + obj.vlen)
293 def test_impl_inherited(self, impl_tag):
294 class Inherited(self.base_klass):
297 self.assertSequenceEqual(obj.impl, impl_tag)
298 self.assertFalse(obj.expled)
301 def test_expl_inherited(self, expl_tag):
302 class Inherited(self.base_klass):
305 self.assertSequenceEqual(obj.expl, expl_tag)
306 self.assertTrue(obj.expled)
308 def assert_copied_basic_fields(self, obj, obj_copied):
309 self.assertEqual(obj, obj_copied)
310 self.assertSequenceEqual(obj.tag, obj_copied.tag)
311 self.assertEqual(obj.expl_tag, obj_copied.expl_tag)
312 self.assertEqual(obj.default, obj_copied.default)
313 self.assertEqual(obj.optional, obj_copied.optional)
314 self.assertEqual(obj.offset, obj_copied.offset)
315 self.assertEqual(obj.llen, obj_copied.llen)
316 self.assertEqual(obj.vlen, obj_copied.vlen)
320 def boolean_values_strat(draw, do_expl=False):
321 value = draw(one_of(none(), booleans()))
325 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
327 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
328 default = draw(one_of(none(), booleans()))
329 optional = draw(one_of(none(), booleans()))
331 draw(integers(min_value=0)),
332 draw(integers(min_value=0)),
333 draw(integers(min_value=0)),
335 return (value, impl, expl, default, optional, _decoded)
338 class BooleanInherited(Boolean):
342 class TestBoolean(CommonMixin, TestCase):
345 def test_invalid_value_type(self):
346 with self.assertRaises(InvalidValueType) as err:
351 def test_optional(self, optional):
352 obj = Boolean(default=Boolean(False), optional=optional)
353 self.assertTrue(obj.optional)
356 def test_ready(self, value):
358 self.assertFalse(obj.ready)
361 with self.assertRaises(ObjNotReady) as err:
365 self.assertTrue(obj.ready)
369 @given(booleans(), booleans(), binary(), binary())
370 def test_comparison(self, value1, value2, tag1, tag2):
371 for klass in (Boolean, BooleanInherited):
374 self.assertEqual(obj1 == obj2, value1 == value2)
375 self.assertEqual(obj1 != obj2, value1 != value2)
376 self.assertEqual(obj1 == bool(obj2), value1 == value2)
377 obj1 = klass(value1, impl=tag1)
378 obj2 = klass(value1, impl=tag2)
379 self.assertEqual(obj1 == obj2, tag1 == tag2)
380 self.assertEqual(obj1 != obj2, tag1 != tag2)
382 @given(data_strategy())
383 def test_call(self, d):
384 for klass in (Boolean, BooleanInherited):
392 ) = d.draw(boolean_values_strat())
398 optional_initial or False,
408 ) = d.draw(boolean_values_strat(do_expl=impl_initial is None))
409 obj = obj_initial(value, impl, expl, default, optional)
411 value_expected = default if value is None else value
413 default_initial if value_expected is None
416 self.assertEqual(obj, value_expected)
417 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
418 self.assertEqual(obj.expl_tag, expl or expl_initial)
421 default_initial if default is None else default,
423 if obj.default is None:
424 optional = optional_initial if optional is None else optional
425 optional = False if optional is None else optional
428 self.assertEqual(obj.optional, optional)
430 @given(boolean_values_strat())
431 def test_copy(self, values):
432 for klass in (Boolean, BooleanInherited):
434 obj_copied = obj.copy()
435 self.assert_copied_basic_fields(obj, obj_copied)
439 integers(min_value=1).map(tag_encode),
441 def test_stripped(self, value, tag_impl):
442 obj = Boolean(value, impl=tag_impl)
443 with self.assertRaises(NotEnoughData):
444 obj.decode(obj.encode()[:-1])
448 integers(min_value=1).map(tag_ctxc),
450 def test_stripped_expl(self, value, tag_expl):
451 obj = Boolean(value, expl=tag_expl)
452 with self.assertRaises(NotEnoughData):
453 obj.decode(obj.encode()[:-1])
456 integers(min_value=31),
457 integers(min_value=0),
460 def test_bad_tag(self, tag, offset, decode_path):
461 decode_path = tuple(str(i) for i in decode_path)
462 with self.assertRaises(DecodeError) as err:
464 tag_encode(tag)[:-1],
466 decode_path=decode_path,
469 self.assertEqual(err.exception.offset, offset)
470 self.assertEqual(err.exception.decode_path, decode_path)
473 integers(min_value=31),
474 integers(min_value=0),
477 def test_bad_expl_tag(self, tag, offset, decode_path):
478 decode_path = tuple(str(i) for i in decode_path)
479 with self.assertRaises(DecodeError) as err:
480 Boolean(expl=Boolean.tag_default).decode(
481 tag_encode(tag)[:-1],
483 decode_path=decode_path,
486 self.assertEqual(err.exception.offset, offset)
487 self.assertEqual(err.exception.decode_path, decode_path)
490 integers(min_value=128),
491 integers(min_value=0),
494 def test_bad_len(self, l, offset, decode_path):
495 decode_path = tuple(str(i) for i in decode_path)
496 with self.assertRaises(DecodeError) as err:
498 Boolean.tag_default + len_encode(l)[:-1],
500 decode_path=decode_path,
503 self.assertEqual(err.exception.offset, offset)
504 self.assertEqual(err.exception.decode_path, decode_path)
507 integers(min_value=128),
508 integers(min_value=0),
511 def test_bad_expl_len(self, l, offset, decode_path):
512 decode_path = tuple(str(i) for i in decode_path)
513 with self.assertRaises(DecodeError) as err:
514 Boolean(expl=Boolean.tag_default).decode(
515 Boolean.tag_default + len_encode(l)[:-1],
517 decode_path=decode_path,
520 self.assertEqual(err.exception.offset, offset)
521 self.assertEqual(err.exception.decode_path, decode_path)
523 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
525 boolean_values_strat(),
527 integers(min_value=1).map(tag_ctxc),
528 integers(min_value=0),
530 def test_symmetric(self, values, value, tag_expl, offset):
531 for klass in (Boolean, BooleanInherited):
532 _, _, _, default, optional, _decoded = values
541 self.assertFalse(obj.expled)
542 obj_encoded = obj.encode()
543 obj_expled = obj(value, expl=tag_expl)
544 self.assertTrue(obj_expled.expled)
547 obj_expled_encoded = obj_expled.encode()
548 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
551 self.assertEqual(tail, b"")
552 self.assertEqual(obj_decoded, obj_expled)
553 self.assertNotEqual(obj_decoded, obj)
554 self.assertEqual(bool(obj_decoded), bool(obj_expled))
555 self.assertEqual(bool(obj_decoded), bool(obj))
556 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
557 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
558 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
560 obj_decoded.expl_llen,
561 len(len_encode(len(obj_encoded))),
563 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
564 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
567 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
569 self.assertEqual(obj_decoded.expl_offset, offset)
571 @given(integers(min_value=2))
572 def test_invalid_len(self, l):
573 with self.assertRaises(InvalidLength):
574 Boolean().decode(b"".join((
580 @given(integers(min_value=0 + 1, max_value=255 - 1))
581 def test_invalid_value(self, value):
582 with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"):
583 Boolean().decode(b"".join((
591 def integer_values_strat(draw, do_expl=False):
592 bound_min, value, default, bound_max = sorted(draw(sets(
601 _specs = draw(sets(text_letters()))
604 min_size=len(_specs),
605 max_size=len(_specs),
607 _specs = list(zip(_specs, values))
610 bounds = (bound_min, bound_max)
614 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
616 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
619 optional = draw(one_of(none(), booleans()))
621 draw(integers(min_value=0)),
622 draw(integers(min_value=0)),
623 draw(integers(min_value=0)),
625 return (value, bounds, impl, expl, default, optional, _specs, _decoded)
628 class IntegerInherited(Integer):
632 class TestInteger(CommonMixin, TestCase):
635 def test_invalid_value_type(self):
636 with self.assertRaises(InvalidValueType) as err:
640 @given(sets(text_letters(), min_size=2))
641 def test_unknown_name(self, names_input):
642 missing = names_input.pop()
645 schema = [(n, 123) for n in names_input]
646 with self.assertRaises(ObjUnknown) as err:
650 @given(sets(text_letters(), min_size=2))
651 def test_known_name(self, names_input):
653 schema = [(n, 123) for n in names_input]
654 Int(names_input.pop())
657 def test_optional(self, optional):
658 obj = Integer(default=Integer(0), optional=optional)
659 self.assertTrue(obj.optional)
662 def test_ready(self, value):
664 self.assertFalse(obj.ready)
667 with self.assertRaises(ObjNotReady) as err:
671 self.assertTrue(obj.ready)
676 @given(integers(), integers(), binary(), binary())
677 def test_comparison(self, value1, value2, tag1, tag2):
678 for klass in (Integer, IntegerInherited):
681 self.assertEqual(obj1 == obj2, value1 == value2)
682 self.assertEqual(obj1 != obj2, value1 != value2)
683 self.assertEqual(obj1 == int(obj2), value1 == value2)
684 obj1 = klass(value1, impl=tag1)
685 obj2 = klass(value1, impl=tag2)
686 self.assertEqual(obj1 == obj2, tag1 == tag2)
687 self.assertEqual(obj1 != obj2, tag1 != tag2)
689 @given(lists(integers()))
690 def test_sorted_works(self, values):
691 self.assertSequenceEqual(
692 [int(v) for v in sorted(Integer(v) for v in values)],
696 @given(data_strategy())
697 def test_named(self, d):
698 names_input = list(d.draw(sets(text_letters(), min_size=1)))
699 values_input = list(d.draw(sets(
701 min_size=len(names_input),
702 max_size=len(names_input),
704 chosen_name = d.draw(sampled_from(names_input))
705 names_input = dict(zip(names_input, values_input))
709 _int = Int(chosen_name)
710 self.assertEqual(_int.named, chosen_name)
711 self.assertEqual(int(_int), names_input[chosen_name])
713 @given(integers(), integers(min_value=0), integers(min_value=0))
714 def test_bounds_satisfied(self, bound_min, bound_delta, value_delta):
715 value = bound_min + value_delta
716 bound_max = value + bound_delta
717 Integer(value=value, bounds=(bound_min, bound_max))
719 @given(sets(integers(), min_size=3, max_size=3))
720 def test_bounds_unsatisfied(self, values):
721 values = sorted(values)
722 with self.assertRaises(BoundsError) as err:
723 Integer(value=values[0], bounds=(values[1], values[2]))
725 with self.assertRaises(BoundsError) as err:
726 Integer(value=values[2], bounds=(values[0], values[1]))
729 @given(data_strategy())
730 def test_call(self, d):
731 for klass in (Integer, IntegerInherited):
741 ) = d.draw(integer_values_strat())
748 optional_initial or False,
761 ) = d.draw(integer_values_strat(do_expl=impl_initial is None))
762 if (default is None) and (obj_initial.default is not None):
766 (value is not None) and
767 (bounds_initial is not None) and
768 not (bounds_initial[0] <= value <= bounds_initial[1])
773 (default is not None) and
774 (bounds_initial is not None) and
775 not (bounds_initial[0] <= default <= bounds_initial[1])
778 obj = obj_initial(value, bounds, impl, expl, default, optional)
780 value_expected = default if value is None else value
782 default_initial if value_expected is None
785 self.assertEqual(obj, value_expected)
786 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
787 self.assertEqual(obj.expl_tag, expl or expl_initial)
790 default_initial if default is None else default,
792 if obj.default is None:
793 optional = optional_initial if optional is None else optional
794 optional = False if optional is None else optional
797 self.assertEqual(obj.optional, optional)
799 (obj._bound_min, obj._bound_max),
800 bounds or bounds_initial or (float("-inf"), float("+inf")),
804 {} if _specs_initial is None else dict(_specs_initial),
807 @given(integer_values_strat())
808 def test_copy(self, values):
809 for klass in (Integer, IntegerInherited):
811 obj_copied = obj.copy()
812 self.assert_copied_basic_fields(obj, obj_copied)
813 self.assertEqual(obj.specs, obj_copied.specs)
814 self.assertEqual(obj._bound_min, obj_copied._bound_min)
815 self.assertEqual(obj._bound_max, obj_copied._bound_max)
816 self.assertEqual(obj._value, obj_copied._value)
820 integers(min_value=1).map(tag_encode),
822 def test_stripped(self, value, tag_impl):
823 obj = Integer(value, impl=tag_impl)
824 with self.assertRaises(NotEnoughData):
825 obj.decode(obj.encode()[:-1])
829 integers(min_value=1).map(tag_ctxc),
831 def test_stripped_expl(self, value, tag_expl):
832 obj = Integer(value, expl=tag_expl)
833 with self.assertRaises(NotEnoughData):
834 obj.decode(obj.encode()[:-1])
836 def test_zero_len(self):
837 with self.assertRaises(NotEnoughData):
838 Integer().decode(b"".join((
844 integers(min_value=31),
845 integers(min_value=0),
848 def test_bad_tag(self, tag, offset, decode_path):
849 decode_path = tuple(str(i) for i in decode_path)
850 with self.assertRaises(DecodeError) as err:
852 tag_encode(tag)[:-1],
854 decode_path=decode_path,
857 self.assertEqual(err.exception.offset, offset)
858 self.assertEqual(err.exception.decode_path, decode_path)
861 integers(min_value=128),
862 integers(min_value=0),
865 def test_bad_len(self, l, offset, decode_path):
866 decode_path = tuple(str(i) for i in decode_path)
867 with self.assertRaises(DecodeError) as err:
869 Integer.tag_default + len_encode(l)[:-1],
871 decode_path=decode_path,
874 self.assertEqual(err.exception.offset, offset)
875 self.assertEqual(err.exception.decode_path, decode_path)
878 sets(integers(), min_size=2, max_size=2),
879 integers(min_value=0),
882 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
883 decode_path = tuple(str(i) for i in decode_path)
884 value, bound_min = list(sorted(ints))
887 bounds = (bound_min, bound_min)
888 with self.assertRaises(DecodeError) as err:
890 Integer(value).encode(),
892 decode_path=decode_path,
895 self.assertEqual(err.exception.offset, offset)
896 self.assertEqual(err.exception.decode_path, decode_path)
898 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
900 integer_values_strat(),
902 integers(min_value=1).map(tag_ctxc),
903 integers(min_value=0),
905 def test_symmetric(self, values, value, tag_expl, offset):
906 for klass in (Integer, IntegerInherited):
907 _, _, _, _, default, optional, _, _decoded = values
916 self.assertFalse(obj.expled)
917 obj_encoded = obj.encode()
918 obj_expled = obj(value, expl=tag_expl)
919 self.assertTrue(obj_expled.expled)
922 obj_expled_encoded = obj_expled.encode()
923 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
926 self.assertEqual(tail, b"")
927 self.assertEqual(obj_decoded, obj_expled)
928 self.assertNotEqual(obj_decoded, obj)
929 self.assertEqual(int(obj_decoded), int(obj_expled))
930 self.assertEqual(int(obj_decoded), int(obj))
931 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
932 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
933 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
935 obj_decoded.expl_llen,
936 len(len_encode(len(obj_encoded))),
938 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
939 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
942 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
944 self.assertEqual(obj_decoded.expl_offset, offset)
946 def test_go_vectors_valid(self):
947 for data, expect in ((
959 (b"\x80\x00\x00\x00\x00\x00\x00\x00", -9223372036854775808),
960 (b"\x80\x00\x00\x00", -2147483648),
963 Integer().decode(b"".join((
965 len_encode(len(data)),
971 def test_go_vectors_invalid(self):
976 with self.assertRaises(DecodeError):
977 Integer().decode(b"".join((
979 len_encode(len(data)),
985 def bit_string_values_strat(draw, schema=None, value_required=False, do_expl=False):
989 schema = draw(sets(text_letters(), min_size=1, max_size=256))
991 integers(min_value=0, max_value=255),
992 min_size=len(schema),
993 max_size=len(schema),
995 schema = list(zip(schema, bits))
997 def _value(value_required):
998 if not value_required and draw(booleans()):
1000 generation_choice = 0
1002 generation_choice = draw(sampled_from((1, 2, 3)))
1003 if generation_choice == 1 or draw(booleans()):
1004 return "'%s'B" % "".join(draw(lists(
1005 sampled_from(("0", "1")),
1006 max_size=len(schema),
1008 elif generation_choice == 2 or draw(booleans()):
1009 return draw(binary(max_size=len(schema) // 8))
1010 elif generation_choice == 3 or draw(booleans()):
1011 return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
1013 value = _value(value_required)
1014 default = _value(value_required=False)
1018 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1020 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1021 optional = draw(one_of(none(), booleans()))
1023 draw(integers(min_value=0)),
1024 draw(integers(min_value=0)),
1025 draw(integers(min_value=0)),
1027 return (schema, value, impl, expl, default, optional, _decoded)
1030 class BitStringInherited(BitString):
1034 class TestBitString(CommonMixin, TestCase):
1035 base_klass = BitString
1037 @given(lists(booleans()))
1038 def test_b_encoding(self, bits):
1039 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1040 self.assertEqual(obj.bit_len, len(bits))
1041 self.assertSequenceEqual(list(obj), bits)
1042 for i, bit in enumerate(bits):
1043 self.assertEqual(obj[i], bit)
1045 @given(lists(booleans()))
1046 def test_out_of_bounds_bits(self, bits):
1047 obj = BitString("'%s'B" % "".join("1" if bit else "0" for bit in bits))
1048 for i in range(len(bits), len(bits) * 2):
1049 self.assertFalse(obj[i])
1051 def test_bad_b_encoding(self):
1052 with self.assertRaises(ValueError):
1053 BitString("'010120101'B")
1056 integers(min_value=1, max_value=255),
1057 integers(min_value=1, max_value=255),
1059 def test_named_are_stripped(self, leading_zeros, trailing_zeros):
1060 obj = BitString("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1061 self.assertEqual(obj.bit_len, leading_zeros + 1 + trailing_zeros)
1062 self.assertGreater(len(obj.encode()), (leading_zeros + 1 + trailing_zeros) // 8)
1064 class BS(BitString):
1065 schema = (("whatever", 0),)
1066 obj = BS("'%s1%s'B" % (("0" * leading_zeros), ("0" * trailing_zeros)))
1067 self.assertEqual(obj.bit_len, leading_zeros + 1)
1068 self.assertGreater(len(obj.encode()), (leading_zeros + 1) // 8)
1070 def test_zero_len(self):
1071 with self.assertRaises(NotEnoughData):
1072 BitString().decode(b"".join((
1073 BitString.tag_default,
1077 def test_invalid_value_type(self):
1078 with self.assertRaises(InvalidValueType) as err:
1081 with self.assertRaises(InvalidValueType) as err:
1085 def test_obj_unknown(self):
1086 with self.assertRaises(ObjUnknown) as err:
1087 BitString(b"whatever")["whenever"]
1090 def test_get_invalid_typ(self):
1091 with self.assertRaises(InvalidValueType) as err:
1092 BitString(b"whatever")[(1, 2, 3)]
1095 @given(data_strategy())
1096 def test_unknown_name(self, d):
1097 _schema = d.draw(sets(text_letters(), min_size=2, max_size=5))
1098 missing = _schema.pop()
1100 class BS(BitString):
1101 schema = [(n, i) for i, n in enumerate(_schema)]
1102 with self.assertRaises(ObjUnknown) as err:
1107 def test_optional(self, optional):
1108 obj = BitString(default=BitString(b""), optional=optional)
1109 self.assertTrue(obj.optional)
1112 def test_ready(self, value):
1114 self.assertFalse(obj.ready)
1117 with self.assertRaises(ObjNotReady) as err:
1120 obj = BitString(value)
1121 self.assertTrue(obj.ready)
1126 tuples(integers(min_value=0), binary()),
1127 tuples(integers(min_value=0), binary()),
1131 def test_comparison(self, value1, value2, tag1, tag2):
1132 for klass in (BitString, BitStringInherited):
1133 obj1 = klass(value1)
1134 obj2 = klass(value2)
1135 self.assertEqual(obj1 == obj2, value1 == value2)
1136 self.assertEqual(obj1 != obj2, value1 != value2)
1137 self.assertEqual(obj1 == bytes(obj2), value1[1] == value2[1])
1138 obj1 = klass(value1, impl=tag1)
1139 obj2 = klass(value1, impl=tag2)
1140 self.assertEqual(obj1 == obj2, tag1 == tag2)
1141 self.assertEqual(obj1 != obj2, tag1 != tag2)
1143 @given(data_strategy())
1144 def test_call(self, d):
1145 for klass in (BitString, BitStringInherited):
1154 ) = d.draw(bit_string_values_strat())
1157 schema = schema_initial
1159 value=value_initial,
1162 default=default_initial,
1163 optional=optional_initial or False,
1164 _decoded=_decoded_initial,
1174 ) = d.draw(bit_string_values_strat(
1175 schema=schema_initial,
1176 do_expl=impl_initial is None,
1185 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1186 self.assertEqual(obj.expl_tag, expl or expl_initial)
1187 if obj.default is None:
1188 optional = optional_initial if optional is None else optional
1189 optional = False if optional is None else optional
1192 self.assertEqual(obj.optional, optional)
1193 self.assertEqual(obj.specs, obj_initial.specs)
1195 @given(bit_string_values_strat())
1196 def test_copy(self, values):
1197 for klass in (BitString, BitStringInherited):
1198 _schema, value, impl, expl, default, optional, _decoded = values
1207 optional=optional or False,
1210 obj_copied = obj.copy()
1211 self.assert_copied_basic_fields(obj, obj_copied)
1212 self.assertEqual(obj.specs, obj_copied.specs)
1213 self.assertEqual(obj._value, obj_copied._value)
1217 integers(min_value=1).map(tag_encode),
1219 def test_stripped(self, value, tag_impl):
1220 obj = BitString(value, impl=tag_impl)
1221 with self.assertRaises(NotEnoughData):
1222 obj.decode(obj.encode()[:-1])
1226 integers(min_value=1).map(tag_ctxc),
1228 def test_stripped_expl(self, value, tag_expl):
1229 obj = BitString(value, expl=tag_expl)
1230 with self.assertRaises(NotEnoughData):
1231 obj.decode(obj.encode()[:-1])
1234 integers(min_value=31),
1235 integers(min_value=0),
1238 def test_bad_tag(self, tag, offset, decode_path):
1239 decode_path = tuple(str(i) for i in decode_path)
1240 with self.assertRaises(DecodeError) as err:
1242 tag_encode(tag)[:-1],
1244 decode_path=decode_path,
1247 self.assertEqual(err.exception.offset, offset)
1248 self.assertEqual(err.exception.decode_path, decode_path)
1251 integers(min_value=128),
1252 integers(min_value=0),
1255 def test_bad_len(self, l, offset, decode_path):
1256 decode_path = tuple(str(i) for i in decode_path)
1257 with self.assertRaises(DecodeError) as err:
1259 BitString.tag_default + len_encode(l)[:-1],
1261 decode_path=decode_path,
1264 self.assertEqual(err.exception.offset, offset)
1265 self.assertEqual(err.exception.decode_path, decode_path)
1267 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1268 @given(data_strategy())
1269 def test_symmetric(self, d):
1278 ) = d.draw(bit_string_values_strat(value_required=True))
1279 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
1280 offset = d.draw(integers(min_value=0))
1281 for klass in (BitString, BitStringInherited):
1292 self.assertFalse(obj.expled)
1293 obj_encoded = obj.encode()
1294 obj_expled = obj(value, expl=tag_expl)
1295 self.assertTrue(obj_expled.expled)
1298 obj_expled_encoded = obj_expled.encode()
1299 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1302 self.assertEqual(tail, b"")
1303 self.assertEqual(obj_decoded, obj_expled)
1304 self.assertNotEqual(obj_decoded, obj)
1305 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1306 self.assertEqual(bytes(obj_decoded), bytes(obj))
1307 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1308 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1309 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1311 obj_decoded.expl_llen,
1312 len(len_encode(len(obj_encoded))),
1314 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1315 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1318 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1320 self.assertEqual(obj_decoded.expl_offset, offset)
1321 if isinstance(value, tuple):
1322 self.assertSetEqual(set(value), set(obj_decoded.named))
1326 @given(integers(min_value=1, max_value=255))
1327 def test_bad_zero_value(self, pad_size):
1328 with self.assertRaises(DecodeError):
1329 BitString().decode(b"".join((
1330 BitString.tag_default,
1335 def test_go_vectors_invalid(self):
1341 with self.assertRaises(DecodeError):
1342 BitString().decode(b"".join((
1343 BitString.tag_default,
1348 def test_go_vectors_valid(self):
1349 obj, _ = BitString().decode(b"".join((
1350 BitString.tag_default,
1354 self.assertEqual(bytes(obj), b"")
1355 self.assertEqual(obj.bit_len, 0)
1357 obj, _ = BitString().decode(b"".join((
1358 BitString.tag_default,
1362 self.assertEqual(bytes(obj), b"\x00")
1363 self.assertEqual(obj.bit_len, 1)
1365 obj = BitString((16, b"\x82\x40"))
1366 self.assertTrue(obj[0])
1367 self.assertFalse(obj[1])
1368 self.assertTrue(obj[6])
1369 self.assertTrue(obj[9])
1370 self.assertFalse(obj[17])
1374 def octet_string_values_strat(draw, do_expl=False):
1375 bound_min, bound_max = sorted(draw(sets(
1376 integers(min_value=0, max_value=1 << 7),
1380 value = draw(one_of(
1382 binary(min_size=bound_min, max_size=bound_max),
1384 default = draw(one_of(
1386 binary(min_size=bound_min, max_size=bound_max),
1389 if draw(booleans()):
1390 bounds = (bound_min, bound_max)
1394 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1396 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1397 optional = draw(one_of(none(), booleans()))
1399 draw(integers(min_value=0)),
1400 draw(integers(min_value=0)),
1401 draw(integers(min_value=0)),
1403 return (value, bounds, impl, expl, default, optional, _decoded)
1406 class OctetStringInherited(OctetString):
1410 class TestOctetString(CommonMixin, TestCase):
1411 base_klass = OctetString
1413 def test_invalid_value_type(self):
1414 with self.assertRaises(InvalidValueType) as err:
1415 OctetString(text_type(123))
1419 def test_optional(self, optional):
1420 obj = OctetString(default=OctetString(b""), optional=optional)
1421 self.assertTrue(obj.optional)
1424 def test_ready(self, value):
1426 self.assertFalse(obj.ready)
1429 with self.assertRaises(ObjNotReady) as err:
1432 obj = OctetString(value)
1433 self.assertTrue(obj.ready)
1437 @given(binary(), binary(), binary(), binary())
1438 def test_comparison(self, value1, value2, tag1, tag2):
1439 for klass in (OctetString, OctetStringInherited):
1440 obj1 = klass(value1)
1441 obj2 = klass(value2)
1442 self.assertEqual(obj1 == obj2, value1 == value2)
1443 self.assertEqual(obj1 != obj2, value1 != value2)
1444 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
1445 obj1 = klass(value1, impl=tag1)
1446 obj2 = klass(value1, impl=tag2)
1447 self.assertEqual(obj1 == obj2, tag1 == tag2)
1448 self.assertEqual(obj1 != obj2, tag1 != tag2)
1450 @given(lists(binary()))
1451 def test_sorted_works(self, values):
1452 self.assertSequenceEqual(
1453 [bytes(v) for v in sorted(OctetString(v) for v in values)],
1457 @given(data_strategy())
1458 def test_bounds_satisfied(self, d):
1459 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
1460 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1461 value = d.draw(binary(min_size=bound_min, max_size=bound_max))
1462 OctetString(value=value, bounds=(bound_min, bound_max))
1464 @given(data_strategy())
1465 def test_bounds_unsatisfied(self, d):
1466 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
1467 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
1468 value = d.draw(binary(max_size=bound_min - 1))
1469 with self.assertRaises(BoundsError) as err:
1470 OctetString(value=value, bounds=(bound_min, bound_max))
1472 value = d.draw(binary(min_size=bound_max + 1))
1473 with self.assertRaises(BoundsError) as err:
1474 OctetString(value=value, bounds=(bound_min, bound_max))
1477 @given(data_strategy())
1478 def test_call(self, d):
1479 for klass in (OctetString, OctetStringInherited):
1488 ) = d.draw(octet_string_values_strat())
1489 obj_initial = klass(
1495 optional_initial or False,
1506 ) = d.draw(octet_string_values_strat(do_expl=impl_initial is None))
1507 if (default is None) and (obj_initial.default is not None):
1510 (bounds is None) and
1511 (value is not None) and
1512 (bounds_initial is not None) and
1513 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
1517 (bounds is None) and
1518 (default is not None) and
1519 (bounds_initial is not None) and
1520 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
1523 obj = obj_initial(value, bounds, impl, expl, default, optional)
1525 value_expected = default if value is None else value
1527 default_initial if value_expected is None
1530 self.assertEqual(obj, value_expected)
1531 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1532 self.assertEqual(obj.expl_tag, expl or expl_initial)
1535 default_initial if default is None else default,
1537 if obj.default is None:
1538 optional = optional_initial if optional is None else optional
1539 optional = False if optional is None else optional
1542 self.assertEqual(obj.optional, optional)
1544 (obj._bound_min, obj._bound_max),
1545 bounds or bounds_initial or (0, float("+inf")),
1548 @given(octet_string_values_strat())
1549 def test_copy(self, values):
1550 for klass in (OctetString, OctetStringInherited):
1551 obj = klass(*values)
1552 obj_copied = obj.copy()
1553 self.assert_copied_basic_fields(obj, obj_copied)
1554 self.assertEqual(obj._bound_min, obj_copied._bound_min)
1555 self.assertEqual(obj._bound_max, obj_copied._bound_max)
1556 self.assertEqual(obj._value, obj_copied._value)
1560 integers(min_value=1).map(tag_encode),
1562 def test_stripped(self, value, tag_impl):
1563 obj = OctetString(value, impl=tag_impl)
1564 with self.assertRaises(NotEnoughData):
1565 obj.decode(obj.encode()[:-1])
1569 integers(min_value=1).map(tag_ctxc),
1571 def test_stripped_expl(self, value, tag_expl):
1572 obj = OctetString(value, expl=tag_expl)
1573 with self.assertRaises(NotEnoughData):
1574 obj.decode(obj.encode()[:-1])
1577 integers(min_value=31),
1578 integers(min_value=0),
1581 def test_bad_tag(self, tag, offset, decode_path):
1582 decode_path = tuple(str(i) for i in decode_path)
1583 with self.assertRaises(DecodeError) as err:
1584 OctetString().decode(
1585 tag_encode(tag)[:-1],
1587 decode_path=decode_path,
1590 self.assertEqual(err.exception.offset, offset)
1591 self.assertEqual(err.exception.decode_path, decode_path)
1594 integers(min_value=128),
1595 integers(min_value=0),
1598 def test_bad_len(self, l, offset, decode_path):
1599 decode_path = tuple(str(i) for i in decode_path)
1600 with self.assertRaises(DecodeError) as err:
1601 OctetString().decode(
1602 OctetString.tag_default + len_encode(l)[:-1],
1604 decode_path=decode_path,
1607 self.assertEqual(err.exception.offset, offset)
1608 self.assertEqual(err.exception.decode_path, decode_path)
1611 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
1612 integers(min_value=0),
1615 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
1616 decode_path = tuple(str(i) for i in decode_path)
1617 value, bound_min = list(sorted(ints))
1619 class String(OctetString):
1620 bounds = (bound_min, bound_min)
1621 with self.assertRaises(DecodeError) as err:
1623 OctetString(b"\x00" * value).encode(),
1625 decode_path=decode_path,
1628 self.assertEqual(err.exception.offset, offset)
1629 self.assertEqual(err.exception.decode_path, decode_path)
1631 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
1633 octet_string_values_strat(),
1635 integers(min_value=1).map(tag_ctxc),
1636 integers(min_value=0),
1638 def test_symmetric(self, values, value, tag_expl, offset):
1639 for klass in (OctetString, OctetStringInherited):
1640 _, _, _, _, default, optional, _decoded = values
1649 self.assertFalse(obj.expled)
1650 obj_encoded = obj.encode()
1651 obj_expled = obj(value, expl=tag_expl)
1652 self.assertTrue(obj_expled.expled)
1655 obj_expled_encoded = obj_expled.encode()
1656 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1659 self.assertEqual(tail, b"")
1660 self.assertEqual(obj_decoded, obj_expled)
1661 self.assertNotEqual(obj_decoded, obj)
1662 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
1663 self.assertEqual(bytes(obj_decoded), bytes(obj))
1664 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1665 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1666 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1668 obj_decoded.expl_llen,
1669 len(len_encode(len(obj_encoded))),
1671 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1672 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1675 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1677 self.assertEqual(obj_decoded.expl_offset, offset)
1681 def null_values_strat(draw, do_expl=False):
1685 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1687 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1688 optional = draw(one_of(none(), booleans()))
1690 draw(integers(min_value=0)),
1691 draw(integers(min_value=0)),
1692 draw(integers(min_value=0)),
1694 return (impl, expl, optional, _decoded)
1697 class NullInherited(Null):
1701 class TestNull(CommonMixin, TestCase):
1704 def test_ready(self):
1706 self.assertTrue(obj.ready)
1710 @given(binary(), binary())
1711 def test_comparison(self, tag1, tag2):
1712 for klass in (Null, NullInherited):
1713 obj1 = klass(impl=tag1)
1714 obj2 = klass(impl=tag2)
1715 self.assertEqual(obj1 == obj2, tag1 == tag2)
1716 self.assertEqual(obj1 != obj2, tag1 != tag2)
1717 self.assertNotEqual(obj1, tag2)
1719 @given(data_strategy())
1720 def test_call(self, d):
1721 for klass in (Null, NullInherited):
1727 ) = d.draw(null_values_strat())
1728 obj_initial = klass(
1731 optional=optional_initial or False,
1732 _decoded=_decoded_initial,
1739 ) = d.draw(null_values_strat(do_expl=impl_initial is None))
1740 obj = obj_initial(impl=impl, expl=expl, optional=optional)
1741 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1742 self.assertEqual(obj.expl_tag, expl or expl_initial)
1743 optional = optional_initial if optional is None else optional
1744 optional = False if optional is None else optional
1745 self.assertEqual(obj.optional, optional)
1747 @given(null_values_strat())
1748 def test_copy(self, values):
1749 for klass in (Null, NullInherited):
1750 impl, expl, optional, _decoded = values
1754 optional=optional or False,
1757 obj_copied = obj.copy()
1758 self.assert_copied_basic_fields(obj, obj_copied)
1760 @given(integers(min_value=1).map(tag_encode))
1761 def test_stripped(self, tag_impl):
1762 obj = Null(impl=tag_impl)
1763 with self.assertRaises(NotEnoughData):
1764 obj.decode(obj.encode()[:-1])
1766 @given(integers(min_value=1).map(tag_ctxc))
1767 def test_stripped_expl(self, tag_expl):
1768 obj = Null(expl=tag_expl)
1769 with self.assertRaises(NotEnoughData):
1770 obj.decode(obj.encode()[:-1])
1773 integers(min_value=31),
1774 integers(min_value=0),
1777 def test_bad_tag(self, tag, offset, decode_path):
1778 decode_path = tuple(str(i) for i in decode_path)
1779 with self.assertRaises(DecodeError) as err:
1781 tag_encode(tag)[:-1],
1783 decode_path=decode_path,
1786 self.assertEqual(err.exception.offset, offset)
1787 self.assertEqual(err.exception.decode_path, decode_path)
1790 integers(min_value=128),
1791 integers(min_value=0),
1794 def test_bad_len(self, l, offset, decode_path):
1795 decode_path = tuple(str(i) for i in decode_path)
1796 with self.assertRaises(DecodeError) as err:
1798 Null.tag_default + len_encode(l)[:-1],
1800 decode_path=decode_path,
1803 self.assertEqual(err.exception.offset, offset)
1804 self.assertEqual(err.exception.decode_path, decode_path)
1806 @given(binary(min_size=1))
1807 def test_tag_mismatch(self, impl):
1808 assume(impl != Null.tag_default)
1809 with self.assertRaises(TagMismatch):
1810 Null(impl=impl).decode(Null().encode())
1813 null_values_strat(),
1814 integers(min_value=1).map(tag_ctxc),
1815 integers(min_value=0),
1817 def test_symmetric(self, values, tag_expl, offset):
1818 for klass in (Null, NullInherited):
1819 _, _, optional, _decoded = values
1820 obj = klass(optional=optional, _decoded=_decoded)
1823 self.assertFalse(obj.expled)
1824 obj_encoded = obj.encode()
1825 obj_expled = obj(expl=tag_expl)
1826 self.assertTrue(obj_expled.expled)
1829 obj_expled_encoded = obj_expled.encode()
1830 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
1833 self.assertEqual(tail, b"")
1834 self.assertEqual(obj_decoded, obj_expled)
1835 self.assertNotEqual(obj_decoded, obj)
1836 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
1837 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
1838 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
1840 obj_decoded.expl_llen,
1841 len(len_encode(len(obj_encoded))),
1843 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
1844 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
1847 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
1849 self.assertEqual(obj_decoded.expl_offset, offset)
1851 @given(integers(min_value=1))
1852 def test_invalid_len(self, l):
1853 with self.assertRaises(InvalidLength):
1854 Null().decode(b"".join((
1861 def oid_strategy(draw):
1862 first_arc = draw(integers(min_value=0, max_value=2))
1864 if first_arc in (0, 1):
1865 second_arc = draw(integers(min_value=0, max_value=39))
1867 second_arc = draw(integers(min_value=0))
1868 other_arcs = draw(lists(integers(min_value=0)))
1869 return tuple([first_arc, second_arc] + other_arcs)
1873 def oid_values_strat(draw, do_expl=False):
1874 value = draw(one_of(none(), oid_strategy()))
1878 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1880 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
1881 default = draw(one_of(none(), oid_strategy()))
1882 optional = draw(one_of(none(), booleans()))
1884 draw(integers(min_value=0)),
1885 draw(integers(min_value=0)),
1886 draw(integers(min_value=0)),
1888 return (value, impl, expl, default, optional, _decoded)
1891 class ObjectIdentifierInherited(ObjectIdentifier):
1895 class TestObjectIdentifier(CommonMixin, TestCase):
1896 base_klass = ObjectIdentifier
1898 def test_invalid_value_type(self):
1899 with self.assertRaises(InvalidValueType) as err:
1900 ObjectIdentifier(123)
1904 def test_optional(self, optional):
1905 obj = ObjectIdentifier(default=ObjectIdentifier("1.2.3"), optional=optional)
1906 self.assertTrue(obj.optional)
1908 @given(oid_strategy())
1909 def test_ready(self, value):
1910 obj = ObjectIdentifier()
1911 self.assertFalse(obj.ready)
1914 with self.assertRaises(ObjNotReady) as err:
1917 obj = ObjectIdentifier(value)
1918 self.assertTrue(obj.ready)
1923 @given(oid_strategy(), oid_strategy(), binary(), binary())
1924 def test_comparison(self, value1, value2, tag1, tag2):
1925 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1926 obj1 = klass(value1)
1927 obj2 = klass(value2)
1928 self.assertEqual(obj1 == obj2, value1 == value2)
1929 self.assertEqual(obj1 != obj2, value1 != value2)
1930 self.assertEqual(obj1 == tuple(obj2), value1 == value2)
1931 self.assertEqual(str(obj1) == str(obj2), value1 == value2)
1932 obj1 = klass(value1, impl=tag1)
1933 obj2 = klass(value1, impl=tag2)
1934 self.assertEqual(obj1 == obj2, tag1 == tag2)
1935 self.assertEqual(obj1 != obj2, tag1 != tag2)
1937 @given(lists(oid_strategy()))
1938 def test_sorted_works(self, values):
1939 self.assertSequenceEqual(
1940 [tuple(v) for v in sorted(ObjectIdentifier(v) for v in values)],
1944 @given(data_strategy())
1945 def test_call(self, d):
1946 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1954 ) = d.draw(oid_values_strat())
1955 obj_initial = klass(
1960 optional_initial or False,
1970 ) = d.draw(oid_values_strat(do_expl=impl_initial is None))
1971 obj = obj_initial(value, impl, expl, default, optional)
1973 value_expected = default if value is None else value
1975 default_initial if value_expected is None
1978 self.assertEqual(obj, value_expected)
1979 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
1980 self.assertEqual(obj.expl_tag, expl or expl_initial)
1983 default_initial if default is None else default,
1985 if obj.default is None:
1986 optional = optional_initial if optional is None else optional
1987 optional = False if optional is None else optional
1990 self.assertEqual(obj.optional, optional)
1992 @given(oid_values_strat())
1993 def test_copy(self, values):
1994 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
1995 obj = klass(*values)
1996 obj_copied = obj.copy()
1997 self.assert_copied_basic_fields(obj, obj_copied)
1998 self.assertEqual(obj._value, obj_copied._value)
2000 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2003 integers(min_value=1).map(tag_encode),
2005 def test_stripped(self, value, tag_impl):
2006 obj = ObjectIdentifier(value, impl=tag_impl)
2007 with self.assertRaises(NotEnoughData):
2008 obj.decode(obj.encode()[:-1])
2012 integers(min_value=1).map(tag_ctxc),
2014 def test_stripped_expl(self, value, tag_expl):
2015 obj = ObjectIdentifier(value, expl=tag_expl)
2016 with self.assertRaises(NotEnoughData):
2017 obj.decode(obj.encode()[:-1])
2020 integers(min_value=31),
2021 integers(min_value=0),
2024 def test_bad_tag(self, tag, offset, decode_path):
2025 decode_path = tuple(str(i) for i in decode_path)
2026 with self.assertRaises(DecodeError) as err:
2027 ObjectIdentifier().decode(
2028 tag_encode(tag)[:-1],
2030 decode_path=decode_path,
2033 self.assertEqual(err.exception.offset, offset)
2034 self.assertEqual(err.exception.decode_path, decode_path)
2037 integers(min_value=128),
2038 integers(min_value=0),
2041 def test_bad_len(self, l, offset, decode_path):
2042 decode_path = tuple(str(i) for i in decode_path)
2043 with self.assertRaises(DecodeError) as err:
2044 ObjectIdentifier().decode(
2045 ObjectIdentifier.tag_default + len_encode(l)[:-1],
2047 decode_path=decode_path,
2050 self.assertEqual(err.exception.offset, offset)
2051 self.assertEqual(err.exception.decode_path, decode_path)
2053 def test_zero_oid(self):
2054 with self.assertRaises(NotEnoughData):
2055 ObjectIdentifier().decode(
2056 b"".join((ObjectIdentifier.tag_default, len_encode(0)))
2059 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2060 @given(oid_strategy())
2061 def test_unfinished_oid(self, value):
2062 assume(list(value)[-1] > 255)
2063 obj_encoded = ObjectIdentifier(value).encode()
2064 obj, _ = ObjectIdentifier().decode(obj_encoded)
2065 data = obj_encoded[obj.tlen + obj.llen:-1]
2067 ObjectIdentifier.tag_default,
2068 len_encode(len(data)),
2071 with assertRaisesRegex(self, DecodeError, "unfinished OID"):
2074 @given(integers(min_value=0))
2075 def test_invalid_short(self, value):
2076 with self.assertRaises(InvalidOID):
2077 ObjectIdentifier((value,))
2078 with self.assertRaises(InvalidOID):
2079 ObjectIdentifier("%d" % value)
2081 @given(integers(min_value=3), integers(min_value=0))
2082 def test_invalid_first_arc(self, first_arc, second_arc):
2083 with self.assertRaises(InvalidOID):
2084 ObjectIdentifier((first_arc, second_arc))
2085 with self.assertRaises(InvalidOID):
2086 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2088 @given(integers(min_value=0, max_value=1), integers(min_value=40))
2089 def test_invalid_second_arc(self, first_arc, second_arc):
2090 with self.assertRaises(InvalidOID):
2091 ObjectIdentifier((first_arc, second_arc))
2092 with self.assertRaises(InvalidOID):
2093 ObjectIdentifier("%d.%d" % (first_arc, second_arc))
2095 @given(text(alphabet=ascii_letters + ".", min_size=1))
2096 def test_junk(self, oid):
2097 with self.assertRaises(InvalidOID):
2098 ObjectIdentifier(oid)
2100 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2101 @given(oid_strategy())
2102 def test_validness(self, oid):
2103 obj = ObjectIdentifier(oid)
2104 self.assertEqual(obj, ObjectIdentifier(".".join(str(arc) for arc in oid)))
2109 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2113 integers(min_value=1).map(tag_ctxc),
2114 integers(min_value=0),
2116 def test_symmetric(self, values, value, tag_expl, offset):
2117 for klass in (ObjectIdentifier, ObjectIdentifierInherited):
2118 _, _, _, default, optional, _decoded = values
2127 self.assertFalse(obj.expled)
2128 obj_encoded = obj.encode()
2129 obj_expled = obj(value, expl=tag_expl)
2130 self.assertTrue(obj_expled.expled)
2133 obj_expled_encoded = obj_expled.encode()
2134 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2137 self.assertEqual(tail, b"")
2138 self.assertEqual(obj_decoded, obj_expled)
2139 self.assertNotEqual(obj_decoded, obj)
2140 self.assertEqual(tuple(obj_decoded), tuple(obj_expled))
2141 self.assertEqual(tuple(obj_decoded), tuple(obj))
2142 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2143 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2144 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2146 obj_decoded.expl_llen,
2147 len(len_encode(len(obj_encoded))),
2149 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2150 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2153 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2155 self.assertEqual(obj_decoded.expl_offset, offset)
2158 oid_strategy().map(ObjectIdentifier),
2159 oid_strategy().map(ObjectIdentifier),
2161 def test_add(self, oid1, oid2):
2162 oid_expect = ObjectIdentifier(str(oid1) + "." + str(oid2))
2163 for oid_to_add in (oid2, tuple(oid2)):
2164 self.assertEqual(oid1 + oid_to_add, oid_expect)
2165 with self.assertRaises(InvalidValueType):
2168 def test_go_vectors_valid(self):
2169 for data, expect in (
2171 (b"\x55\x02", (2, 5, 2)),
2172 (b"\x55\x02\xc0\x00", (2, 5, 2, 8192)),
2173 (b"\x81\x34\x03", (2, 100, 3)),
2176 ObjectIdentifier().decode(b"".join((
2177 ObjectIdentifier.tag_default,
2178 len_encode(len(data)),
2184 def test_go_vectors_invalid(self):
2185 data = b"\x55\x02\xc0\x80\x80\x80\x80"
2186 with self.assertRaises(DecodeError):
2187 ObjectIdentifier().decode(b"".join((
2188 Integer.tag_default,
2189 len_encode(len(data)),
2195 def enumerated_values_strat(draw, schema=None, do_expl=False):
2197 schema = list(draw(sets(text_printable, min_size=1, max_size=3)))
2198 values = list(draw(sets(
2200 min_size=len(schema),
2201 max_size=len(schema),
2203 schema = list(zip(schema, values))
2204 value = draw(one_of(none(), sampled_from([k for k, v in schema])))
2208 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2210 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2211 default = draw(one_of(none(), sampled_from([v for k, v in schema])))
2212 optional = draw(one_of(none(), booleans()))
2214 draw(integers(min_value=0)),
2215 draw(integers(min_value=0)),
2216 draw(integers(min_value=0)),
2218 return (schema, value, impl, expl, default, optional, _decoded)
2221 class TestEnumerated(CommonMixin, TestCase):
2222 class EWhatever(Enumerated):
2223 schema = (("whatever", 0),)
2225 base_klass = EWhatever
2227 def test_schema_required(self):
2228 with assertRaisesRegex(self, ValueError, "schema must be specified"):
2231 def test_invalid_value_type(self):
2232 with self.assertRaises(InvalidValueType) as err:
2233 self.base_klass((1, 2))
2236 @given(sets(text_letters(), min_size=2))
2237 def test_unknown_name(self, schema_input):
2238 missing = schema_input.pop()
2240 class E(Enumerated):
2241 schema = [(n, 123) for n in schema_input]
2242 with self.assertRaises(ObjUnknown) as err:
2247 sets(text_letters(), min_size=2),
2248 sets(integers(), min_size=2),
2250 def test_unknown_value(self, schema_input, values_input):
2252 missing_value = values_input.pop()
2253 _input = list(zip(schema_input, values_input))
2255 class E(Enumerated):
2257 with self.assertRaises(DecodeError) as err:
2262 def test_optional(self, optional):
2263 obj = self.base_klass(default="whatever", optional=optional)
2264 self.assertTrue(obj.optional)
2266 def test_ready(self):
2267 obj = self.base_klass()
2268 self.assertFalse(obj.ready)
2271 with self.assertRaises(ObjNotReady) as err:
2274 obj = self.base_klass("whatever")
2275 self.assertTrue(obj.ready)
2279 @given(integers(), integers(), binary(), binary())
2280 def test_comparison(self, value1, value2, tag1, tag2):
2281 class E(Enumerated):
2283 ("whatever0", value1),
2284 ("whatever1", value2),
2287 class EInherited(E):
2289 for klass in (E, EInherited):
2290 obj1 = klass(value1)
2291 obj2 = klass(value2)
2292 self.assertEqual(obj1 == obj2, value1 == value2)
2293 self.assertEqual(obj1 != obj2, value1 != value2)
2294 self.assertEqual(obj1 == int(obj2), value1 == value2)
2295 obj1 = klass(value1, impl=tag1)
2296 obj2 = klass(value1, impl=tag2)
2297 self.assertEqual(obj1 == obj2, tag1 == tag2)
2298 self.assertEqual(obj1 != obj2, tag1 != tag2)
2300 @given(data_strategy())
2301 def test_call(self, d):
2310 ) = d.draw(enumerated_values_strat())
2312 class E(Enumerated):
2313 schema = schema_initial
2315 value=value_initial,
2318 default=default_initial,
2319 optional=optional_initial or False,
2320 _decoded=_decoded_initial,
2330 ) = d.draw(enumerated_values_strat(
2331 schema=schema_initial,
2332 do_expl=impl_initial is None,
2342 value_expected = default if value is None else value
2344 default_initial if value_expected is None
2349 dict(schema_initial).get(value_expected, value_expected),
2351 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2352 self.assertEqual(obj.expl_tag, expl or expl_initial)
2355 default_initial if default is None else default,
2357 if obj.default is None:
2358 optional = optional_initial if optional is None else optional
2359 optional = False if optional is None else optional
2362 self.assertEqual(obj.optional, optional)
2363 self.assertEqual(obj.specs, dict(schema_initial))
2365 @given(enumerated_values_strat())
2366 def test_copy(self, values):
2367 schema_input, value, impl, expl, default, optional, _decoded = values
2369 class E(Enumerated):
2370 schema = schema_input
2379 obj_copied = obj.copy()
2380 self.assert_copied_basic_fields(obj, obj_copied)
2381 self.assertEqual(obj.specs, obj_copied.specs)
2383 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2384 @given(data_strategy())
2385 def test_symmetric(self, d):
2386 schema_input, _, _, _, default, optional, _decoded = d.draw(
2387 enumerated_values_strat(),
2389 tag_expl = d.draw(integers(min_value=1).map(tag_ctxc))
2390 offset = d.draw(integers(min_value=0))
2391 value = d.draw(sampled_from(sorted([v for _, v in schema_input])))
2393 class E(Enumerated):
2394 schema = schema_input
2403 self.assertFalse(obj.expled)
2404 obj_encoded = obj.encode()
2405 obj_expled = obj(value, expl=tag_expl)
2406 self.assertTrue(obj_expled.expled)
2409 obj_expled_encoded = obj_expled.encode()
2410 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2413 self.assertEqual(tail, b"")
2414 self.assertEqual(obj_decoded, obj_expled)
2415 self.assertNotEqual(obj_decoded, obj)
2416 self.assertEqual(int(obj_decoded), int(obj_expled))
2417 self.assertEqual(int(obj_decoded), int(obj))
2418 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2419 self.assertEqual(obj_decoded.expl_tag, tag_expl)
2420 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2422 obj_decoded.expl_llen,
2423 len(len_encode(len(obj_encoded))),
2425 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2426 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2429 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2431 self.assertEqual(obj_decoded.expl_offset, offset)
2435 def string_values_strat(draw, alphabet, do_expl=False):
2436 bound_min, bound_max = sorted(draw(sets(
2437 integers(min_value=0, max_value=1 << 7),
2441 value = draw(one_of(
2443 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2445 default = draw(one_of(
2447 text(alphabet=alphabet, min_size=bound_min, max_size=bound_max),
2450 if draw(booleans()):
2451 bounds = (bound_min, bound_max)
2455 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2457 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2458 optional = draw(one_of(none(), booleans()))
2460 draw(integers(min_value=0)),
2461 draw(integers(min_value=0)),
2462 draw(integers(min_value=0)),
2464 return (value, bounds, impl, expl, default, optional, _decoded)
2467 class StringMixin(object):
2468 def test_invalid_value_type(self):
2469 with self.assertRaises(InvalidValueType) as err:
2470 self.base_klass((1, 2))
2473 def text_alphabet(self):
2474 if self.base_klass.encoding in ("ascii", "iso-8859-1"):
2475 return printable + whitespace
2479 def test_optional(self, optional):
2480 obj = self.base_klass(default=self.base_klass(""), optional=optional)
2481 self.assertTrue(obj.optional)
2483 @given(data_strategy())
2484 def test_ready(self, d):
2485 obj = self.base_klass()
2486 self.assertFalse(obj.ready)
2490 with self.assertRaises(ObjNotReady) as err:
2493 value = d.draw(text(alphabet=self.text_alphabet()))
2494 obj = self.base_klass(value)
2495 self.assertTrue(obj.ready)
2500 @given(data_strategy())
2501 def test_comparison(self, d):
2502 value1 = d.draw(text(alphabet=self.text_alphabet()))
2503 value2 = d.draw(text(alphabet=self.text_alphabet()))
2504 tag1 = d.draw(binary())
2505 tag2 = d.draw(binary())
2506 obj1 = self.base_klass(value1)
2507 obj2 = self.base_klass(value2)
2508 self.assertEqual(obj1 == obj2, value1 == value2)
2509 self.assertEqual(obj1 != obj2, value1 != value2)
2510 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2511 self.assertEqual(obj1 == text_type(obj2), value1 == value2)
2512 obj1 = self.base_klass(value1, impl=tag1)
2513 obj2 = self.base_klass(value1, impl=tag2)
2514 self.assertEqual(obj1 == obj2, tag1 == tag2)
2515 self.assertEqual(obj1 != obj2, tag1 != tag2)
2517 @given(data_strategy())
2518 def test_bounds_satisfied(self, d):
2519 bound_min = d.draw(integers(min_value=0, max_value=1 << 7))
2520 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2521 value = d.draw(text(
2522 alphabet=self.text_alphabet(),
2526 self.base_klass(value=value, bounds=(bound_min, bound_max))
2528 @given(data_strategy())
2529 def test_bounds_unsatisfied(self, d):
2530 bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
2531 bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
2532 value = d.draw(text(alphabet=self.text_alphabet(), max_size=bound_min - 1))
2533 with self.assertRaises(BoundsError) as err:
2534 self.base_klass(value=value, bounds=(bound_min, bound_max))
2536 value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
2537 with self.assertRaises(BoundsError) as err:
2538 self.base_klass(value=value, bounds=(bound_min, bound_max))
2541 @given(data_strategy())
2542 def test_call(self, d):
2551 ) = d.draw(string_values_strat(self.text_alphabet()))
2552 obj_initial = self.base_klass(
2558 optional_initial or False,
2569 ) = d.draw(string_values_strat(
2570 self.text_alphabet(),
2571 do_expl=impl_initial is None,
2573 if (default is None) and (obj_initial.default is not None):
2576 (bounds is None) and
2577 (value is not None) and
2578 (bounds_initial is not None) and
2579 not (bounds_initial[0] <= len(value) <= bounds_initial[1])
2583 (bounds is None) and
2584 (default is not None) and
2585 (bounds_initial is not None) and
2586 not (bounds_initial[0] <= len(default) <= bounds_initial[1])
2589 obj = obj_initial(value, bounds, impl, expl, default, optional)
2591 value_expected = default if value is None else value
2593 default_initial if value_expected is None
2596 self.assertEqual(obj, value_expected)
2597 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2598 self.assertEqual(obj.expl_tag, expl or expl_initial)
2601 default_initial if default is None else default,
2603 if obj.default is None:
2604 optional = optional_initial if optional is None else optional
2605 optional = False if optional is None else optional
2608 self.assertEqual(obj.optional, optional)
2610 (obj._bound_min, obj._bound_max),
2611 bounds or bounds_initial or (0, float("+inf")),
2614 @given(data_strategy())
2615 def test_copy(self, d):
2616 values = d.draw(string_values_strat(self.text_alphabet()))
2617 obj = self.base_klass(*values)
2618 obj_copied = obj.copy()
2619 self.assert_copied_basic_fields(obj, obj_copied)
2620 self.assertEqual(obj._bound_min, obj_copied._bound_min)
2621 self.assertEqual(obj._bound_max, obj_copied._bound_max)
2622 self.assertEqual(obj._value, obj_copied._value)
2624 @given(data_strategy())
2625 def test_stripped(self, d):
2626 value = d.draw(text(alphabet=self.text_alphabet()))
2627 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2628 obj = self.base_klass(value, impl=tag_impl)
2629 with self.assertRaises(NotEnoughData):
2630 obj.decode(obj.encode()[:-1])
2632 @given(data_strategy())
2633 def test_stripped_expl(self, d):
2634 value = d.draw(text(alphabet=self.text_alphabet()))
2635 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2636 obj = self.base_klass(value, expl=tag_expl)
2637 with self.assertRaises(NotEnoughData):
2638 obj.decode(obj.encode()[:-1])
2641 integers(min_value=31),
2642 integers(min_value=0),
2645 def test_bad_tag(self, tag, offset, decode_path):
2646 decode_path = tuple(str(i) for i in decode_path)
2647 with self.assertRaises(DecodeError) as err:
2648 self.base_klass().decode(
2649 tag_encode(tag)[:-1],
2651 decode_path=decode_path,
2654 self.assertEqual(err.exception.offset, offset)
2655 self.assertEqual(err.exception.decode_path, decode_path)
2658 integers(min_value=128),
2659 integers(min_value=0),
2662 def test_bad_len(self, l, offset, decode_path):
2663 decode_path = tuple(str(i) for i in decode_path)
2664 with self.assertRaises(DecodeError) as err:
2665 self.base_klass().decode(
2666 self.base_klass.tag_default + len_encode(l)[:-1],
2668 decode_path=decode_path,
2671 self.assertEqual(err.exception.offset, offset)
2672 self.assertEqual(err.exception.decode_path, decode_path)
2675 sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
2676 integers(min_value=0),
2679 def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
2680 decode_path = tuple(str(i) for i in decode_path)
2681 value, bound_min = list(sorted(ints))
2683 class String(self.base_klass):
2684 # Multiply this value by four, to satisfy UTF-32 bounds
2685 # (4 bytes per character) validation
2686 bounds = (bound_min * 4, bound_min * 4)
2687 with self.assertRaises(DecodeError) as err:
2689 self.base_klass(b"\x00\x00\x00\x00" * value).encode(),
2691 decode_path=decode_path,
2694 self.assertEqual(err.exception.offset, offset)
2695 self.assertEqual(err.exception.decode_path, decode_path)
2697 @given(data_strategy())
2698 def test_symmetric(self, d):
2699 values = d.draw(string_values_strat(self.text_alphabet()))
2700 value = d.draw(text(alphabet=self.text_alphabet()))
2701 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2702 offset = d.draw(integers(min_value=0))
2703 _, _, _, _, default, optional, _decoded = values
2704 obj = self.base_klass(
2712 self.assertFalse(obj.expled)
2713 obj_encoded = obj.encode()
2714 obj_expled = obj(value, expl=tag_expl)
2715 self.assertTrue(obj_expled.expled)
2718 obj_expled_encoded = obj_expled.encode()
2719 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
2722 self.assertEqual(tail, b"")
2723 self.assertEqual(obj_decoded, obj_expled)
2724 self.assertNotEqual(obj_decoded, obj)
2725 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
2726 self.assertEqual(bytes(obj_decoded), bytes(obj))
2727 self.assertEqual(text_type(obj_decoded), text_type(obj_expled))
2728 self.assertEqual(text_type(obj_decoded), text_type(obj))
2729 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
2730 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
2731 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
2733 obj_decoded.expl_llen,
2734 len(len_encode(len(obj_encoded))),
2736 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
2737 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
2740 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
2742 self.assertEqual(obj_decoded.expl_offset, offset)
2745 class TestUTF8String(StringMixin, CommonMixin, TestCase):
2746 base_klass = UTF8String
2749 class TestNumericString(StringMixin, CommonMixin, TestCase):
2750 base_klass = NumericString
2753 class TestPrintableString(StringMixin, CommonMixin, TestCase):
2754 base_klass = PrintableString
2757 class TestTeletexString(StringMixin, CommonMixin, TestCase):
2758 base_klass = TeletexString
2761 class TestVideotexString(StringMixin, CommonMixin, TestCase):
2762 base_klass = VideotexString
2765 class TestIA5String(StringMixin, CommonMixin, TestCase):
2766 base_klass = IA5String
2769 class TestGraphicString(StringMixin, CommonMixin, TestCase):
2770 base_klass = GraphicString
2773 class TestVisibleString(StringMixin, CommonMixin, TestCase):
2774 base_klass = VisibleString
2777 class TestGeneralString(StringMixin, CommonMixin, TestCase):
2778 base_klass = GeneralString
2781 class TestUniversalString(StringMixin, CommonMixin, TestCase):
2782 base_klass = UniversalString
2785 class TestBMPString(StringMixin, CommonMixin, TestCase):
2786 base_klass = BMPString
2790 def generalized_time_values_strat(
2798 if draw(booleans()):
2799 value = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2801 value = value.replace(microsecond=0)
2803 if draw(booleans()):
2804 default = draw(datetimes(min_value=min_datetime, max_value=max_datetime))
2806 default = default.replace(microsecond=0)
2810 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2812 impl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
2813 optional = draw(one_of(none(), booleans()))
2815 draw(integers(min_value=0)),
2816 draw(integers(min_value=0)),
2817 draw(integers(min_value=0)),
2819 return (value, impl, expl, default, optional, _decoded)
2822 class TimeMixin(object):
2823 def test_invalid_value_type(self):
2824 with self.assertRaises(InvalidValueType) as err:
2825 self.base_klass(datetime.now().timetuple())
2828 @given(data_strategy())
2829 def test_optional(self, d):
2830 default = d.draw(datetimes(
2831 min_value=self.min_datetime,
2832 max_value=self.max_datetime,
2834 optional = d.draw(booleans())
2835 obj = self.base_klass(default=default, optional=optional)
2836 self.assertTrue(obj.optional)
2838 @given(data_strategy())
2839 def test_ready(self, d):
2840 obj = self.base_klass()
2841 self.assertFalse(obj.ready)
2844 with self.assertRaises(ObjNotReady) as err:
2847 value = d.draw(datetimes(min_value=self.min_datetime))
2848 obj = self.base_klass(value)
2849 self.assertTrue(obj.ready)
2853 @given(data_strategy())
2854 def test_comparison(self, d):
2855 value1 = d.draw(datetimes(
2856 min_value=self.min_datetime,
2857 max_value=self.max_datetime,
2859 value2 = d.draw(datetimes(
2860 min_value=self.min_datetime,
2861 max_value=self.max_datetime,
2863 tag1 = d.draw(binary())
2864 tag2 = d.draw(binary())
2866 value1 = value1.replace(microsecond=0)
2867 value2 = value2.replace(microsecond=0)
2868 obj1 = self.base_klass(value1)
2869 obj2 = self.base_klass(value2)
2870 self.assertEqual(obj1 == obj2, value1 == value2)
2871 self.assertEqual(obj1 != obj2, value1 != value2)
2872 self.assertEqual(obj1 == obj2.todatetime(), value1 == value2)
2873 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
2874 obj1 = self.base_klass(value1, impl=tag1)
2875 obj2 = self.base_klass(value1, impl=tag2)
2876 self.assertEqual(obj1 == obj2, tag1 == tag2)
2877 self.assertEqual(obj1 != obj2, tag1 != tag2)
2879 @given(data_strategy())
2880 def test_call(self, d):
2888 ) = d.draw(generalized_time_values_strat(
2889 min_datetime=self.min_datetime,
2890 max_datetime=self.max_datetime,
2891 omit_ms=self.omit_ms,
2893 obj_initial = self.base_klass(
2894 value=value_initial,
2897 default=default_initial,
2898 optional=optional_initial or False,
2899 _decoded=_decoded_initial,
2908 ) = d.draw(generalized_time_values_strat(
2909 min_datetime=self.min_datetime,
2910 max_datetime=self.max_datetime,
2911 omit_ms=self.omit_ms,
2912 do_expl=impl_initial is None,
2922 value_expected = default if value is None else value
2924 default_initial if value_expected is None
2927 self.assertEqual(obj, value_expected)
2928 self.assertEqual(obj.tag, impl or impl_initial or obj.tag_default)
2929 self.assertEqual(obj.expl_tag, expl or expl_initial)
2932 default_initial if default is None else default,
2934 if obj.default is None:
2935 optional = optional_initial if optional is None else optional
2936 optional = False if optional is None else optional
2939 self.assertEqual(obj.optional, optional)
2941 @given(data_strategy())
2942 def test_copy(self, d):
2943 values = d.draw(generalized_time_values_strat(
2944 min_datetime=self.min_datetime,
2945 max_datetime=self.max_datetime,
2947 obj = self.base_klass(*values)
2948 obj_copied = obj.copy()
2949 self.assert_copied_basic_fields(obj, obj_copied)
2950 self.assertEqual(obj._value, obj_copied._value)
2952 @given(data_strategy())
2953 def test_stripped(self, d):
2954 value = d.draw(datetimes(
2955 min_value=self.min_datetime,
2956 max_value=self.max_datetime,
2958 tag_impl = tag_encode(d.draw(integers(min_value=1)))
2959 obj = self.base_klass(value, impl=tag_impl)
2960 with self.assertRaises(NotEnoughData):
2961 obj.decode(obj.encode()[:-1])
2963 @given(data_strategy())
2964 def test_stripped_expl(self, d):
2965 value = d.draw(datetimes(
2966 min_value=self.min_datetime,
2967 max_value=self.max_datetime,
2969 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2970 obj = self.base_klass(value, expl=tag_expl)
2971 with self.assertRaises(NotEnoughData):
2972 obj.decode(obj.encode()[:-1])
2974 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
2975 @given(data_strategy())
2976 def test_symmetric(self, d):
2977 values = d.draw(generalized_time_values_strat(
2978 min_datetime=self.min_datetime,
2979 max_datetime=self.max_datetime,
2981 value = d.draw(datetimes(
2982 min_value=self.min_datetime,
2983 max_value=self.max_datetime,
2985 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
2986 offset = d.draw(integers(min_value=0))
2987 _, _, _, default, optional, _decoded = values
2988 obj = self.base_klass(
2996 self.assertFalse(obj.expled)
2997 obj_encoded = obj.encode()
2998 obj_expled = obj(value, expl=tag_expl)
2999 self.assertTrue(obj_expled.expled)
3002 obj_expled_encoded = obj_expled.encode()
3003 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3006 self.assertEqual(tail, b"")
3007 self.assertEqual(obj_decoded, obj_expled)
3008 self.assertEqual(obj_decoded.todatetime(), obj_expled.todatetime())
3009 self.assertEqual(obj_decoded.todatetime(), obj.todatetime())
3010 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3011 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3012 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3014 obj_decoded.expl_llen,
3015 len(len_encode(len(obj_encoded))),
3017 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3018 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3021 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3023 self.assertEqual(obj_decoded.expl_offset, offset)
3026 class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
3027 base_klass = GeneralizedTime
3029 min_datetime = datetime(1900, 1, 1)
3030 max_datetime = datetime(9999, 12, 31)
3032 def test_go_vectors_invalid(self):
3044 b"-20100102030410Z",
3045 b"2010-0102030410Z",
3046 b"2010-0002030410Z",
3047 b"201001-02030410Z",
3048 b"20100102-030410Z",
3049 b"2010010203-0410Z",
3050 b"201001020304-10Z",
3051 # These ones are INVALID in *DER*, but accepted
3052 # by Go's encoding/asn1
3053 b"20100102030405+0607",
3054 b"20100102030405-0607",
3056 with self.assertRaises(DecodeError) as err:
3057 GeneralizedTime(data)
3060 def test_go_vectors_valid(self):
3062 GeneralizedTime(b"20100102030405Z").todatetime(),
3063 datetime(2010, 1, 2, 3, 4, 5, 0),
3067 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
3068 base_klass = UTCTime
3070 min_datetime = datetime(2000, 1, 1)
3071 max_datetime = datetime(2049, 12, 31)
3073 def test_go_vectors_invalid(self):
3099 # These ones are INVALID in *DER*, but accepted
3100 # by Go's encoding/asn1
3101 b"910506164540-0700",
3102 b"910506164540+0730",
3106 with self.assertRaises(DecodeError) as err:
3110 def test_go_vectors_valid(self):
3112 UTCTime(b"910506234540Z").todatetime(),
3113 datetime(1991, 5, 6, 23, 45, 40, 0),
3116 @given(integers(min_value=0, max_value=49))
3117 def test_pre50(self, year):
3119 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3123 @given(integers(min_value=50, max_value=99))
3124 def test_post50(self, year):
3126 UTCTime(("%02d1231235959Z" % year).encode("ascii")).todatetime().year,
3132 def any_values_strat(draw, do_expl=False):
3133 value = draw(one_of(none(), binary()))
3136 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3137 optional = draw(one_of(none(), booleans()))
3139 draw(integers(min_value=0)),
3140 draw(integers(min_value=0)),
3141 draw(integers(min_value=0)),
3143 return (value, expl, optional, _decoded)
3146 class AnyInherited(Any):
3150 class TestAny(CommonMixin, TestCase):
3153 def test_invalid_value_type(self):
3154 with self.assertRaises(InvalidValueType) as err:
3159 def test_optional(self, optional):
3160 obj = Any(optional=optional)
3161 self.assertEqual(obj.optional, optional)
3164 def test_ready(self, value):
3166 self.assertFalse(obj.ready)
3169 with self.assertRaises(ObjNotReady) as err:
3173 self.assertTrue(obj.ready)
3178 def test_basic(self, value):
3179 integer_encoded = Integer(value).encode()
3181 Any(integer_encoded),
3182 Any(Integer(value)),
3183 Any(Any(Integer(value))),
3185 self.assertSequenceEqual(bytes(obj), integer_encoded)
3187 obj.decode(obj.encode())[0].vlen,
3188 len(integer_encoded),
3192 self.assertSequenceEqual(obj.encode(), integer_encoded)
3194 @given(binary(), binary())
3195 def test_comparison(self, value1, value2):
3196 for klass in (Any, AnyInherited):
3197 obj1 = klass(value1)
3198 obj2 = klass(value2)
3199 self.assertEqual(obj1 == obj2, value1 == value2)
3200 self.assertEqual(obj1 != obj2, value1 != value2)
3201 self.assertEqual(obj1 == bytes(obj2), value1 == value2)
3203 @given(data_strategy())
3204 def test_call(self, d):
3205 for klass in (Any, AnyInherited):
3211 ) = d.draw(any_values_strat())
3212 obj_initial = klass(
3215 optional_initial or False,
3223 ) = d.draw(any_values_strat(do_expl=True))
3224 obj = obj_initial(value, expl, optional)
3226 value_expected = None if value is None else value
3227 self.assertEqual(obj, value_expected)
3228 self.assertEqual(obj.expl_tag, expl or expl_initial)
3229 if obj.default is None:
3230 optional = optional_initial if optional is None else optional
3231 optional = False if optional is None else optional
3232 self.assertEqual(obj.optional, optional)
3234 def test_simultaneous_impl_expl(self):
3235 # override it, as Any does not have implicit tag
3238 def test_decoded(self):
3239 # override it, as Any does not have implicit tag
3242 @given(any_values_strat())
3243 def test_copy(self, values):
3244 for klass in (Any, AnyInherited):
3245 obj = klass(*values)
3246 obj_copied = obj.copy()
3247 self.assert_copied_basic_fields(obj, obj_copied)
3248 self.assertEqual(obj._value, obj_copied._value)
3250 @given(binary().map(OctetString))
3251 def test_stripped(self, value):
3253 with self.assertRaises(NotEnoughData):
3254 obj.decode(obj.encode()[:-1])
3258 integers(min_value=1).map(tag_ctxc),
3260 def test_stripped_expl(self, value, tag_expl):
3261 obj = Any(value, expl=tag_expl)
3262 with self.assertRaises(NotEnoughData):
3263 obj.decode(obj.encode()[:-1])
3266 integers(min_value=31),
3267 integers(min_value=0),
3270 def test_bad_tag(self, tag, offset, decode_path):
3271 decode_path = tuple(str(i) for i in decode_path)
3272 with self.assertRaises(DecodeError) as err:
3274 tag_encode(tag)[:-1],
3276 decode_path=decode_path,
3279 self.assertEqual(err.exception.offset, offset)
3280 self.assertEqual(err.exception.decode_path, decode_path)
3283 integers(min_value=128),
3284 integers(min_value=0),
3287 def test_bad_len(self, l, offset, decode_path):
3288 decode_path = tuple(str(i) for i in decode_path)
3289 with self.assertRaises(DecodeError) as err:
3291 Any.tag_default + len_encode(l)[:-1],
3293 decode_path=decode_path,
3296 self.assertEqual(err.exception.offset, offset)
3297 self.assertEqual(err.exception.decode_path, decode_path)
3299 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3302 integers().map(lambda x: Integer(x).encode()),
3303 integers(min_value=1).map(tag_ctxc),
3304 integers(min_value=0),
3306 def test_symmetric(self, values, value, tag_expl, offset):
3307 for klass in (Any, AnyInherited):
3308 _, _, optional, _decoded = values
3309 obj = klass(value=value, optional=optional, _decoded=_decoded)
3312 self.assertFalse(obj.expled)
3313 obj_encoded = obj.encode()
3314 obj_expled = obj(value, expl=tag_expl)
3315 self.assertTrue(obj_expled.expled)
3318 obj_expled_encoded = obj_expled.encode()
3319 obj_decoded, tail = obj_expled.decode(obj_expled_encoded, offset=offset)
3322 self.assertEqual(tail, b"")
3323 self.assertEqual(obj_decoded, obj_expled)
3324 self.assertEqual(bytes(obj_decoded), bytes(obj_expled))
3325 self.assertEqual(bytes(obj_decoded), bytes(obj))
3326 self.assertSequenceEqual(obj_decoded.encode(), obj_expled_encoded)
3327 self.assertSequenceEqual(obj_decoded.expl_tag, tag_expl)
3328 self.assertEqual(obj_decoded.expl_tlen, len(tag_expl))
3330 obj_decoded.expl_llen,
3331 len(len_encode(len(obj_encoded))),
3333 self.assertEqual(obj_decoded.tlvlen, len(obj_encoded))
3334 self.assertEqual(obj_decoded.expl_vlen, len(obj_encoded))
3337 offset + obj_decoded.expl_tlen + obj_decoded.expl_llen,
3339 self.assertEqual(obj_decoded.expl_offset, offset)
3340 self.assertEqual(obj_decoded.tlen, 0)
3341 self.assertEqual(obj_decoded.llen, 0)
3342 self.assertEqual(obj_decoded.vlen, len(value))
3346 def choice_values_strat(draw, value_required=False, schema=None, do_expl=False):
3348 names = list(draw(sets(text_letters(), min_size=1, max_size=5)))
3349 tags = [tag_encode(tag) for tag in draw(sets(
3350 integers(min_value=0),
3351 min_size=len(names),
3352 max_size=len(names),
3354 schema = [(name, Integer(impl=tag)) for name, tag in zip(names, tags)]
3356 if value_required or draw(booleans()):
3357 value = draw(tuples(
3358 sampled_from([name for name, _ in schema]),
3359 integers().map(Integer),
3363 expl = draw(one_of(none(), integers(min_value=1).map(tag_encode)))
3364 default = draw(one_of(
3366 tuples(sampled_from([name for name, _ in schema]), integers().map(Integer)),
3368 optional = draw(one_of(none(), booleans()))
3370 draw(integers(min_value=0)),
3371 draw(integers(min_value=0)),
3372 draw(integers(min_value=0)),
3374 return (schema, value, expl, default, optional, _decoded)
3377 class ChoiceInherited(Choice):
3381 class TestChoice(CommonMixin, TestCase):
3383 schema = (("whatever", Boolean()),)
3386 def test_schema_required(self):
3387 with assertRaisesRegex(self, ValueError, "schema must be specified"):
3390 def test_impl_forbidden(self):
3391 with assertRaisesRegex(self, ValueError, "no implicit tag allowed"):
3392 Choice(impl=b"whatever")
3394 def test_invalid_value_type(self):
3395 with self.assertRaises(InvalidValueType) as err:
3396 self.base_klass(123)
3398 with self.assertRaises(ObjUnknown) as err:
3399 self.base_klass(("whenever", Boolean(False)))
3401 with self.assertRaises(InvalidValueType) as err:
3402 self.base_klass(("whatever", Integer(123)))
3406 def test_optional(self, optional):
3407 obj = self.base_klass(
3408 default=self.base_klass(("whatever", Boolean(False))),
3411 self.assertTrue(obj.optional)
3414 def test_ready(self, value):
3415 obj = self.base_klass()
3416 self.assertFalse(obj.ready)
3419 self.assertIsNone(obj["whatever"])
3420 with self.assertRaises(ObjNotReady) as err:
3423 obj["whatever"] = Boolean()
3424 self.assertFalse(obj.ready)
3427 obj["whatever"] = Boolean(value)
3428 self.assertTrue(obj.ready)
3432 @given(booleans(), booleans())
3433 def test_comparison(self, value1, value2):
3434 class WahlInherited(self.base_klass):
3436 for klass in (self.base_klass, WahlInherited):
3437 obj1 = klass(("whatever", Boolean(value1)))
3438 obj2 = klass(("whatever", Boolean(value2)))
3439 self.assertEqual(obj1 == obj2, value1 == value2)
3440 self.assertEqual(obj1 != obj2, value1 != value2)
3441 self.assertEqual(obj1 == obj2._value, value1 == value2)
3442 self.assertFalse(obj1 == obj2._value[1])
3444 @given(data_strategy())
3445 def test_call(self, d):
3446 for klass in (Choice, ChoiceInherited):
3454 ) = d.draw(choice_values_strat())
3457 schema = schema_initial
3459 value=value_initial,
3461 default=default_initial,
3462 optional=optional_initial or False,
3463 _decoded=_decoded_initial,
3472 ) = d.draw(choice_values_strat(schema=schema_initial, do_expl=True))
3473 obj = obj_initial(value, expl, default, optional)
3475 value_expected = default if value is None else value
3477 default_initial if value_expected is None
3480 self.assertEqual(obj.choice, value_expected[0])
3481 self.assertEqual(obj.value, int(value_expected[1]))
3482 self.assertEqual(obj.expl_tag, expl or expl_initial)
3483 default_expect = default_initial if default is None else default
3484 if default_expect is not None:
3485 self.assertEqual(obj.default.choice, default_expect[0])
3486 self.assertEqual(obj.default.value, int(default_expect[1]))
3487 if obj.default is None:
3488 optional = optional_initial if optional is None else optional
3489 optional = False if optional is None else optional
3492 self.assertEqual(obj.optional, optional)
3493 self.assertEqual(obj.specs, obj_initial.specs)
3495 def test_simultaneous_impl_expl(self):
3496 # override it, as Any does not have implicit tag
3499 def test_decoded(self):
3500 # override it, as Any does not have implicit tag
3503 @given(choice_values_strat())
3504 def test_copy(self, values):
3505 _schema, value, expl, default, optional, _decoded = values
3507 class Wahl(self.base_klass):
3513 optional=optional or False,
3516 obj_copied = obj.copy()
3517 self.assertIsNone(obj.tag)
3518 self.assertIsNone(obj_copied.tag)
3519 # hack for assert_copied_basic_fields
3520 obj.tag = "whatever"
3521 obj_copied.tag = "whatever"
3522 self.assert_copied_basic_fields(obj, obj_copied)
3523 self.assertEqual(obj._value, obj_copied._value)
3524 self.assertEqual(obj.specs, obj_copied.specs)
3527 def test_stripped(self, value):
3528 obj = self.base_klass(("whatever", Boolean(value)))
3529 with self.assertRaises(NotEnoughData):
3530 obj.decode(obj.encode()[:-1])
3534 integers(min_value=1).map(tag_ctxc),
3536 def test_stripped_expl(self, value, tag_expl):
3537 obj = self.base_klass(("whatever", Boolean(value)), expl=tag_expl)
3538 with self.assertRaises(NotEnoughData):
3539 obj.decode(obj.encode()[:-1])
3541 @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
3542 @given(data_strategy())
3543 def test_symmetric(self, d):
3544 _schema, value, _, default, optional, _decoded = d.draw(
3545 choice_values_strat(value_required=True)
3547 tag_expl = tag_ctxc(d.draw(integers(min_value=1)))
3548 offset = d.draw(integers(min_value=0))
3550 class Wahl(self.base_klass):
3560 self.assertFalse(obj.expled)
3561 obj_encoded = obj.encode()
3562 obj_expled = obj(value, expl=tag_expl)
3563 self.assertTrue(obj_expled.expled)
3566 obj_expled_encoded = obj_expled.encode()