From f25c8bdc4e7bfbf1c211f8ce439c50e34bf109f2 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Sat, 16 Nov 2024 14:43:26 +0000 Subject: [PATCH 1/2] Improve processing of DEFVAL values This commit aims to define clearly which combinations of DEFVAL value types and underlying syntax types are supported, and to implement support for those cases. Various bugs in the previous code are resolved as well. The overall result is that the generated Python code provides proper default values for object types in more cases than before, and that it no longer assigns values that are not used or usable by pyasn1. Concretely, the following DEFVAL-related bugfixes are applied: - Empty quoted strings are no longer discarded; - Decimal values are no longer assigned to string-type and OID-type objects, which used to lead to corrupted default values; - Integer values with hex/binary notation are no longer assigned incorrectly, previously resulting in them being discarded; - For strings, binary notation no longer discards leading zero octets; - Leading zeroes are added to hex/binary notation values with invalid lengths, which often used to result in unintended default values; - Numeric values for enumerated integers that fall outside of the permitted enumeration values are now discarded; - Code generation no longer produces extra unnecessary _Xyz_Type type classes without contents. In addition, the code is changed so that it no longer fails compiling MIBs for any case in which a DEFVAL value can be parsed but not processed. The result is that fewer MIBs fail compilation altogether. As part of this commit, the functions that process default values are restructured, primarily to filter by the syntax base type first and only then by the input type, rather than the other way around. That change opens up the possibility of applying additional checks to the default values in a central place, as will be done in a follow-up commit. The code is cleaned up somewhat as well. The intermediate code no longer uses the same gen_def_val() method for two different purposes. The template code now has fewer cases handling default values. Unused DEFVAL code is removed from the symtable code. A few Python2 remnants are cleaned up as well. The test set is extended with many more DEFVAL test cases. As part of that, all the DEFVAL-specific tests are moved to a new module, as their original location was getting too large. This commit slightly alters the JSON output format. --- pysmi/codegen/base.py | 4 +- pysmi/codegen/intermediate.py | 244 +-- pysmi/codegen/symtable.py | 34 +- .../templates/pysnmp/mib-definitions.j2 | 14 +- tests/__main__.py | 1 + tests/test_defval_smiv2_pysnmp.py | 1358 +++++++++++++++++ tests/test_objecttype_smiv2_pysnmp.py | 436 ------ 7 files changed, 1510 insertions(+), 581 deletions(-) create mode 100644 tests/test_defval_smiv2_pysnmp.py diff --git a/pysmi/codegen/base.py b/pysmi/codegen/base.py index 827f8b0..41f1a90 100644 --- a/pysmi/codegen/base.py +++ b/pysmi/codegen/base.py @@ -293,11 +293,11 @@ def gen_index(self, mibsMap, **kwargs): @staticmethod def is_binary(s): - return isinstance(s, str) and s[0] == "'" and s[-2:] in ("'b", "'B") + return isinstance(s, str) and s and s[0] == "'" and s[-2:] in ("'b", "'B") @staticmethod def is_hex(s): - return isinstance(s, str) and s[0] == "'" and s[-2:] in ("'h", "'H") + return isinstance(s, str) and s and s[0] == "'" and s[-2:] in ("'h", "'H") def str2int(self, s): if self.is_binary(s): diff --git a/pysmi/codegen/intermediate.py b/pysmi/codegen/intermediate.py index 4fdc30b..9318af8 100644 --- a/pysmi/codegen/intermediate.py +++ b/pysmi/codegen/intermediate.py @@ -13,10 +13,6 @@ from pysmi.codegen.base import AbstractCodeGen from pysmi.mibinfo import MibInfo -if sys.version_info[0] > 2: - unicode = str - long = int - class IntermediateCodeGen(AbstractCodeGen): """Turns MIB AST into an intermediate representation. @@ -486,7 +482,7 @@ def gen_object_type(self, data): oidStr, parentOid = oid indexStr, fakeSyms, fakeSymDicts = index or ("", [], []) - defval = self.gen_def_val(defval, objname=pysmiName) + defval = self.process_defval(defval, objname=pysmiName) outDict = OrderedDict() outDict["name"] = name @@ -671,121 +667,171 @@ def gen_contact_info(self, data): def gen_display_hint(self, data): return data[0] - # noinspection PyUnusedLocal - def gen_def_val(self, data, objname=None): - if not data: - return {} + # noinspection PyMethodMayBeStatic,PyUnusedLocal + def gen_def_val(self, data): + return data[0] - if not objname: - return data + def _process_integer_defval(self, defval, defvalType): + """Process a DEFVAL value for an integer/enumeration type.""" + if isinstance(defval, int): # decimal + value = defval - defval = data[0] - defvalType = self.get_base_type(objname, self.moduleName[0]) + elif self.is_hex(defval): # hex + value = int(defval[1:-2] or "0", 16) + + elif self.is_binary(defval): # binary + value = int(defval[1:-2] or "0", 2) + + elif isinstance(defvalType[1], list): # enumeration label + # For enumerations, the ASN.1 DEFVAL statements contain names, + # whereas the code generation template expects integer values + # (represented as strings). + nameToValueMap = dict(defvalType[1]) - outDict = OrderedDict(basetype=defvalType[0][0]) + # buggy MIB: DEFVAL { { ... } } + if isinstance(defval, list): + defval = [dv for dv in defval if dv in nameToValueMap] + if defval: + defval = defval[0] + # (fall through) - if isinstance(defval, (int, long)): # number - outDict.update(value=defval, format="decimal") + # good MIB: DEFVAL { ... } + if defval not in nameToValueMap: + raise ValueError("unknown enumeration label") + + # Return early so as to skip the enumeration value check below. + # After all, we already know the resulting number is valid. + return str(nameToValueMap[defval]), "decimal" + + else: + raise ValueError("wrong input type for integer") + + if isinstance(defvalType[1], list): # enumeration number + # For numerical values given for enumerated integers, make sure + # that they are valid, because pyasn1 will not check this case and + # thus let us set a default value that is not valid for the type. + if value not in {num for name, num in defvalType[1]}: + raise ValueError("wrong enumeration value") + + return str(value), "decimal" + + def _process_string_defval(self, defval, defvalType): + """Process a DEFVAL value for a string type (including BITS).""" + defvalBaseType = defvalType[0][0] # either "OctetString" or "Bits" + + if isinstance(defval, int): # decimal + if defvalBaseType != "Bits": + raise ValueError("decimal values have no meaning for OCTET STRING") + + # Convert the value to a hex string. Add padding if needed. + value = defval and hex(defval)[2:] or "" + value = ("0" + value) if len(value) % 2 == 1 else value + + fmt = "hex" elif self.is_hex(defval): # hex - # common bug in MIBs - if defvalType[0][0] in ("Integer32", "Integer"): - outDict.update( - value=str(int(len(defval) > 3 and defval[1:-2] or "0", 16)), - format="hex", - ) + # Extract the value as hex string. Add padding if needed. + value = defval[1:-2] + value = ("0" + value) if len(value) % 2 == 1 else value - else: - outDict.update(value=defval[1:-2], format="hex") + fmt = "hex" elif self.is_binary(defval): # binary binval = defval[1:-2] - # common bug in MIBs - if defvalType[0][0] in ("Integer32", "Integer"): - outDict.update(value=str(int(binval or "0", 2)), format="bin") + # Make sure not to lose any leading zeroes. Add padding if needed. + width = ((len(binval) + 7) // 8) * 2 + value = width and "{:0{width}x}".format(int(binval, 2), width=width) or "" + fmt = "hex" - else: - hexval = binval and hex(int(binval, 2))[2:] or "" - outDict.update(value=hexval, format="hex") + elif defval and defval[0] == '"' and defval[-1] == '"': # quoted string + if defvalBaseType != "OctetString": + raise ValueError("quoted strings have no meaning for BITS") + + value = defval[1:-1] + fmt = "string" + + elif defvalBaseType == "Bits" and isinstance(defval, list): # bit labels + defvalBits = [] + + bits = dict(defvalType[1]) - # quoted string - elif defval and defval[0] == defval[-1] and defval[0] == '"': - # common bug in MIBs - if defval[1:-1] == "" and defvalType != "OctetString": - # a warning should be here - return {} # we will set no default value + for bit in defval: + bitValue = bits.get(bit, None) + if bitValue is not None: + defvalBits.append((bit, bitValue)) + else: + raise ValueError("unknown bit") - outDict.update(value=defval[1:-1], format="string") + return self.gen_bits([defvalBits])[1], "bits" - # symbol (oid as defval) or name for enumeration member else: - # oid - if defvalType[0][0] == "ObjectIdentifier" and ( - self.trans_opers(defval) in self.symbolTable[self.moduleName[0]] - or self.trans_opers(defval) in self._importMap - ): - pysmiDefval = self.trans_opers(defval) - module = self._importMap.get(pysmiDefval, self.moduleName[0]) - - try: - val = str( - self.gen_numeric_oid( - self.symbolTable[module][pysmiDefval]["oid"] - ) - ) + raise ValueError("wrong input type for string") - outDict.update(value=val, format="oid") + return value, fmt - except Exception: - # or no module if it will be borrowed later - raise error.PySmiSemanticError( - f'no symbol "{defval}" in module "{module}"' - ) + def _process_oid_defval(self, defval, defvalType): + """Process a DEFVAL value for an object identifier.""" + if isinstance(defval, str) and ( + self.trans_opers(defval) in self.symbolTable[self.moduleName[0]] + or self.trans_opers(defval) in self._importMap + ): + pysmiDefval = self.trans_opers(defval) + module = self._importMap.get(pysmiDefval, self.moduleName[0]) - # enumeration - elif defvalType[0][0] in ("Integer32", "Integer") and isinstance( - defvalType[1], list - ): - # For enumerations, the ASN.1 DEFVAL statements contain names, - # whereas the code generation template expects integer values - # (represented as strings). - nameToValueMap = dict(defvalType[1]) - - # buggy MIB: DEFVAL { { ... } } - if isinstance(defval, list): - defval = [dv for dv in defval if dv in nameToValueMap] - if defval: - outDict.update( - value=str(nameToValueMap[defval[0]]), format="enum" - ) - - # good MIB: DEFVAL { ... } - elif defval in nameToValueMap: - outDict.update(value=str(nameToValueMap[defval]), format="enum") - - elif defvalType[0][0] == "Bits": - defvalBits = [] - - bits = dict(defvalType[1]) - - for bit in defval: - bitValue = bits.get(bit, None) - if bitValue is not None: - defvalBits.append((bit, bitValue)) + value = self.gen_numeric_oid(self.symbolTable[module][pysmiDefval]["oid"]) - else: - raise error.PySmiSemanticError( - f'no such bit as "{bit}" for symbol "{objname}"' - ) + return str(value), "oid" - outDict.update(value=self.gen_bits([defvalBits])[1], format="bits") + else: + raise ValueError("wrong input type for object identifier") - else: - raise error.PySmiSemanticError( - f'unknown type "{defvalType}" for defval "{defval}" of symbol "{objname}"' - ) + def process_defval(self, defval, objname): + if defval is None: + return {} + + defvalType = self.get_base_type(objname, self.moduleName[0]) + defvalBaseType = defvalType[0][0] + + # Our general policy is that DEFVAL values are considered discardable: + # any values that were accepted by the parser but turn out to be + # invalid, are dropped here, so that they will not keep the MIB from + # being compiled or loaded. The underlying idea is that DEFVAL values + # are not all that important, and therefore better discarded than the + # cause of a MIB loading failure. + # + # For each combination of input value and object type, the following + # table shows whether the combination is: + # - required to be supported by RFC 2578; + # - accepted out of lenience by our implementation; or, + # - discarded for being no meaningful combination. + # Note that enumerations are also Integer32/Integer types, but handled + # slightly differently, so they are a separate column in this table. + # + # Input Integer Enumeration OctetString ObjectId. Bits + # ------------- ----------- ----------- ----------- ----------- --------- + # decimal required accepted discarded discarded accepted + # hex accepted accepted required discarded accepted + # binary accepted accepted required discarded accepted + # quoted string discarded discarded required discarded discarded + # symbol/label discarded required discarded required discarded + # brackets discarded accepted discarded discarded required + + try: + if defvalBaseType in ("Integer32", "Integer"): + value, fmt = self._process_integer_defval(defval, defvalType) + elif defvalBaseType in ("OctetString", "Bits"): + value, fmt = self._process_string_defval(defval, defvalType) + elif defvalBaseType == "ObjectIdentifier": + value, fmt = self._process_oid_defval(defval, defvalType) + else: # pragma: no cover + raise ValueError("unknown base type") + + except ValueError: + # Discard the given default value. + return {} + outDict = OrderedDict(basetype=defvalBaseType, value=value, format=fmt) return {"default": outDict} # noinspection PyMethodMayBeStatic @@ -903,11 +949,11 @@ def gen_oid(self, data): out = () parent = "" for el in data[0]: - if isinstance(el, (str, unicode)): + if isinstance(el, str): parent = self.trans_opers(el) out += ((parent, self._importMap.get(parent, self.moduleName[0])),) - elif isinstance(el, (int, long)): + elif isinstance(el, int): out += (el,) elif isinstance(el, tuple): diff --git a/pysmi/codegen/symtable.py b/pysmi/codegen/symtable.py index 5223b0d..c74ce1f 100644 --- a/pysmi/codegen/symtable.py +++ b/pysmi/codegen/symtable.py @@ -312,9 +312,6 @@ def gen_object_type(self, data, classmode=False): if augmention: parents.append(self.trans_opers(augmention)) - if defval: # XXX - symProps["defval"] = defval - if index and index[1]: namepart, fakeIndexes, fakeSymSyntax = index for fakeIdx, fakeSyntax in zip(fakeIndexes, fakeSymSyntax): @@ -406,34 +403,9 @@ def gen_contact_info(self, data, classmode=False): def gen_display_hint(self, data, classmode=False): return "" - # noinspection PyUnusedLocal - def gen_def_val(self, data, classmode=False): # XXX should be fixed, see pysnmp.py - defval = data[0] - - if isinstance(defval, int): # number - val = str(defval) - - elif self.is_hex(defval): # hex - val = 'hexValue="' + defval[1:-2] + '"' # not working for Integer baseTypes - - elif self.is_binary(defval): # binary - binval = defval[1:-2] - hexval = binval and hex(int(binval, 2))[2:] or "" - val = 'hexValue="' + hexval + '"' - - elif isinstance(defval, list): # bits list - val = defval - - elif defval and defval[0] == defval[-1] and defval[0] == '"': # quoted string - val = dorepr(defval[1:-1]) - - else: # symbol (oid as defval) or name for enumeration member - if defval in self._out or defval in self._importMap: - val = defval + ".getName()" - else: - val = dorepr(defval) - - return val + # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic + def gen_def_val(self, data, classmode=False): + return "" # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def gen_description(self, data, classmode=False): diff --git a/pysmi/codegen/templates/pysnmp/mib-definitions.j2 b/pysmi/codegen/templates/pysnmp/mib-definitions.j2 index ff1d348..0a7c729 100644 --- a/pysmi/codegen/templates/pysnmp/mib-definitions.j2 +++ b/pysmi/codegen/templates/pysnmp/mib-definitions.j2 @@ -177,23 +177,11 @@ if mibBuilder.loadTexts: {% if definition['default']['default']['format'] == 'decimal' %} defaultValue = {{ definition['default']['default']['value'] }} {% elif definition['default']['default']['format'] == 'hex' %} - {# TODO: pyasn1 Integer does not have defaultHexValue #} - {% if definition['default']['default']['basetype'] in ('Integer', 'Integer32') %} - defaultHexValue = {{ definition['default']['default']['value'] }} - {% else %} defaultHexValue = "{{ definition['default']['default']['value'] }}" - {% endif %} - {# TODO: pyasn1 Integer does not have defaultBinValue #} - {% elif definition['default']['default']['format'] == 'bin' %} - {% if definition['default']['default']['basetype'] in ('Integer', 'Integer32') %} - defaultBinValue = {{ definition['default']['default']['value'] }} - {% else %} - defaultBinValue = "{{ definition['default']['default']['value'] }}" - {% endif %} {% elif definition['default']['default']['format'] == 'string' %} {# TODO: pyasn1 does not like defaulted strings #} defaultValue = OctetString({{ definition['default']['default']['value']|pythonstr }}) - {% elif definition['default']['default']['format'] in ('oid', 'enum') %} + {% elif definition['default']['default']['format'] == 'oid' %} defaultValue = {{ definition['default']['default']['value'] }} {% elif definition['default']['default']['format'] == 'bits' %} {# TODO: pyasn1 does not like default named bits #} diff --git a/tests/__main__.py b/tests/__main__.py index 1574b5b..fce7baf 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -14,6 +14,7 @@ [ "test_zipreader", "test_agentcapabilities_smiv2_pysnmp", + "test_defval_smiv2_pysnmp", "test_imports_smiv2_pysnmp", "test_modulecompliance_smiv2_pysnmp", "test_moduleidentity_smiv2_pysnmp", diff --git a/tests/test_defval_smiv2_pysnmp.py b/tests/test_defval_smiv2_pysnmp.py new file mode 100644 index 0000000..80d72a2 --- /dev/null +++ b/tests/test_defval_smiv2_pysnmp.py @@ -0,0 +1,1358 @@ +# +# This file is part of pysmi software. +# +# Copyright (c) 2015-2020, Ilya Etingof; Copyright (c) 2022-2024, others +# License: https://www.pysnmp.com/pysmi/license.html +# +import sys +import textwrap + +try: + import unittest2 as unittest + +except ImportError: + import unittest + +from pysmi.parser.smi import parserFactory +from pysmi.codegen.pysnmp import PySnmpCodeGen +from pysmi.codegen.symtable import SymtableCodeGen +from pysnmp.smi.builder import MibBuilder + + +class DefaultIntegerTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 123456 } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), 123456, "bad DEFVAL") + + +class DefaultIntegerZeroTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalZeroSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), 0, "bad DEFVAL") + + +class DefaultIntegerNegativeTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + + testObjectType OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -123 } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalSyntaxIsValue(self): + # This test basically verifies that isValue is working at all, so that + # we can be sure the assertFalse tests in the extended tests (further + # below) are meaningful. + self.assertTrue(self.ctx["testObjectType"].getSyntax().isValue, "bad DEFVAL") + + def testIntegerDefvalNegativeSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), -123, "bad DEFVAL") + + +class DefaultIntegerFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + testObjectTypeHex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 'abCD0e'H } + ::= { 1 3 } + + testObjectTypeBinary OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '11011100'B } + ::= { 1 4 } + + testObjectTypeString OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "0" } + ::= { 1 5 } + + testObjectTypeSymbol OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { testObjectTypeString } + ::= { 1 6 } + + testObjectTypeBrackets OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { 0 } } + ::= { 1 7 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeHex"].getSyntax(), 0xABCD0E, "bad DEFVAL" + ) + + def testIntegerDefvalBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeBinary"].getSyntax(), 220, "bad DEFVAL" + ) + + def testIntegerDefvalStringSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeString"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalSymbolSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalBracketsSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBrackets"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultIntegerValueTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + testObjectTypePaddedHex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00abCD0e'H } + ::= { 1 3 } + + testObjectTypePaddedBinary OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '0000000011011100'B } + ::= { 1 4 } + + testObjectTypeZeroHex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { ''H } + ::= { 1 5 } + + testObjectTypeZeroBinary OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { ''B } + ::= { 1 6 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalPaddedHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypePaddedHex"].getSyntax(), 0xABCD0E, "bad DEFVAL" + ) + + def testIntegerDefvalPaddedBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypePaddedBinary"].getSyntax(), 220, "bad DEFVAL" + ) + + def testIntegerDefvalZeroHexSyntax(self): + self.assertEqual(self.ctx["testObjectTypeZeroHex"].getSyntax(), 0, "bad DEFVAL") + + def testIntegerDefvalZeroBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeZeroBinary"].getSyntax(), 0, "bad DEFVAL" + ) + + +class DefaultEnumTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX INTEGER { + enable(1), + disable(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { enable } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), 1, "bad DEFVAL") + + +class DefaultEnumNegativeTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX INTEGER { + enable(-1), + disable(-2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { disable } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalNegativeSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), -2, "bad DEFVAL") + + +class DefaultEnumFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeDecimal OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 } + + testObjectTypeHex OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '01'H } + ::= { 1 4 } + + testObjectTypeBinary OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00000010'B } + ::= { 1 5 } + + testObjectTypeString OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "0" } + ::= { 1 6 } + + testObjectTypeSymbol OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { testObjectTypeString } + ::= { 1 7 } + + testObjectTypeBrackets OBJECT-TYPE + SYNTAX INTEGER { enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { disable } } + ::= { 1 8 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalDecimalSyntax(self): + self.assertEqual(self.ctx["testObjectTypeDecimal"].getSyntax(), 0, "bad DEFVAL") + + def testEnumDefvalHexSyntax(self): + self.assertEqual(self.ctx["testObjectTypeHex"].getSyntax(), 1, "bad DEFVAL") + + def testEnumDefvalBinarySyntax(self): + self.assertEqual(self.ctx["testObjectTypeBinary"].getSyntax(), 2, "bad DEFVAL") + + def testEnumDefvalStringSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeString"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalSymbolSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalBracketsSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeBrackets"].getSyntax(), 2, "bad DEFVAL" + ) + + +class DefaultEnumValueTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeBadDecimal OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -1 } + ::= { 1 3 } + + testObjectTypeBadHex OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 'FF'H } + ::= { 1 4 } + + testObjectTypeBadBinary OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00000011'B } + ::= { 1 5 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalBadDecimalSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadDecimal"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalBadHexSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadHex"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalBadBinarySyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadBinary"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultStringTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "test value" } + ::= { 1 3 } + + testObjectTypeEmpty OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "" } + ::= { 1 4 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testStringDefvalSyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), b"test value", "bad DEFVAL" + ) + + def testStringDefvalEmptySyntax(self): + self.assertEqual(self.ctx["testObjectTypeEmpty"].getSyntax(), b"", "bad DEFVAL") + + +class DefaultStringTextTestCase(unittest.TestCase): + R""" + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "\ntest + value\" } + ::= { 1 3 } + + END + """ + + def setUp(self): + docstring = textwrap.dedent(self.__class__.__doc__) + ast = parserFactory()().parse(docstring)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testStringDefvalTextSyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), + b"\\ntest\nvalue\\", + "bad DEFVAL", + ) + + +class DefaultStringFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeDecimal OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 } + + testObjectTypeHex OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 'abCD'H } + ::= { 1 4 } + + testObjectTypeBinary OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '000100100011010001010110'B } + ::= { 1 5 } + + testObjectTypeSymbol OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { testObjectTypeString } + ::= { 1 6 } + + testObjectTypeBrackets OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { string } } + ::= { 1 7 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testStringDefvalDecimalSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeHex"].getSyntax(), + bytes((0xAB, 0xCD)), + "bad DEFVAL", + ) + + def testStringDefvalBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeBinary"].getSyntax(), + bytes((0x12, 0x34, 0x56)), + "bad DEFVAL", + ) + + def testStringDefvalSymbolSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalBracketsSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBrackets"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultStringValueTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeEmptyHex OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { ''H } + ::= { 1 3 } + + testObjectTypeEmptyBinary OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { ''B } + ::= { 1 4 } + + testObjectTypePaddedHex OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00abCD'H } + ::= { 1 5 } + + testObjectTypePaddedBinary OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '0000000000000000000100100011010001010110'B } + ::= { 1 6 } + + testObjectTypeUnpaddedHex OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '789'H } + ::= { 1 7 } + + testObjectTypeUnpaddedBinary OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '100100011'B } + ::= { 1 8 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testStringDefvalEmptyHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeEmptyHex"].getSyntax(), bytes(), "bad DEFVAL" + ) + + def testStringDefvalEmptyBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeEmptyBinary"].getSyntax(), bytes(), "bad DEFVAL" + ) + + def testStringDefvalPaddedHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypePaddedHex"].getSyntax(), + bytes((0x00, 0xAB, 0xCD)), + "bad DEFVAL", + ) + + def testStringDefvalPaddedBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypePaddedBinary"].getSyntax(), + bytes((0x00, 0x00, 0x12, 0x34, 0x56)), + "bad DEFVAL", + ) + + def testStringDefvalUnpaddedHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeUnpaddedHex"].getSyntax(), + bytes((0x07, 0x89)), + "bad DEFVAL", + ) + + def testStringDefvalUnpaddedBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeUnpaddedBinary"].getSyntax(), + bytes((0x01, 0x23)), + "bad DEFVAL", + ) + + +class DefaultBitsTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType1 OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { present, absent } } + ::= { 1 3 } + + testObjectType2 OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { changed } } + ::= { 1 4 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testBitsDefvalSyntax1(self): + self.assertEqual( + self.ctx["testObjectType1"].getSyntax(), + bytes((0xC0,)), + "bad DEFVAL", + ) + + def testBitsDefvalSyntax2(self): + self.assertEqual( + self.ctx["testObjectType2"].getSyntax(), + bytes((0x20,)), + "bad DEFVAL", + ) + + +class DefaultBitsMultiOctetTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX BITS { a(0), b(1), c(2), d(3), e(4), f(5), g(6), h(7), i(8), j(9), k(10), l(11), m(12), n(13), o(14), p(15), q(16) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { b, c, m } } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testBitsDefvalMultiOctetSyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), + bytes((0x60, 0x08)), + "bad DEFVAL", + ) + + +class DefaultBitsEmptySetTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { } } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testBitsDefvalEmptySyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), + bytes((0x00,)), + "bad DEFVAL", + ) + + +class DefaultBitsFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeDecimal OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 1 } + ::= { 1 3 } + + testObjectTypeHex OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '04'H } + ::= { 1 4 } + + testObjectTypeBinary OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00000111'B } + ::= { 1 5 } + + testObjectTypeString OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "0" } + ::= { 1 6 } + + testObjectTypeSymbol OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { present } + ::= { 1 7 } + + testObjectTypeBrackets OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { 0 } } + ::= { 1 8 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testBitsDefvalDecimalSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeDecimal"].getSyntax(), + bytes((0x01,)), + "bad DEFVAL", + ) + + def testBitsDefvalHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeHex"].getSyntax(), + bytes((0x04,)), + "bad DEFVAL", + ) + + def testBitsDefvalBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeBinary"].getSyntax(), + bytes((0x07,)), + "bad DEFVAL", + ) + + def testBitsDefvalStringSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeString"].getSyntax().isValue, "bad DEFVAL" + ) + + def testBitsDefvalSymbolSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + ) + + def testBitsDefvalBracketsSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBrackets"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultBitsValueTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeDuplicateLabel OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { absent, absent } } + ::= { 1 3 } + + testObjectTypeBadLabel OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { unchanged } } + ::= { 1 4 } + + testObjectTypeOneBadLabel OBJECT-TYPE + SYNTAX BITS { present(0), absent(1), changed(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { present, unchanged, absent } } + ::= { 1 5 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testBitsDefvalDuplicateLabelSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeDuplicateLabel"].getSyntax(), + bytes((0x40,)), + "bad DEFVAL", + ) + + def testBitsDefvalBadLabelSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadLabel"].getSyntax().isValue, "bad DEFVAL" + ) + + def testBitsDefvalOneBadLabelSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeOneBadLabel"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultObjectIdentifierTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, Integer32 + FROM SNMPv2-SMI; + + testTargetObjectType OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test target object" + ::= { 1 3 } + + testObjectType OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { testTargetObjectType } + ::= { 1 4 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testObjectIdentifierDefvalSyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), + (1, 3), + "bad DEFVAL", + ) + + +class DefaultObjectIdentifierInvalidTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { 0 0 } } + ::= { 1 3 } + + END + """ + + def testObjectIdentifierDefvalInvalidSyntax(self): + # The "{{0 0}}" type notation is invalid and currently not supported. + # This test verifies that such notations can be parsed at all, which + # is why the parsing is part of the actual test, and why successful + # instantiation of the syntax is enough here. + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + self.ctx["testObjectType"].getSyntax() + + +class DefaultObjectIdentifierHyphenTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + test-target-object-type OBJECT IDENTIFIER ::= { 1 3 } + global OBJECT IDENTIFIER ::= { 1 4 } -- a reserved Python keyword + + testObjectType1 OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { test-target-object-type } + ::= { 1 5 } + + testObjectType2 OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { global } + ::= { 1 6 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testObjectIdentifierDefvalHyphenSyntax(self): + self.assertEqual( + self.ctx["testObjectType1"].getSyntax(), + (1, 3), + "bad DEFVAL", + ) + + def testObjectIdentifierDefvalKeywordSyntax(self): + self.assertEqual( + self.ctx["testObjectType2"].getSyntax(), + (1, 4), + "bad DEFVAL", + ) + + +class DefaultObjectIdentifierFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeDecimal OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 } + + testObjectTypeHex OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00'H } + ::= { 1 4 } + + testObjectTypeBinary OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00000000'B } + ::= { 1 5 } + + testObjectTypeString OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "0" } + ::= { 1 6 } + + testObjectTypeSymbol OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { doesNotExist } + ::= { 1 7 } + + testObjectTypeBrackets OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { testObjectTypeSymbol } } + ::= { 1 8 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testObjectIdentifierDefvalDecimalSyntax(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal"].getSyntax().isValue, "bad DEFVAL" + ) + + def testObjectIdentifierDefvalHexSyntax(self): + self.assertFalse( + self.ctx["testObjectTypeHex"].getSyntax().isValue, "bad DEFVAL" + ) + + def testObjectIdentifierDefvalBinarySyntax(self): + self.assertFalse( + self.ctx["testObjectTypeBinary"].getSyntax().isValue, "bad DEFVAL" + ) + + def testObjectIdentifierDefvalStringSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeString"].getSyntax().isValue, "bad DEFVAL" + ) + + def testObjectIdentifierDefvalSymbolSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + ) + + def testObjectIdentifierDefvalBracketsSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBrackets"].getSyntax().isValue, "bad DEFVAL" + ) + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/tests/test_objecttype_smiv2_pysnmp.py b/tests/test_objecttype_smiv2_pysnmp.py index ff15709..2b94e9e 100644 --- a/tests/test_objecttype_smiv2_pysnmp.py +++ b/tests/test_objecttype_smiv2_pysnmp.py @@ -253,190 +253,6 @@ def testObjectTypeUnits(self): self.assertEqual(self.ctx["testObjectType"].getUnits(), "", "bad UNITS") -class ObjectTypeIntegerDefaultTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE, - Integer32 - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { 123456 } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual(self.ctx["testObjectType"].getSyntax(), 123456, "bad DEFVAL") - - -class ObjectTypeIntegerDefaultZeroTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE, - Integer32 - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { 0 } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual(self.ctx["testObjectType"].getSyntax(), 0, "bad DEFVAL") - - -class ObjectTypeEnumDefaultTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX INTEGER { - enable(1), - disable(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { enable } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual(self.ctx["testObjectType"].getSyntax(), 1, "bad DEFVAL") - - -class ObjectTypeStringDefaultTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX OCTET STRING - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { "test value" } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - # TODO: pyasn1 does not like OctetString.defaultValue - def testObjectTypeSyntax(self): - self.assertEqual( - self.ctx["testObjectType"].getSyntax(), b"test value", "bad DEFVAL" - ) - - -class ObjectTypeStringDefaultTextTestCase(unittest.TestCase): - R""" - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX OCTET STRING - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { "\ntest - value\" } - ::= { 1 3 } - - END - """ - - def setUp(self): - docstring = textwrap.dedent(self.__class__.__doc__) - ast = parserFactory()().parse(docstring)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual( - self.ctx["testObjectType"].getSyntax(), - b"\\ntest\nvalue\\", - "bad DEFVAL", - ) - - class ObjectTypeWithIntegerConstraintTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN @@ -589,258 +405,6 @@ def testObjectTypeSyntax(self): ) -class ObjectTypeBitsDefaultTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX BITS { present(0), absent(1), changed(2) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { { present, absent } } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual( - self.ctx["testObjectType"].getSyntax(), - bytes((0xC0,)), - "bad DEFVAL", - ) - - -class ObjectTypeBitsDefaultMultiOctetTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX BITS { a(0), b(1), c(2), d(3), e(4), f(5), g(6), h(7), i(8), j(9), k(10), l(11), m(12), n(13), o(14), p(15), q(16) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { { b, c, m } } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual( - self.ctx["testObjectType"].getSyntax(), - bytes((0x60, 0x08)), - "bad DEFVAL", - ) - - -class ObjectTypeBitsDefaultEmptySetTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX BITS { present(0), absent(1), changed(2) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { { } } - ::= { 1 3 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual( - self.ctx["testObjectType"].getSyntax(), - bytes((0x00,)), - "bad DEFVAL", - ) - - -class ObjectTypeObjectIdentifierTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE, Integer32 - FROM SNMPv2-SMI; - - testTargetObjectType OBJECT-TYPE - SYNTAX Integer32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test target object" - ::= { 1 3 } - - testObjectType OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { testTargetObjectType } - ::= { 1 4 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax(self): - self.assertEqual( - self.ctx["testObjectType"].getSyntax(), - (1, 3), - "bad DEFVAL", - ) - - -class ObjectTypeObjectIdentifierInvalidTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - testObjectType OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { { 0 0 } } - ::= { 1 3 } - - END - """ - - def testObjectTypeSyntax(self): - # The "{{0 0}}" type notation is invalid and currently not supported. - # This test verifies that such notations can be parsed at all, which - # is why the parsing is part of the actual test, and why successful - # instantiation of the syntax is enough here. - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - self.ctx["testObjectType"].getSyntax() - - -class ObjectTypeObjectIdentifierHyphenTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; - - test-target-object-type OBJECT IDENTIFIER ::= { 1 3 } - global OBJECT IDENTIFIER ::= { 1 4 } -- a reserved Python keyword - - testObjectType1 OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { test-target-object-type } - ::= { 1 5 } - - testObjectType2 OBJECT-TYPE - SYNTAX OBJECT IDENTIFIER - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { global } - ::= { 1 6 } - - END - """ - - def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True - ) - codeobj = compile(pycode, "test", "exec") - - self.ctx = {"mibBuilder": MibBuilder()} - - exec(codeobj, self.ctx, self.ctx) - - def testObjectTypeSyntax1(self): - self.assertEqual( - self.ctx["testObjectType1"].getSyntax(), - (1, 3), - "bad DEFVAL", - ) - - def testObjectTypeSyntax2(self): - self.assertEqual( - self.ctx["testObjectType2"].getSyntax(), - (1, 4), - "bad DEFVAL", - ) - - class ObjectTypeMibTableTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN From 9b416932afe1f482370ccc3ef61352aab3c6aad8 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Sun, 17 Nov 2024 15:15:08 +0000 Subject: [PATCH 2/2] Apply constraints checks to DEFVAL values For DEFVAL clauses associated with object type syntaxes that are: 1. derived from octet strings or (non-enumerated) integers, and, 2. sub-typed with value range or size constraints, ..the DEFVAL values are now checked against those constraints, and discarded if they do not adhere to the constraints. As a result, any DEFVAL values that would otherwise cause a MIB loading failure due to pyasn1 value constraint errors, are now kept out of the generated Python code altogether. That allows many more slightly buggy MIBs to be loaded and used than before, albeit without the offending DEFVAL values of course. The test set is extended to cover the new functionality. --- pysmi/codegen/intermediate.py | 60 +- pysmi/codegen/symtable.py | 6 +- tests/test_defval_smiv2_pysnmp.py | 1660 +++++++++++++++++++++++++---- 3 files changed, 1522 insertions(+), 204 deletions(-) diff --git a/pysmi/codegen/intermediate.py b/pysmi/codegen/intermediate.py index 9318af8..a7e9ed9 100644 --- a/pysmi/codegen/intermediate.py +++ b/pysmi/codegen/intermediate.py @@ -216,7 +216,23 @@ def get_base_type(self, symName, module): else: baseSymType, baseSymSubtype = self.get_base_type(*symType) - if isinstance(baseSymSubtype, list): + + if isinstance(baseSymSubtype, dict): + # An enumeration (INTEGER or BITS). Combine the enumeration + # lists when applicable. That is a bit more permissive than + # strictly needed, as syntax refinement may only remove entries + # from the base enumeration (RFC 2578 Sec. 9 point (2)). + if isinstance(symSubtype, dict): + baseSymSubtype.update(symSubtype) + symSubtype = baseSymSubtype + + elif isinstance(baseSymSubtype, list): + # A value range or size constraint. Note that each list is an + # intersection of unions of ranges. Taking the intersection + # instead of the most-top level union of ranges is a bit more + # restrictive than strictly needed, as range syntax refinement + # may only remove allowed values from the base type (RFC 2578 + # Sec. 9. points (1) and (3)), but it matches what pyasn1 does. if isinstance(symSubtype, list): symSubtype += baseSymSubtype else: @@ -663,6 +679,26 @@ def gen_contact_info(self, data): text = data[0] return self.textFilter("contact-info", text) + def is_in_range(self, intersection, value): + """Check whether the given value falls within the given constraints. + + The given list represents an intersection and contains elements that + represent unions of individual ranges. Each individual range consists + of one or two elements (a single value, or a low..high range). The + given value is considered in range if it falls within range for each of + the unions within the intersection. If the intersection is empty, the + value is accepted as well. + """ + for union in intersection: + in_range = False + for rng in union: + if self.str2int(rng[0]) <= value <= self.str2int(rng[-1]): + in_range = True + break + if not in_range: + return False + return True + # noinspection PyUnusedLocal def gen_display_hint(self, data): return data[0] @@ -682,11 +718,11 @@ def _process_integer_defval(self, defval, defvalType): elif self.is_binary(defval): # binary value = int(defval[1:-2] or "0", 2) - elif isinstance(defvalType[1], list): # enumeration label + elif isinstance(defvalType[1], dict): # enumeration label # For enumerations, the ASN.1 DEFVAL statements contain names, # whereas the code generation template expects integer values # (represented as strings). - nameToValueMap = dict(defvalType[1]) + nameToValueMap = defvalType[1] # buggy MIB: DEFVAL { { ... } } if isinstance(defval, list): @@ -706,13 +742,17 @@ def _process_integer_defval(self, defval, defvalType): else: raise ValueError("wrong input type for integer") - if isinstance(defvalType[1], list): # enumeration number + if isinstance(defvalType[1], dict): # enumeration number # For numerical values given for enumerated integers, make sure # that they are valid, because pyasn1 will not check this case and # thus let us set a default value that is not valid for the type. - if value not in {num for name, num in defvalType[1]}: + if value not in defvalType[1].values(): raise ValueError("wrong enumeration value") + elif isinstance(defvalType[1], list): # range constraints + if not self.is_in_range(defvalType[1], value): + raise ValueError("value does not conform to range constraints") + return str(value), "decimal" def _process_string_defval(self, defval, defvalType): @@ -754,7 +794,7 @@ def _process_string_defval(self, defval, defvalType): elif defvalBaseType == "Bits" and isinstance(defval, list): # bit labels defvalBits = [] - bits = dict(defvalType[1]) + bits = defvalType[1] for bit in defval: bitValue = bits.get(bit, None) @@ -768,6 +808,14 @@ def _process_string_defval(self, defval, defvalType): else: raise ValueError("wrong input type for string") + if defvalBaseType == "OctetString" and isinstance( + defvalType[1], list + ): # size constraints + size = len(value) // 2 if fmt == "hex" else len(value) + + if not self.is_in_range(defvalType[1], size): + raise ValueError("value does not conform to size constraints") + return value, fmt def _process_oid_defval(self, defval, defvalType): diff --git a/pysmi/codegen/symtable.py b/pysmi/codegen/symtable.py index c74ce1f..6dd0856 100644 --- a/pysmi/codegen/symtable.py +++ b/pysmi/codegen/symtable.py @@ -381,7 +381,7 @@ def gen_bit_names(self, data, classmode=False): # noinspection PyUnusedLocal,PyMethodMayBeStatic def gen_bits(self, data, classmode=False): - bits = data[0] + bits = dict(data[0]) return ("Bits", ""), bits # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic @@ -444,7 +444,7 @@ def gen_index(self, data, classmode=False): # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def gen_integer_subtype(self, data, classmode=False): - return "" + return [data[0]] # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def gen_max_access(self, data, classmode=False): @@ -452,7 +452,7 @@ def gen_max_access(self, data, classmode=False): # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def gen_octetstring_subtype(self, data, classmode=False): - return "" + return [data[0]] # noinspection PyUnusedLocal def gen_oid(self, data, classmode=False): diff --git a/tests/test_defval_smiv2_pysnmp.py b/tests/test_defval_smiv2_pysnmp.py index 80d72a2..a8a2213 100644 --- a/tests/test_defval_smiv2_pysnmp.py +++ b/tests/test_defval_smiv2_pysnmp.py @@ -294,6 +294,685 @@ def testIntegerDefvalZeroBinarySyntax(self): ) +class DefaultIntegerConstraintsTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + testObjectTypeDecimal1 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -3 } + ::= { 1 3 1 } + + testObjectTypeDecimal2 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -2 } + ::= { 1 3 2 } + + testObjectTypeDecimal3 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -1 } + ::= { 1 3 3 } + + testObjectTypeDecimal4 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 4 } + + testObjectTypeDecimal5 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 1 } + ::= { 1 3 5 } + + testObjectTypeDecimal6 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 2 } + ::= { 1 3 6 } + + testObjectTypeDecimal7 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 3 } + ::= { 1 3 7 } + + testObjectTypeDecimal8 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 4 } + ::= { 1 3 8 } + + testObjectTypeDecimal9 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 5 } + ::= { 1 3 9 } + + testObjectTypeDecimal10 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 6 } + ::= { 1 3 10 } + + testObjectTypeDecimal11 OBJECT-TYPE + SYNTAX Integer32 (-2..-1 | 3 | 5..6) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 7 } + ::= { 1 3 11 } + + testObjectTypeHex1 OBJECT-TYPE + SYNTAX Integer32 (12345) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '3038'H } + ::= { 1 4 1 } + + testObjectTypeHex2 OBJECT-TYPE + SYNTAX Integer32 (12345) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '3039'H } + ::= { 1 4 2 } + + testObjectTypeHex3 OBJECT-TYPE + SYNTAX Integer32 (12345) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '303A'H } + ::= { 1 4 3 } + + testObjectTypeHex4 OBJECT-TYPE + SYNTAX Integer32 (12345) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '003039'H } + ::= { 1 4 4 } + + testObjectTypeBinary1 OBJECT-TYPE + SYNTAX Integer32 (67..68) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '01000010'B } + ::= { 1 5 1 } + + testObjectTypeBinary2 OBJECT-TYPE + SYNTAX Integer32 (67..68) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '01000011'B } + ::= { 1 5 2 } + + testObjectTypeBinary3 OBJECT-TYPE + SYNTAX Integer32 (67..68) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '0000000001000100'B } + ::= { 1 5 3 } + + testObjectTypeBinary4 OBJECT-TYPE + SYNTAX Integer32 (67..68) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '01000101'B } + ::= { 1 5 4 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalDecimalSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeDecimal2"].getSyntax(), -2, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntax3(self): + self.assertEqual( + self.ctx["testObjectTypeDecimal3"].getSyntax(), -1, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntaxIsValue4(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal4"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntaxIsValue5(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal5"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntaxIsValue6(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal6"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntax7(self): + self.assertEqual( + self.ctx["testObjectTypeDecimal7"].getSyntax(), 3, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntaxIsValue8(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal8"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntax9(self): + self.assertEqual( + self.ctx["testObjectTypeDecimal9"].getSyntax(), 5, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntax10(self): + self.assertEqual( + self.ctx["testObjectTypeDecimal10"].getSyntax(), 6, "bad DEFVAL" + ) + + def testIntegerDefvalDecimalSyntaxIsValue11(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal11"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalHexSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeHex1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalHexSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeHex2"].getSyntax(), 12345, "bad DEFVAL" + ) + + def testIntegerDefvalHexSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeHex3"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalHexSyntax4(self): + self.assertEqual( + self.ctx["testObjectTypeHex4"].getSyntax(), 12345, "bad DEFVAL" + ) + + def testIntegerDefvalBinarySyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeBinary1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalBinarySyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeBinary2"].getSyntax(), 67, "bad DEFVAL" + ) + + def testIntegerDefvalBinarySyntax3(self): + self.assertEqual( + self.ctx["testObjectTypeBinary3"].getSyntax(), 68, "bad DEFVAL" + ) + + def testIntegerDefvalBinarySyntaxIsValue4(self): + self.assertFalse( + self.ctx["testObjectTypeBinary4"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultIntegerConstraintsLayersTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION + FROM SNMPv2-TC; + + SimpleConstrainedInteger ::= Integer32 (1..2) + + testObjectTypeSimple1 OBJECT-TYPE + SYNTAX SimpleConstrainedInteger + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -1 } + ::= { 1 3 1 } + + testObjectTypeSimple2 OBJECT-TYPE + SYNTAX SimpleConstrainedInteger + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 2 } + + testObjectTypeSimple3 OBJECT-TYPE + SYNTAX SimpleConstrainedInteger + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 1 } + ::= { 1 3 3 } + + -- The extra constraints are not correct, as they are not a subset of the + -- original constraints, but pysmi should deal with them properly. + testObjectTypeLayeredSimple1 OBJECT-TYPE + SYNTAX SimpleConstrainedInteger (2..3) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 1 } + ::= { 1 3 4 } + + testObjectTypeLayeredSimple2 OBJECT-TYPE + SYNTAX SimpleConstrainedInteger (2..3) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 2 } + ::= { 1 3 5 } + + testObjectTypeLayeredSimple3 OBJECT-TYPE + SYNTAX SimpleConstrainedInteger (2..3) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 3 } + ::= { 1 3 6 } + + TextualConstrainedInteger ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION "Test TC" + SYNTAX Integer32 (-4..-3) + + testObjectTypeTextual1 OBJECT-TYPE + SYNTAX TextualConstrainedInteger + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -5 } + ::= { 1 4 1 } + + testObjectTypeTextual2 OBJECT-TYPE + SYNTAX TextualConstrainedInteger + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 4 } + ::= { 1 4 2 } + + testObjectTypeTextual3 OBJECT-TYPE + SYNTAX TextualConstrainedInteger + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -4 } + ::= { 1 4 3 } + + testObjectTypeLayeredTextual1 OBJECT-TYPE + SYNTAX TextualConstrainedInteger (-3..-2) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -4 } + ::= { 1 4 4 } + + testObjectTypeLayeredTextual2 OBJECT-TYPE + SYNTAX TextualConstrainedInteger (-3..-2) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -3 } + ::= { 1 4 5 } + + testObjectTypeLayeredTextual3 OBJECT-TYPE + SYNTAX TextualConstrainedInteger (-3..-2) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -2 } + ::= { 1 4 6 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalSimpleSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeSimple1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalSimpleSyntaxIsValue2(self): + self.assertFalse( + self.ctx["testObjectTypeSimple2"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalSimpleSyntax3(self): + self.assertEqual(self.ctx["testObjectTypeSimple3"].getSyntax(), 1, "bad DEFVAL") + + def testIntegerDefvalLayeredSimpleSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredSimple1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalLayeredSimpleSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeLayeredSimple2"].getSyntax(), 2, "bad DEFVAL" + ) + + def testIntegerDefvalLayeredSimpleSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredSimple3"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalTextualSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeTextual1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalTextualSyntaxIsValue2(self): + self.assertFalse( + self.ctx["testObjectTypeTextual2"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalTextualSyntax3(self): + self.assertEqual( + self.ctx["testObjectTypeTextual3"].getSyntax(), -4, "bad DEFVAL" + ) + + def testIntegerDefvalLayeredTextualSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredTextual1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalLayeredTextualSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeLayeredTextual2"].getSyntax(), -3, "bad DEFVAL" + ) + + def testIntegerDefvalLayeredTextualSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredTextual3"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultIntegerConstraintsFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE, + Integer32 + FROM SNMPv2-SMI; + + testObjectTypeHexFormat1 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 1 } + ::= { 1 3 1 } + + testObjectTypeHexFormat2 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 2 } + ::= { 1 3 2 } + + testObjectTypeHexFormat3 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 3 } + ::= { 1 3 3 } + + testObjectTypeHexFormat4 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 4 } + ::= { 1 3 4 } + + testObjectTypeHexFormat5 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 509 } + ::= { 1 3 5 } + + testObjectTypeHexFormat6 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 510 } + ::= { 1 3 6 } + + testObjectTypeHexFormat7 OBJECT-TYPE + SYNTAX Integer32 ('02'H..'03'H | '01FE'H) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 511 } + ::= { 1 3 7 } + + testObjectTypeBinaryFormat1 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 4 1 } + + testObjectTypeBinaryFormat2 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 1 } + ::= { 1 4 2 } + + testObjectTypeBinaryFormat3 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 2 } + ::= { 1 4 3 } + + testObjectTypeBinaryFormat4 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 123455 } + ::= { 1 4 4 } + + testObjectTypeBinaryFormat5 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 123456 } + ::= { 1 4 5 } + + testObjectTypeBinaryFormat6 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '01E241'H } + ::= { 1 4 6 } + + testObjectTypeBinaryFormat7 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 123458 } + ::= { 1 4 7 } + + testObjectTypeBinaryFormat8 OBJECT-TYPE + SYNTAX Integer32 ('00000001'B | '00011110001001000000'B..'00011110001001000010'B) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 123459 } + ::= { 1 4 8 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testIntegerDefvalHexFormatSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeHexFormat1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalHexFormatSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeHexFormat2"].getSyntax(), 2, "bad DEFVAL" + ) + + def testIntegerDefvalHexFormatSyntax3(self): + self.assertEqual( + self.ctx["testObjectTypeHexFormat3"].getSyntax(), 3, "bad DEFVAL" + ) + + def testIntegerDefvalHexFormatSyntaxIsValue4(self): + self.assertFalse( + self.ctx["testObjectTypeHexFormat4"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalHexFormatSyntaxIsValue5(self): + self.assertFalse( + self.ctx["testObjectTypeHexFormat5"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalHexFormatSyntax6(self): + self.assertEqual( + self.ctx["testObjectTypeHexFormat6"].getSyntax(), 510, "bad DEFVAL" + ) + + def testIntegerDefvalHexFormatSyntaxIsValue7(self): + self.assertFalse( + self.ctx["testObjectTypeHexFormat7"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeBinaryFormat2"].getSyntax(), 1, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat3"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntaxIsValue4(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat4"].getSyntax().isValue, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntax5(self): + self.assertEqual( + self.ctx["testObjectTypeBinaryFormat5"].getSyntax(), 123456, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntax6(self): + self.assertEqual( + self.ctx["testObjectTypeBinaryFormat6"].getSyntax(), 123457, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntax7(self): + self.assertEqual( + self.ctx["testObjectTypeBinaryFormat7"].getSyntax(), 123458, "bad DEFVAL" + ) + + def testIntegerDefvalBinaryFormatSyntaxIsValue8(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat8"].getSyntax().isValue, "bad DEFVAL" + ) + + class DefaultEnumTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN @@ -302,16 +981,252 @@ class DefaultEnumTestCase(unittest.TestCase): FROM SNMPv2-SMI; testObjectType OBJECT-TYPE - SYNTAX INTEGER { - enable(1), - disable(2) - } + SYNTAX INTEGER { + enable(1), + disable(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { enable } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), 1, "bad DEFVAL") + + +class DefaultEnumNegativeTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX INTEGER { + enable(-1), + disable(-2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { disable } + ::= { 1 3 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalNegativeSyntax(self): + self.assertEqual(self.ctx["testObjectType"].getSyntax(), -2, "bad DEFVAL") + + +class DefaultEnumFormatTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeDecimal OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 0 } + ::= { 1 3 } + + testObjectTypeHex OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '01'H } + ::= { 1 4 } + + testObjectTypeBinary OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00000010'B } + ::= { 1 5 } + + testObjectTypeString OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "0" } + ::= { 1 6 } + + testObjectTypeSymbol OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { testObjectTypeString } + ::= { 1 7 } + + testObjectTypeBrackets OBJECT-TYPE + SYNTAX INTEGER { enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { { disable } } + ::= { 1 8 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalDecimalSyntax(self): + self.assertEqual(self.ctx["testObjectTypeDecimal"].getSyntax(), 0, "bad DEFVAL") + + def testEnumDefvalHexSyntax(self): + self.assertEqual(self.ctx["testObjectTypeHex"].getSyntax(), 1, "bad DEFVAL") + + def testEnumDefvalBinarySyntax(self): + self.assertEqual(self.ctx["testObjectTypeBinary"].getSyntax(), 2, "bad DEFVAL") + + def testEnumDefvalStringSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeString"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalSymbolSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalBracketsSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeBrackets"].getSyntax(), 2, "bad DEFVAL" + ) + + +class DefaultEnumValueTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeBadDecimal OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { -1 } + ::= { 1 3 } + + testObjectTypeBadHex OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { 'FF'H } + ::= { 1 4 } + + testObjectTypeBadBinary OBJECT-TYPE + SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '00000011'B } + ::= { 1 5 } + + END + """ + + def setUp(self): + ast = parserFactory()().parse(self.__class__.__doc__)[0] + mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) + self.mibInfo, pycode = PySnmpCodeGen().gen_code( + ast, {mibInfo.name: symtable}, genTexts=True + ) + codeobj = compile(pycode, "test", "exec") + + self.ctx = {"mibBuilder": MibBuilder()} + + exec(codeobj, self.ctx, self.ctx) + + def testEnumDefvalBadDecimalSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadDecimal"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalBadHexSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadHex"].getSyntax().isValue, "bad DEFVAL" + ) + + def testEnumDefvalBadBinarySyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBadBinary"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultStringTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectType OBJECT-TYPE + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { enable } + DEFVAL { "test value" } ::= { 1 3 } + testObjectTypeEmpty OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "" } + ::= { 1 4 } + END """ @@ -327,33 +1242,37 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testEnumDefvalSyntax(self): - self.assertEqual(self.ctx["testObjectType"].getSyntax(), 1, "bad DEFVAL") + def testStringDefvalSyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), b"test value", "bad DEFVAL" + ) + + def testStringDefvalEmptySyntax(self): + self.assertEqual(self.ctx["testObjectTypeEmpty"].getSyntax(), b"", "bad DEFVAL") -class DefaultEnumNegativeTestCase(unittest.TestCase): - """ +class DefaultStringTextTestCase(unittest.TestCase): + R""" TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testObjectType OBJECT-TYPE - SYNTAX INTEGER { - enable(-1), - disable(-2) - } + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { disable } + DEFVAL { "\ntest + value\" } ::= { 1 3 } END """ def setUp(self): - ast = parserFactory()().parse(self.__class__.__doc__)[0] + docstring = textwrap.dedent(self.__class__.__doc__) + ast = parserFactory()().parse(docstring)[0] mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().gen_code( ast, {mibInfo.name: symtable}, genTexts=True @@ -364,11 +1283,15 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testEnumDefvalNegativeSyntax(self): - self.assertEqual(self.ctx["testObjectType"].getSyntax(), -2, "bad DEFVAL") + def testStringDefvalTextSyntax(self): + self.assertEqual( + self.ctx["testObjectType"].getSyntax(), + b"\\ntest\nvalue\\", + "bad DEFVAL", + ) -class DefaultEnumFormatTestCase(unittest.TestCase): +class DefaultStringFormatTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS @@ -376,7 +1299,7 @@ class DefaultEnumFormatTestCase(unittest.TestCase): FROM SNMPv2-SMI; testObjectTypeDecimal OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" @@ -384,44 +1307,36 @@ class DefaultEnumFormatTestCase(unittest.TestCase): ::= { 1 3 } testObjectTypeHex OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '01'H } + DEFVAL { 'abCD'H } ::= { 1 4 } testObjectTypeBinary OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '00000010'B } + DEFVAL { '000100100011010001010110'B } ::= { 1 5 } - testObjectTypeString OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { "0" } - ::= { 1 6 } - testObjectTypeSymbol OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" DEFVAL { testObjectTypeString } - ::= { 1 7 } + ::= { 1 6 } testObjectTypeBrackets OBJECT-TYPE - SYNTAX INTEGER { enable(1), disable(2) } + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { { disable } } - ::= { 1 8 } + DEFVAL { { string } } + ::= { 1 7 } END """ @@ -438,62 +1353,91 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testEnumDefvalDecimalSyntax(self): - self.assertEqual(self.ctx["testObjectTypeDecimal"].getSyntax(), 0, "bad DEFVAL") - - def testEnumDefvalHexSyntax(self): - self.assertEqual(self.ctx["testObjectTypeHex"].getSyntax(), 1, "bad DEFVAL") + def testStringDefvalDecimalSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeDecimal"].getSyntax().isValue, "bad DEFVAL" + ) - def testEnumDefvalBinarySyntax(self): - self.assertEqual(self.ctx["testObjectTypeBinary"].getSyntax(), 2, "bad DEFVAL") + def testStringDefvalHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeHex"].getSyntax(), + bytes((0xAB, 0xCD)), + "bad DEFVAL", + ) - def testEnumDefvalStringSyntaxIsValue(self): - self.assertFalse( - self.ctx["testObjectTypeString"].getSyntax().isValue, "bad DEFVAL" + def testStringDefvalBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeBinary"].getSyntax(), + bytes((0x12, 0x34, 0x56)), + "bad DEFVAL", ) - def testEnumDefvalSymbolSyntaxIsValue(self): + def testStringDefvalSymbolSyntaxIsValue(self): self.assertFalse( self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" ) - def testEnumDefvalBracketsSyntax(self): - self.assertEqual( - self.ctx["testObjectTypeBrackets"].getSyntax(), 2, "bad DEFVAL" + def testStringDefvalBracketsSyntaxIsValue(self): + self.assertFalse( + self.ctx["testObjectTypeBrackets"].getSyntax().isValue, "bad DEFVAL" ) -class DefaultEnumValueTestCase(unittest.TestCase): +class DefaultStringValueTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; - testObjectTypeBadDecimal OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + testObjectTypeEmptyHex OBJECT-TYPE + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { -1 } + DEFVAL { ''H } ::= { 1 3 } - testObjectTypeBadHex OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + testObjectTypeEmptyBinary OBJECT-TYPE + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { 'FF'H } + DEFVAL { ''B } ::= { 1 4 } - testObjectTypeBadBinary OBJECT-TYPE - SYNTAX INTEGER { unknown(0), enable(1), disable(2) } + testObjectTypePaddedHex OBJECT-TYPE + SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '00000011'B } + DEFVAL { '00abCD'H } ::= { 1 5 } + testObjectTypePaddedBinary OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '0000000000000000000100100011010001010110'B } + ::= { 1 6 } + + testObjectTypeUnpaddedHex OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '789'H } + ::= { 1 7 } + + testObjectTypeUnpaddedBinary OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '100100011'B } + ::= { 1 8 } + END """ @@ -509,44 +1453,171 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testEnumDefvalBadDecimalSyntaxIsValue(self): - self.assertFalse( - self.ctx["testObjectTypeBadDecimal"].getSyntax().isValue, "bad DEFVAL" + def testStringDefvalEmptyHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeEmptyHex"].getSyntax(), bytes(), "bad DEFVAL" ) - def testEnumDefvalBadHexSyntaxIsValue(self): - self.assertFalse( - self.ctx["testObjectTypeBadHex"].getSyntax().isValue, "bad DEFVAL" + def testStringDefvalEmptyBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeEmptyBinary"].getSyntax(), bytes(), "bad DEFVAL" ) - def testEnumDefvalBadBinarySyntaxIsValue(self): - self.assertFalse( - self.ctx["testObjectTypeBadBinary"].getSyntax().isValue, "bad DEFVAL" + def testStringDefvalPaddedHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypePaddedHex"].getSyntax(), + bytes((0x00, 0xAB, 0xCD)), + "bad DEFVAL", + ) + + def testStringDefvalPaddedBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypePaddedBinary"].getSyntax(), + bytes((0x00, 0x00, 0x12, 0x34, 0x56)), + "bad DEFVAL", + ) + + def testStringDefvalUnpaddedHexSyntax(self): + self.assertEqual( + self.ctx["testObjectTypeUnpaddedHex"].getSyntax(), + bytes((0x07, 0x89)), + "bad DEFVAL", + ) + + def testStringDefvalUnpaddedBinarySyntax(self): + self.assertEqual( + self.ctx["testObjectTypeUnpaddedBinary"].getSyntax(), + bytes((0x01, 0x23)), + "bad DEFVAL", ) -class DefaultStringTestCase(unittest.TestCase): - """ - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; +class DefaultStringConstraintsTestCase(unittest.TestCase): + """ + TEST-MIB DEFINITIONS ::= BEGIN + IMPORTS + OBJECT-TYPE + FROM SNMPv2-SMI; + + testObjectTypeString1 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..3)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "" } + ::= { 1 3 1 } + + testObjectTypeString2 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..3)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "a" } + ::= { 1 3 2 } + + testObjectTypeString3 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..3)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "ab" } + ::= { 1 3 3 } + + testObjectTypeString4 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..3)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "abc" } + ::= { 1 3 4 } + + testObjectTypeString5 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (1..3)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "abcd" } + ::= { 1 3 5 } + + testObjectTypeZeroString1 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (0)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "" } + ::= { 1 3 6 } + + testObjectTypeZeroString2 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (0)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "x" } + ::= { 1 3 7 } + + testObjectTypeHex1 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (4 | 6)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '414243'H } + ::= { 1 4 1 } + + testObjectTypeHex2 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (4 | 6)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '41424344'H } + ::= { 1 4 2 } + + testObjectTypeHex3 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (4 | 6)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '4142434445'H } + ::= { 1 4 3 } + + testObjectTypeHex4 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (4 | 6)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '414243444546'H } + ::= { 1 4 4 } + + testObjectTypeHex5 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (4 | 6)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '41424344454647'H } + ::= { 1 4 5 } + + testObjectTypeBinary1 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (3)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { '0011000100110010'B } + ::= { 1 5 1 } - testObjectType OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeBinary2 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (3)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { "test value" } - ::= { 1 3 } + DEFVAL { '001100010011001000110011'B } + ::= { 1 5 2 } - testObjectTypeEmpty OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeBinary3 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (3)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { "" } - ::= { 1 4 } + DEFVAL { '00110001001100100011001100110100'B } + ::= { 1 5 3 } END """ @@ -563,101 +1634,195 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testStringDefvalSyntax(self): + def testStringDefvalStringSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeString1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalStringSyntax2(self): self.assertEqual( - self.ctx["testObjectType"].getSyntax(), b"test value", "bad DEFVAL" + self.ctx["testObjectTypeString2"].getSyntax(), b"a", "bad DEFVAL" ) - def testStringDefvalEmptySyntax(self): - self.assertEqual(self.ctx["testObjectTypeEmpty"].getSyntax(), b"", "bad DEFVAL") + def testStringDefvalStringSyntax3(self): + self.assertEqual( + self.ctx["testObjectTypeString3"].getSyntax(), b"ab", "bad DEFVAL" + ) + def testStringDefvalStringSyntax4(self): + self.assertEqual( + self.ctx["testObjectTypeString4"].getSyntax(), b"abc", "bad DEFVAL" + ) -class DefaultStringTextTestCase(unittest.TestCase): - R""" - TEST-MIB DEFINITIONS ::= BEGIN - IMPORTS - OBJECT-TYPE - FROM SNMPv2-SMI; + def testStringDefvalStringSyntaxIsValue5(self): + self.assertFalse( + self.ctx["testObjectTypeString5"].getSyntax().isValue, "bad DEFVAL" + ) - testObjectType OBJECT-TYPE - SYNTAX OCTET STRING - MAX-ACCESS read-only - STATUS current - DESCRIPTION "Test object" - DEFVAL { "\ntest - value\" } - ::= { 1 3 } + def testStringDefvalZeroStringSyntax1(self): + self.assertEqual( + self.ctx["testObjectTypeZeroString1"].getSyntax(), b"", "bad DEFVAL" + ) - END - """ + def testStringDefvalZeroStringSyntaxIsValue2(self): + self.assertFalse( + self.ctx["testObjectTypeZeroString2"].getSyntax().isValue, "bad DEFVAL" + ) - def setUp(self): - docstring = textwrap.dedent(self.__class__.__doc__) - ast = parserFactory()().parse(docstring)[0] - mibInfo, symtable = SymtableCodeGen().gen_code(ast, {}, genTexts=True) - self.mibInfo, pycode = PySnmpCodeGen().gen_code( - ast, {mibInfo.name: symtable}, genTexts=True + def testStringDefvalHexSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeHex1"].getSyntax().isValue, "bad DEFVAL" ) - codeobj = compile(pycode, "test", "exec") - self.ctx = {"mibBuilder": MibBuilder()} + def testStringDefvalHexSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeHex2"].getSyntax(), b"ABCD", "bad DEFVAL" + ) - exec(codeobj, self.ctx, self.ctx) + def testStringDefvalHexSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeHex3"].getSyntax().isValue, "bad DEFVAL" + ) - def testStringDefvalTextSyntax(self): + def testStringDefvalHexSyntax4(self): self.assertEqual( - self.ctx["testObjectType"].getSyntax(), - b"\\ntest\nvalue\\", - "bad DEFVAL", + self.ctx["testObjectTypeHex4"].getSyntax(), b"ABCDEF", "bad DEFVAL" ) + def testStringDefvalHexSyntaxIsValue5(self): + self.assertFalse( + self.ctx["testObjectTypeHex5"].getSyntax().isValue, "bad DEFVAL" + ) -class DefaultStringFormatTestCase(unittest.TestCase): + def testStringDefvalBinarySyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeBinary1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalBinarySyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeBinary2"].getSyntax(), b"123", "bad DEFVAL" + ) + + def testStringDefvalBinarySyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeBinary3"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultStringConstraintsLayersTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE - FROM SNMPv2-SMI; + FROM SNMPv2-SMI + TEXTUAL-CONVENTION + FROM SNMPv2-TC; - testObjectTypeDecimal OBJECT-TYPE - SYNTAX OCTET STRING + SimpleConstrainedString ::= OCTET STRING (SIZE (2 | 4)) + + testObjectTypeSimple1 OBJECT-TYPE + SYNTAX SimpleConstrainedString MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { 0 } - ::= { 1 3 } + DEFVAL { "ab" } + ::= { 1 3 1 } - testObjectTypeHex OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeSimple2 OBJECT-TYPE + SYNTAX SimpleConstrainedString MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { 'abCD'H } - ::= { 1 4 } + DEFVAL { "abc" } + ::= { 1 3 2 } - testObjectTypeBinary OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeSimple3 OBJECT-TYPE + SYNTAX SimpleConstrainedString MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '000100100011010001010110'B } - ::= { 1 5 } + DEFVAL { "abcd" } + ::= { 1 3 3 } - testObjectTypeSymbol OBJECT-TYPE - SYNTAX OCTET STRING + -- The extra constraints are not correct, as they are not a subset of the + -- original constraints, but pysmi should deal with them properly. + testObjectTypeLayeredSimple1 OBJECT-TYPE + SYNTAX SimpleConstrainedString (SIZE (1..2)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { testObjectTypeString } - ::= { 1 6 } + DEFVAL { "a" } + ::= { 1 3 4 } - testObjectTypeBrackets OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeLayeredSimple2 OBJECT-TYPE + SYNTAX SimpleConstrainedString (SIZE (1..2)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { { string } } - ::= { 1 7 } + DEFVAL { "ab" } + ::= { 1 3 5 } + + testObjectTypeLayeredSimple3 OBJECT-TYPE + SYNTAX SimpleConstrainedString (SIZE (1..2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "abcd" } + ::= { 1 3 6 } + + TextualConstrainedString ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION "Test TC" + SYNTAX OCTET STRING (SIZE (0..1)) + + testObjectTypeTextual1 OBJECT-TYPE + SYNTAX TextualConstrainedString + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "" } + ::= { 1 4 1 } + + testObjectTypeTextual2 OBJECT-TYPE + SYNTAX TextualConstrainedString + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "a" } + ::= { 1 4 2 } + + testObjectTypeTextual3 OBJECT-TYPE + SYNTAX TextualConstrainedString + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "ab" } + ::= { 1 4 3 } + + testObjectTypeLayeredTextual1 OBJECT-TYPE + SYNTAX TextualConstrainedString (SIZE (0 | 2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "" } + ::= { 1 4 4 } + + testObjectTypeLayeredTextual2 OBJECT-TYPE + SYNTAX TextualConstrainedString (SIZE (0 | 2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "a" } + ::= { 1 4 5 } + + testObjectTypeLayeredTextual3 OBJECT-TYPE + SYNTAX TextualConstrainedString (SIZE (0 | 2)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "ab" } + ::= { 1 4 6 } END """ @@ -674,90 +1839,169 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testStringDefvalDecimalSyntaxIsValue(self): + def testStringDefvalSimpleSyntax1(self): + self.assertEqual( + self.ctx["testObjectTypeSimple1"].getSyntax(), b"ab", "bad DEFVAL" + ) + + def testStringDefvalSimpleSyntaxIsValue2(self): self.assertFalse( - self.ctx["testObjectTypeDecimal"].getSyntax().isValue, "bad DEFVAL" + self.ctx["testObjectTypeSimple2"].getSyntax().isValue, "bad DEFVAL" ) - def testStringDefvalHexSyntax(self): + def testStringDefvalSimpleSyntax3(self): self.assertEqual( - self.ctx["testObjectTypeHex"].getSyntax(), - bytes((0xAB, 0xCD)), - "bad DEFVAL", + self.ctx["testObjectTypeSimple3"].getSyntax(), b"abcd", "bad DEFVAL" ) - def testStringDefvalBinarySyntax(self): + def testStringDefvalLayeredSimpleSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredSimple1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalLayeredSimpleSyntax2(self): self.assertEqual( - self.ctx["testObjectTypeBinary"].getSyntax(), - bytes((0x12, 0x34, 0x56)), - "bad DEFVAL", + self.ctx["testObjectTypeLayeredSimple2"].getSyntax(), b"ab", "bad DEFVAL" ) - def testStringDefvalSymbolSyntaxIsValue(self): + def testStringDefvalLayeredSimpleSyntaxIsValue3(self): self.assertFalse( - self.ctx["testObjectTypeSymbol"].getSyntax().isValue, "bad DEFVAL" + self.ctx["testObjectTypeLayeredSimple3"].getSyntax().isValue, "bad DEFVAL" ) - def testStringDefvalBracketsSyntaxIsValue(self): + def testStringDefvalTextualSyntax1(self): + self.assertEqual( + self.ctx["testObjectTypeTextual1"].getSyntax(), b"", "bad DEFVAL" + ) + + def testStringDefvalTextualSyntax2(self): + self.assertEqual( + self.ctx["testObjectTypeTextual2"].getSyntax(), b"a", "bad DEFVAL" + ) + + def testStringDefvalTextualSyntaxIsValue3(self): self.assertFalse( - self.ctx["testObjectTypeBrackets"].getSyntax().isValue, "bad DEFVAL" + self.ctx["testObjectTypeTextual3"].getSyntax().isValue, "bad DEFVAL" ) + def testStringDefvalLayeredTextualSyntax1(self): + self.assertEqual( + self.ctx["testObjectTypeLayeredTextual1"].getSyntax(), b"", "bad DEFVAL" + ) -class DefaultStringValueTestCase(unittest.TestCase): + def testStringDefvalLayeredTextualSyntaxIsValue2(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredTextual2"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalLayeredTextualSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeLayeredTextual3"].getSyntax().isValue, "bad DEFVAL" + ) + + +class DefaultStringConstraintsFormatTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; - testObjectTypeEmptyHex OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeHexFormat1 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('01'H..'02'H | '03'H)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { ''H } - ::= { 1 3 } + DEFVAL { "" } + ::= { 1 3 1 } - testObjectTypeEmptyBinary OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeHexFormat2 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('01'H..'02'H | '03'H)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { ''B } - ::= { 1 4 } + DEFVAL { "a" } + ::= { 1 3 2 } - testObjectTypePaddedHex OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeHexFormat3 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('01'H..'02'H | '03'H)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '00abCD'H } - ::= { 1 5 } + DEFVAL { "ab" } + ::= { 1 3 3 } - testObjectTypePaddedBinary OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeHexFormat4 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('01'H..'02'H | '03'H)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '0000000000000000000100100011010001010110'B } - ::= { 1 6 } + DEFVAL { "abc" } + ::= { 1 3 4 } - testObjectTypeUnpaddedHex OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeHexFormat5 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('01'H..'02'H | '03'H)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '789'H } - ::= { 1 7 } + DEFVAL { "abcd" } + ::= { 1 3 5 } - testObjectTypeUnpaddedBinary OBJECT-TYPE - SYNTAX OCTET STRING + testObjectTypeBinaryFormat1 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" - DEFVAL { '100100011'B } - ::= { 1 8 } + DEFVAL { "" } + ::= { 1 4 1 } + + testObjectTypeBinaryFormat2 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "a" } + ::= { 1 4 2 } + + testObjectTypeBinaryFormat3 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "ab" } + ::= { 1 4 3 } + + testObjectTypeBinaryFormat4 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "this is a tes" } + ::= { 1 4 4 } + + testObjectTypeBinaryFormat5 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "this is a test" } + ::= { 1 4 5 } + + testObjectTypeBinaryFormat6 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "this is a test!" } + ::= { 1 4 6 } + + testObjectTypeBinaryFormat7 OBJECT-TYPE + SYNTAX OCTET STRING (SIZE ('00000001'B | '00001110'B..'00001111'B)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION "Test object" + DEFVAL { "this is a test!?" } + ::= { 1 4 7 } END """ @@ -774,44 +2018,70 @@ def setUp(self): exec(codeobj, self.ctx, self.ctx) - def testStringDefvalEmptyHexSyntax(self): + def testStringDefvalHexFormatSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeHexFormat1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalHexFormatSyntax2(self): self.assertEqual( - self.ctx["testObjectTypeEmptyHex"].getSyntax(), bytes(), "bad DEFVAL" + self.ctx["testObjectTypeHexFormat2"].getSyntax(), b"a", "bad DEFVAL" ) - def testStringDefvalEmptyBinarySyntax(self): + def testStringDefvalHexFormatSyntax3(self): self.assertEqual( - self.ctx["testObjectTypeEmptyBinary"].getSyntax(), bytes(), "bad DEFVAL" + self.ctx["testObjectTypeHexFormat3"].getSyntax(), b"ab", "bad DEFVAL" ) - def testStringDefvalPaddedHexSyntax(self): + def testStringDefvalHexFormatSyntax4(self): self.assertEqual( - self.ctx["testObjectTypePaddedHex"].getSyntax(), - bytes((0x00, 0xAB, 0xCD)), - "bad DEFVAL", + self.ctx["testObjectTypeHexFormat4"].getSyntax(), b"abc", "bad DEFVAL" ) - def testStringDefvalPaddedBinarySyntax(self): + def testStringDefvalHexFormatSyntaxIsValue5(self): + self.assertFalse( + self.ctx["testObjectTypeHexFormat5"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalBinaryFormatSyntaxIsValue1(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat1"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalBinaryFormatSyntax2(self): self.assertEqual( - self.ctx["testObjectTypePaddedBinary"].getSyntax(), - bytes((0x00, 0x00, 0x12, 0x34, 0x56)), - "bad DEFVAL", + self.ctx["testObjectTypeBinaryFormat2"].getSyntax(), b"a", "bad DEFVAL" ) - def testStringDefvalUnpaddedHexSyntax(self): + def testStringDefvalBinaryFormatSyntaxIsValue3(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat3"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalBinaryFormatSyntaxIsValue4(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat4"].getSyntax().isValue, "bad DEFVAL" + ) + + def testStringDefvalBinaryFormatSyntax5(self): self.assertEqual( - self.ctx["testObjectTypeUnpaddedHex"].getSyntax(), - bytes((0x07, 0x89)), + self.ctx["testObjectTypeBinaryFormat5"].getSyntax(), + b"this is a test", "bad DEFVAL", ) - def testStringDefvalUnpaddedBinarySyntax(self): + def testStringDefvalBinaryFormatSyntax6(self): self.assertEqual( - self.ctx["testObjectTypeUnpaddedBinary"].getSyntax(), - bytes((0x01, 0x23)), + self.ctx["testObjectTypeBinaryFormat6"].getSyntax(), + b"this is a test!", "bad DEFVAL", ) + def testStringDefvalBinaryFormatSyntaxIsValue7(self): + self.assertFalse( + self.ctx["testObjectTypeBinaryFormat7"].getSyntax().isValue, "bad DEFVAL" + ) + class DefaultBitsTestCase(unittest.TestCase): """