blob: b687cca0036223fe589012e24937fc193665f2e0 [file] [log] [blame]
import typing
import unittest
from dataclasses import dataclass
from chip.clusters import ClusterObjects
from chip.tlv import TLVReader, TLVWriter, uint
import chip.ChipUtility
'''
This file contains tests for checking if the cluster object can generate correct TLV data.
For readability, the TLV related tests are placed in test_tlv.py, and we will test the following case:
1. Generate a struct, encode it, and decode it using TLVReader
2. Generate a dict, encode it using TLVWriter, and decode it using the cluster objects
If TLVReader / TLVWriter emitted wrong TLV data, related test cases should be added to test_tlv.py.
To avoid failures caused by schema change, this file should only contain manually crafted structs.
'''
def _encode_and_then_decode_to_native(data: ClusterObjects.ClusterObject):
tlv = data.ToTLV()
return TLVReader(tlv).get()['Any']
def _encode_attribute_and_then_decode_to_native(data, type: ClusterObjects.ClusterAttributeDescriptor):
return TLVReader(type.ToTLV(None, data)).get()['Any']
def _encode_from_native_and_then_decode(data, cls: typing.Union[ClusterObjects.ClusterObject, ClusterObjects.ClusterAttributeDescriptor]):
tlv = TLVWriter()
tlv.put(None, data)
return cls.FromTLV(bytes(tlv.encoding))
class TestClusterObjects(unittest.TestCase):
@dataclass
class C(ClusterObjects.ClusterObject):
@chip.ChipUtility.classproperty
def descriptor(cls) -> ClusterObjects.ClusterObjectDescriptor:
return ClusterObjects.ClusterObjectDescriptor(
Fields=[
ClusterObjects.ClusterObjectFieldDescriptor(
Label="X", Tag=0, Type=uint),
ClusterObjects.ClusterObjectFieldDescriptor(
Label="Y", Tag=1, Type=int),
])
X: 'uint' = None
Y: 'int' = None
def test_basic_encode(self):
data = TestClusterObjects.C(X=5, Y=23)
res = _encode_and_then_decode_to_native(data)
self.assertEqual(res, {0: 5, 1: 23})
def test_basic_decode(self):
res = _encode_from_native_and_then_decode(
{0: uint(5), 1: 23}, TestClusterObjects.C)
self.assertEqual(res, TestClusterObjects.C(X=5, Y=23))
@dataclass
class StructWithArray(ClusterObjects.ClusterObject):
@chip.ChipUtility.classproperty
def descriptor(cls) -> ClusterObjects.ClusterObjectDescriptor:
return ClusterObjects.ClusterObjectDescriptor(
Fields=[
ClusterObjects.ClusterObjectFieldDescriptor(
Label="X", Tag=0, Type=typing.List[uint]),
ClusterObjects.ClusterObjectFieldDescriptor(
Label="Y", Tag=1, Type=int),
])
X: typing.List['uint'] = None
Y: int = None
def test_struct_w_array_encode(self):
data = TestClusterObjects.StructWithArray(X=[5, 6], Y=23)
res = _encode_and_then_decode_to_native(data)
self.assertEqual(res, {0: [5, 6], 1: 23})
def test_struct_w_array_decode(self):
res = _encode_from_native_and_then_decode(
{0: [uint(5), uint(6)], 1: 23}, TestClusterObjects.StructWithArray)
self.assertEqual(
res, TestClusterObjects.StructWithArray(X=[5, 6], Y=23))
@dataclass
class StructWithEmbeddedStructAndString(ClusterObjects.ClusterObject):
@chip.ChipUtility.classproperty
def descriptor(cls) -> ClusterObjects.ClusterObjectDescriptor:
return ClusterObjects.ClusterObjectDescriptor(
Fields=[
ClusterObjects.ClusterObjectFieldDescriptor(
Label="X", Tag=0, Type=str),
ClusterObjects.ClusterObjectFieldDescriptor(
Label="Y", Tag=1, Type=TestClusterObjects.C),
ClusterObjects.ClusterObjectFieldDescriptor(
Label="Z", Tag=2, Type=bytes),
])
X: 'str' = None
Y: 'TestClusterObjects.C' = None
Z: 'bytes' = None
def test_struct_w_string_and_string_encode(self):
data = TestClusterObjects.StructWithEmbeddedStructAndString(
X='test-str', Y=TestClusterObjects.C(X=12, Y=34), Z=b'byte-string')
res = _encode_and_then_decode_to_native(data)
self.assertEqual(
res, {0: 'test-str', 1: {0: 12, 1: 34}, 2: b'byte-string'})
def test_struct_w_string_and_string_decode(self):
res = _encode_from_native_and_then_decode(
{0: 'test-str', 1: {0: uint(12), 1: 34}, 2: b'byte-string'},
TestClusterObjects.StructWithEmbeddedStructAndString)
self.assertEqual(
res, TestClusterObjects.StructWithEmbeddedStructAndString(
X='test-str', Y=TestClusterObjects.C(X=12, Y=34), Z=b'byte-string'))
@dataclass
class StructWithArrayOfStructWithArray(ClusterObjects.ClusterObject):
@chip.ChipUtility.classproperty
def descriptor(cls) -> ClusterObjects.ClusterObjectDescriptor:
return ClusterObjects.ClusterObjectDescriptor(
Fields=[
ClusterObjects.ClusterObjectFieldDescriptor(
Label="X", Tag=0, Type=typing.List[str]),
ClusterObjects.ClusterObjectFieldDescriptor(
Label="Y", Tag=1, Type=typing.List[TestClusterObjects.C]),
ClusterObjects.ClusterObjectFieldDescriptor(
Label="Z", Tag=2, Type=typing.List[TestClusterObjects.StructWithArray]),
# Recursive!
ClusterObjects.ClusterObjectFieldDescriptor(
Label="W", Tag=3, Type=typing.List[TestClusterObjects.StructWithArrayOfStructWithArray]),
])
X: typing.List['str'] = None
Y: typing.List['TestClusterObjects.C'] = None
Z: typing.List['TestClusterObjects.StructWithArray'] = None
W: typing.List['TestClusterObjects.StructWithArrayOfStructWithArray'] = None
def test_struct_with_array_of_struct_with_array_encode(self):
C = TestClusterObjects.C
SWA = TestClusterObjects.StructWithArray
SWAOSWA = TestClusterObjects.StructWithArrayOfStructWithArray
data = TestClusterObjects.StructWithArrayOfStructWithArray(
X=['test-str1', 'test-str2', 'test-str3'],
Y=[C(X=12, Y=34), C(X=56, Y=78), C(X=23, Y=33)],
Z=[SWA(X=[12, 34], Y=5678), SWA(X=[1, 3], Y=57),
SWA(X=[2, 4], Y=68), SWA(X=[233, 333], Y=333)],
W=[SWAOSWA(X=['test-str4'], Y=[C(X=55, Y=66)], Z=[SWA(X=[123], Y=456)], W=[])])
res = _encode_and_then_decode_to_native(data)
self.assertEqual(
res,
{0: ['test-str1', 'test-str2', 'test-str3'],
1: [{0: 12, 1: 34}, {0: 56, 1: 78}, {0: 23, 1: 33}],
2: [{0: [12, 34], 1: 5678},
{0: [1, 3], 1: 57},
{0: [2, 4], 1: 68},
{0: [233, 333], 1: 333}],
3: [{0: ['test-str4'], 1: [{0: 55, 1: 66}], 2: [{0: [123], 1: 456}], 3: []}]})
def test_struct_with_array_of_struct_with_array_decode(self):
res = _encode_from_native_and_then_decode(
{0: ['test-str1', 'test-str2', 'test-str3'],
1: [{0: uint(12), 1: 34}, {0: uint(56), 1: 78}, {0: uint(23), 1: 33}],
2: [{0: [uint(12), uint(34)], 1: 5678},
{0: [uint(1), uint(3)], 1: 57},
{0: [uint(2), uint(4)], 1: 68},
{0: [uint(233), uint(333)], 1: 333}],
3: [{0: ['test-str4'], 1: [{0: uint(55), 1: 66}], 2: [{0: [uint(123)], 1: 456}], 3: []}]},
TestClusterObjects.StructWithArrayOfStructWithArray)
C = TestClusterObjects.C
SWA = TestClusterObjects.StructWithArray
SWAOSWA = TestClusterObjects.StructWithArrayOfStructWithArray
data = TestClusterObjects.StructWithArrayOfStructWithArray(
X=['test-str1', 'test-str2', 'test-str3'],
Y=[C(X=12, Y=34), C(X=56, Y=78), C(X=23, Y=33)],
Z=[SWA(X=[12, 34], Y=5678), SWA(X=[1, 3], Y=57),
SWA(X=[2, 4], Y=68), SWA(X=[233, 333], Y=333)],
W=[SWAOSWA(X=['test-str4'], Y=[C(X=55, Y=66)], Z=[SWA(X=[123], Y=456)], W=[])])
self.assertEqual(res, data)
class TestAttributeDescriptor(unittest.TestCase):
class IntAttribute(ClusterObjects.ClusterAttributeDescriptor):
@chip.ChipUtility.classproperty
def attribute_type(cls) -> ClusterObjects.ClusterObjectFieldDescriptor:
return ClusterObjects.ClusterObjectFieldDescriptor(Type=int)
def test_basic_encode(self):
res = _encode_attribute_and_then_decode_to_native(
42, TestAttributeDescriptor.IntAttribute)
self.assertEqual(res, 42)
def test_basic_decode(self):
res = _encode_from_native_and_then_decode(
42, TestAttributeDescriptor.IntAttribute)
self.assertEqual(res, 42)
class StructAttribute(ClusterObjects.ClusterAttributeDescriptor):
@chip.ChipUtility.classproperty
def attribute_type(cls) -> ClusterObjects.ClusterObjectFieldDescriptor:
return ClusterObjects.ClusterObjectFieldDescriptor(Type=TestClusterObjects.C)
def test_struct_encode(self):
res = _encode_attribute_and_then_decode_to_native(
TestClusterObjects.C(X=42, Y=24), TestAttributeDescriptor.StructAttribute)
self.assertEqual(res, {0: 42, 1: 24})
def test_struct_decode(self):
res = _encode_from_native_and_then_decode(
{0: uint(42), 1: 24}, TestClusterObjects.C)
self.assertEqual(res, TestClusterObjects.C(X=42, Y=24))
class ArrayAttribute(ClusterObjects.ClusterAttributeDescriptor):
@chip.ChipUtility.classproperty
def attribute_type(cls) -> ClusterObjects.ClusterObjectFieldDescriptor:
return ClusterObjects.ClusterObjectFieldDescriptor(Type=typing.List[int])
def test_array_encode(self):
res = _encode_attribute_and_then_decode_to_native(
[1, 2, 3, 4, 5], TestAttributeDescriptor.ArrayAttribute)
self.assertEqual(res, [1, 2, 3, 4, 5])
def test_array_decode(self):
res = _encode_from_native_and_then_decode(
[1, 2, 3, 4, 5], TestAttributeDescriptor.ArrayAttribute)
self.assertEqual(res, [1, 2, 3, 4, 5])
if __name__ == '__main__':
unittest.main()