Move adding end container into subclass. Struct requires a tag
This commit is contained in:
parent
05745b1952
commit
51ce818a6a
7 changed files with 154 additions and 127 deletions
|
|
@ -534,8 +534,6 @@ class Message:
|
|||
unencrypted_offset = self.application_payload.encode_into(
|
||||
unencrypted_buffer, unencrypted_offset
|
||||
)
|
||||
unencrypted_buffer[unencrypted_offset] = 0x18
|
||||
unencrypted_offset += 1
|
||||
elif isinstance(self.application_payload, StatusReport):
|
||||
unencrypted_offset = self.application_payload.encode_into(
|
||||
unencrypted_buffer, unencrypted_offset
|
||||
|
|
@ -554,22 +552,18 @@ class Message:
|
|||
# Encrypt the payload
|
||||
if cipher is not None:
|
||||
# The message may not include the source_node_id so we encode the nonce separately.
|
||||
print(self.message_counter)
|
||||
nonce = struct.pack(
|
||||
"<BIQ", self.security_flags, self.message_counter, self.source_node_id
|
||||
)
|
||||
print("nonce", nonce_end - nonce_start, nonce.hex(" "))
|
||||
additional = buffer[:offset]
|
||||
self.payload = cipher.encrypt(
|
||||
nonce, bytes(unencrypted_buffer[:unencrypted_offset]), bytes(additional)
|
||||
)
|
||||
print("encrypted", len(self.payload), self.payload.hex(" "))
|
||||
buffer[offset : offset + len(self.payload)] = self.payload
|
||||
offset += len(self.payload)
|
||||
else:
|
||||
offset = unencrypted_offset
|
||||
|
||||
print("encoded", buffer[:offset].hex(" "))
|
||||
return offset
|
||||
|
||||
@property
|
||||
|
|
@ -896,7 +890,6 @@ class GeneralCommissioningCluster(data_model.GeneralCommissioningCluster):
|
|||
) -> data_model.GeneralCommissioningCluster.ArmFailSafeResponse:
|
||||
response = data_model.GeneralCommissioningCluster.ArmFailSafeResponse()
|
||||
response.ErrorCode = data_model.CommissioningErrorEnum.OK
|
||||
print("respond", response)
|
||||
return response
|
||||
|
||||
|
||||
|
|
@ -1001,14 +994,15 @@ class CircuitMatter:
|
|||
|
||||
def get_report(self, cluster, path):
|
||||
report = interaction_model.AttributeReportIB()
|
||||
astatus = interaction_model.AttributeStatusIB()
|
||||
astatus.Path = path
|
||||
status = interaction_model.StatusIB()
|
||||
status.Status = 0
|
||||
status.ClusterStatus = 0
|
||||
astatus.Status = status
|
||||
report.AttributeStatus = astatus
|
||||
report.AttributeData = cluster.get_attribute_data(path)
|
||||
# Only add status if an error occurs
|
||||
# astatus = interaction_model.AttributeStatusIB()
|
||||
# astatus.Path = path
|
||||
# status = interaction_model.StatusIB()
|
||||
# status.Status = 0
|
||||
# status.ClusterStatus = 0
|
||||
# astatus.Status = status
|
||||
# report.AttributeStatus = astatus
|
||||
return report
|
||||
|
||||
def invoke(self, cluster, path, fields, command_ref):
|
||||
|
|
@ -1066,7 +1060,7 @@ class CircuitMatter:
|
|||
|
||||
# This is Section 4.14.1.2
|
||||
request, _ = pase.PBKDFParamRequest.decode(
|
||||
message.application_payload[0], message.application_payload[1:-1]
|
||||
message.application_payload[0], message.application_payload[1:]
|
||||
)
|
||||
print("PBKDF", request)
|
||||
exchange.commissioning_hash = hashlib.sha256(
|
||||
|
|
@ -1094,7 +1088,7 @@ class CircuitMatter:
|
|||
params.salt = binascii.a2b_base64(self.nonvolatile["salt"])
|
||||
response.pbkdf_parameters = params
|
||||
|
||||
encoded = b"\x15" + response.encode() + b"\x18"
|
||||
encoded = response.encode()
|
||||
exchange.commissioning_hash.update(encoded)
|
||||
exchange.send(
|
||||
ProtocolId.SECURE_CHANNEL,
|
||||
|
|
@ -1206,6 +1200,8 @@ class CircuitMatter:
|
|||
for endpoint in self._endpoints:
|
||||
if path.Cluster in self._endpoints[endpoint]:
|
||||
cluster = self._endpoints[endpoint][path.Cluster]
|
||||
# TODO: The path object probably needs to be cloned. Otherwise we'll
|
||||
# change the endpoint for all uses.
|
||||
path.Endpoint = endpoint
|
||||
attribute_reports.append(self.get_report(cluster, path))
|
||||
else:
|
||||
|
|
@ -1261,8 +1257,6 @@ class CircuitMatter:
|
|||
)
|
||||
else:
|
||||
print(f"Cluster 0x{path.Cluster:02x} not found")
|
||||
for r in invoke_responses:
|
||||
print(r)
|
||||
response = interaction_model.InvokeResponseMessage()
|
||||
response.SuppressResponse = False
|
||||
response.InvokeResponses = invoke_responses
|
||||
|
|
|
|||
|
|
@ -36,6 +36,15 @@ class ReplaySocket:
|
|||
def sendto(self, data, address):
|
||||
if address is None:
|
||||
raise ValueError("Address must be set")
|
||||
direction, _, address, data_b64 = self.replay_data.pop(0)
|
||||
if direction == "send":
|
||||
decoded = binascii.a2b_base64(data_b64)
|
||||
for i, b in enumerate(data):
|
||||
if b != decoded[i]:
|
||||
print("sent", data.hex(" "))
|
||||
print("old ", decoded.hex(" "))
|
||||
print(i, hex(b), hex(decoded[i]))
|
||||
raise RuntimeError("Next replay packet does not match sent data")
|
||||
return len(data)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -153,16 +153,13 @@ class Cluster:
|
|||
yield field_name, descriptor
|
||||
|
||||
def get_attribute_data(self, path) -> interaction_model.AttributeDataIB:
|
||||
print("get_attribute_data", path.Attribute)
|
||||
data = interaction_model.AttributeDataIB()
|
||||
data.DataVersion = 0
|
||||
data.Path = path
|
||||
found = False
|
||||
for field_name, descriptor in self._attributes():
|
||||
print("maybe", field_name, descriptor)
|
||||
if descriptor.id != path.Attribute:
|
||||
continue
|
||||
print("read", field_name, descriptor)
|
||||
data.Data = descriptor.encode(getattr(self, field_name))
|
||||
found = True
|
||||
break
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ class AttributeStatusIB(tlv.Structure):
|
|||
|
||||
|
||||
class AttributeReportIB(tlv.Structure):
|
||||
AttributeStatus = tlv.StructMember(0, AttributeStatusIB)
|
||||
AttributeData = tlv.StructMember(1, AttributeDataIB)
|
||||
AttributeStatus = tlv.StructMember(0, AttributeStatusIB, optional=True)
|
||||
AttributeData = tlv.StructMember(1, AttributeDataIB, optional=True)
|
||||
|
||||
|
||||
class ReadRequestMessage(tlv.Structure):
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class Container:
|
|||
def max_length(cls):
|
||||
if cls._max_length is None:
|
||||
cls._max_length = sum(member.max_length for _, member in cls._members())
|
||||
return cls._max_length
|
||||
return cls._max_length + 2
|
||||
|
||||
@classmethod
|
||||
def _members(cls) -> Iterable[tuple[str, Member]]:
|
||||
|
|
@ -125,6 +125,9 @@ class Container:
|
|||
cls._members_by_tag_cache = members
|
||||
return members
|
||||
|
||||
def set_value(self, tag, value):
|
||||
self.values[tag] = value
|
||||
|
||||
|
||||
class Structure(Container):
|
||||
def __str__(self):
|
||||
|
|
@ -144,13 +147,15 @@ class Structure(Container):
|
|||
|
||||
def encode(self) -> memoryview:
|
||||
buffer = bytearray(self.max_length())
|
||||
end = self.encode_into(buffer)
|
||||
buffer[0] = ElementType.STRUCTURE
|
||||
end = self.encode_into(buffer, offset=1)
|
||||
return memoryview(buffer)[:end]
|
||||
|
||||
def encode_into(self, buffer: bytearray, offset: int = 0) -> int:
|
||||
for _, descriptor_class in self._members():
|
||||
offset = descriptor_class.encode_into(self, buffer, offset)
|
||||
return offset
|
||||
buffer[offset] = ElementType.END_OF_CONTAINER
|
||||
return offset + 1
|
||||
|
||||
@classmethod
|
||||
def decode(cls, control_octet, buffer, offset=0, depth=0) -> tuple[dict, int]:
|
||||
|
|
@ -168,15 +173,11 @@ class Structure(Container):
|
|||
return cls.from_value(values), offset
|
||||
|
||||
def construct_containers(self):
|
||||
print("construct_containers")
|
||||
for name, member_class in self._members():
|
||||
print(name, member_class)
|
||||
tag = member_class.tag
|
||||
if tag not in self.values:
|
||||
continue
|
||||
self.values[tag] = member_class.from_value(self.values[tag])
|
||||
print("replaced", name, self.values[tag])
|
||||
print("construct_containers done")
|
||||
|
||||
@classmethod
|
||||
def from_value(cls, value):
|
||||
|
|
@ -262,7 +263,7 @@ class Member(ABC, Generic[_T, _OPT, _NULLABLE]):
|
|||
def __set__(self, obj, value):
|
||||
if value is None and not self.nullable:
|
||||
raise ValueError("Not nullable")
|
||||
obj.values[self.tag] = value
|
||||
obj.set_value(self.tag, value)
|
||||
|
||||
def encode_into(
|
||||
self, obj: Container, buffer: bytearray, offset: int, anonymous_ok=False
|
||||
|
|
@ -544,11 +545,11 @@ class StringMember(Member[AnyStr, _OPT, _NULLABLE], Generic[AnyStr, _OPT, _NULLA
|
|||
nullable: _NULLABLE = False,
|
||||
**kwargs,
|
||||
):
|
||||
self.max_value_length = max_length
|
||||
length_encoding = int(math.log(max_length, 256))
|
||||
self._element_type = self._base_element_type | length_encoding
|
||||
self.length_format = INT_SIZE[length_encoding]
|
||||
self.length_length = struct.calcsize(self.length_format)
|
||||
self.max_value_length = max_length + self.length_length
|
||||
super().__init__(tag, optional=optional, nullable=nullable, **kwargs)
|
||||
|
||||
def print(self, value):
|
||||
|
|
@ -629,8 +630,7 @@ class StructMember(Member[_TLVStruct, _OPT, _NULLABLE]):
|
|||
|
||||
def encode_value_into(self, value, buffer: bytearray, offset: int) -> int:
|
||||
offset = value.encode_into(buffer, offset)
|
||||
buffer[offset] = ElementType.END_OF_CONTAINER
|
||||
return offset + 1
|
||||
return offset
|
||||
|
||||
def from_value(self, value):
|
||||
return self.substruct_class.from_value(value)
|
||||
|
|
@ -677,6 +677,8 @@ class ArrayMember(Member[_TLVStruct, _OPT, _NULLABLE]):
|
|||
buffer[offset] = ElementType.STRUCTURE
|
||||
elif isinstance(v, List):
|
||||
buffer[offset] = ElementType.LIST
|
||||
else:
|
||||
raise NotImplementedError("Unknown type")
|
||||
offset = v.encode_into(buffer, offset + 1)
|
||||
buffer[offset] = ElementType.END_OF_CONTAINER
|
||||
offset += 1
|
||||
|
|
@ -726,7 +728,8 @@ class List(Container):
|
|||
|
||||
def encode(self) -> memoryview:
|
||||
buffer = bytearray(self.max_length())
|
||||
end = self.encode_into(buffer)
|
||||
buffer[0] = ElementType.LIST
|
||||
end = self.encode_into(buffer, offset=1)
|
||||
return memoryview(buffer)[:end]
|
||||
|
||||
def encode_into(self, buffer: bytearray, offset: int = 0) -> int:
|
||||
|
|
@ -741,7 +744,8 @@ class List(Container):
|
|||
offset = member.encode_into(self, buffer, offset, anonymous_ok=True)
|
||||
else:
|
||||
raise NotImplementedError("Anonymous list member")
|
||||
return offset
|
||||
buffer[offset] = ElementType.END_OF_CONTAINER
|
||||
return offset + 1
|
||||
|
||||
@classmethod
|
||||
def from_value(cls, value):
|
||||
|
|
@ -760,6 +764,14 @@ class List(Container):
|
|||
instance.values[tag] = value
|
||||
return instance
|
||||
|
||||
def set_value(self, tag, value):
|
||||
if tag in self.values:
|
||||
i = self.items.index((tag, self.values[tag]))
|
||||
self.items[i] = (tag, value)
|
||||
else:
|
||||
self.values[tag] = value
|
||||
self.items.append((tag, value))
|
||||
|
||||
|
||||
_TLVList = TypeVar("_TLVList", bound=List)
|
||||
|
||||
|
|
@ -801,8 +813,7 @@ class ListMember(Member):
|
|||
|
||||
def encode_value_into(self, value, buffer: bytearray, offset: int) -> int:
|
||||
offset = value.encode_into(buffer, offset)
|
||||
buffer[offset] = ElementType.END_OF_CONTAINER
|
||||
return offset + 1
|
||||
return offset
|
||||
|
||||
def from_value(self, value):
|
||||
return self.substruct_class.from_value(value)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
["urandom", 350585853607419, 8, "xA4yE5YTpkA="]
|
||||
["receive", 350587096075493, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "BAAAAMa1vQPUSbbPrqLtJgUggP8AABUwASD2zxwaK72yIGXgGo6eoto/w+n5f2yRavZXWHgi+PXapiUC7d0kAwAoBDUFJQH0ASUCLAElA6APJAQRJAULJgYAAAMBJAcBGBg="]
|
||||
["urandom", 350587128879760, 32, "xzGpsJxnxQou/EF15WCv/oi7aedtmlZU4Q6aV6MxybA="]
|
||||
["send", 350587129006309, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AQAAANcK+wHUSbbPrqLtJgIhgP8AAMa1vQMVMAEg9s8cGiu9siBl4BqOnqLaP8Pp+X9skWr2V1h4Ivj12qYwAiDHMamwnGfFCi78QXXlYK/+iLtp522aVlThDppXozHJsCUDAQA1BCYBECcAADACIObgj9CEx2MyPagRHuoX1OB32N8u1aKUpNKjb4b854YkGBg="]
|
||||
["receive", 350587135507153, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "BAAAAMe1vQPUSbbPrqLtJgUigP8AABUwAUEEFc1AB41Tr1tAfC+PmT/xEy1cglver2gjGxbxKQqOEwQwtzj5tIZk1CFEUZv5VhlQEO8FK9E+Zf1vn34PckFIURg="]
|
||||
["randbelow", 350587135613023, 115792089210356248762697446949407573529996955224135760342422259061068512044369, 115473339479673884280104370450166017066816674872314297419471759872926838745841]
|
||||
["send", 350587151156721, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AQAAANgK+wHUSbbPrqLtJgIjgP8AAMe1vQMVMAFBBAcGjqic2zu9I/CWQ37MQ5Cq/uQwGTiRZZ6x43FGUqrqb23/8yKqDH97/lXjZhuvNkEXdJyYekesbJRmDoSx9GIwAiAhyUXSRm/Nx/uuT0x/rFn4daOLfydl7fB9o3ri4KTsThg="]
|
||||
["receive", 350587151563108, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "BAAAAMi1vQPUSbbPrqLtJgUkgP8AABUwASAOyxB90IQ4pXVTkJGMAzxfshniG0vsE4vJxJUXpJgDOxg="]
|
||||
["send", 350587151661434, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AQAAANkK+wHUSbbPrqLtJgJAgP8AAMi1vQMAAAAAAAAAAA=="]
|
||||
["receive", 350587151843067, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AAEAAMvQfgqe1+b0ErOxGZUF3l4lhUVdlt+wCpTEaf28uQeGD6X2KPek1H52Uj2ePzDcnG28EM3DR7goMhI9+quoNZNEUASzCTDWppnMtUNZCeKOXYkadV1xURswla3q2PBBbFMclILwJRat6AB4G0oD6n9ciGcYMGdL9mwXuJR0hKE="]
|
||||
["send", 350587152774505, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AO3dAFApww0GutoB/WkZhRK+lHoiYxg7UjxXqyc0Vo4IvBw35itUf36ndZZ8qEjcqq3ukqUkAUcW3bs27R6Gg47aG1tgP4BNalazU8GZWxsDE36+VQSjQvF+NcipaAJT8Y4gbX98B41duYkP6GQI4M9v7Id9rlyC2AImwnGiRlTTDkkPsibLxXgVHAVzR2+BezIxPz5i+Q6wSg0tyn2R5gablGAC1NE2OzLqZkqY0lRz6khr2WNHRjf3Da6hbzdc+UPk1uI7kFZ9A9ZGYddIqBiENkUK2m5s8CDPcOeFOtsqlKxArldwMmPcUxKfklwdbCvHDyk3BR6G/DTmbS5OYWLEApSQfkIYGyc0263HwVDWvszaREkPiQw5nFoGa/cnjTt04gPyBl+SVkUJgGtq+UTszBm0t8401Jn04/rf7ekzaIlYYnjIAdBQkn6Hhg6ERrOMWN5K5WQG5vJbo4LX4r9L5SkeCsB9MLbq8KLvc/quWFPwNHYF2sHUKnT2za/rJUiRiZo+TIbwMIb9LrobUrKVSzo4Gj4SCElJCHv9z1Gdzs5pa7QOetjyZJ6817Gane0P639wm5C0fWOnu9obXha2FVB/oNIxuuiMqNA/Yi+CkQ8g3geK0D07LfL+RTcQrTIyFnCK/nCE0qCiNe+oi1rlQKo+zGCu9/fOX2ObqlO24xcYJ4ds8e+GC+eu4U6YztcqORp9hweYzHdui8J93w=="]
|
||||
["receive", 350587159372072, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AAEAAMzQfgptUG7fZgN3ppDYyBO7CiMe3ENiO7eXLyCv+YWjYv4="]
|
||||
["receive", 350587159472783, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AAEAAM3Qfgrgg3jWjNGgrTnf6GrhD/hniSA4j+7sRWnSu649VdCgKoz0ie0mLC2wunbfPDriu3ZzaQ/5H0ILqB4kVgIr2wQniwuEW1kFraee9/Asyw=="]
|
||||
["send", 350587159756658, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AO3dAFEpww07UbyghW+JBq253x+tXYUe/KjdCdeEUVy1HIUJ6FEQOiNSFRwVtS5+ZWpGcGGud/Yr02ZmhLtzHiH3KapX332etipkfIEbG2t84fFKJ17C9pUddLjUwEzsNiiNyX/U"]
|
||||
["receive", 350587161059829, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AAEAAM7QfgpRsOL0plLx7IwHLDLy/owyMK2cA8FWoBOmDf0eEVE="]
|
||||
["receive", 350587161149769, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AAEAAM/QfgqOO+MnXhNDVBSV19QiDStKc+ubq3myHXfyvduZdu29jZw93Lp0Kb+6kSU6OcpYqs+uubMBipiCo0w="]
|
||||
["send", 350587161501002, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 49091, 0, 0], "AO3dAFIpww03V0tvzqO+Gcb4kRjJ9bhHZsZ7MR/oLOE6EakbF5ftcueaktUx+ccNFQYJUnu4YozpT7Y7p2Zs2bxa9jnZ6er12+ekgInHNq3eca5Du0e8Pyvq+h1cUJqBH1SoFhA7UnY="]
|
||||
["urandom", 611538362769836, 8, "7IqPDolswXE="]
|
||||
["receive", 611542342146276, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "BAAAALOJYA42R2d4e1fWQQUg4sIAABUwASDozjMsxicrnDj/NjeSaB9m8NX7G4LdPJnqm4uWwo7S9iUCVnMkAwAoBDUFJQH0ASUCLAElA6APJAQRJAULJgYAAAMBJAcBGBg="]
|
||||
["urandom", 611542373385499, 32, "amrbDtzcWt2dJboBhSVhVAriSUlrFBxMUpW8ti+9lWw="]
|
||||
["send", 611542373589975, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AQAAANMJMg42R2d4e1fWQQIh4sIAALOJYA4VMAEg6M4zLMYnK5w4/zY3kmgfZvDV+xuC3TyZ6puLlsKO0vYwAiBqatsO3Nxa3Z0lugGFJWFUCuJJSWsUHExSlby2L72VbCUDAQA1BCYBECcAADACIObgj9CEx2MyPagRHuoX1OB32N8u1aKUpNKjb4b854YkGBg="]
|
||||
["receive", 611542379685073, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "BAAAALSJYA42R2d4e1fWQQUi4sIAABUwAUEE4dM8AKRxdKyocQVO66aeobNSpjdAT+SUaM9WRRwvUQxYlDRgG6tvGzME1em13s/p3s0UxOGd8ZfjjnlP6g07Khg="]
|
||||
["randbelow", 611542379785923, 115792089210356248762697446949407573529996955224135760342422259061068512044369, 18686455751714252099427219551429565272567932817770329314969969789848945100921]
|
||||
["send", 611542395205834, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AQAAANQJMg42R2d4e1fWQQIj4sIAALSJYA4VMAFBBKVs5C/yQ3zmpRjWWITnJFvTA5eK04zPlLpZ/xFHnrjXZ6KvD4CwYeH3XRUN/ogNaN1g9yl4WqCUyPpgTLn9jDYwAiBdQqEMicwLaMyAl13/N6aoyXZlObtk5/S9nUsm+pVWVBg="]
|
||||
["receive", 611542395669018, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "BAAAALWJYA42R2d4e1fWQQUk4sIAABUwASDTWToRuOYxnSZIUTzy/5Fsd4ytbi9Bn8MrOw8A1v6lTRg="]
|
||||
["send", 611542395771731, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AQAAANUJMg42R2d4e1fWQQJA4sIAALWJYA4AAAAAAAAAAA=="]
|
||||
["receive", 611542395940870, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AAEAAB0yugTvmTZ+TWtppwYBzVVge27aOTCoKcz8bddeiIPpiK9FKYNhjU8NYXkThvO48PxKDSXNup6TnxzxLIr4WlRdIgDDhjxw1ZFNWCl+w6VAW22ewNv5ZmS8IVfbKBGzsKlIremKCLjZ5ru3Z2tBvmF/h+aCPP/eIyOBIwQQ+WU="]
|
||||
["send", 611542396948932, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AFZzAO5wmAop3tJHsU/2PUDdpaQCNFauxcgwzp3GWJuCQWdVI6MeiAmEQwgTl9caHeohNo3j3ySc+DagOwyz1BhkyV2F5L0Kdnzxc4hBrYKZaqVA/NKQy4jQ1d9/Jsp/JZWSwDUPKlmwgBYXom9jYPTJ/Q6AHrIRoUuhjj60m5VVsNdLf9G/hw8XWr4OmwduzQGRJntAoRvArhax8hzII/fnTS2UgSPUF1Xt283CHdMrdZ4oeOlPMo9V07bgDs0zvJLyV6OO1LdUxeT8g2mRKSiepjoR5mEQe+lLpYh2jDn3Y5Kt4SfzCZH7ssmwTZyoheQtUHTOyFu4DPrDQWR91ISAvK7vwrMvPd+xms/Fh8duEyRGL9mgrwLDLkBgMrFX9lRDoGBHMIJYYw39R1H6qvcE5guEXqnS8v5KSBR6Phwm"]
|
||||
["receive", 611542397100839, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AAEAAB4yugQRmjD6ItRCbJzoGAHAbdXYq9K3559GlLfYG4XYLic="]
|
||||
["receive", 611542397196479, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AAEAAB8yugQGuEaWHI2lm801cUoFP3zTOjHD8ZALr6FM9LM9m2OrWWToL8VwGuMa6NJGXohvkhXeRu3fJQl3tQqckkYk267vy/H6QbreqIA2HNb91w=="]
|
||||
["send", 611542397496766, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AFZzAO9wmAqY4GYHxiwxqrs+Jh4i+msLc7f5d5WaiFrIacMs89uk3eNOX42c55b5kh9ZtGCpAavifRjWJNwp1cCk9kV+9RWp"]
|
||||
["receive", 611542398355386, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AAEAACAyugT0CApC4YECx60j1svaX1+xPU+rgo1Mxktq7xX2TD8="]
|
||||
["receive", 611542398452960, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AAEAACEyugSo6dyOf3rdLZogs5AXfa0nGZyMzJb776xye5L4/n5mdxsYu8Gy0Jx/pK/vwaf4E49W39id9SJwV88="]
|
||||
["send", 611542398901516, ["fd98:bbab:bd61:8040:642:1aff:fe0c:9f2a", 33687, 0, 0], "AFZzAPBwmArRIbed47XNIBhM1dGbfV2EsZbpg0DjI7maFko4C61hoB/7WEvLEbvH1aV3AdXMS5FuEcmJQUacYCnnsPZAkhAsDszflspu+kWkWecwp2rEQWy4reEDGwUWrzl+HVGLR207Zd8="]
|
||||
|
|
|
|||
|
|
@ -19,45 +19,45 @@ from circuitmatter import tlv
|
|||
|
||||
|
||||
class Bool(tlv.Structure):
|
||||
b = tlv.BoolMember(None)
|
||||
b = tlv.BoolMember(0)
|
||||
|
||||
|
||||
class TestBool:
|
||||
def test_bool_false_decode(self):
|
||||
s, _ = Bool.decode(0x15, b"\x08\x18")
|
||||
s, _ = Bool.decode(0x15, b"\x28\x00\x18")
|
||||
assert str(s) == "{\n b = false\n}"
|
||||
assert s.b is False
|
||||
|
||||
def test_bool_true_decode(self):
|
||||
s, _ = Bool.decode(0x15, b"\x09\x18")
|
||||
s, _ = Bool.decode(0x15, b"\x29\x00\x18")
|
||||
assert str(s) == "{\n b = true\n}"
|
||||
assert s.b is True
|
||||
|
||||
def test_bool_false_encode(self):
|
||||
s = Bool()
|
||||
s.b = False
|
||||
assert s.encode().tobytes() == b"\x08"
|
||||
assert s.encode().tobytes() == b"\x15\x28\x00\x18"
|
||||
|
||||
def test_bool_true_encode(self):
|
||||
s = Bool()
|
||||
s.b = True
|
||||
assert s.encode().tobytes() == b"\x09"
|
||||
assert s.encode().tobytes() == b"\x15\x29\x00\x18"
|
||||
|
||||
|
||||
class SignedIntOneOctet(tlv.Structure):
|
||||
i = tlv.NumberMember(None, "b")
|
||||
i = tlv.NumberMember(0, "b")
|
||||
|
||||
|
||||
class SignedIntTwoOctet(tlv.Structure):
|
||||
i = tlv.NumberMember(None, "h")
|
||||
i = tlv.NumberMember(0, "h")
|
||||
|
||||
|
||||
class SignedIntFourOctet(tlv.Structure):
|
||||
i = tlv.NumberMember(None, "i")
|
||||
i = tlv.NumberMember(0, "i")
|
||||
|
||||
|
||||
class SignedIntEightOctet(tlv.Structure):
|
||||
i = tlv.NumberMember(None, "q")
|
||||
i = tlv.NumberMember(0, "q")
|
||||
|
||||
|
||||
# Signed Integer, 1-octet, value 42
|
||||
|
|
@ -72,54 +72,58 @@ class SignedIntEightOctet(tlv.Structure):
|
|||
# 03 00 90 2f 50 09 00 00 00
|
||||
class TestSignedInt:
|
||||
def test_signed_int_42_decode(self):
|
||||
s, _ = SignedIntOneOctet.decode(0x15, b"\x00\x2a")
|
||||
s, _ = SignedIntOneOctet.decode(0x15, b"\x20\x00\x2a")
|
||||
assert str(s) == "{\n i = 42\n}"
|
||||
assert s.i == 42
|
||||
|
||||
def test_signed_int_negative_17_decode(self):
|
||||
s, _ = SignedIntOneOctet.decode(0x15, b"\x00\xef")
|
||||
s, _ = SignedIntOneOctet.decode(0x15, b"\x20\x00\xef")
|
||||
assert str(s) == "{\n i = -17\n}"
|
||||
assert s.i == -17
|
||||
|
||||
def test_signed_int_42_two_octet_decode(self):
|
||||
s, _ = SignedIntTwoOctet.decode(0x15, b"\x01\x2a\x00")
|
||||
s, _ = SignedIntTwoOctet.decode(0x15, b"\x21\x00\x2a\x00")
|
||||
assert str(s) == "{\n i = 42\n}"
|
||||
assert s.i == 42
|
||||
|
||||
def test_signed_int_negative_170000_decode(self):
|
||||
s, _ = SignedIntFourOctet.decode(0x15, b"\x02\xf0\x67\xfd\xff")
|
||||
s, _ = SignedIntFourOctet.decode(0x15, b"\x22\x00\xf0\x67\xfd\xff")
|
||||
assert str(s) == "{\n i = -170000\n}"
|
||||
assert s.i == -170000
|
||||
|
||||
def test_signed_int_40000000000_decode(self):
|
||||
s, _ = SignedIntEightOctet.decode(0x15, b"\x03\x00\x90\x2f\x50\x09\x00\x00\x00")
|
||||
s, _ = SignedIntEightOctet.decode(
|
||||
0x15, b"\x23\x00\x00\x90\x2f\x50\x09\x00\x00\x00"
|
||||
)
|
||||
assert str(s) == "{\n i = 40000000000\n}"
|
||||
assert s.i == 40000000000
|
||||
|
||||
def test_signed_int_42_encode(self):
|
||||
s = SignedIntOneOctet()
|
||||
s.i = 42
|
||||
assert s.encode().tobytes() == b"\x00\x2a"
|
||||
assert s.encode().tobytes() == b"\x15\x20\x00\x2a\x18"
|
||||
|
||||
def test_signed_int_negative_17_encode(self):
|
||||
s = SignedIntOneOctet()
|
||||
s.i = -17
|
||||
assert s.encode().tobytes() == b"\x00\xef"
|
||||
assert s.encode().tobytes() == b"\x15\x20\x00\xef\x18"
|
||||
|
||||
def test_signed_int_42_two_octet_encode(self):
|
||||
s = SignedIntTwoOctet()
|
||||
s.i = 42
|
||||
assert s.encode().tobytes() == b"\x01\x2a\x00"
|
||||
assert s.encode().tobytes() == b"\x15\x21\x00\x2a\x00\x18"
|
||||
|
||||
def test_signed_int_negative_170000_encode(self):
|
||||
s = SignedIntFourOctet()
|
||||
s.i = -170000
|
||||
assert s.encode().tobytes() == b"\x02\xf0\x67\xfd\xff"
|
||||
assert s.encode().tobytes() == b"\x15\x22\x00\xf0\x67\xfd\xff\x18"
|
||||
|
||||
def test_signed_int_40000000000_encode(self):
|
||||
s = SignedIntEightOctet()
|
||||
s.i = 40000000000
|
||||
assert s.encode().tobytes() == b"\x03\x00\x90\x2f\x50\x09\x00\x00\x00"
|
||||
assert (
|
||||
s.encode().tobytes() == b"\x15\x23\x00\x00\x90\x2f\x50\x09\x00\x00\x00\x18"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"octets,lower,upper",
|
||||
|
|
@ -147,21 +151,21 @@ class TestSignedInt:
|
|||
|
||||
|
||||
class UnsignedIntOneOctet(tlv.Structure):
|
||||
i = tlv.NumberMember(None, "B")
|
||||
i = tlv.NumberMember(0, "B")
|
||||
|
||||
|
||||
# Unsigned Integer, 1-octet, value 42U
|
||||
# 04 2a
|
||||
class TestUnsignedInt:
|
||||
def test_unsigned_int_42_decode(self):
|
||||
s, _ = UnsignedIntOneOctet.decode(0x15, b"\x04\x2a")
|
||||
s, _ = UnsignedIntOneOctet.decode(0x15, b"\x24\x00\x2a\x18")
|
||||
assert str(s) == "{\n i = 42U\n}"
|
||||
assert s.i == 42
|
||||
|
||||
def test_unsigned_int_42_encode(self):
|
||||
s = UnsignedIntOneOctet()
|
||||
s.i = 42
|
||||
assert s.encode().tobytes() == b"\x04\x2a"
|
||||
assert s.encode().tobytes() == b"\x15\x24\x00\x2a\x18"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"octets,lower,upper",
|
||||
|
|
@ -193,7 +197,7 @@ class TestUnsignedInt:
|
|||
s.i = v
|
||||
buffer = s.encode().tobytes()
|
||||
|
||||
s2, _ = UnsignedIntOneOctet.decode(0x15, buffer)
|
||||
s2, _ = UnsignedIntOneOctet.decode(0x15, buffer[1:])
|
||||
|
||||
assert s2.i == s.i
|
||||
assert str(s2) == str(s)
|
||||
|
|
@ -219,37 +223,38 @@ class TestUnsignedInt:
|
|||
# UTF-8 String, 1-octet length, "Tschüs"
|
||||
# 0c 07 54 73 63 68 c3 bc 73
|
||||
class UTF8StringOneOctet(tlv.Structure):
|
||||
s = tlv.UTF8StringMember(None, 16)
|
||||
s = tlv.UTF8StringMember(0, 16)
|
||||
|
||||
|
||||
class TestUTF8String:
|
||||
def test_utf8_string_hello_decode(self):
|
||||
s, _ = UTF8StringOneOctet.decode(0x15, b"\x0c\x06Hello!")
|
||||
s, _ = UTF8StringOneOctet.decode(0x15, b"\x2c\x00\x06Hello!")
|
||||
assert str(s) == '{\n s = "Hello!"\n}'
|
||||
assert s.s == "Hello!"
|
||||
|
||||
def test_utf8_string_tschs_decode(self):
|
||||
s, _ = UTF8StringOneOctet.decode(0x15, b"\x0c\x07Tsch\xc3\xbcs")
|
||||
s, _ = UTF8StringOneOctet.decode(0x15, b"\x2c\x00\x07Tsch\xc3\xbcs")
|
||||
assert str(s) == '{\n s = "Tschüs"\n}'
|
||||
assert s.s == "Tschüs"
|
||||
|
||||
def test_utf8_string_hello_encode(self):
|
||||
s = UTF8StringOneOctet()
|
||||
s.s = "Hello!"
|
||||
assert s.encode().tobytes() == b"\x0c\x06Hello!"
|
||||
assert s.encode().tobytes() == b"\x15\x2c\x00\x06Hello!\x18"
|
||||
|
||||
def test_utf8_string_tschs_encode(self):
|
||||
s = UTF8StringOneOctet()
|
||||
s.s = "Tschüs"
|
||||
assert s.encode().tobytes() == b"\x0c\x07Tsch\xc3\xbcs"
|
||||
assert s.encode().tobytes() == b"\x15\x2c\x00\x07Tsch\xc3\xbcs\x18"
|
||||
|
||||
@given(v=...)
|
||||
@given(v=st.text(max_size=4))
|
||||
def test_roundtrip(self, v: str):
|
||||
s = UTF8StringOneOctet()
|
||||
print(len(v))
|
||||
s.s = v
|
||||
buffer = s.encode().tobytes()
|
||||
|
||||
s2, _ = UTF8StringOneOctet.decode(0x15, buffer)
|
||||
s2, _ = UTF8StringOneOctet.decode(0x15, buffer[1:])
|
||||
|
||||
assert s2.s == s.s
|
||||
assert str(s2) == str(s)
|
||||
|
|
@ -258,27 +263,27 @@ class TestUTF8String:
|
|||
# Octet String, 1-octet length, octets 00 01 02 03 04
|
||||
# encoded: 10 05 00 01 02 03 04
|
||||
class OctetStringOneOctet(tlv.Structure):
|
||||
s = tlv.OctetStringMember(None, 16)
|
||||
s = tlv.OctetStringMember(0, 16)
|
||||
|
||||
|
||||
class TestOctetString:
|
||||
def test_octet_string_decode(self):
|
||||
s, _ = OctetStringOneOctet.decode(0x15, b"\x10\x05\x00\x01\x02\x03\x04")
|
||||
s, _ = OctetStringOneOctet.decode(0x15, b"\x30\x00\x05\x00\x01\x02\x03\x04\x18")
|
||||
assert str(s) == "{\n s = 00 01 02 03 04\n}"
|
||||
assert s.s == b"\x00\x01\x02\x03\x04"
|
||||
|
||||
def test_octet_string_encode(self):
|
||||
s = OctetStringOneOctet()
|
||||
s.s = b"\x00\x01\x02\x03\x04"
|
||||
assert s.encode().tobytes() == b"\x10\x05\x00\x01\x02\x03\x04"
|
||||
assert s.encode().tobytes() == b"\x15\x30\x00\x05\x00\x01\x02\x03\x04\x18"
|
||||
|
||||
@given(v=...)
|
||||
@given(v=st.binary(max_size=16))
|
||||
def test_roundtrip(self, v: bytes):
|
||||
s = OctetStringOneOctet()
|
||||
s.s = v
|
||||
buffer = s.encode().tobytes()
|
||||
|
||||
s2, _ = OctetStringOneOctet.decode(0x15, buffer)
|
||||
s2, _ = OctetStringOneOctet.decode(0x15, buffer[1:])
|
||||
|
||||
assert s2.s == s.s
|
||||
assert str(s2) == str(s)
|
||||
|
|
@ -289,24 +294,24 @@ class TestOctetString:
|
|||
|
||||
|
||||
class Null(tlv.Structure):
|
||||
n = tlv.BoolMember(None, nullable=True)
|
||||
n = tlv.BoolMember(0, nullable=True)
|
||||
|
||||
|
||||
class NotNull(tlv.Structure):
|
||||
n = tlv.BoolMember(None, nullable=True)
|
||||
b = tlv.BoolMember(None)
|
||||
n = tlv.BoolMember(0, nullable=True)
|
||||
b = tlv.BoolMember(1)
|
||||
|
||||
|
||||
class TestNull:
|
||||
def test_null_decode(self):
|
||||
s, _ = Null.decode(0x15, b"\x14")
|
||||
s, _ = Null.decode(0x15, b"\x34\x00\x18")
|
||||
assert str(s) == "{\n n = null\n}"
|
||||
assert s.n is None
|
||||
|
||||
def test_null_encode(self):
|
||||
s = Null()
|
||||
s.n = None
|
||||
assert s.encode().tobytes() == b"\x14"
|
||||
assert s.encode().tobytes() == b"\x15\x34\x00\x18"
|
||||
|
||||
def test_nullable(self):
|
||||
s = NotNull()
|
||||
|
|
@ -338,64 +343,64 @@ class TestNull:
|
|||
# Double precision floating point negative infinity 0b 00 00 00 00 00 00 f0 ff
|
||||
# (-∞)
|
||||
class FloatSingle(tlv.Structure):
|
||||
f = tlv.FloatMember(None)
|
||||
f = tlv.FloatMember(0)
|
||||
|
||||
|
||||
class FloatDouble(tlv.Structure):
|
||||
f = tlv.FloatMember(None, octets=8)
|
||||
f = tlv.FloatMember(0, octets=8)
|
||||
|
||||
|
||||
class TestFloatSingle:
|
||||
def test_precision_float_0_0_decode(self):
|
||||
s, _ = FloatSingle.decode(0x15, b"\x0a\x00\x00\x00\x00")
|
||||
s, _ = FloatSingle.decode(0x15, b"\x2a\x00\x00\x00\x00\x00\x18")
|
||||
assert str(s) == "{\n f = 0.0\n}"
|
||||
assert s.f == 0.0
|
||||
|
||||
def test_precision_float_1_3_decode(self):
|
||||
s, _ = FloatSingle.decode(0x15, b"\x0a\xab\xaa\xaa\x3e")
|
||||
s, _ = FloatSingle.decode(0x15, b"\x2a\x00\xab\xaa\xaa\x3e\x18")
|
||||
# assert str(s) == "{\n f = 0.3333333432674408\n}"
|
||||
f = s.f
|
||||
assert math.isclose(f, 1.0 / 3.0, rel_tol=1e-06)
|
||||
|
||||
def test_precision_float_17_9_decode(self):
|
||||
s, _ = FloatSingle.decode(0x15, b"\x0a\x33\x33\x8f\x41")
|
||||
s, _ = FloatSingle.decode(0x15, b"\x2a\x00\x33\x33\x8f\x41\x18")
|
||||
assert str(s) == "{\n f = 17.899999618530273\n}"
|
||||
assert math.isclose(s.f, 17.9, rel_tol=1e-06)
|
||||
|
||||
def test_precision_float_infinity_decode(self):
|
||||
s, _ = FloatSingle.decode(0x15, b"\x0a\x00\x00\x80\x7f")
|
||||
s, _ = FloatSingle.decode(0x15, b"\x2a\x00\x00\x00\x80\x7f\x18")
|
||||
assert str(s) == "{\n f = inf\n}"
|
||||
assert math.isinf(s.f)
|
||||
|
||||
def test_precision_float_negative_infinity_decode(self):
|
||||
s, _ = FloatSingle.decode(0x15, b"\x0a\x00\x00\x80\xff")
|
||||
s, _ = FloatSingle.decode(0x15, b"\x2a\x00\x00\x00\x80\xff\x18")
|
||||
assert str(s) == "{\n f = -inf\n}"
|
||||
assert math.isinf(s.f)
|
||||
|
||||
def test_precision_float_0_0_encode(self):
|
||||
s = FloatSingle()
|
||||
s.f = 0.0
|
||||
assert s.encode().tobytes() == b"\x0a\x00\x00\x00\x00"
|
||||
assert s.encode().tobytes() == b"\x15\x2a\x00\x00\x00\x00\x00\x18"
|
||||
|
||||
def test_precision_float_1_3_encode(self):
|
||||
s = FloatSingle()
|
||||
s.f = 1.0 / 3.0
|
||||
assert s.encode().tobytes() == b"\x0a\xab\xaa\xaa\x3e"
|
||||
assert s.encode().tobytes() == b"\x15\x2a\x00\xab\xaa\xaa\x3e\x18"
|
||||
|
||||
def test_precision_float_17_9_encode(self):
|
||||
s = FloatSingle()
|
||||
s.f = 17.9
|
||||
assert s.encode().tobytes() == b"\x0a\x33\x33\x8f\x41"
|
||||
assert s.encode().tobytes() == b"\x15\x2a\x00\x33\x33\x8f\x41\x18"
|
||||
|
||||
def test_precision_float_infinity_encode(self):
|
||||
s = FloatSingle()
|
||||
s.f = float("inf")
|
||||
assert s.encode().tobytes() == b"\x0a\x00\x00\x80\x7f"
|
||||
assert s.encode().tobytes() == b"\x15\x2a\x00\x00\x00\x80\x7f\x18"
|
||||
|
||||
def test_precision_float_negative_infinity_encode(self):
|
||||
s = FloatSingle()
|
||||
s.f = float("-inf")
|
||||
assert s.encode().tobytes() == b"\x0a\x00\x00\x80\xff"
|
||||
assert s.encode().tobytes() == b"\x15\x2a\x00\x00\x00\x80\xff\x18"
|
||||
|
||||
@given(v=...)
|
||||
def test_roundtrip_double(self, v: float):
|
||||
|
|
@ -403,7 +408,7 @@ class TestFloatSingle:
|
|||
s.f = v
|
||||
buffer = s.encode().tobytes()
|
||||
|
||||
s2, _ = FloatDouble.decode(0x15, buffer)
|
||||
s2, _ = FloatDouble.decode(0x15, buffer[1:])
|
||||
|
||||
assert (
|
||||
(math.isnan(s.f) and math.isnan(s2.f))
|
||||
|
|
@ -424,8 +429,9 @@ class TestFloatSingle:
|
|||
s = FloatSingle()
|
||||
s.f = v
|
||||
buffer = s.encode().tobytes()
|
||||
print("Buffer", buffer.hex(" "))
|
||||
|
||||
s2, _ = FloatSingle.decode(0x15, buffer)
|
||||
s2, _ = FloatSingle.decode(0x15, buffer[1:])
|
||||
|
||||
assert (math.isnan(s.f) and math.isnan(s2.f)) or math.isclose(
|
||||
s2.f, s.f, rel_tol=1e-7, abs_tol=1e-9
|
||||
|
|
@ -434,55 +440,65 @@ class TestFloatSingle:
|
|||
|
||||
class TestFloatDouble:
|
||||
def test_precision_float_0_0_decode(self):
|
||||
s, _ = FloatDouble.decode(0x15, b"\x0b\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
s, _ = FloatDouble.decode(0x15, b"\x2b\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
assert str(s) == "{\n f = 0.0\n}"
|
||||
assert s.f == 0.0
|
||||
|
||||
def test_precision_float_1_3_decode(self):
|
||||
s, _ = FloatDouble.decode(0x15, b"\x0b\x55\x55\x55\x55\x55\x55\xd5\x3f")
|
||||
s, _ = FloatDouble.decode(0x15, b"\x2b\x00\x55\x55\x55\x55\x55\x55\xd5\x3f")
|
||||
# assert str(s) == "{\n f = 0.3333333333333333\n}"
|
||||
f = s.f
|
||||
assert math.isclose(f, 1.0 / 3.0, rel_tol=1e-06)
|
||||
|
||||
def test_precision_float_17_9_decode(self):
|
||||
s, _ = FloatDouble.decode(0x15, b"\x0b\x66\x66\x66\x66\x66\xe6\x31\x40")
|
||||
s, _ = FloatDouble.decode(0x15, b"\x2b\x00\x66\x66\x66\x66\x66\xe6\x31\x40")
|
||||
assert str(s) == "{\n f = 17.9\n}"
|
||||
assert math.isclose(s.f, 17.9, rel_tol=1e-06)
|
||||
|
||||
def test_precision_float_infinity_decode(self):
|
||||
s, _ = FloatDouble.decode(0x15, b"\x0b\x00\x00\x00\x00\x00\x00\xf0\x7f")
|
||||
s, _ = FloatDouble.decode(0x15, b"\x2b\x00\x00\x00\x00\x00\x00\x00\xf0\x7f")
|
||||
assert str(s) == "{\n f = inf\n}"
|
||||
assert math.isinf(s.f)
|
||||
|
||||
def test_precision_float_negative_infinity_decode(self):
|
||||
s, _ = FloatDouble.decode(0x15, b"\x0b\x00\x00\x00\x00\x00\x00\xf0\xff")
|
||||
s, _ = FloatDouble.decode(0x15, b"\x2b\x00\x00\x00\x00\x00\x00\x00\xf0\xff")
|
||||
assert str(s) == "{\n f = -inf\n}"
|
||||
assert math.isinf(s.f)
|
||||
|
||||
def test_precision_float_0_0_encode(self):
|
||||
s = FloatDouble()
|
||||
s.f = 0.0
|
||||
assert s.encode().tobytes() == b"\x0b\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
assert (
|
||||
s.encode().tobytes() == b"\x15\x2b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"
|
||||
)
|
||||
|
||||
def test_precision_float_1_3_encode(self):
|
||||
s = FloatDouble()
|
||||
s.f = 1.0 / 3.0
|
||||
assert s.encode().tobytes() == b"\x0b\x55\x55\x55\x55\x55\x55\xd5\x3f"
|
||||
assert (
|
||||
s.encode().tobytes() == b"\x15\x2b\x00\x55\x55\x55\x55\x55\x55\xd5\x3f\x18"
|
||||
)
|
||||
|
||||
def test_precision_float_17_9_encode(self):
|
||||
s = FloatDouble()
|
||||
s.f = 17.9
|
||||
assert s.encode().tobytes() == b"\x0b\x66\x66\x66\x66\x66\xe6\x31\x40"
|
||||
assert (
|
||||
s.encode().tobytes() == b"\x15\x2b\x00\x66\x66\x66\x66\x66\xe6\x31\x40\x18"
|
||||
)
|
||||
|
||||
def test_precision_float_infinity_encode(self):
|
||||
s = FloatDouble()
|
||||
s.f = float("inf")
|
||||
assert s.encode().tobytes() == b"\x0b\x00\x00\x00\x00\x00\x00\xf0\x7f"
|
||||
assert (
|
||||
s.encode().tobytes() == b"\x15\x2b\x00\x00\x00\x00\x00\x00\x00\xf0\x7f\x18"
|
||||
)
|
||||
|
||||
def test_precision_float_negative_infinity_encode(self):
|
||||
s = FloatDouble()
|
||||
s.f = float("-inf")
|
||||
assert s.encode().tobytes() == b"\x0b\x00\x00\x00\x00\x00\x00\xf0\xff"
|
||||
assert (
|
||||
s.encode().tobytes() == b"\x15\x2b\x00\x00\x00\x00\x00\x00\x00\xf0\xff\x18"
|
||||
)
|
||||
|
||||
@given(v=...)
|
||||
def test_roundtrip(self, v: float):
|
||||
|
|
@ -490,7 +506,7 @@ class TestFloatDouble:
|
|||
s.f = v
|
||||
buffer = s.encode().tobytes()
|
||||
|
||||
s2, _ = FloatDouble.decode(0x15, buffer)
|
||||
s2, _ = FloatDouble.decode(0x15, buffer[1:])
|
||||
|
||||
assert (
|
||||
(math.isnan(s.f) and math.isnan(s2.f))
|
||||
|
|
@ -506,12 +522,12 @@ class InnerStruct(tlv.Structure):
|
|||
|
||||
|
||||
class OuterStruct(tlv.Structure):
|
||||
s = tlv.StructMember(None, InnerStruct)
|
||||
s = tlv.StructMember(0, InnerStruct)
|
||||
|
||||
|
||||
class TestStruct:
|
||||
def test_inner_struct_decode(self):
|
||||
s, _ = OuterStruct.decode(0x15, b"\x15\x20\x00\x2a\x20\x01\xef\x18")
|
||||
s, _ = OuterStruct.decode(0x15, b"\x35\x00\x20\x00\x2a\x20\x01\xef\x18\x18")
|
||||
assert_type(s, OuterStruct)
|
||||
assert_type(s.s, InnerStruct)
|
||||
assert_type(s.s.a, Optional[int])
|
||||
|
|
@ -520,7 +536,7 @@ class TestStruct:
|
|||
assert s.s.b == -17
|
||||
|
||||
def test_inner_struct_decode_empty(self):
|
||||
s, _ = OuterStruct.decode(0x15, b"\x15\x18")
|
||||
s, _ = OuterStruct.decode(0x15, b"\x35\x00\x18\x18")
|
||||
assert str(s) == "{\n s = {\n \n }\n}"
|
||||
assert s.s.a is None
|
||||
assert s.s.b is None
|
||||
|
|
@ -533,13 +549,13 @@ class TestStruct:
|
|||
s.s = inner
|
||||
assert (
|
||||
s.encode().tobytes()
|
||||
== b"\x15\x22\x00\x2a\x00\x00\x00\x22\x01\xef\xff\xff\xff\x18"
|
||||
== b"\x15\x35\x00\x22\x00\x2a\x00\x00\x00\x22\x01\xef\xff\xff\xff\x18\x18"
|
||||
)
|
||||
|
||||
def test_inner_struct_encode_empty(self):
|
||||
s = OuterStruct()
|
||||
s.s = InnerStruct()
|
||||
assert s.encode().tobytes() == b"\x15\x18"
|
||||
assert s.encode().tobytes() == b"\x15\x35\x00\x18\x18"
|
||||
|
||||
|
||||
class FullyQualified(tlv.Structure):
|
||||
|
|
@ -551,7 +567,7 @@ class TestFullyQualifiedTags:
|
|||
def test_decode(self):
|
||||
s, _ = FullyQualified.decode(
|
||||
0x15,
|
||||
b"\xc2\xda\x0a\x00\x0f\x23\x01\x2a\x00\x00\x00\xe2\xda\x0a\x00\x0f\x45\x23\x01\x00\xef\xff\xff\xff",
|
||||
b"\xc2\xda\x0a\x00\x0f\x23\x01\x2a\x00\x00\x00\xe2\xda\x0a\x00\x0f\x45\x23\x01\x00\xef\xff\xff\xff\x18",
|
||||
)
|
||||
assert_type(s, FullyQualified)
|
||||
assert_type(s.a, Optional[int])
|
||||
|
|
@ -565,5 +581,5 @@ class TestFullyQualifiedTags:
|
|||
s.b = -17
|
||||
assert (
|
||||
s.encode().tobytes()
|
||||
== b"\xc2\xda\x0a\x00\x0f\x23\x01\x2a\x00\x00\x00\xe2\xda\x0a\x00\x0f\x45\x23\x01\x00\xef\xff\xff\xff"
|
||||
== b"\x15\xc2\xda\x0a\x00\x0f\x23\x01\x2a\x00\x00\x00\xe2\xda\x0a\x00\x0f\x45\x23\x01\x00\xef\xff\xff\xff\x18"
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue