# # Copyright (C) 2014-2015 UAVCAN Development Team # # This software is distributed under the terms of the MIT License. # # Author: Ben Dyer # Pavel Kirienko # import unittest from uavcan import transport from uavcan.dsdl import parser class TestBitsFromBytes(unittest.TestCase): def test_empty(self): bits = transport.bits_from_bytes(bytearray(b"")) self.assertEqual(bits, "") def test_single_byte(self): bits = transport.bits_from_bytes(bytearray(b"\x00")) self.assertEqual(bits, "00000000") bits = transport.bits_from_bytes(bytearray(b"\xA5")) self.assertEqual(bits, "10100101") bits = transport.bits_from_bytes(bytearray(b"\xFF")) self.assertEqual(bits, "11111111") bits = transport.bits_from_bytes(bytearray(b"\x0F")) self.assertEqual(bits, "00001111") bits = transport.bits_from_bytes(bytearray(b"\xF0")) self.assertEqual(bits, "11110000") def test_multiple_bytes(self): bits = transport.bits_from_bytes(bytearray(b"\x00\xFF")) self.assertEqual(bits, "0000000011111111") bits = transport.bits_from_bytes(bytearray(b"\xFF\x00")) self.assertEqual(bits, "1111111100000000") bits = transport.bits_from_bytes(bytearray(b"\x00\x00\xAA\x55\xFF\xFF")) self.assertEqual( bits, "000000000000000010101010010101011111111111111111") class TestBytesFromBits(unittest.TestCase): def test_empty(self): result_bytes = transport.bytes_from_bits("") self.assertEqual(result_bytes, b"") def test_partial_byte(self): result_bytes = transport.bytes_from_bits("0") self.assertEqual(result_bytes, b"\x00") result_bytes = transport.bytes_from_bits("1") self.assertEqual(result_bytes, b"\x01") result_bytes = transport.bytes_from_bits("100") self.assertEqual(result_bytes, b"\x04") result_bytes = transport.bytes_from_bits("001") self.assertEqual(result_bytes, b"\x01") result_bytes = transport.bytes_from_bits("1001") self.assertEqual(result_bytes, b"\x09") result_bytes = transport.bytes_from_bits("01001") self.assertEqual(result_bytes, b"\x09") result_bytes = transport.bytes_from_bits("0001001") self.assertEqual(result_bytes, b"\x09") result_bytes = transport.bytes_from_bits("1001001") self.assertEqual(result_bytes, b"\x49") def test_single_byte(self): result_bytes = transport.bytes_from_bits("10010110") self.assertEqual(result_bytes, b"\x96") result_bytes = transport.bytes_from_bits("10100101") self.assertEqual(result_bytes, b"\xA5") result_bytes = transport.bytes_from_bits("00000000") self.assertEqual(result_bytes, b"\x00") def test_multiple_bytes(self): result_bytes = transport.bytes_from_bits("1010010110010110") self.assertEqual(result_bytes, b"\xA5\x96") result_bytes = transport.bytes_from_bits("11010010110010110") self.assertEqual(result_bytes, b"\xD2\xCB\x00") result_bytes = transport.bytes_from_bits("10100101100101101") self.assertEqual(result_bytes, b"\xA5\x96\x01") class TestBEFromLEBits(unittest.TestCase): def test_partial_byte(self): for bits in ("0", "1", "100", "001", "1001", "01001", "001001", "1001001"): out_bits = transport.be_from_le_bits(bits, len(bits)) self.assertEqual(out_bits, bits) def test_single_byte(self): for bits in ("10010110", "10100101", "00000000"): out_bits = transport.be_from_le_bits(bits, 8) self.assertEqual(out_bits, bits) def test_multiple_bytes(self): # llllllllmmmm out_bits = transport.be_from_le_bits("110110101110", 12) # mmmmllllllll self.assertEqual(out_bits, "111011011010") # llllllllmmmmmmmm out_bits = transport.be_from_le_bits("1010010110010110", 16) # mmmmmmmmllllllll self.assertEqual(out_bits, "1001011010100101") # llllllll........m out_bits = transport.be_from_le_bits("11010010110010110", 17) # m........llllllll self.assertEqual(out_bits, "01100101111010010") # llllllll........m out_bits = transport.be_from_le_bits("10100101100101101", 17) # m........llllllll self.assertEqual(out_bits, "11001011010100101") class TestLEFromBEBits(unittest.TestCase): def test_partial_byte(self): for bits in ("0", "1", "100", "001", "1001", "01001", "001001", "1001001"): out_bits = transport.le_from_be_bits(bits, len(bits)) self.assertEqual(out_bits, bits) def test_single_byte(self): for bits in ("10010110", "10100101", "00000000"): out_bits = transport.le_from_be_bits(bits, 8) self.assertEqual(out_bits, bits) def test_multiple_bytes(self): # mmmmllllllll out_bits = transport.le_from_be_bits("111011011010", 12) # llllllllmmmm self.assertEqual(out_bits, "110110101110") # mmmmmmmmllllllll out_bits = transport.le_from_be_bits("1001011010100101", 16) # llllllllmmmmmmmm self.assertEqual(out_bits, "1010010110010110") # m........llllllll out_bits = transport.le_from_be_bits("01100101111010010", 17) # llllllll........m self.assertEqual(out_bits, "11010010110010110") # m........llllllll out_bits = transport.le_from_be_bits("11001011010100101", 17) # llllllll........m self.assertEqual(out_bits, "10100101100101101") class TestCast(unittest.TestCase): def test_truncated_1bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 1, parser.PrimitiveType.CAST_MODE_TRUNCATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(1, dtype) self.assertEqual(value, 1) value = transport.cast(2, dtype) self.assertEqual(value, 0) value = transport.cast(-1, dtype) self.assertEqual(value, 1) value = transport.cast(5, dtype) self.assertEqual(value, 1) value = transport.cast(-10, dtype) self.assertEqual(value, 0) def test_truncated_4bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 4, parser.PrimitiveType.CAST_MODE_TRUNCATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(15, dtype) self.assertEqual(value, 15) value = transport.cast(16, dtype) self.assertEqual(value, 0) value = transport.cast(-1, dtype) self.assertEqual(value, 15) value = transport.cast(30, dtype) self.assertEqual(value, 14) def test_truncated_33bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 33, parser.PrimitiveType.CAST_MODE_TRUNCATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(8589934591, dtype) self.assertEqual(value, 8589934591) value = transport.cast(8589934592, dtype) self.assertEqual(value, 0) value = transport.cast(-1, dtype) self.assertEqual(value, 8589934591) def test_truncated_64bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 64, parser.PrimitiveType.CAST_MODE_TRUNCATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(18446744073709551615, dtype) self.assertEqual(value, 18446744073709551615) value = transport.cast(-1, dtype) self.assertEqual(value, 18446744073709551615) value = transport.cast(18446744073709551617, dtype) self.assertEqual(value, 1) value = transport.cast(-18446744073709551615, dtype) self.assertEqual(value, 1) def test_unsigned_saturated_1bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 1, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(1, dtype) self.assertEqual(value, 1) value = transport.cast(2, dtype) self.assertEqual(value, 1) value = transport.cast(-1, dtype) self.assertEqual(value, 0) value = transport.cast(5, dtype) self.assertEqual(value, 1) value = transport.cast(-10, dtype) self.assertEqual(value, 0) def test_unsigned_saturated_4bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 4, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(15, dtype) self.assertEqual(value, 15) value = transport.cast(16, dtype) self.assertEqual(value, 15) value = transport.cast(-1, dtype) self.assertEqual(value, 0) value = transport.cast(30, dtype) self.assertEqual(value, 15) def test_unsigned_saturated_33bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 33, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(8589934591, dtype) self.assertEqual(value, 8589934591) value = transport.cast(8589934592, dtype) self.assertEqual(value, 8589934591) value = transport.cast(-1, dtype) self.assertEqual(value, 0) def test_unsigned_saturated_64bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 64, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(18446744073709551615, dtype) self.assertEqual(value, 18446744073709551615) value = transport.cast(-1, dtype) self.assertEqual(value, 0) value = transport.cast(18446744073709551617, dtype) self.assertEqual(value, 18446744073709551615) value = transport.cast(-18446744073709551615, dtype) self.assertEqual(value, 0) def test_signed_saturated_4bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_SIGNED_INT, 4, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(15, dtype) self.assertEqual(value, 7) value = transport.cast(16, dtype) self.assertEqual(value, 7) value = transport.cast(-1, dtype) self.assertEqual(value, -1) value = transport.cast(-30, dtype) self.assertEqual(value, -8) def test_signed_saturated_33bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_SIGNED_INT, 33, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(8589934591, dtype) self.assertEqual(value, 4294967295) value = transport.cast(-8589934592, dtype) self.assertEqual(value, -4294967296) value = transport.cast(-1, dtype) self.assertEqual(value, -1) def test_signed_saturated_64bit(self): dtype = parser.PrimitiveType( parser.PrimitiveType.KIND_SIGNED_INT, 64, parser.PrimitiveType.CAST_MODE_SATURATED) value = transport.cast(0, dtype) self.assertEqual(value, 0) value = transport.cast(18446744073709551615, dtype) self.assertEqual(value, 9223372036854775808) value = transport.cast(-1, dtype) self.assertEqual(value, -1) value = transport.cast(-18446744073709551617, dtype) self.assertEqual(value, -9223372036854775809) value = transport.cast(-9223372036854775808, dtype) self.assertEqual(value, -9223372036854775808) def test_float16_truncated(self): pass def test_float16_saturated(self): pass def test_float32_truncated(self): pass def test_float32_saturated(self): pass class TestArrayBasic(unittest.TestCase): def setUp(self): custom_type = parser.CompoundType( "CustomType", parser.CompoundType.KIND_MESSAGE, "source.uavcan", 0, "" ) custom_type.fields = [ parser.Field( parser.PrimitiveType( parser.PrimitiveType.KIND_SIGNED_INT, 8, parser.PrimitiveType.CAST_MODE_TRUNCATED ), "a" ), parser.Field( parser.PrimitiveType( parser.PrimitiveType.KIND_FLOAT, 16, parser.PrimitiveType.CAST_MODE_SATURATED ), "b" ), parser.Field( parser.ArrayType( parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 1, parser.PrimitiveType.CAST_MODE_SATURATED ), parser.ArrayType.MODE_DYNAMIC, 5 ), "c" ) ] def custom_type_factory(*args, **kwargs): return transport.CompoundValue(custom_type, *args, **kwargs) custom_type._instantiate = custom_type_factory self.a1_type = parser.ArrayType( parser.PrimitiveType( parser.PrimitiveType.KIND_SIGNED_INT, 8, parser.PrimitiveType.CAST_MODE_TRUNCATED ), parser.ArrayType.MODE_STATIC, 4 ) self.a2_type = parser.ArrayType( parser.PrimitiveType( parser.PrimitiveType.KIND_FLOAT, 16, parser.PrimitiveType.CAST_MODE_SATURATED ), parser.ArrayType.MODE_STATIC, 2 ) self.a3_type = parser.ArrayType( custom_type, parser.ArrayType.MODE_STATIC, 2 ) def test_size(self): self.assertEqual(self.a3_type.value_type.fields[2].type.value_type.bitlen, 1) self.assertEqual(self.a1_type.get_max_bitlen(), 8 * 4) self.assertEqual(self.a2_type.get_max_bitlen(), 16 * 2) self.assertEqual(self.a3_type.get_max_bitlen(), (8 + 16 + 5 + 3) * 2) def test_representation(self): a1 = transport.ArrayValue(self.a1_type) a2 = transport.ArrayValue(self.a2_type) a3 = transport.ArrayValue(self.a3_type) for i in range(4): a1[i] = i for i in range(2): a2[i] = i for i in range(2): a3[i].a = i a3[i].b = i for i2 in range(5): a3[i].c.append(i2 & 1) self.assertEqual(len(a3[i].c), 5) self.assertEqual( transport.format_bits(a1._pack(False)), "00000000 00000001 00000010 00000011" ) self.assertEqual( transport.format_bits(a2._pack(False)), "00000000 00000000 00000000 00111100" ) self.assertEqual( transport.format_bits(a3._pack(True)), "00000000 00000000 00000000 10101010 " + "00000001 00000000 00111100 10101010" ) class TestVoid(unittest.TestCase): def setUp(self): self.custom_type = parser.CompoundType( "CustomType", parser.CompoundType.KIND_MESSAGE, "source.uavcan", 0, "" ) self.custom_type.fields = [ parser.Field( parser.PrimitiveType( parser.PrimitiveType.KIND_FLOAT, 16, parser.PrimitiveType.CAST_MODE_SATURATED ), "a" ), parser.Field(parser.VoidType(3), None), parser.Field( parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 1, parser.PrimitiveType.CAST_MODE_SATURATED ), "b" ) ] def custom_type_factory(*args, **kwargs): return transport.CompoundValue(self.custom_type, *args, **kwargs) self.custom_type._instantiate = custom_type_factory def test_size(self): self.assertEqual(self.custom_type.fields[1].type.bitlen, 3) self.assertEqual(self.custom_type.get_max_bitlen(), 20) def test_representation(self): c1 = self.custom_type() self.assertEqual( transport.format_bits(c1._pack(False)), "00000000 00000000 0000" ) c1.a = 1 c1.b = 1 self.assertEqual( transport.format_bits(c1._pack(False)), "00000000 00111100 0001" ) class TestMessageUnion(unittest.TestCase): def setUp(self): self.custom_type = parser.CompoundType( "CustomType", parser.CompoundType.KIND_MESSAGE, "source.uavcan", 0, "" ) self.custom_type.union = True self.custom_type.fields = [ parser.Field( parser.PrimitiveType( parser.PrimitiveType.KIND_FLOAT, 16, parser.PrimitiveType.CAST_MODE_SATURATED ), "a" ), parser.Field( parser.ArrayType( parser.PrimitiveType( parser.PrimitiveType.KIND_UNSIGNED_INT, 8, parser.PrimitiveType.CAST_MODE_SATURATED ), parser.ArrayType.MODE_STATIC, 2 ), "b" ) ] def custom_type_factory(*args, **kwargs): return transport.CompoundValue(self.custom_type, *args, **kwargs) self.custom_type._instantiate = custom_type_factory def test_size(self): self.assertEqual(self.custom_type.fields[0].type.bitlen, 16) self.assertEqual(self.custom_type.fields[1].type.get_max_bitlen(), 16) self.assertEqual(self.custom_type.get_max_bitlen(), 17) def test_representation(self): c1 = self.custom_type() self.assertEqual( transport.format_bits(c1._pack(True)), "00000000 00000000 0" ) c2 = self.custom_type() c2.a = 1 self.assertEqual(transport.get_active_union_field(c2), "a") self.assertEqual( transport.format_bits(c2._pack(True)), "00000000 00011110 0" ) c3 = self.custom_type() c3.b[0] = 1 c3.b[1] = 3 self.assertEqual(transport.get_active_union_field(c3), "b") self.assertEqual( transport.format_bits(c3._pack(False)), "10000000 10000001 1" ) class TestAssignment(unittest.TestCase): def setUp(self): import uavcan self.a = uavcan.protocol.GetNodeInfo.Response() def test_compound_assignment(self): import uavcan orig_status = self.a.status print(orig_status) self.assertEqual(orig_status.mode, 0) self.assertEqual(orig_status.uptime_sec, 0) self.a.status = uavcan.protocol.NodeStatus(mode=3, uptime_sec=12345) new_status = self.a.status print(new_status) self.assertEqual(new_status.mode, 3) self.assertEqual(new_status.uptime_sec, 12345) def test_array_assignment(self): print(repr(self.a.name)) print(str(self.a.name)) self.assertEqual(self.a.name, []) self.assertEqual(self.a.name, '') self.a.name = '123' self.assertEqual(self.a.name, [49, 50, 51]) self.assertEqual(self.a.name, '123') self.a.name = [52, 53, 54] self.assertEqual(self.a.name, [52, 53, 54]) self.assertEqual(self.a.name, '456') print(repr(self.a.name)) print(str(self.a.name)) class TestFloats(unittest.TestCase): def test_basic(self): def make_float(bitlen): return parser.PrimitiveType(parser.PrimitiveType.KIND_FLOAT, bitlen, parser.PrimitiveType.CAST_MODE_TRUNCATED) # 64 bit a = transport.PrimitiveValue(make_float(64)) print(a.value) self.assertEqual(a.value, 0) a.value = 123.456 print(a.value) self.assertEqual(a.value, 123.456) # 16 bit a = transport.PrimitiveValue(make_float(16)) print(a.value) self.assertEqual(a.value, 0) # nan a.value = float('nan') print(a.value) self.assertEqual(str(a.value), 'nan') # positive infinity a.value = float('inf') print(a.value) self.assertEqual(str(a.value), 'inf') # negative infinity a.value = float('-inf') print(a.value) self.assertEqual(str(a.value), '-inf') if __name__ == '__main__': unittest.main()