168 lines
5.3 KiB
Python
168 lines
5.3 KiB
Python
"""Tests de l'extracteur incrémental REG3, indépendants de Home Assistant."""
|
|
|
|
from pathlib import Path
|
|
|
|
from custom_components.arkteos.frame_extractor import FrameExtractor
|
|
|
|
|
|
FIXTURES_PATH = Path(__file__).with_name("fixtures")
|
|
|
|
|
|
def _load_frames() -> dict[str, bytes]:
|
|
return {
|
|
"metadata": (FIXTURES_PATH / "metadata_95.bin").read_bytes(),
|
|
"frigo": (FIXTURES_PATH / "frigo_163.bin").read_bytes(),
|
|
"regulation": (FIXTURES_PATH / "regulation_227.bin").read_bytes(),
|
|
}
|
|
|
|
|
|
def test_no_bytes() -> None:
|
|
extractor = FrameExtractor()
|
|
assert extractor.feed(b"") == []
|
|
assert extractor.buffered_bytes == b""
|
|
|
|
|
|
def test_complete_metadata_frame() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
assert FrameExtractor().feed(metadata) == [metadata]
|
|
|
|
|
|
def test_complete_frigo_frame() -> None:
|
|
frigo = _load_frames()["frigo"]
|
|
assert FrameExtractor().feed(frigo) == [frigo]
|
|
|
|
|
|
def test_complete_regulation_frame() -> None:
|
|
regulation = _load_frames()["regulation"]
|
|
assert FrameExtractor().feed(regulation) == [regulation]
|
|
|
|
|
|
def test_frame_split_in_two_calls() -> None:
|
|
frigo = _load_frames()["frigo"]
|
|
extractor = FrameExtractor()
|
|
assert extractor.feed(frigo[:80]) == []
|
|
assert extractor.feed(frigo[80:]) == [frigo]
|
|
|
|
|
|
def test_frame_provided_byte_by_byte() -> None:
|
|
regulation = _load_frames()["regulation"]
|
|
extractor = FrameExtractor()
|
|
extracted = [frame for byte in regulation for frame in extractor.feed(bytes([byte]))]
|
|
assert extracted == [regulation]
|
|
|
|
|
|
def test_multiple_concatenated_frames() -> None:
|
|
frames = _load_frames()
|
|
sequence = frames["metadata"] + frames["frigo"] + frames["regulation"]
|
|
assert FrameExtractor().feed(sequence) == [
|
|
frames["metadata"],
|
|
frames["frigo"],
|
|
frames["regulation"],
|
|
]
|
|
|
|
|
|
def test_order_different_from_observed_cycle() -> None:
|
|
frames = _load_frames()
|
|
sequence = frames["frigo"] + frames["metadata"] + frames["regulation"]
|
|
assert FrameExtractor().feed(sequence) == [
|
|
frames["frigo"],
|
|
frames["metadata"],
|
|
frames["regulation"],
|
|
]
|
|
|
|
|
|
def test_noise_before_signature() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
assert FrameExtractor().feed(b"parasites" + metadata) == [metadata]
|
|
|
|
|
|
def test_signature_split_between_calls() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
extractor = FrameExtractor()
|
|
assert extractor.feed(b"parasites\x55") == []
|
|
assert extractor.buffered_bytes == b"\x55"
|
|
assert extractor.feed(metadata[1:]) == [metadata]
|
|
|
|
|
|
def test_incoherent_type_header_resynchronizes() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
invalid = bytearray(metadata)
|
|
invalid[8] = 0x0A
|
|
assert FrameExtractor().feed(bytes(invalid) + metadata) == [metadata]
|
|
|
|
|
|
def test_unknown_length_header_resynchronizes() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
invalid = bytearray(metadata)
|
|
invalid[10:12] = (81).to_bytes(2, "little")
|
|
assert FrameExtractor().feed(bytes(invalid) + metadata) == [metadata]
|
|
|
|
|
|
def test_announced_size_above_limit_resynchronizes() -> None:
|
|
frames = _load_frames()
|
|
extractor = FrameExtractor(max_buffer_size=200)
|
|
assert extractor.feed(frames["regulation"] + frames["metadata"]) == [
|
|
frames["metadata"]
|
|
]
|
|
|
|
|
|
def test_false_signature_in_noise() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
false_header = b"\x55\x00" + b"\x00" * 10
|
|
assert FrameExtractor().feed(b"\x10" + false_header + metadata) == [metadata]
|
|
|
|
|
|
def test_complete_frame_followed_by_incomplete_frame() -> None:
|
|
frames = _load_frames()
|
|
extractor = FrameExtractor()
|
|
assert extractor.feed(frames["metadata"] + frames["frigo"][:20]) == [
|
|
frames["metadata"]
|
|
]
|
|
assert extractor.buffered_bytes == frames["frigo"][:20]
|
|
assert extractor.feed(frames["frigo"][20:]) == [frames["frigo"]]
|
|
|
|
|
|
def test_variable_size_fragments() -> None:
|
|
frames = _load_frames()
|
|
sequence = frames["frigo"] + frames["metadata"] + frames["regulation"]
|
|
extractor = FrameExtractor()
|
|
extracted: list[bytes] = []
|
|
fragment_sizes = (1, 7, 31, 2, 83, 19, 11, 131)
|
|
offset = 0
|
|
for size in fragment_sizes:
|
|
extracted.extend(extractor.feed(sequence[offset : offset + size]))
|
|
offset += size
|
|
extracted.extend(extractor.feed(sequence[offset:]))
|
|
assert extracted == [frames["frigo"], frames["metadata"], frames["regulation"]]
|
|
|
|
|
|
def test_buffer_is_empty_after_complete_extraction() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
extractor = FrameExtractor()
|
|
extractor.feed(metadata)
|
|
assert extractor.buffered_size == 0
|
|
|
|
|
|
def test_incomplete_buffer_is_preserved() -> None:
|
|
metadata = _load_frames()["metadata"]
|
|
extractor = FrameExtractor()
|
|
assert extractor.feed(metadata[:10]) == []
|
|
assert extractor.buffered_bytes == metadata[:10]
|
|
|
|
|
|
def test_repeated_invalid_data_terminates() -> None:
|
|
invalid_header = b"\x55\x00" + b"\xff" * 10
|
|
extractor = FrameExtractor()
|
|
assert extractor.feed(invalid_header * 100) == []
|
|
assert extractor.buffered_size == 0
|
|
|
|
|
|
def test_sequence_with_all_real_fixtures() -> None:
|
|
frames = _load_frames()
|
|
sequence = frames["regulation"] + frames["frigo"] + frames["metadata"]
|
|
assert FrameExtractor().feed(sequence) == [
|
|
frames["regulation"],
|
|
frames["frigo"],
|
|
frames["metadata"],
|
|
]
|