X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=tests%2Ftest_pyderasn.py;h=46e10e53abdbb12848d8be51d21d58f43ff0a11b;hb=659eb0e090ad8c9209c4e5b030806125509844f9;hp=cd165b857a40b5d628e5839082895b3fdb33a18b;hpb=011b627453f5bfe82bdd160edbb249a73f21082a;p=pyderasn.git diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index cd165b8..46e10e5 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -1,5 +1,5 @@ # coding: utf-8 -# PyDERASN -- Python ASN.1 DER/BER codec with abstract structures +# PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures # Copyright (C) 2017-2020 Sergey Matveev # # This program is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ from copy import deepcopy from datetime import datetime from datetime import timedelta from importlib import import_module +from io import BytesIO from operator import attrgetter from os import environ from os import urandom @@ -60,6 +61,7 @@ from six import iterbytes from six import PY2 from six import text_type from six import unichr as six_unichr +from six.moves import xrange as six_xrange from six.moves.cPickle import dumps as pickle_dumps from six.moves.cPickle import HIGHEST_PROTOCOL as pickle_proto from six.moves.cPickle import loads as pickle_loads @@ -74,6 +76,7 @@ from pyderasn import BoundsError from pyderasn import Choice from pyderasn import DecodeError from pyderasn import DecodePathDefBy +from pyderasn import encode2pass from pyderasn import encode_cer from pyderasn import Enumerated from pyderasn import EOC @@ -421,6 +424,8 @@ class TestBoolean(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) with self.assertRaises(ObjNotReady) as err: obj.encode() + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) repr(err.exception) obj = Boolean(value) self.assertTrue(obj.ready) @@ -505,6 +510,8 @@ class TestBoolean(CommonMixin, TestCase): obj = Boolean(value, impl=tag_impl) with self.assertRaises(NotEnoughData): obj.decode(obj.encode()[:-1]) + with self.assertRaises(NotEnoughData): + obj.decode(encode2pass(obj)[:-1]) @given( booleans(), @@ -514,6 +521,8 @@ class TestBoolean(CommonMixin, TestCase): obj = Boolean(value, expl=tag_expl) with self.assertRaises(NotEnoughData): obj.decode(obj.encode()[:-1]) + with self.assertRaises(NotEnoughData): + obj.decode(encode2pass(obj)[:-1]) @given( integers(min_value=31), @@ -602,6 +611,7 @@ class TestBoolean(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.assertSequenceEqual(encode_cer(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -862,6 +872,8 @@ class TestInteger(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) with self.assertRaises(ObjNotReady) as err: obj.encode() + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) repr(err.exception) obj = Integer(value) self.assertTrue(obj.ready) @@ -924,6 +936,10 @@ class TestInteger(CommonMixin, TestCase): Integer(values[0]).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + Integer(bounds=(values[1], values[2])).decode( + encode2pass(Integer(values[0])) + ) with self.assertRaises(BoundsError) as err: Integer(value=values[2], bounds=(values[0], values[1])) repr(err.exception) @@ -932,6 +948,10 @@ class TestInteger(CommonMixin, TestCase): Integer(values[2]).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + Integer(bounds=(values[0], values[1])).decode( + encode2pass(Integer(values[2])) + ) @given(data_strategy()) def test_call(self, d): @@ -1123,6 +1143,7 @@ class TestInteger(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.assertSequenceEqual(encode_cer(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -1361,6 +1382,8 @@ class TestBitString(CommonMixin, TestCase): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) obj = BitString(value) self.assertTrue(obj.ready) repr(obj) @@ -1539,6 +1562,7 @@ class TestBitString(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.assertSequenceEqual(encode_cer(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -1964,6 +1988,8 @@ class TestOctetString(CommonMixin, TestCase): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) obj = OctetString(value) self.assertTrue(obj.ready) repr(obj) @@ -2010,6 +2036,10 @@ class TestOctetString(CommonMixin, TestCase): OctetString(value).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + OctetString(bounds=(bound_min, bound_max)).decode( + encode2pass(OctetString(value)) + ) value = d.draw(binary(min_size=bound_max + 1)) with self.assertRaises(BoundsError) as err: OctetString(value=value, bounds=(bound_min, bound_max)) @@ -2019,6 +2049,10 @@ class TestOctetString(CommonMixin, TestCase): OctetString(value).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + OctetString(bounds=(bound_min, bound_max)).decode( + encode2pass(OctetString(value)) + ) @given(data_strategy()) def test_call(self, d): @@ -2195,6 +2229,7 @@ class TestOctetString(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.assertSequenceEqual(encode_cer(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -2565,6 +2600,7 @@ class TestNull(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.assertSequenceEqual(encode_cer(obj), obj_encoded) obj_expled = obj(expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -2694,6 +2730,8 @@ class TestObjectIdentifier(CommonMixin, TestCase): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) obj = ObjectIdentifier(value) self.assertTrue(obj.ready) self.assertFalse(obj.ber_encoded) @@ -2931,6 +2969,7 @@ class TestObjectIdentifier(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.assertSequenceEqual(encode_cer(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -3326,6 +3365,7 @@ class TestEnumerated(CommonMixin, TestCase): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) repr(obj_expled) @@ -3443,6 +3483,8 @@ class StringMixin(object): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) value = d.draw(text(alphabet=self.text_alphabet())) obj = self.base_klass(value) self.assertTrue(obj.ready) @@ -3492,6 +3534,10 @@ class StringMixin(object): self.base_klass(value).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + self.base_klass(bounds=(bound_min, bound_max)).decode( + encode2pass(self.base_klass(value)) + ) value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1)) with self.assertRaises(BoundsError) as err: self.base_klass(value=value, bounds=(bound_min, bound_max)) @@ -3501,6 +3547,10 @@ class StringMixin(object): self.base_klass(value).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + self.base_klass(bounds=(bound_min, bound_max)).decode( + encode2pass(self.base_klass(value)) + ) @given(data_strategy()) def test_call(self, d): @@ -3676,6 +3726,7 @@ class StringMixin(object): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) repr(obj_expled) @@ -3736,10 +3787,6 @@ class StringMixin(object): list(obj.pps()) -class TestUTF8String(StringMixin, CommonMixin, TestCase): - base_klass = UTF8String - - cyrillic_letters = text( alphabet="".join(six_unichr(i) for i in list(range(0x0410, 0x044f + 1))), min_size=1, @@ -3747,6 +3794,26 @@ cyrillic_letters = text( ) +class TestUTF8String(StringMixin, CommonMixin, TestCase): + base_klass = UTF8String + + @given(cyrillic_letters) + def test_byte_per_primitive(self, chars): + char = chars[0] + char_raw = char.encode("utf-8") + encoded = b"".join(( + self.base_klass().tag_constructed, + LENINDEF, + OctetString(char_raw[:1]).encode(), + OctetString(char_raw[1:2]).encode(), + EOC, + )) + self.assertEqual( + self.base_klass().decod(encoded, ctx={"bered": True}), + char, + ) + + class UnicodeDecodeErrorMixin(object): @given(cyrillic_letters) def test_unicode_decode_error(self, cyrillic_text): @@ -3785,6 +3852,19 @@ class TestNumericString(StringMixin, CommonMixin, TestCase): self.assertEqual(err.exception.offset, offset) self.assertEqual(err.exception.decode_path, decode_path) + def test_byte_per_primitive(self): + encoded = b"".join(( + self.base_klass().tag_constructed, + LENINDEF, + OctetString(b"1").encode(), + OctetString(b"2").encode(), + EOC, + )) + self.assertEqual( + self.base_klass().decod(encoded, ctx={"bered": True}), + "12", + ) + class TestPrintableString( UnicodeDecodeErrorMixin, @@ -4003,6 +4083,8 @@ class TimeMixin(object): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) value = d.draw(datetimes( min_value=self.min_datetime, max_value=self.max_datetime, @@ -4161,6 +4243,7 @@ class TimeMixin(object): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) self.additional_symmetric_check(value, obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) @@ -4970,6 +5053,8 @@ class TestAny(CommonMixin, TestCase): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) obj = Any(value) self.assertTrue(obj.ready) repr(obj) @@ -5118,6 +5203,7 @@ class TestAny(CommonMixin, TestCase): tag_class, _, tag_num = tag_decode(tag_strip(value)[0]) self.assertEqual(obj.tag_order, (tag_class, tag_num)) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) tag_class, _, tag_num = tag_decode(tag_expl) @@ -5354,6 +5440,8 @@ class TestChoice(CommonMixin, TestCase): with self.assertRaises(ObjNotReady) as err: obj.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(obj) obj["whatever"] = Boolean() self.assertFalse(obj.ready) repr(obj) @@ -5502,6 +5590,7 @@ class TestChoice(CommonMixin, TestCase): self.assertFalse(obj.expled) self.assertEqual(obj.tag_order, obj.value.tag_order) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) obj_expled = obj(value, expl=tag_expl) self.assertTrue(obj_expled.expled) tag_class, _, tag_num = tag_decode(tag_expl) @@ -5849,6 +5938,8 @@ class SeqMixing(object): with self.assertRaises(ObjNotReady) as err: seq.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(seq) for name, value in non_ready.items(): seq[name] = Boolean(value) self.assertTrue(seq.ready) @@ -6037,6 +6128,7 @@ class SeqMixing(object): pprint(seq, big_blobs=True, with_decode_path=True) self.assertTrue(seq.ready) seq_encoded = seq.encode() + self.assertEqual(encode2pass(seq), seq_encoded) seq_encoded_cer = encode_cer(seq) self.assertNotEqual(seq_encoded_cer, seq_encoded) self.assertSequenceEqual( @@ -6125,6 +6217,7 @@ class SeqMixing(object): seq, expect_outers = d.draw(sequences_strategy(seq_klass=self.base_klass)) self.assertTrue(seq.ready) seq_encoded = seq.encode() + self.assertEqual(encode2pass(seq), seq_encoded) seq_decoded, tail = seq.decode(seq_encoded) self.assertEqual(tail, b"") self.assertTrue(seq.ready) @@ -6497,6 +6590,8 @@ class SeqOfMixing(object): with self.assertRaises(ObjNotReady) as err: seqof.encode() repr(err.exception) + with self.assertRaises(ObjNotReady) as err: + encode2pass(seqof) for i, value in enumerate(values): self.assertEqual(seqof[i], value) if not seqof[i].ready: @@ -6540,6 +6635,10 @@ class SeqOfMixing(object): SeqOf(value).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + SeqOf(bounds=(bound_min, bound_max)).decode( + encode2pass(SeqOf(value)) + ) value = [Boolean(True)] * d.draw(integers( min_value=bound_max + 1, max_value=bound_max + 10, @@ -6552,6 +6651,10 @@ class SeqOfMixing(object): SeqOf(value).encode() ) repr(err.exception) + with assertRaisesRegex(self, DecodeError, "bounds") as err: + SeqOf(bounds=(bound_min, bound_max)).decode( + encode2pass(SeqOf(value)) + ) @given(integers(min_value=1, max_value=10)) def test_out_of_bounds(self, bound_max): @@ -6758,6 +6861,7 @@ class SeqOfMixing(object): pprint(obj, big_blobs=True, with_decode_path=True) self.assertFalse(obj.expled) obj_encoded = obj.encode() + self.assertEqual(encode2pass(obj), obj_encoded) obj_encoded_cer = encode_cer(obj) self.assertNotEqual(obj_encoded_cer, obj_encoded) self.assertSequenceEqual( @@ -6899,6 +7003,77 @@ class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase): self.assertEqual(obj1, obj2) self.assertSequenceEqual(list(obj1), list(obj2)) + def test_iterator_pickling(self): + class SeqOf(SequenceOf): + schema = Integer() + register_class(SeqOf) + seqof = SeqOf() + pickle_dumps(seqof) + seqof = seqof(iter(six_xrange(10))) + with assertRaisesRegex(self, ValueError, "iterator"): + pickle_dumps(seqof) + + def test_iterator_bounds(self): + class SeqOf(SequenceOf): + schema = Integer() + bounds = (10, 20) + seqof = None + def gen(n): + for i in six_xrange(n): + yield Integer(i) + for n in (9, 21): + seqof = SeqOf(gen(n)) + self.assertTrue(seqof.ready) + with self.assertRaises(BoundsError): + seqof.encode() + self.assertFalse(seqof.ready) + seqof = seqof(gen(n)) + self.assertTrue(seqof.ready) + with self.assertRaises(BoundsError): + encode_cer(seqof) + self.assertFalse(seqof.ready) + + def test_iterator_twice(self): + class SeqOf(SequenceOf): + schema = Integer() + bounds = (1, float("+inf")) + def gen(): + for i in six_xrange(10): + yield Integer(i) + seqof = SeqOf(gen()) + self.assertTrue(seqof.ready) + seqof.encode() + self.assertFalse(seqof.ready) + register_class(SeqOf) + pickle_dumps(seqof) + + def test_iterator_2pass(self): + class SeqOf(SequenceOf): + schema = Integer() + bounds = (1, float("+inf")) + def gen(): + for i in six_xrange(10): + yield Integer(i) + seqof = SeqOf(gen()) + self.assertTrue(seqof.ready) + _, state = seqof.encode1st() + self.assertFalse(seqof.ready) + seqof = seqof(gen()) + self.assertTrue(seqof.ready) + buf = BytesIO() + seqof.encode2nd(buf.write, iter(state)) + self.assertSequenceEqual( + [int(i) for i in seqof.decod(buf.getvalue())], + list(gen()), + ) + + def test_non_ready_bound_min(self): + class SeqOf(SequenceOf): + schema = Integer() + bounds = (1, float("+inf")) + seqof = SeqOf() + self.assertFalse(seqof.ready) + class TestSetOf(SeqOfMixing, CommonMixin, TestCase): class SeqOf(SetOf): @@ -7513,11 +7688,13 @@ class TestStrictDefaultExistence(TestCase): class TestX690PrefixedType(TestCase): - def runTest(self): + def test_1(self): self.assertSequenceEqual( VisibleString("Jones").encode(), hexdec("1A054A6F6E6573"), ) + + def test_2(self): self.assertSequenceEqual( VisibleString( "Jones", @@ -7525,6 +7702,8 @@ class TestX690PrefixedType(TestCase): ).encode(), hexdec("43054A6F6E6573"), ) + + def test_3(self): self.assertSequenceEqual( Any( VisibleString( @@ -7535,6 +7714,8 @@ class TestX690PrefixedType(TestCase): ).encode(), hexdec("A20743054A6F6E6573"), ) + + def test_4(self): self.assertSequenceEqual( OctetString( VisibleString( @@ -7545,6 +7726,8 @@ class TestX690PrefixedType(TestCase): ).encode(), hexdec("670743054A6F6E6573"), ) + + def test_5(self): self.assertSequenceEqual( VisibleString("Jones", impl=tag_ctxp(2)).encode(), hexdec("82054A6F6E6573"),