From 66d329acaaf204eff63ae595fd7d6f56cd530c72 Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Sun, 23 Jun 2019 19:48:31 +0200 Subject: SequenceOf/SetOf to remain a schema objects (#162) * Add `omitEmptyOptionals` encoder option Added `omitEmptyOptionals` option which is respected by `Sequence` and `Set` encoders. When `omitEmptyOptionals` is set to `True`, empty initialized optional components are not encoded. Default is `False`. * Change `SequenceOf`/`SetOf` behaviour - New elements to `SequenceOf`/`SetOf` objects can now be added at any position - the requirement for the new elements to reside at the end of the existing ones (i.e. s[len(s)] = 123) is removed. - Removed default initializer from `SequenceOf`/`SetOf` types to ensure consistent behaviour with the rest of ASN.1 types. Before this change, `SequenceOf`/`SetOf` instances immediately become value objects behaving like an empty list. With this change, `SequenceOf`/`SetOf` objects remain schema objects unless a component is added or `.clear()` is called. - Added `.reset()` method to all constructed types to turn value object into a schema object. --- tests/type/test_univ.py | 170 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 145 insertions(+), 25 deletions(-) (limited to 'tests/type/test_univ.py') diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py index a44f82a..3cd125b 100644 --- a/tests/type/test_univ.py +++ b/tests/type/test_univ.py @@ -1027,21 +1027,25 @@ class SequenceOf(BaseTestCase): } def testSubtype(self): - self.s1.clear() - assert self.s1.subtype( + subtype = self.s1.subtype( implicitTag=tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 2), subtypeSpec=constraint.SingleValueConstraint(1, 3), sizeSpec=constraint.ValueSizeConstraint(0, 1) - ) == self.s1.clone( + ) + subtype.clear() + clone = self.s1.clone( tagSet=tag.TagSet(tag.Tag(tag.tagClassPrivate, tag.tagFormatSimple, 2)), subtypeSpec=constraint.ConstraintsIntersection(constraint.SingleValueConstraint(1, 3)), sizeSpec=constraint.ValueSizeConstraint(0, 1) ) + clone.clear() + assert clone == subtype def testClone(self): self.s1.setComponentByPosition(0, univ.OctetString('abc')) s = self.s1.clone() + s.clear() assert len(s) == 0 s = self.s1.clone(cloneValueFlag=1) assert len(s) == 1 @@ -1056,31 +1060,15 @@ class SequenceOf(BaseTestCase): s.append('xxx') assert s[0] - try: - s[2] - - except IndexError: - pass - - else: - assert False, 'IndexError not raised' - # this is a deviation from standard sequence protocol - assert not s[1] + assert not s[2] def testSetItem(self): s = self.s1.clone() s.append('xxx') - - try: - - s[2] = 'xxx' - - except IndexError: - pass - - else: - assert False, 'IndexError not raised' + s[2] = 'yyy' + assert len(s) == 3 + assert s[1] == str2octs('') def testAppend(self): self.s1.clear() @@ -1132,6 +1120,15 @@ class SequenceOf(BaseTestCase): assert len(s) == 1 assert s == [str2octs('abc')] + def testUntyped(self): + n = univ.SequenceOf() + + assert not n.isValue + + n[0] = univ.OctetString('fox') + + assert n.isValue + def testLegacyInitializer(self): n = univ.SequenceOf( componentType=univ.OctetString() @@ -1174,6 +1171,39 @@ class SequenceOf(BaseTestCase): s.clear() assert s.getComponentByPosition(0, instantiate=False) is univ.noValue + def testClear(self): + + class SequenceOf(univ.SequenceOf): + componentType = univ.OctetString() + + s = SequenceOf() + s.setComponentByPosition(0, 'test') + + assert s.getComponentByPosition(0) == str2octs('test') + assert len(s) == 1 + assert s.isValue + + s.clear() + + assert len(s) == 0 + assert s == [] + assert s.isValue + + def testReset(self): + + class SequenceOf(univ.SequenceOf): + componentType = univ.OctetString() + + s = SequenceOf() + s.setComponentByPosition(0, 'test') + + assert s.getComponentByPosition(0) == str2octs('test') + assert s.isValue + + s.reset() + + assert not s.isValue + class SequenceOfPicklingTestCase(unittest.TestCase): @@ -1441,6 +1471,75 @@ class Sequence(BaseTestCase): s.clear() assert s.getComponentByPosition(1, instantiate=False) is univ.noValue + def testSchemaWithComponents(self): + + class Sequence(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('name', univ.OctetString()) + ) + + s = Sequence() + + assert not s.isValue + + s[0] = 'test' + + assert s.isValue + + s.clear() + + assert not s.isValue + + s.reset() + + assert not s.isValue + + def testSchemaWithOptionalComponents(self): + + class Sequence(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('name', univ.OctetString()) + ) + + s = Sequence() + + assert s.isValue + + s[0] = 'test' + + assert s.isValue + + s.clear() + + assert s.isValue + + s.reset() + + assert not s.isValue + + def testSchemaWithOptionalComponents(self): + + class Sequence(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.DefaultedNamedType('name', univ.OctetString('')) + ) + + s = Sequence() + + assert s.isValue + + s[0] = 'test' + + assert s.isValue + + s.clear() + + assert s.isValue + + s.reset() + + assert not s.isValue + class SequenceWithoutSchema(BaseTestCase): @@ -1500,7 +1599,7 @@ class SequenceWithoutSchema(BaseTestCase): assert list(s.items()) == [('field-0', str2octs('abc')), ('field-1', 123)] def testUpdate(self): - s = univ.Sequence() + s = univ.Sequence().clear() assert not s s.setComponentByPosition(0, univ.OctetString('abc')) s.setComponentByPosition(1, univ.Integer(123)) @@ -1522,6 +1621,27 @@ class SequenceWithoutSchema(BaseTestCase): s.clear() assert 'field-0' not in s + def testSchema(self): + + class Sequence(univ.Sequence): + pass + + s = Sequence() + + assert not s.isValue + + s[0] = univ.OctetString('test') + + assert s.isValue + + s.clear() + + assert s.isValue + + s.reset() + + assert not s.isValue + class SequencePicklingTestCase(unittest.TestCase): @@ -1633,7 +1753,7 @@ class Set(BaseTestCase): def testGetTagMap(self): assert self.s1.tagMap.presentTypes == { - univ.Set.tagSet: univ.Set() + univ.Set.tagSet: univ.Set().clear() } def testGetComponentTagMap(self): -- cgit v1.2.3 From 4a9abf7ae867e9ebabc850320d87a7c1230acfad Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Sat, 29 Jun 2019 08:50:35 +0200 Subject: Rename pyasn1 unicode exceptions The new exception classes names are `PyAsn1UnicodeDecodeError` and `PyAsn1UnicodeEncodeError`. Also, unit tests added. --- tests/type/test_univ.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'tests/type/test_univ.py') diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py index 3cd125b..169b73e 100644 --- a/tests/type/test_univ.py +++ b/tests/type/test_univ.py @@ -22,8 +22,9 @@ from pyasn1.type import constraint from pyasn1.type import namedtype from pyasn1.type import namedval from pyasn1.type import error -from pyasn1.compat.octets import str2octs, ints2octs, octs2ints +from pyasn1.compat.octets import str2octs, ints2octs, octs2ints, octs2str from pyasn1.error import PyAsn1Error +from pyasn1.error import PyAsn1UnicodeEncodeError, PyAsn1UnicodeDecodeError class NoValueTestCase(BaseTestCase): @@ -543,6 +544,32 @@ class OctetStringWithAsciiTestCase(OctetStringWithUnicodeMixIn, BaseTestCase): encoding = 'us-ascii' +class OctetStringUnicodeErrorTestCase(BaseTestCase): + def testEncodeError(self): + text = octs2str(ints2octs((0xff, 0xfe))) + + try: + univ.OctetString(text, encoding='us-ascii') + + except PyAsn1UnicodeEncodeError: + pass + + else: + assert False, 'Unicode encoding error not caught' + + def testDecodeError(self): + serialized = ints2octs((0xff, 0xfe)) + + try: + str(univ.OctetString(serialized, encoding='us-ascii')) + + except PyAsn1UnicodeDecodeError: + pass + + else: + assert False, 'Unicode decoding error not caught' + + class OctetStringWithUtf8TestCase(OctetStringWithUnicodeMixIn, BaseTestCase): initializer = (208, 176, 208, 177, 208, 178) encoding = 'utf-8' -- cgit v1.2.3 From 7b3f79cac2ce765537baa406762d59eae47de04c Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Fri, 12 Jul 2019 22:31:41 +0200 Subject: Add `SequenceOf`/`SetOf` list-like slicing support (#168) --- tests/type/test_univ.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests/type/test_univ.py') diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py index 169b73e..de7cdee 100644 --- a/tests/type/test_univ.py +++ b/tests/type/test_univ.py @@ -1090,6 +1090,13 @@ class SequenceOf(BaseTestCase): # this is a deviation from standard sequence protocol assert not s[2] + def testGetItemSlice(self): + s = self.s1.clone() + s.extend(['xxx', 'yyy', 'zzz']) + assert s[:1] == [str2octs('xxx')] + assert s[-2:] == [str2octs('yyy'), str2octs('zzz')] + assert s[1:2] == [str2octs('yyy')] + def testSetItem(self): s = self.s1.clone() s.append('xxx') @@ -1097,6 +1104,16 @@ class SequenceOf(BaseTestCase): assert len(s) == 3 assert s[1] == str2octs('') + def testSetItemSlice(self): + s = self.s1.clone() + s[:1] = ['xxx'] + assert s == [str2octs('xxx')] + s[-2:] = ['yyy', 'zzz'] + assert s == [str2octs('yyy'), str2octs('zzz')] + s[1:2] = ['yyy'] + assert s == [str2octs('yyy'), str2octs('yyy')] + assert len(s) == 2 + def testAppend(self): self.s1.clear() self.s1.setComponentByPosition(0, univ.OctetString('abc')) -- cgit v1.2.3 From fb824beb47f0e58463bb9a4b4b50bd804f30b9f2 Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Wed, 31 Jul 2019 21:40:15 +0200 Subject: Fix failing unit tests on Py25 --- tests/type/test_univ.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'tests/type/test_univ.py') diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py index de7cdee..0092588 100644 --- a/tests/type/test_univ.py +++ b/tests/type/test_univ.py @@ -150,13 +150,18 @@ class NoValueTestCase(BaseTestCase): try: if hasattr(sys, 'getsizeof'): sys.getsizeof(univ.noValue) - else: + + # TODO: remove when Py2.5 support is gone + elif sys.version_info > (2, 6): raise unittest.SkipTest("no sys.getsizeof() method") except PyAsn1Error: assert False, 'sizeof failed for NoValue object' + except TypeError: - raise unittest.SkipTest("sys.getsizeof() raises TypeError") + # TODO: remove when Py2.5 support is gone + if sys.version_info > (2, 6): + raise unittest.SkipTest("sys.getsizeof() raises TypeError") class IntegerTestCase(BaseTestCase): @@ -554,8 +559,10 @@ class OctetStringUnicodeErrorTestCase(BaseTestCase): except PyAsn1UnicodeEncodeError: pass + # TODO: remove when Py2.5 support is gone else: - assert False, 'Unicode encoding error not caught' + if sys.version_info > (2, 6): + assert False, 'Unicode encoding error not caught' def testDecodeError(self): serialized = ints2octs((0xff, 0xfe)) @@ -566,8 +573,10 @@ class OctetStringUnicodeErrorTestCase(BaseTestCase): except PyAsn1UnicodeDecodeError: pass + # TODO: remove when Py2.5 support is gone else: - assert False, 'Unicode decoding error not caught' + if sys.version_info > (2, 6): + assert False, 'Unicode decoding error not caught' class OctetStringWithUtf8TestCase(OctetStringWithUnicodeMixIn, BaseTestCase): -- cgit v1.2.3