summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2019-06-23 19:48:31 +0200
committerGitHub <noreply@github.com>2019-06-23 19:48:31 +0200
commit66d329acaaf204eff63ae595fd7d6f56cd530c72 (patch)
tree46187ae1df17aa9eb728abc2c55ef5ce612c6764
parentb028644dea4244f1cd2513ab0241c8cb9be43324 (diff)
downloadpyasn1-git-66d329acaaf204eff63ae595fd7d6f56cd530c72.tar.gz
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.
-rw-r--r--CHANGES.rst27
-rw-r--r--pyasn1/codec/ber/decoder.py4
-rw-r--r--pyasn1/codec/ber/encoder.py25
-rw-r--r--pyasn1/type/base.py31
-rw-r--r--pyasn1/type/univ.py171
-rw-r--r--tests/codec/ber/test_encoder.py2
-rw-r--r--tests/codec/cer/test_encoder.py2
-rw-r--r--tests/type/test_univ.py170
8 files changed, 346 insertions, 86 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index dabdb33..19e7bd9 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,8 +1,31 @@
-Revision 0.4.6, released XX-01-2019
+Revision 0.4.6, released XX-06-2019
-----------------------------------
-No changes yet
+- 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`.
+- 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.
+ This change can potentially cause incompatibilities with existing
+ pyasn1 objects which assume `SequenceOf`/`SetOf` instances are value
+ objects right upon instantiation.
+ The behaviour of `Sequence`/`Set` types depends on the `componentType`
+ initializer: if on `componentType` is given, the behaviour is the
+ same as `SequenceOf`/`SetOf` have. IF `componentType` is given, but
+ neither optional nor defaulted components are present, the created
+ instance remains schema object, If, however, either optional or
+ defaulted component isi present, the created instance immediately
+ becomes a value object.
+- Added `.reset()` method to all constructed types to turn value object
+ into a schema object.
Revision 0.4.5, released 29-12-2018
-----------------------------------
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
index 591bbc4..2e4afbb 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -567,6 +567,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
return asn1Object, tail
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
@@ -682,6 +683,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
else:
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
componentType = asn1Spec.componentType
@@ -727,6 +729,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
)
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
@@ -847,6 +850,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
else:
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
componentType = asn1Spec.componentType
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index 65b8514..325ed46 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -4,6 +4,8 @@
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
+import sys
+
from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo
@@ -93,9 +95,15 @@ class AbstractItemEncoder(object):
# base tag?
if not idx:
- substrate, isConstructed, isOctets = self.encodeValue(
- value, asn1Spec, encodeFun, **options
- )
+ try:
+ substrate, isConstructed, isOctets = self.encodeValue(
+ value, asn1Spec, encodeFun, **options
+ )
+
+ except error.PyAsn1Error:
+ exc = sys.exc_info()
+ raise error.PyAsn1Error(
+ 'Error encoding %r: %s' % (value, exc[1]))
if LOG:
LOG('encoded %svalue %s into %s' % (
@@ -518,6 +526,13 @@ class SequenceEncoder(AbstractItemEncoder):
substrate = null
+ omitEmptyOptionals = options.get(
+ 'omitEmptyOptionals', self.omitEmptyOptionals)
+
+ if LOG:
+ LOG('%sencoding empty OPTIONAL components' % (
+ omitEmptyOptionals and 'not ' or ''))
+
if asn1Spec is None:
# instance of ASN.1 schema
value.verifySizeSpec()
@@ -538,7 +553,7 @@ class SequenceEncoder(AbstractItemEncoder):
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
- if self.omitEmptyOptionals:
+ if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
chunk = encodeFun(component, asn1Spec, **options)
@@ -575,7 +590,7 @@ class SequenceEncoder(AbstractItemEncoder):
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
- if self.omitEmptyOptionals:
+ if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
chunk = encodeFun(component, asn1Spec[idx], **options)
diff --git a/pyasn1/type/base.py b/pyasn1/type/base.py
index 7995118..b231482 100644
--- a/pyasn1/type/base.py
+++ b/pyasn1/type/base.py
@@ -467,8 +467,6 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
Asn1ItemBase.__init__(self, **readOnly)
- self._componentValues = []
-
def __repr__(self):
representation = '%s %s object at 0x%x' % (
self.__class__.__name__, self.isValue and 'value' or 'schema', id(self)
@@ -478,38 +476,40 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
if value is not noValue:
representation += ' %s=%r' % (attr, value)
- if self.isValue and self._componentValues:
- representation += ' payload [%s]' % ', '.join([repr(x) for x in self._componentValues])
+ if self.isValue and self.components:
+ representation += ' payload [%s]' % ', '.join(
+ [repr(x) for x in self.components])
return '<%s>' % representation
def __eq__(self, other):
- return self is other and True or self._componentValues == other
+ return self is other or self.components == other
def __ne__(self, other):
- return self._componentValues != other
+ return self.components != other
def __lt__(self, other):
- return self._componentValues < other
+ return self.components < other
def __le__(self, other):
- return self._componentValues <= other
+ return self.components <= other
def __gt__(self, other):
- return self._componentValues > other
+ return self.components > other
def __ge__(self, other):
- return self._componentValues >= other
+ return self.components >= other
if sys.version_info[0] <= 2:
def __nonzero__(self):
- return self._componentValues and True or False
+ return bool(self.components)
else:
def __bool__(self):
- return self._componentValues and True or False
+ return bool(self.components)
- def __len__(self):
- return len(self._componentValues)
+ @property
+ def components(self):
+ raise error.PyAsn1Error('Method not implemented')
def _cloneComponentValues(self, myClone, cloneValueFlag):
pass
@@ -631,9 +631,6 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
self[k] = kwargs[k]
return self
- def clear(self):
- self._componentValues = []
-
# backward compatibility
def setDefaultComponents(self):
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
index 7fab69f..4c8c8e4 100644
--- a/pyasn1/type/univ.py
+++ b/pyasn1/type/univ.py
@@ -1610,6 +1610,8 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
raise error.PyAsn1Error('Conflicting positional and keyword params!')
kwargs['componentType'] = value
+ self._componentValues = noValue
+
base.AbstractConstructedAsn1Item.__init__(self, **kwargs)
# Python list protocol
@@ -1628,24 +1630,33 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
except error.PyAsn1Error:
raise IndexError(sys.exc_info()[1])
- def clear(self):
- self._componentValues = []
-
def append(self, value):
- self[len(self)] = value
+ if self._componentValues is noValue:
+ pos = 0
+
+ else:
+ pos = len(self._componentValues)
+
+ self[pos] = value
def count(self, value):
- return self._componentValues.count(value)
+ return list(self._componentValues.values()).count(value)
def extend(self, values):
for value in values:
self.append(value)
+ if self._componentValues is noValue:
+ self._componentValues = {}
+
def index(self, value, start=0, stop=None):
if stop is None:
stop = len(self)
+
+ indices, values = zip(*self._componentValues.items())
+
try:
- return self._componentValues.index(value, start, stop)
+ return indices[values.index(value, start, stop)]
except error.PyAsn1Error:
raise ValueError(sys.exc_info()[1])
@@ -1654,13 +1665,22 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
self._componentValues.reverse()
def sort(self, key=None, reverse=False):
- self._componentValues.sort(key=key, reverse=reverse)
+ self._componentValues = dict(
+ enumerate(sorted(self._componentValues.values(),
+ key=key, reverse=reverse)))
+
+ def __len__(self):
+ if not self._componentValues:
+ return 0
+
+ return max(self._componentValues) + 1
def __iter__(self):
- return iter(self._componentValues)
+ for idx in range(0, len(self)):
+ yield self.getComponentByPosition(idx)
def _cloneComponentValues(self, myClone, cloneValueFlag):
- for idx, componentValue in enumerate(self._componentValues):
+ for idx, componentValue in self._componentValues.items():
if componentValue is not noValue:
if isinstance(componentValue, base.AbstractConstructedAsn1Item):
myClone.setComponentByPosition(
@@ -1738,7 +1758,7 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
try:
componentValue = self._componentValues[idx]
- except IndexError:
+ except (KeyError, error.PyAsn1Error):
if not instantiate:
return default
@@ -1792,35 +1812,55 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
IndexError:
When idx > len(self)
"""
+ if idx < 0:
+ raise error.PyAsn1Error(
+ 'SequenceOf/SetOf index must not be negative')
+
componentType = self.componentType
- try:
- currentValue = self._componentValues[idx]
- except IndexError:
- currentValue = noValue
+ if self._componentValues is noValue:
+ componentValues = {}
- if len(self._componentValues) < idx:
- raise error.PyAsn1Error('Component index out of range')
+ else:
+ componentValues = self._componentValues
+
+ currentValue = componentValues.get(idx, noValue)
if value is noValue:
if componentType is not None:
value = componentType.clone()
+
elif currentValue is noValue:
raise error.PyAsn1Error('Component type not defined')
+
elif not isinstance(value, base.Asn1Item):
- if componentType is not None and isinstance(componentType, base.AbstractSimpleAsn1Item):
+ if (componentType is not None and
+ isinstance(componentType, base.AbstractSimpleAsn1Item)):
value = componentType.clone(value=value)
- elif currentValue is not noValue and isinstance(currentValue, base.AbstractSimpleAsn1Item):
+
+ elif (currentValue is not noValue and
+ isinstance(currentValue, base.AbstractSimpleAsn1Item)):
value = currentValue.clone(value=value)
+
else:
- raise error.PyAsn1Error('Non-ASN.1 value %r and undefined component type at %r' % (value, self))
+ raise error.PyAsn1Error(
+ 'Non-ASN.1 value %r and undefined component'
+ ' type at %r' % (value, self))
+
elif componentType is not None:
if self.strictConstraints:
- if not componentType.isSameTypeWith(value, matchTags, matchConstraints):
- raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
+ if not componentType.isSameTypeWith(
+ value, matchTags, matchConstraints):
+ raise error.PyAsn1Error(
+ 'Component value is tag-incompatible: %r '
+ 'vs %r' % (value, componentType))
+
else:
- if not componentType.isSuperTypeOf(value, matchTags, matchConstraints):
- raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType))
+ if not componentType.isSuperTypeOf(
+ value, matchTags, matchConstraints):
+ raise error.PyAsn1Error(
+ 'Component value is tag-incompatible: '
+ '%r vs %r' % (value, componentType))
if verifyConstraints and value.isValue:
try:
@@ -1830,10 +1870,9 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
exType, exValue, exTb = sys.exc_info()
raise exType('%s at %s' % (exValue, self.__class__.__name__))
- if currentValue is noValue:
- self._componentValues.append(value)
- else:
- self._componentValues[idx] = value
+ componentValues[idx] = value
+
+ self._componentValues = componentValues
return self
@@ -1842,16 +1881,34 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
if self.componentType is not None:
return self.componentType.tagMap
+ @property
+ def components(self):
+ return [self._componentValues[idx]
+ for idx in sorted(self._componentValues)]
+
+ def clear(self):
+ self._componentValues = {}
+ return self
+
+ def reset(self):
+ self._componentValues = noValue
+ return self
+
def prettyPrint(self, scope=0):
scope += 1
representation = self.__class__.__name__ + ':\n'
- for idx, componentValue in enumerate(self._componentValues):
+
+ if not self.isValue:
+ return representation
+
+ for idx, componentValue in enumerate(self):
representation += ' ' * scope
if (componentValue is noValue and
self.componentType is not None):
representation += '<empty>'
else:
representation += componentValue.prettyPrint(scope)
+
return representation
def prettyPrintType(self, scope=0):
@@ -1890,7 +1947,13 @@ class SequenceOfAndSetOfBase(base.AbstractConstructedAsn1Item):
The PyASN1 value objects can **additionally** participate in many operations
involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
- for componentValue in self._componentValues:
+ if self._componentValues is noValue:
+ return False
+
+ if len(self._componentValues) != len(self):
+ return False
+
+ for componentValue in self._componentValues.values():
if componentValue is noValue or not componentValue.isValue:
return False
@@ -2044,6 +2107,10 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
def __init__(self, **kwargs):
base.AbstractConstructedAsn1Item.__init__(self, **kwargs)
self._componentTypeLen = len(self.componentType)
+ if self._componentTypeLen:
+ self._componentValues = []
+ else:
+ self._componentValues = noValue
self._dynamicNames = self._componentTypeLen or self.DynamicNames()
def __getitem__(self, idx):
@@ -2086,6 +2153,9 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
else:
return key in self._dynamicNames
+ def __len__(self):
+ return len(self._componentValues)
+
def __iter__(self):
return iter(self.componentType or self._dynamicNames)
@@ -2114,8 +2184,21 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
def clear(self):
self._componentValues = []
self._dynamicNames = self.DynamicNames()
+ return self
+
+ def reset(self):
+ self._componentValues = noValue
+ self._dynamicNames = self.DynamicNames()
+ return self
+
+ @property
+ def components(self):
+ return self._componentValues
def _cloneComponentValues(self, myClone, cloneValueFlag):
+ if self._componentValues is noValue:
+ return
+
for idx, componentValue in enumerate(self._componentValues):
if componentValue is not noValue:
if isinstance(componentValue, base.AbstractConstructedAsn1Item):
@@ -2275,7 +2358,11 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
s.getComponentByPosition(0, instantiate=False)
"""
try:
- componentValue = self._componentValues[idx]
+ if self._componentValues is noValue:
+ componentValue = noValue
+
+ else:
+ componentValue = self._componentValues[idx]
except IndexError:
componentValue = noValue
@@ -2334,8 +2421,14 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
componentType = self.componentType
componentTypeLen = self._componentTypeLen
+ if self._componentValues is noValue:
+ componentValues = []
+
+ else:
+ componentValues = self._componentValues
+
try:
- currentValue = self._componentValues[idx]
+ currentValue = componentValues[idx]
except IndexError:
currentValue = noValue
@@ -2343,7 +2436,7 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
if componentTypeLen < idx:
raise error.PyAsn1Error('component index out of range')
- self._componentValues = [noValue] * componentTypeLen
+ componentValues = [noValue] * componentTypeLen
if value is noValue:
if componentTypeLen:
@@ -2389,15 +2482,17 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
raise exType('%s at %s' % (exValue, self.__class__.__name__))
if componentTypeLen or idx in self._dynamicNames:
- self._componentValues[idx] = value
+ componentValues[idx] = value
- elif len(self._componentValues) == idx:
- self._componentValues.append(value)
+ elif len(componentValues) == idx:
+ componentValues.append(value)
self._dynamicNames.addField(idx)
else:
raise error.PyAsn1Error('Component index out of range')
+ self._componentValues = componentValues
+
return self
@property
@@ -2427,6 +2522,9 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
The PyASN1 value objects can **additionally** participate in many operations
involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
+ if self._componentValues is noValue:
+ return False
+
componentType = self.componentType
if componentType:
@@ -2497,7 +2595,6 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
if self._componentTypeLen:
return self.componentType[idx].name
-
class Sequence(SequenceAndSetBase):
__doc__ = SequenceAndSetBase.__doc__
@@ -2959,7 +3056,7 @@ class Choice(Set):
def clear(self):
self._currentIdx = None
- Set.clear(self)
+ return Set.clear(self)
# compatibility stubs
diff --git a/tests/codec/ber/test_encoder.py b/tests/codec/ber/test_encoder.py
index 26819bd..da14830 100644
--- a/tests/codec/ber/test_encoder.py
+++ b/tests/codec/ber/test_encoder.py
@@ -476,6 +476,7 @@ class UTF8StringEncoderWithSchemaTestCase(BaseTestCase):
class SequenceOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SequenceOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((48, 0))
def testDefMode(self):
@@ -570,6 +571,7 @@ class SequenceOfEncoderWithComponentsSchemaTestCase(BaseTestCase):
class SetOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SetOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((49, 0))
def testDefMode(self):
diff --git a/tests/codec/cer/test_encoder.py b/tests/codec/cer/test_encoder.py
index d9d9212..ea8f813 100644
--- a/tests/codec/cer/test_encoder.py
+++ b/tests/codec/cer/test_encoder.py
@@ -155,6 +155,7 @@ class UTCTimeEncoderTestCase(BaseTestCase):
class SequenceOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SequenceOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((48, 128, 0, 0))
def testDefMode1(self):
@@ -219,6 +220,7 @@ class SequenceOfEncoderWithSchemaTestCase(BaseTestCase):
class SetOfEncoderTestCase(BaseTestCase):
def testEmpty(self):
s = univ.SetOf()
+ s.clear()
assert encoder.encode(s) == ints2octs((49, 128, 0, 0))
def testDefMode1(self):
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):