diff --git a/py25/bacpypes/primitivedata.py b/py25/bacpypes/primitivedata.py index 83f4ebf..d00d9dd 100755 --- a/py25/bacpypes/primitivedata.py +++ b/py25/bacpypes/primitivedata.py @@ -92,17 +92,13 @@ class Tag(object): self.tagData = tdata def encode(self, pdu): - # check for special encoding of open and close tags - if (self.tagClass == Tag.openingTagClass): - pdu.put(((self.tagNumber & 0x0F) << 4) + 0x0E) - return - if (self.tagClass == Tag.closingTagClass): - pdu.put(((self.tagNumber & 0x0F) << 4) + 0x0F) - return - - # check for context encoding + # check for special encoding if (self.tagClass == Tag.contextTagClass): data = 0x08 + elif (self.tagClass == Tag.openingTagClass): + data = 0x0E + elif (self.tagClass == Tag.closingTagClass): + data = 0x0F else: data = 0x00 @@ -1051,7 +1047,7 @@ class Enumerated(Atomic): def encode(self, tag): if isinstance(self.value, int): value = long(self.value) - if isinstance(self.value, long): + elif isinstance(self.value, long): value = self.value elif isinstance(self.value, str): value = self._xlate_table[self.value] @@ -1084,7 +1080,7 @@ class Enumerated(Atomic): self.value = rslt def __str__(self): - return "Enumerated(%s)" % (self.value,) + return "%s(%s)" % (self.__class__.__name__, self.value) # # expand_enumerations @@ -1093,13 +1089,17 @@ class Enumerated(Atomic): def expand_enumerations(klass): # build a value dictionary xlateTable = {} - for name, value in klass.enumerations.items(): - # save the results - xlateTable[name] = value - xlateTable[value] = name - # save the name in the class - setattr(klass, name, value) + for c in klass.__mro__: + enumerations = getattr(c, 'enumerations', {}) + if enumerations: + for name, value in enumerations.items(): + # save the results + xlateTable[name] = value + xlateTable[value] = name + + # save the name in the class + setattr(klass, name, value) # save the dictionary in the class setattr(klass, '_xlate_table', xlateTable) @@ -1248,11 +1248,15 @@ class Time(Atomic): raise ValueError("invalid time pattern") tup_list = [] - for s in tup_match: + tup_items = list(tup_match.groups()) + for s in tup_items: if s == '*': tup_list.append(255) - elif s in None: - tup_list.append(0) + elif s is None: + if '*' in tup_items: + tup_list.append(255) + else: + tup_list.append(0) else: tup_list.append(int(s)) @@ -1393,12 +1397,12 @@ class ObjectIdentifier(Atomic): self.set_long(arg) elif isinstance(arg, tuple): self.set_tuple(*arg) + elif isinstance(arg, ObjectIdentifier): + self.value = arg.value else: raise TypeError("invalid constructor datatype") elif len(args) == 2: self.set_tuple(*args) - elif isinstance(arg, ObjectIdentifier): - self.value = arg.value else: raise ValueError("invalid constructor parameters") diff --git a/py27/bacpypes/primitivedata.py b/py27/bacpypes/primitivedata.py index c9464a6..d99fc69 100755 --- a/py27/bacpypes/primitivedata.py +++ b/py27/bacpypes/primitivedata.py @@ -92,17 +92,13 @@ class Tag(object): self.tagData = tdata def encode(self, pdu): - # check for special encoding of open and close tags - if (self.tagClass == Tag.openingTagClass): - pdu.put(((self.tagNumber & 0x0F) << 4) + 0x0E) - return - if (self.tagClass == Tag.closingTagClass): - pdu.put(((self.tagNumber & 0x0F) << 4) + 0x0F) - return - - # check for context encoding + # check for special encoding if (self.tagClass == Tag.contextTagClass): data = 0x08 + elif (self.tagClass == Tag.openingTagClass): + data = 0x0E + elif (self.tagClass == Tag.closingTagClass): + data = 0x0F else: data = 0x00 @@ -1051,7 +1047,7 @@ class Enumerated(Atomic): def encode(self, tag): if isinstance(self.value, int): value = long(self.value) - if isinstance(self.value, long): + elif isinstance(self.value, long): value = self.value elif isinstance(self.value, str): value = self._xlate_table[self.value] @@ -1084,7 +1080,7 @@ class Enumerated(Atomic): self.value = rslt def __str__(self): - return "Enumerated(%s)" % (self.value,) + return "%s(%s)" % (self.__class__.__name__, self.value) # # expand_enumerations @@ -1093,13 +1089,17 @@ class Enumerated(Atomic): def expand_enumerations(klass): # build a value dictionary xlateTable = {} - for name, value in klass.enumerations.items(): - # save the results - xlateTable[name] = value - xlateTable[value] = name - # save the name in the class - setattr(klass, name, value) + for c in klass.__mro__: + enumerations = getattr(c, 'enumerations', {}) + if enumerations: + for name, value in enumerations.items(): + # save the results + xlateTable[name] = value + xlateTable[value] = name + + # save the name in the class + setattr(klass, name, value) # save the dictionary in the class setattr(klass, '_xlate_table', xlateTable) @@ -1248,11 +1248,15 @@ class Time(Atomic): raise ValueError("invalid time pattern") tup_list = [] - for s in tup_match: + tup_items = list(tup_match.groups()) + for s in tup_items: if s == '*': tup_list.append(255) - elif s in None: - tup_list.append(0) + elif s is None: + if '*' in tup_items: + tup_list.append(255) + else: + tup_list.append(0) else: tup_list.append(int(s)) @@ -1393,12 +1397,12 @@ class ObjectIdentifier(Atomic): self.set_long(arg) elif isinstance(arg, tuple): self.set_tuple(*arg) + elif isinstance(arg, ObjectIdentifier): + self.value = arg.value else: raise TypeError("invalid constructor datatype") elif len(args) == 2: self.set_tuple(*args) - elif isinstance(arg, ObjectIdentifier): - self.value = arg.value else: raise ValueError("invalid constructor parameters") diff --git a/py34/bacpypes/primitivedata.py b/py34/bacpypes/primitivedata.py index 115fc06..1208cb3 100755 --- a/py34/bacpypes/primitivedata.py +++ b/py34/bacpypes/primitivedata.py @@ -92,17 +92,13 @@ class Tag(object): self.tagData = tdata def encode(self, pdu): - # check for special encoding of open and close tags - if (self.tagClass == Tag.openingTagClass): - pdu.put(((self.tagNumber & 0x0F) << 4) + 0x0E) - return - if (self.tagClass == Tag.closingTagClass): - pdu.put(((self.tagNumber & 0x0F) << 4) + 0x0F) - return - - # check for context encoding + # check for special encoding if (self.tagClass == Tag.contextTagClass): data = 0x08 + elif (self.tagClass == Tag.openingTagClass): + data = 0x0E + elif (self.tagClass == Tag.closingTagClass): + data = 0x0F else: data = 0x00 @@ -797,14 +793,15 @@ class CharacterString(Atomic): def __init__(self, arg=None): self.value = '' self.strEncoding = 0 - self.strValue = '' + self.strValue = b'' if arg is None: pass elif isinstance(arg, Tag): self.decode(arg) elif isinstance(arg, str): - self.strValue = self.value = arg + self.value = arg + self.strValue = arg.encode('utf-8') elif isinstance(arg, CharacterString): self.value = arg.value self.strEncoding = arg.strEncoding @@ -814,7 +811,7 @@ class CharacterString(Atomic): def encode(self, tag): # encode the tag - tag.set_app_data(Tag.characterStringAppTag, (chr(self.strEncoding)+self.strValue.encode('latin-1'))) + tag.set_app_data(Tag.characterStringAppTag, bytes([self.strEncoding]) + self.strValue) def decode(self, tag): if (tag.tagClass != Tag.applicationTagClass) or (tag.tagNumber != Tag.characterStringAppTag): @@ -829,26 +826,18 @@ class CharacterString(Atomic): # normalize the value if (self.strEncoding == 0): - udata = self.strValue.decode('utf-8') - self.value = str(udata) - #self.value = str(udata.encode('ascii', 'backslashreplace')) + self.value = self.strValue.decode('utf-8') elif (self.strEncoding == 3): - udata = self.strValue.decode('utf_32be') - self.value = str(udata) - #self.value = str(udata.encode('ascii', 'backslashreplace')) + self.value = self.strValue.decode('utf_32be') elif (self.strEncoding == 4): - udata = self.strValue.decode('utf_16be') - self.value = str(udata) - #self.value = str(udata.encode('ascii', 'backslashreplace')) + self.value = self.strValue.decode('utf_16be') elif (self.strEncoding == 5): - udata = self.strValue.decode('latin_1') - self.value = str(udata) - #self.value = str(udata.encode('ascii', 'backslashreplace')) + self.value = self.strValue.decode('latin_1') else: self.value = '### unknown encoding: %d ###' % (self.strEncoding,) def __str__(self): - return "CharacterString(%d," % (self.strEncoding,) + repr(self.strValue) + ")" + return "CharacterString(%d," % (self.strEncoding,) + repr(self.value) + ")" # # BitString @@ -1102,7 +1091,7 @@ class Enumerated(Atomic): self.value = rslt def __str__(self): - return "Enumerated(%s)" % (self.value,) + return "%s(%s)" % (self.__class__.__name__, self.value) # # expand_enumerations @@ -1111,13 +1100,17 @@ class Enumerated(Atomic): def expand_enumerations(klass): # build a value dictionary xlateTable = {} - for name, value in klass.enumerations.items(): - # save the results - xlateTable[name] = value - xlateTable[value] = name - # save the name in the class - setattr(klass, name, value) + for c in klass.__mro__: + enumerations = getattr(c, 'enumerations', {}) + if enumerations: + for name, value in enumerations.items(): + # save the results + xlateTable[name] = value + xlateTable[value] = name + + # save the name in the class + setattr(klass, name, value) # save the dictionary in the class setattr(klass, '_xlate_table', xlateTable) @@ -1266,11 +1259,15 @@ class Time(Atomic): raise ValueError("invalid time pattern") tup_list = [] - for s in tup_match: + tup_items = list(tup_match.groups()) + for s in tup_items: if s == '*': tup_list.append(255) - elif s in None: - tup_list.append(0) + elif s is None: + if '*' in tup_items: + tup_list.append(255) + else: + tup_list.append(0) else: tup_list.append(int(s)) @@ -1409,12 +1406,12 @@ class ObjectIdentifier(Atomic): self.set_long(arg) elif isinstance(arg, tuple): self.set_tuple(*arg) + elif isinstance(arg, ObjectIdentifier): + self.value = arg.value else: raise TypeError("invalid constructor datatype") elif len(args) == 2: self.set_tuple(*args) - elif isinstance(arg, ObjectIdentifier): - self.value = arg.value else: raise ValueError("invalid constructor parameters") diff --git a/setup.py b/setup.py index b325225..3380a8f 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ test_requirements = [ setup( name='bacpypes', - version="0.13.1", + version="0.13.2", description="Testing multiple versions of python", long_description="This is a long line of text", author="Joel Bender", diff --git a/tests/test_primitive_data/test_bit_string.py b/tests/test_primitive_data/test_bit_string.py index e69de29..e874ebc 100644 --- a/tests/test_primitive_data/test_bit_string.py +++ b/tests/test_primitive_data/test_bit_string.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Bit String +------------------------- +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import BitString, Tag + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +class SampleBitString(BitString): + bitLen = 13 + bitNames = { + 'b0': 0, + 'b1': 1, + 'b4': 4, + 'b7': 7, + 'b8': 8, + 'b12': 12, + } + + +@bacpypes_debugging +def bit_string_tag(x): + """Convert a hex string to an bit_string application tag.""" + if _debug: bit_string_tag._debug("bit_string_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.bitStringAppTag, len(b), b) + if _debug: bit_string_endec._debug(" - tag: %r", tag) + + return tag + +@bacpypes_debugging +def bit_string_encode(obj): + """Encode an BitString object into a tag.""" + if _debug: bit_string_encode._debug("bit_string_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: bit_string_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def bit_string_decode(tag): + """Decode an bit_string application tag into an bit_string.""" + if _debug: bit_string_decode._debug("bit_string_decode %r", tag) + + obj = BitString(tag) + if _debug: bit_string_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def bit_string_endec(v, x): + """Pass the value to BitString, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: bit_string_endec._debug("bit_string_endec %r %r", v, x) + + tag = bit_string_tag(x) + if _debug: bit_string_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = BitString(v) + if _debug: bit_string_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert bit_string_encode(obj) == tag + assert bit_string_decode(tag) == obj + + +@bacpypes_debugging +class TestBitString(unittest.TestCase): + + def test_bit_string(self): + if _debug: TestBitString._debug("test_bit_string") + + obj = BitString() + assert obj.value == [] + assert str(obj) == "BitString()" + + obj = BitString([0]) + assert obj.value == [0] + assert str(obj) == "BitString(0)" + + obj = BitString([0, 1]) + assert obj.value == [0, 1] + assert str(obj) == "BitString(0,1)" + + with self.assertRaises(TypeError): + BitString("some string") + with self.assertRaises(TypeError): + BitString(1.0) + + def test_bit_string_sample(self): + if _debug: TestBitString._debug("test_bit_string_sample") + + obj = SampleBitString() + assert obj.value == [0] * SampleBitString.bitLen + + obj = SampleBitString([1]) + assert str(obj) == "BitString(b0)" + + obj = SampleBitString(['b4']) + assert str(obj) == "BitString(!b0,!b1,0,0,b4,0,0,!b7,!b8,0,0,0,!b12)" + + with self.assertRaises(TypeError): + SampleBitString(["x1"]) + + def test_bit_string_tag(self): + if _debug: TestBitString._debug("test_bit_string_tag") + + tag = Tag(Tag.applicationTagClass, Tag.bitStringAppTag, 1, xtob('08')) + obj = BitString(tag) + if _debug: TestBitString._debug(" - obj.value: %r", obj.value) + assert obj.value == [] + + tag = Tag(Tag.applicationTagClass, Tag.bitStringAppTag, 2, xtob('0102')) + obj = BitString(tag) + if _debug: TestBitString._debug(" - obj.value: %r", obj.value) + assert obj.value == [0, 0, 0, 0, 0, 0, 1] + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + BitString(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + BitString(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + BitString(tag) + + def test_bit_string_copy(self): + if _debug: TestBitString._debug("test_bit_string_copy") + + sample_value = [0, 1, 0, 1] + obj1 = BitString(sample_value) + obj2 = BitString(obj1) + assert obj2.value == sample_value + + def test_bit_string_endec(self): + if _debug: TestBitString._debug("test_bit_string_endec") + + bit_string_endec([], '00') + bit_string_endec([0], '0700') + bit_string_endec([1], '0780') + bit_string_endec([0] * 2, '0600') + bit_string_endec([1] * 2, '06c0') + bit_string_endec([0] * 10, '060000') + bit_string_endec([1] * 10, '06ffc0') + diff --git a/tests/test_primitive_data/test_character_string.py b/tests/test_primitive_data/test_character_string.py index e69de29..bfede20 100644 --- a/tests/test_primitive_data/test_character_string.py +++ b/tests/test_primitive_data/test_character_string.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data Character String +------------------------------------ +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import CharacterString, Tag, DecodingError + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +# globals +fox_message = "the quick brown fox jumped over the lazy dog" + +@bacpypes_debugging +def character_string_tag(x): + """Convert a hex string to an character_string application tag.""" + if _debug: character_string_tag._debug("character_string_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.characterStringAppTag, len(b), b) + if _debug: character_string_endec._debug(" - tag: %r", tag) + + return tag + +@bacpypes_debugging +def character_string_encode(obj): + """Encode an CharacterString object into a tag.""" + if _debug: character_string_encode._debug("character_string_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: character_string_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def character_string_decode(tag): + """Decode an character_string application tag into an character_string.""" + if _debug: character_string_decode._debug("character_string_decode %r", tag) + + obj = CharacterString(tag) + if _debug: character_string_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def character_string_endec(v, x): + """Pass the value to CharacterString, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: character_string_endec._debug("character_string_endec %r %r", v, x) + + tag = character_string_tag(x) + if _debug: character_string_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = CharacterString(v) + if _debug: character_string_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert character_string_encode(obj) == tag + assert character_string_decode(tag) == obj + + +@bacpypes_debugging +class TestCharacterString(unittest.TestCase): + + def test_character_string(self): + if _debug: TestCharacterString._debug("test_character_string") + + obj = CharacterString() + assert obj.value == '' + + with self.assertRaises(TypeError): + CharacterString(1) + with self.assertRaises(TypeError): + CharacterString(1.0) + + def test_character_string_str(self): + if _debug: TestCharacterString._debug("test_character_string_str") + + obj = CharacterString("hello") + assert obj.value == "hello" + assert str(obj) == "CharacterString(0,'hello')" + + def test_character_string_tag(self): + if _debug: TestCharacterString._debug("test_character_string_tag") + + tag = Tag(Tag.applicationTagClass, Tag.characterStringAppTag, 1, xtob('00')) + obj = CharacterString(tag) + assert obj.value == '' + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + CharacterString(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + CharacterString(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + CharacterString(tag) + + def test_character_string_copy(self): + if _debug: TestCharacterString._debug("test_character_string_copy") + + obj1 = CharacterString(fox_message) + obj2 = CharacterString(obj1) + assert obj2.value == fox_message + + def test_character_string_endec(self): + if _debug: TestCharacterString._debug("test_character_string_endec") + +# with self.assertRaises(DecodingError): +# obj = CharacterString(character_string_tag('')) + + character_string_endec("", '00') + character_string_endec("abc", '00616263') diff --git a/tests/test_primitive_data/test_date.py b/tests/test_primitive_data/test_date.py index e69de29..e704ed4 100644 --- a/tests/test_primitive_data/test_date.py +++ b/tests/test_primitive_data/test_date.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data Date +--------------------------- +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import Date, Tag, DecodingError + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +@bacpypes_debugging +def date_tag(x): + """Convert a hex string to an date application tag.""" + if _debug: date_tag._debug("date_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.dateAppTag, len(b), b) + if _debug: date_endec._debug(" - tag: %r", tag) + + return tag + +@bacpypes_debugging +def date_encode(obj): + """Encode an Date object into a tag.""" + if _debug: date_encode._debug("date_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: date_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def date_decode(tag): + """Decode an date application tag into an date.""" + if _debug: date_decode._debug("date_decode %r", tag) + + obj = Date(tag) + if _debug: date_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def date_endec(v, x): + """Pass the value to Date, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: date_endec._debug("date_endec %r %r", v, x) + + tag = date_tag(x) + if _debug: date_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = Date(v) + if _debug: date_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert date_encode(obj) == tag + assert date_decode(tag) == obj + + +@bacpypes_debugging +class TestDate(unittest.TestCase): + + def test_date(self): + if _debug: TestDate._debug("test_date") + + # default values is all dont care + obj = Date() + assert obj.value == (255, 255, 255, 255) + + with self.assertRaises(ValueError): + Date("some string") + with self.assertRaises(TypeError): + Date(1.0) + + def test_date_tuple(self): + if _debug: TestDate._debug("test_date_tuple") + + obj = Date((1,2,3,4)) + assert obj.value == (1, 2, 3, 4) + assert str(obj) == "Date(2/3/1901 Thu)" + + ### issue-48 + # obj = Date("1/2/3") + # assert obj.value == (1, 2, x, y) + + # obj = Date("*/2/3") + # assert obj.value == (255, 2, x, 255) + + # obj = Date("1/*/3") + # assert obj.value == (1, 255, x, 255) + + # obj = Date("1/2/*") + # assert obj.value == (1, 2, 255, 255) + + # obj = Date("1/2/3 *") + # assert obj.value == (1, 2, 3, 255) + + def test_date_tag(self): + if _debug: TestDate._debug("test_date_tag") + + tag = Tag(Tag.applicationTagClass, Tag.dateAppTag, 1, xtob('01020304')) + obj = Date(tag) + assert obj.value == (1, 2, 3, 4) + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + Date(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + Date(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + Date(tag) + + def test_date_copy(self): + if _debug: TestDate._debug("test_date_copy") + + date_value = (2, 3, 4, 5) + obj1 = Date(date_value) + obj2 = Date(obj1) + assert obj2.value == date_value + + def test_date_now(self): + if _debug: TestDate._debug("test_date_now") + + # obj = Date().now() + ### how to test? + + def test_date_endec(self): + if _debug: TestDate._debug("test_date_endec") + +# with self.assertRaises(DecodingError): +# obj = Date(date_tag('')) + + date_endec((0, 0, 0, 0), '00000000') + date_endec((1, 0, 0, 0), '01000000') + date_endec((0, 2, 0, 0), '00020000') + date_endec((0, 0, 3, 0), '00000300') + date_endec((0, 0, 0, 4), '00000004') diff --git a/tests/test_primitive_data/test_double.py b/tests/test_primitive_data/test_double.py index 04a66e1..e35e45a 100644 --- a/tests/test_primitive_data/test_double.py +++ b/tests/test_primitive_data/test_double.py @@ -11,7 +11,7 @@ import struct import math from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob -from bacpypes.primitivedata import Double, Tag +from bacpypes.primitivedata import Double, Tag, DecodingError # some debugging _debug = 0 @@ -126,8 +126,8 @@ class TestDouble(unittest.TestCase): def test_double_endec(self): if _debug: TestDouble._debug("test_double_endec") - with self.assertRaises(struct.error): - obj = Double(double_tag('')) +# with self.assertRaises(DecodingError): +# obj = Double(double_tag('')) double_endec(0, '0000000000000000') double_endec(1, '3ff0000000000000') diff --git a/tests/test_primitive_data/test_enumerated.py b/tests/test_primitive_data/test_enumerated.py index e69de29..dd1534d 100644 --- a/tests/test_primitive_data/test_enumerated.py +++ b/tests/test_primitive_data/test_enumerated.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data Enumerated +------------------------------ +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import Enumerated, Tag, DecodingError + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +@bacpypes_debugging +def enumerated_tag(x): + """Convert a hex string to an enumerated application tag.""" + if _debug: enumerated_tag._debug("enumerated_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.enumeratedAppTag, len(b), b) + if _debug: enumerated_endec._debug(" - tag: %r", tag) + + return tag + +@bacpypes_debugging +def enumerated_encode(obj): + """Encode an Enumerated object into a tag.""" + if _debug: enumerated_encode._debug("enumerated_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: enumerated_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def enumerated_decode(tag): + """Decode an enumerated application tag into an enumerated.""" + if _debug: enumerated_decode._debug("enumerated_decode %r", tag) + + obj = Enumerated(tag) + if _debug: enumerated_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def enumerated_endec(v, x): + """Pass the value to Enumerated, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: enumerated_endec._debug("enumerated_endec %r %r", v, x) + + tag = enumerated_tag(x) + if _debug: enumerated_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = Enumerated(v) + if _debug: enumerated_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert enumerated_encode(obj) == tag + assert enumerated_decode(tag) == obj + + +@bacpypes_debugging +class TestEnumerated(unittest.TestCase): + + def test_enumerated(self): + if _debug: TestEnumerated._debug("test_enumerated") + + obj = Enumerated() + assert obj.value == 0 + + with self.assertRaises(ValueError): + Enumerated("label") + with self.assertRaises(TypeError): + Enumerated(1.0) + + def test_enumerated_int(self): + if _debug: TestEnumerated._debug("test_enumerated_int") + + obj = Enumerated(1) + assert obj.value == 1 + assert str(obj) == "Enumerated(1)" + + with self.assertRaises(ValueError): + Enumerated(-1) + + def test_enumerated_tag(self): + if _debug: TestEnumerated._debug("test_enumerated_tag") + + tag = Tag(Tag.applicationTagClass, Tag.enumeratedAppTag, 1, xtob('01')) + obj = Enumerated(tag) + assert obj.value == 1 + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + Enumerated(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + Enumerated(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + Enumerated(tag) + + def test_enumerated_copy(self): + if _debug: TestEnumerated._debug("test_enumerated_copy") + + obj1 = Enumerated(12) + obj2 = Enumerated(obj1) + assert obj2.value == 12 + + def test_enumerated_endec(self): + if _debug: TestEnumerated._debug("test_enumerated_endec") + +# with self.assertRaises(DecodingError): +# obj = Enumerated(enumerated_tag('')) + + enumerated_endec(0, '00') + enumerated_endec(1, '01') + enumerated_endec(127, '7f') + enumerated_endec(128, '80') + enumerated_endec(255, 'ff') + + enumerated_endec(32767, '7fff') + enumerated_endec(32768, '8000') + + enumerated_endec(8388607, '7fffff') + enumerated_endec(8388608, '800000') + + enumerated_endec(2147483647, '7fffffff') + enumerated_endec(2147483648, '80000000') diff --git a/tests/test_primitive_data/test_integer.py b/tests/test_primitive_data/test_integer.py index fde04f0..73a1c54 100644 --- a/tests/test_primitive_data/test_integer.py +++ b/tests/test_primitive_data/test_integer.py @@ -9,7 +9,7 @@ Test Primitive Data Integer import unittest from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob -from bacpypes.primitivedata import Integer, Tag +from bacpypes.primitivedata import Integer, Tag, DecodingError # some debugging _debug = 0 @@ -120,8 +120,8 @@ class TestInteger(unittest.TestCase): def test_integer_endec(self): if _debug: TestInteger._debug("test_integer_endec") - with self.assertRaises(IndexError): - obj = Integer(integer_tag('')) +# with self.assertRaises(DecodingError): +# obj = Integer(integer_tag('')) integer_endec(0, '00') integer_endec(1, '01') diff --git a/tests/test_primitive_data/test_object_identifier.py b/tests/test_primitive_data/test_object_identifier.py index e69de29..c1102eb 100644 --- a/tests/test_primitive_data/test_object_identifier.py +++ b/tests/test_primitive_data/test_object_identifier.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data Object Identifier +------------------------------------- +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import ObjectIdentifier, Tag, DecodingError + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +@bacpypes_debugging +def object_identifier_tag(x): + """Convert a hex string to an object_identifier application tag.""" + if _debug: object_identifier_tag._debug("object_identifier_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.objectIdentifierAppTag, len(b), b) + if _debug: object_identifier_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def object_identifier_encode(obj): + """Encode an ObjectIdentifier object into a tag.""" + if _debug: object_identifier_encode._debug("object_identifier_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: object_identifier_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def object_identifier_decode(tag): + """Decode an object_identifier application tag into an object_identifier.""" + if _debug: object_identifier_decode._debug("object_identifier_decode %r", tag) + + obj = ObjectIdentifier(tag) + if _debug: object_identifier_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def object_identifier_endec(v, x): + """Pass the value to ObjectIdentifier, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: object_identifier_endec._debug("object_identifier_endec %r %r", v, x) + + tag = object_identifier_tag(x) + if _debug: object_identifier_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = ObjectIdentifier(v) + if _debug: object_identifier_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert object_identifier_encode(obj) == tag + assert object_identifier_decode(tag) == obj + + +@bacpypes_debugging +class TestObjectIdentifier(unittest.TestCase): + + def test_object_identifier(self): + if _debug: TestObjectIdentifier._debug("test_object_identifier") + + obj = ObjectIdentifier() + assert obj.value == ('analogInput', 0) + + with self.assertRaises(TypeError): + ObjectIdentifier("some string") + with self.assertRaises(TypeError): + ObjectIdentifier(1.0) + + def test_object_identifier_int(self): + if _debug: TestObjectIdentifier._debug("test_object_identifier_int") + + obj = ObjectIdentifier(1) + assert obj.value == ('analogInput', 1) + assert str(obj) == "ObjectIdentifier(analogInput,1)" + + obj = ObjectIdentifier(0x0400002) + assert obj.value == ('analogOutput', 2) + assert str(obj) == "ObjectIdentifier(analogOutput,2)" + + def test_object_identifier_tag(self): + if _debug: TestObjectIdentifier._debug("test_object_identifier_tag") + + tag = Tag(Tag.applicationTagClass, Tag.objectIdentifierAppTag, 1, xtob('06000003')) + obj = ObjectIdentifier(tag) + assert obj.value == ('pulseConverter', 3) + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + ObjectIdentifier(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + ObjectIdentifier(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + ObjectIdentifier(tag) + + def test_object_identifier_copy(self): + if _debug: TestObjectIdentifier._debug("test_object_identifier_copy") + + obj1 = ObjectIdentifier(('analogInput', 1)) + obj2 = ObjectIdentifier(obj1) + assert obj2.value == ('analogInput', 1) + + def test_object_identifier_endec(self): + if _debug: TestObjectIdentifier._debug("test_object_identifier_endec") + + ### this should raise a DecodingError + # with self.assertRaises(DecodingError): + # obj = ObjectIdentifier(object_identifier_tag('')) + + # test standard types + object_identifier_endec(('analogInput', 0), '00000000') + + # test vendor types diff --git a/tests/test_primitive_data/test_object_type.py b/tests/test_primitive_data/test_object_type.py index e69de29..648d627 100644 --- a/tests/test_primitive_data/test_object_type.py +++ b/tests/test_primitive_data/test_object_type.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data ObjectType +------------------------------ +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import ObjectType, Tag, DecodingError, \ + expand_enumerations + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +class MyObjectType(ObjectType): + enumerations = { + 'myAnalogInput': 128, + 'myAnalogOutput': 129, + 'myAnalogValue': 130, + } + +expand_enumerations(MyObjectType) + + +@bacpypes_debugging +def object_type_tag(x): + """Convert a hex string to an enumerated application tag.""" + if _debug: object_type_tag._debug("object_type_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.enumeratedAppTag, len(b), b) + if _debug: object_type_endec._debug(" - tag: %r", tag) + + return tag + +@bacpypes_debugging +def object_type_encode(obj): + """Encode an ObjectType object into a tag.""" + if _debug: object_type_encode._debug("object_type_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: object_type_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def object_type_decode(tag): + """Decode an enumerated application tag into an object_type.""" + if _debug: object_type_decode._debug("object_type_decode %r", tag) + + obj = ObjectType(tag) + if _debug: object_type_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def object_type_endec(v, x): + """Pass the value to ObjectType, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: object_type_endec._debug("object_type_endec %r %r", v, x) + + tag = object_type_tag(x) + if _debug: object_type_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = ObjectType(v) + if _debug: object_type_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert object_type_encode(obj) == tag + assert object_type_decode(tag) == obj + + +@bacpypes_debugging +class TestObjectType(unittest.TestCase): + + def test_object_type(self): + if _debug: TestObjectType._debug("test_object_type") + + obj = ObjectType() + assert obj.value == 0 + + with self.assertRaises(ValueError): + ObjectType("unknownType") + with self.assertRaises(TypeError): + ObjectType(1.0) + + def test_object_type_int(self): + if _debug: TestObjectType._debug("test_object_type_int") + + # known values are translated into strings + obj = ObjectType(0) + assert obj.value == 'analogInput' + assert str(obj) == "ObjectType(analogInput)" + + # unknown values are kept as integers + obj = ObjectType(127) + assert obj.value == 127 + assert str(obj) == "ObjectType(127)" + + def test_object_type_str(self): + if _debug: TestObjectType._debug("test_object_type_str") + + # known strings are accepted + obj = ObjectType('analogInput') + assert obj.value == 'analogInput' + + def test_extended_object_type_int(self): + if _debug: TestObjectType._debug("test_extended_object_type_int") + + # known values are translated into strings + obj = MyObjectType(0) + assert obj.value == 'analogInput' + assert str(obj) == "MyObjectType(analogInput)" + + # unknown values are kept as integers + obj = MyObjectType(128) + assert obj.value == 'myAnalogInput' + assert str(obj) == "MyObjectType(myAnalogInput)" + + def test_extended_object_type_str(self): + if _debug: TestObjectType._debug("test_extended_object_type_str") + + # known strings are accepted + obj = MyObjectType('myAnalogInput') + assert obj.value == 'myAnalogInput' + + # unknown strings are rejected + with self.assertRaises(ValueError): + MyObjectType('snork') + + def test_object_type_tag(self): + if _debug: TestObjectType._debug("test_object_type_tag") + + tag = Tag(Tag.applicationTagClass, Tag.enumeratedAppTag, 1, xtob('01')) + obj = ObjectType(tag) + assert obj.value == 'analogOutput' + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + ObjectType(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + ObjectType(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + ObjectType(tag) + + def test_object_type_copy(self): + if _debug: TestObjectType._debug("test_object_type_copy") + + # known values are translated into strings + obj1 = ObjectType(12) + obj2 = ObjectType(obj1) + assert obj2.value == 'loop' + + def test_object_type_endec(self): + if _debug: TestObjectType._debug("test_object_type_endec") + +# with self.assertRaises(DecodingError): +# obj = ObjectType(object_type_tag('')) + + object_type_endec('analogInput', '00') + object_type_endec('analogOutput', '01') + + object_type_endec(127, '7f') + object_type_endec(128, '80') diff --git a/tests/test_primitive_data/test_real.py b/tests/test_primitive_data/test_real.py index 7f14710..c0758d2 100644 --- a/tests/test_primitive_data/test_real.py +++ b/tests/test_primitive_data/test_real.py @@ -11,7 +11,7 @@ import struct import math from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob -from bacpypes.primitivedata import Real, Tag +from bacpypes.primitivedata import Real, Tag, DecodingError # some debugging _debug = 0 @@ -127,8 +127,8 @@ class TestReal(unittest.TestCase): def test_real_endec(self): if _debug: TestReal._debug("test_real_endec") - with self.assertRaises(struct.error): - obj = Real(real_tag('')) +# with self.assertRaises(DecodingError): +# obj = Real(real_tag('')) real_endec(0, '00000000') real_endec(1, '3f800000') diff --git a/tests/test_primitive_data/test_tag.py b/tests/test_primitive_data/test_tag.py index e69de29..1bcfa84 100644 --- a/tests/test_primitive_data/test_tag.py +++ b/tests/test_primitive_data/test_tag.py @@ -0,0 +1,595 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data Tag +----------------------- +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob, btox +from bacpypes.primitivedata import Tag, ApplicationTag, ContextTag, \ + OpeningTag, ClosingTag, TagList, \ + Null, Boolean, Unsigned, Integer, Real, Double, OctetString, \ + CharacterString, BitString, Enumerated, Date, Time, ObjectIdentifier, \ + DecodingError +from bacpypes.pdu import PDUData + + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +def tag_tuple(tag): + """Simple function to decompose a tag for debugging.""" + return (tag.tagClass, tag.tagNumber, tag.tagLVT, tag.tagData) + + +@bacpypes_debugging +def IntegerTag(v): + """Return an application encoded integer tag with the appropriate value. + """ + obj = Integer(v) + tag = Tag() + obj.encode(tag) + return tag + + +@bacpypes_debugging +def obj_decode(blob): + """Build PDU from the string, decode the tag, convert to an object.""" + if _debug: obj_decode._debug("obj_decode %r", blob) + + data = PDUData(blob) + tag = Tag(data) + obj = tag.app_to_object() + return obj + + +@bacpypes_debugging +def obj_encode(obj): + """Encode the object into a tag, encode it in a PDU, return the data.""" + if _debug: obj_encode._debug("obj_encode %r", obj) + + tag = Tag() + obj.encode(tag) + data = PDUData() + tag.encode(data) + return data.pduData + + +@bacpypes_debugging +def obj_endec(obj, x): + """Convert the value (a primitive object) to a hex encoded string, + convert the hex encoded string to and object, and compare the results to + each other.""" + if _debug: obj_endec._debug("obj_endec %r %r", obj, x) + + # convert the hex string to a blob + blob = xtob(x) + + # decode the blob into an object + obj2 = obj_decode(blob) + if _debug: obj_endec._debug(" - obj: %r, %r", obj, obj.value) + + # encode the object into a blob + blob2 = obj_encode(obj) + if _debug: obj_endec._debug(" - blob2: %r", blob2) + + # compare the results + assert obj == obj2 + assert blob == blob2 + + +@bacpypes_debugging +def context_decode(blob): + """Build PDU from the string, decode the tag, convert to an object.""" + if _debug: context_decode._debug("context_decode %r", blob) + + data = PDUData(blob) + tag = ContextTag(data) + return tag + + +@bacpypes_debugging +def context_encode(tag): + """Encode the object into a tag, encode it in a PDU, return the data.""" + if _debug: context_encode._debug("context_encode %r", tag) + + data = PDUData() + tag.encode(data) + return data.pduData + + +@bacpypes_debugging +def context_endec(tnum, x, y): + """Convert the value (a primitive object) to a hex encoded string, + convert the hex encoded string to and object, and compare the results to + each other.""" + if _debug: context_endec._debug("context_endec %r %r %r", tnum, x, y) + + # convert the hex strings to a blobs + tdata = xtob(x) + blob1 = xtob(y) + + # make a context tag + tag1 = ContextTag(tnum, tdata) + + # decode the blob into a tag + tag2 = context_decode(blob1) + if _debug: context_endec._debug(" - tag: %r", tag) + + # encode the tag into a blob + blob2 = context_encode(tag1) + if _debug: context_endec._debug(" - blob2: %r", blob2) + + # compare the results + assert tag1 == tag2 + assert blob1 == blob2 + + +@bacpypes_debugging +def opening_decode(blob): + """Build PDU from the string, decode the tag, convert to an object.""" + if _debug: opening_decode._debug("opening_decode %r", blob) + + data = PDUData(blob) + tag = OpeningTag(data) + return tag + + +@bacpypes_debugging +def opening_encode(tag): + """Encode the object into a tag, encode it in a PDU, return the data.""" + if _debug: opening_encode._debug("opening_encode %r", tag) + + data = PDUData() + tag.encode(data) + return data.pduData + + +@bacpypes_debugging +def opening_endec(tnum, x): + """Convert the value (a primitive object) to a hex encoded string, + convert the hex encoded string to and object, and compare the results to + each other.""" + if _debug: opening_endec._debug("opening_endec %r %r", tnum, x) + + # convert the hex string to a blob + blob1 = xtob(x) + + # make a context tag + tag1 = OpeningTag(tnum) + if _debug: opening_endec._debug(" - tag1: %r", tag1) + + # decode the blob into a tag + tag2 = opening_decode(blob1) + if _debug: opening_endec._debug(" - tag2: %r", tag2) + + # encode the tag into a blob + blob2 = opening_encode(tag1) + if _debug: opening_endec._debug(" - blob2: %r", blob2) + + # compare the results + assert tag1 == tag2 + assert blob1 == blob2 + + +@bacpypes_debugging +def closing_decode(blob): + """Build PDU from the string, decode the tag, convert to an object.""" + if _debug: closing_decode._debug("closing_decode %r", blob) + + data = PDUData(blob) + tag = ClosingTag(data) + return tag + + +@bacpypes_debugging +def closing_encode(tag): + """Encode the object into a tag, encode it in a PDU, return the data.""" + if _debug: closing_encode._debug("closing_encode %r", tag) + + data = PDUData() + tag.encode(data) + return data.pduData + + +@bacpypes_debugging +def closing_endec(tnum, x): + """Convert the value (a primitive object) to a hex encoded string, + convert the hex encoded string to and object, and compare the results to + each other.""" + if _debug: closing_endec._debug("closing_endec %r %r", tnum, x) + + # convert the hex string to a blob + blob1 = xtob(x) + + # make a context tag + tag1 = ClosingTag(tnum) + if _debug: closing_endec._debug(" - tag1: %r", tag1) + + # decode the blob into a tag + tag2 = closing_decode(blob1) + if _debug: closing_endec._debug(" - tag2: %r", tag2) + + # encode the tag into a blob + blob2 = closing_encode(tag1) + if _debug: closing_endec._debug(" - blob2: %r", blob2) + + # compare the results + assert tag1 == tag2 + assert blob1 == blob2 + + +@bacpypes_debugging +def tag(tag_class, tag_number, x): + """Create a tag object with the given class, number, and data.""" + if _debug: tag._debug("tag %r %r %r", tag_class, tag_number, x) + + b = xtob(x) + tag = Tag(tag_class, tag_number, len(b), b) + if _debug: tag_tuple._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +class TestTag(unittest.TestCase): + + def test_tag(self): + if _debug: TestTag._debug("test_tag") + + # test tag construction + tag = Tag() + assert (tag.tagClass, tag.tagNumber) == (None, None) + + # must have a valid encoded tag to extract from the data + data = PDUData(xtob('')) + with self.assertRaises(DecodingError): + tag = Tag(data) + + # must have two values, class and number + with self.assertRaises(ValueError): + tag = Tag(0) + + tag = Tag(0, 1) + assert (tag.tagClass, tag.tagNumber) == (0, 1) + + tag = Tag(0, 1, 2) + assert (tag.tagClass, tag.tagNumber, tag.tagLVT) == (0, 1, 2) + + # tag data must be bytes or bytearray + with self.assertRaises(TypeError): + tag = Tag(0, 1, 2, 3) + +@bacpypes_debugging +class TestApplicationTag(unittest.TestCase): + + def test_application_tag(self): + if _debug: TestApplicationTag._debug("test_application_tag") + + # application tag construction, encoding, and decoding + tag = ApplicationTag(0, xtob('')) + if _debug: TestApplicationTag._debug(" - tag: %r", tag_tuple(tag)) + + with self.assertRaises(ValueError): + tag = ApplicationTag(0) + + def test_generic_application_to_context(self): + if _debug: TestApplicationTag._debug("test_generic_application_to_context") + + # create an application + tag = ApplicationTag(0, xtob('01')) + if _debug: TestApplicationTag._debug(" - tag: %r", tag_tuple(tag)) + + # convert it to context tagged, context 0 + ctag = tag.app_to_context(0) + if _debug: TestApplicationTag._debug(" - ctag: %r", tag_tuple(ctag)) + + # create a context tag with the same shape + ttag = ContextTag(0, xtob('01')) + if _debug: TestApplicationTag._debug(" - ttag: %r", tag_tuple(ttag)) + + # check to see they are the same + assert ctag == ttag + + # convert the context tag back to an application tag + dtag = ctag.context_to_app(0) + if _debug: TestApplicationTag._debug(" - dtag: %r", tag_tuple(dtag)) + + # check to see it round-tripped + assert dtag == tag + + def test_boolean_application_to_context(self): + if _debug: TestApplicationTag._debug("test_boolean_application_to_context") + + # create an application + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0) + if _debug: TestApplicationTag._debug(" - tag: %r", tag_tuple(tag)) + + # convert it to context tagged, context 0 + ctag = tag.app_to_context(0) + if _debug: TestApplicationTag._debug(" - ctag: %r", tag_tuple(ctag)) + + # create a context tag with the same shape + ttag = ContextTag(0, xtob('00')) + if _debug: TestApplicationTag._debug(" - ttag: %r", tag_tuple(ttag)) + + # check to see they are the same + assert ctag == ttag + + # convert the context tag back to an application tag + dtag = ctag.context_to_app(Tag.booleanAppTag) + if _debug: TestApplicationTag._debug(" - dtag: %r", tag_tuple(dtag)) + + # check to see it round-tripped + assert dtag == tag + + def test_boolean_application_to_object(self): + if _debug: TestApplicationTag._debug("test_boolean_application_to_object") + + # null + obj_endec(Null(), '00') + + # boolean + obj_endec(Boolean(True), '11') + obj_endec(Boolean(False), '10') + + # unsigned + obj_endec(Unsigned(0), '2100') + obj_endec(Unsigned(1), '2101') + obj_endec(Unsigned(127), '217F') + obj_endec(Unsigned(128), '2180') + + # integer + obj_endec(Integer(0), '3100') + obj_endec(Integer(1), '3101') + obj_endec(Integer(-1), '31FF') + obj_endec(Integer(128), '320080') + obj_endec(Integer(-128), '3180') + + # real + obj_endec(Real(0), '4400000000') + obj_endec(Real(1), '443F800000') + obj_endec(Real(-1), '44BF800000') + obj_endec(Real(73.5), '4442930000') + + # double + obj_endec(Double(0), '55080000000000000000') + obj_endec(Double(1), '55083FF0000000000000') + obj_endec(Double(-1), '5508BFF0000000000000') + obj_endec(Double(73.5), '55084052600000000000') + + # octet string + obj_endec(OctetString(xtob('')), '60') + obj_endec(OctetString(xtob('01')), '6101') + obj_endec(OctetString(xtob('0102')), '620102') + obj_endec(OctetString(xtob('010203040506')), '6506010203040506') + + # character string + obj_endec(CharacterString(''), '7100') + obj_endec(CharacterString('a'), '720061') + obj_endec(CharacterString('abcde'), '7506006162636465') + + # bit string + obj_endec(BitString([]), '8100') + obj_endec(BitString([0]), '820700') + obj_endec(BitString([1]), '820780') + obj_endec(BitString([1, 1, 1, 1, 1]), '8203F8') + obj_endec(BitString([1] * 10), '8306FFC0') + + # enumerated + obj_endec(Enumerated(0), '9100') + obj_endec(Enumerated(1), '9101') + obj_endec(Enumerated(127), '917F') + obj_endec(Enumerated(128), '9180') + + # date + obj_endec(Date((1,2,3,4)), 'A401020304') + obj_endec(Date((255,2,3,4)), 'A4FF020304') + obj_endec(Date((1,255,3,4)), 'A401FF0304') + obj_endec(Date((1,2,255,4)), 'A40102FF04') + obj_endec(Date((1,2,3,255)), 'A4010203FF') + + # time + obj_endec(Time((1,2,3,4)), 'B401020304') + obj_endec(Time((255,2,3,4)), 'B4FF020304') + obj_endec(Time((1,255,3,4)), 'B401FF0304') + obj_endec(Time((1,2,255,4)), 'B40102FF04') + obj_endec(Time((1,2,3,255)), 'B4010203FF') + + # object identifier + obj_endec(ObjectIdentifier(0,0), 'C400000000') + obj_endec(ObjectIdentifier(1,0), 'C400400000') + obj_endec(ObjectIdentifier(0,2), 'C400000002') + obj_endec(ObjectIdentifier(3,4), 'C400C00004') + + +@bacpypes_debugging +class TestContextTag(unittest.TestCase): + + def test_context_tag(self): + if _debug: TestContextTag._debug("test_context_tag") + + # test context tag construction + tag = ContextTag(0, xtob('')) + with self.assertRaises(ValueError): + tag = ContextTag() + + # test encoding and decoding + context_endec(0, '', '08') + context_endec(1, '01', '1901') + context_endec(2, '0102', '2A0102') + context_endec(3, '010203', '3B010203') + context_endec(14, '010203', 'EB010203') + context_endec(15, '010203', 'FB0F010203') + +@bacpypes_debugging +class TestOpeningTag(unittest.TestCase): + + def test_opening_tag(self): + if _debug: TestOpeningTag._debug("test_opening_tag") + + # test opening tag construction + tag = OpeningTag(0) + with self.assertRaises(TypeError): + tag = OpeningTag() + + # test encoding, and decoding + opening_endec(0, '0E') + opening_endec(1, '1E') + opening_endec(2, '2E') + opening_endec(3, '3E') + opening_endec(14, 'EE') + opening_endec(15, 'FE0F') + opening_endec(254, 'FEFE') + + +@bacpypes_debugging +class TestClosingTag(unittest.TestCase): + + def test_closing_tag(self): + if _debug: TestClosingTag._debug("test_closing_tag") + + # test closing tag construction + tag = ClosingTag(0) + with self.assertRaises(TypeError): + tag = ClosingTag() + + # test encoding, and decoding + closing_endec(0, '0F') + closing_endec(1, '1F') + closing_endec(2, '2F') + closing_endec(3, '3F') + closing_endec(14, 'EF') + closing_endec(15, 'FF0F') + closing_endec(254, 'FFFE') + + +@bacpypes_debugging +class TestTagList(unittest.TestCase): + + def test_tag_list(self): + if _debug: TestTagList._debug("test_tag_list") + + # test tag list construction + tag_list = TagList() + tag_list = TagList([]) + + def test_peek(self): + if _debug: TestTagList._debug("test_peek") + + tag0 = IntegerTag(0) + taglist = TagList([tag0]) + + # peek at the first tag + assert tag0 == taglist.Peek() + + # pop of the front + tag1 = taglist.Pop() + assert taglist.tagList == [] + + # push it back on the front + taglist.push(tag1) + assert taglist.tagList == [tag1] + + def test_get_context(self): + """Test extracting specific context encoded content. + """ + if _debug: TestTagList._debug("test_get_context") + + tag_list_data = [ + ContextTag(0, xtob('00')), + ContextTag(1, xtob('01')), + OpeningTag(2), + IntegerTag(3), + OpeningTag(0), + IntegerTag(4), + ClosingTag(0), + ClosingTag(2), + ] + taglist = TagList(tag_list_data) + + # known to be a simple context encoded element + context_0 = taglist.get_context(0) + if _debug: TestTagList._debug(" - context_0: %r", context_0) + assert context_0 == tag_list_data[0] + + # known to be a simple context encoded list of element(s) + context_2 = taglist.get_context(2) + if _debug: TestTagList._debug(" - context_2: %r", context_2) + assert context_2.tagList == tag_list_data[3:7] + + # known missing context + context_3 = taglist.get_context(3) + if _debug: TestTagList._debug(" - context_3: %r", context_3) + assert taglist.get_context(3) is None + + def test_endec_0(self): + """Test empty tag list encoding and decoding. + """ + if _debug: TestTagList._debug("test_endec_0") + + taglist = TagList([]) + + data = PDUData() + taglist.encode(data) + assert data.pduData == xtob('') + + taglist = TagList() + taglist.decode(data) + assert taglist.tagList == [] + + def test_endec_1(self): + """Test short tag list encoding and decoding, application tags. + """ + if _debug: TestTagList._debug("test_endec_1") + + tag0 = IntegerTag(0x00) + tag1 = IntegerTag(0x01) + taglist = TagList([tag0, tag1]) + + data = PDUData() + taglist.encode(data) + assert data.pduData == xtob('31003101') + + taglist = TagList() + taglist.decode(data) + assert taglist.tagList == [tag0, tag1] + + def test_endec_2(self): + """Test short tag list encoding and decoding, context tags. + """ + if _debug: TestTagList._debug("test_endec_2") + + tag0 = ContextTag(0, xtob('00')) + tag1 = ContextTag(1, xtob('01')) + taglist = TagList([tag0, tag1]) + + data = PDUData() + taglist.encode(data) + assert data.pduData == xtob('09001901') + + taglist = TagList() + taglist.decode(data) + assert taglist.tagList == [tag0, tag1] + + def test_endec_3(self): + """Test bracketed application tagged integer encoding and decoding.""" + if _debug: TestTagList._debug("test_endec_2") + + tag0 = OpeningTag(0) + tag1 = IntegerTag(0x0102) + tag2 = ClosingTag(0) + taglist = TagList([tag0, tag1, tag2]) + + data = PDUData() + taglist.encode(data) + assert data.pduData == xtob('0E3201020F') + + taglist = TagList() + taglist.decode(data) + assert taglist.tagList == [tag0, tag1, tag2] diff --git a/tests/test_primitive_data/test_time.py b/tests/test_primitive_data/test_time.py index e69de29..1af71f0 100644 --- a/tests/test_primitive_data/test_time.py +++ b/tests/test_primitive_data/test_time.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test Primitive Data Time +--------------------------- +""" + +import unittest + +from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob +from bacpypes.primitivedata import Time, Tag + +# some debugging +_debug = 0 +_log = ModuleLogger(globals()) + + +@bacpypes_debugging +def time_tag(x): + """Convert a hex string to an time application tag.""" + if _debug: time_tag._debug("time_tag %r", x) + + b = xtob(x) + tag = Tag(Tag.applicationTagClass, Tag.timeAppTag, len(b), b) + if _debug: time_endec._debug(" - tag: %r", tag) + + return tag + +@bacpypes_debugging +def time_encode(obj): + """Encode an Time object into a tag.""" + if _debug: time_encode._debug("time_encode %r", obj) + + tag = Tag() + obj.encode(tag) + if _debug: time_endec._debug(" - tag: %r", tag) + + return tag + + +@bacpypes_debugging +def time_decode(tag): + """Decode an time application tag into an time.""" + if _debug: time_decode._debug("time_decode %r", tag) + + obj = Time(tag) + if _debug: time_decode._debug(" - obj: %r", obj) + + return obj + + +@bacpypes_debugging +def time_endec(v, x): + """Pass the value to Time, construct a tag from the hex string, + and compare results of encode and decoding each other.""" + if _debug: time_endec._debug("time_endec %r %r", v, x) + + tag = time_tag(x) + if _debug: time_endec._debug(" - tag: %r, %r", tag, tag.tagData) + + obj = Time(v) + if _debug: time_endec._debug(" - obj: %r, %r", obj, obj.value) + + assert time_encode(obj) == tag + assert time_decode(tag) == obj + + +@bacpypes_debugging +class TestTime(unittest.TestCase): + + def test_time(self): + if _debug: TestTime._debug("test_time") + + # default values is all dont care + obj = Time() + assert obj.value == (255, 255, 255, 255) + + with self.assertRaises(ValueError): + Time("some string") + with self.assertRaises(TypeError): + Time(1.0) + + def test_time_tuple(self): + if _debug: TestTime._debug("test_time_tuple") + + obj = Time((1,2,3,4)) + assert obj.value == (1, 2, 3, 4) + assert str(obj) == "Time(01:02:03.04)" + + assert Time("1:2").value == (1, 2, 0, 0) + assert Time("1:2:3").value == (1, 2, 3, 0) + assert Time("1:2:3.4").value == (1, 2, 3, 40) + assert Time("1:*").value == (1, 255, 255, 255) + assert Time("1:2:*").value == (1, 2, 255, 255) + assert Time("1:2:3.*").value == (1, 2, 3, 255) + + def test_time_tag(self): + if _debug: TestTime._debug("test_time_tag") + + tag = Tag(Tag.applicationTagClass, Tag.timeAppTag, 1, xtob('01020304')) + obj = Time(tag) + assert obj.value == (1, 2, 3, 4) + + tag = Tag(Tag.applicationTagClass, Tag.booleanAppTag, 0, xtob('')) + with self.assertRaises(ValueError): + Time(tag) + + tag = Tag(Tag.contextTagClass, 0, 1, xtob('ff')) + with self.assertRaises(ValueError): + Time(tag) + + tag = Tag(Tag.openingTagClass, 0) + with self.assertRaises(ValueError): + Time(tag) + + def test_time_copy(self): + if _debug: TestTime._debug("test_time_copy") + + time_value = (2, 3, 4, 5) + obj1 = Time(time_value) + obj2 = Time(obj1) + assert obj2.value == time_value + + def test_time_now(self): + if _debug: TestTime._debug("test_time_now") + + # obj = Time().now() + ### how to test? + + def test_time_endec(self): + if _debug: TestTime._debug("test_time_endec") + + ### this should raise a decoding error + # with self.assertRaises(IndexError): + # obj = Time(time_tag('')) + + time_endec((0, 0, 0, 0), '00000000') + time_endec((1, 0, 0, 0), '01000000') + time_endec((0, 2, 0, 0), '00020000') + time_endec((0, 0, 3, 0), '00000300') + time_endec((0, 0, 0, 4), '00000004') diff --git a/tests/test_primitive_data/test_unsigned.py b/tests/test_primitive_data/test_unsigned.py index 28c567e..368af06 100644 --- a/tests/test_primitive_data/test_unsigned.py +++ b/tests/test_primitive_data/test_unsigned.py @@ -9,7 +9,7 @@ Test Primitive Data Unsigned import unittest from bacpypes.debugging import bacpypes_debugging, ModuleLogger, xtob -from bacpypes.primitivedata import Unsigned, Tag +from bacpypes.primitivedata import Unsigned, Tag, DecodingError # some debugging _debug = 0 @@ -119,7 +119,7 @@ class TestUnsigned(unittest.TestCase): def test_unsigned_endec(self): if _debug: TestUnsigned._debug("test_unsigned_endec") -# with self.assertRaises(IndexError): +# with self.assertRaises(DecodingError): # obj = Unsigned(unsigned_tag('')) unsigned_endec(0, '00')