feat(ppclock): 命令层/传输层/CLI/本地模板渲染,90 测试全绿

This commit is contained in:
agent committed 2026-07-24 10:57:25 +00:00
1 parent 6f5b0c60be
commit 2b01e5f589
60 files changed
+16869

No files matched your search

+138
View File
@@ -0,0 +1,138 @@
"""命令层测试 — 用 FakeTransport 验证高层操作的帧序列与顺序(证据 docs/protocol.md)。"""
import datetime
import pytest
from ppclock import commands as C
class FakeTransport:
def __init__(self, id_response="DEVICE12345678"):
self.epd_writes = []
self.rxtx_writes = []
self.id_response = id_response
self.delays = []
async def write_epd(self, data, response=True):
self.epd_writes.append(data)
async def write_rxtx(self, data, response=True):
self.rxtx_writes.append(data)
async def request_device_id(self, timeout=8.0):
self.rxtx_writes.append(bytes([0xEF, 0xEF]))
return self.id_response
async def delay(self, seconds):
self.delays.append(seconds)
@pytest.fixture
def t():
return FakeTransport()
class TestTimeAndMode:
@pytest.mark.asyncio
async def test_set_time_sends_dd_then_commit(self, t):
dt = datetime.datetime(2026, 7, 24, 15, 30, 0)
await C.set_time(t, dt)
assert t.rxtx_writes[0][0] == 0xDD
assert t.rxtx_writes[-1] == bytes([0xE2])
@pytest.mark.asyncio
async def test_set_mode_appends_commit(self, t):
await C.set_mode(t, "clock1")
assert t.rxtx_writes == [bytes.fromhex("e10201"), bytes([0xE2])]
@pytest.mark.asyncio
async def test_clear_uses_epd_channel(self, t):
await C.clear(t)
assert t.epd_writes == [bytes([0x00, 0x00]), bytes([0x01])]
assert t.rxtx_writes == []
class TestUploadImage:
@pytest.mark.asyncio
async def test_full_image_sequence(self, t):
"""整图:bw块×63 → 红块×63 → 延时 → 01"""
bw = bytes(15000)
red = bytes([0xFF]) * 15000
await C.upload_image(t, bw, red, small=False)
assert t.epd_writes[0][:4] == bytes([0x03, 0xFF, 0x00, 0x00])
assert t.epd_writes[63][:2] == bytes([0x03, 0x00]) # 红平面首块
assert t.epd_writes[-1] == bytes([0x01])
assert len(t.epd_writes) == 63 + 63 + 1
@pytest.mark.asyncio
async def test_mono_image_no_red_blocks(self, t):
await C.upload_image(t, bytes(15000), None, small=False)
assert len(t.epd_writes) == 63 + 1
@pytest.mark.asyncio
async def test_slot_select_before_upload(self, t):
await C.upload_image(t, bytes(15000), None, small=False, slot=2)
assert t.rxtx_writes[0] == bytes([0xEA, 0x02])
@pytest.mark.asyncio
async def test_small_image_ends_with_AA(self, t):
await C.upload_image(t, bytes(3500), None, small=True)
assert t.epd_writes[-1] == bytes([0xAA])
assert t.epd_writes[0][0] == 0x04
class TestOtherCommands:
@pytest.mark.asyncio
async def test_countdown_set(self, t):
d = datetime.date(2026, 12, 31)
await C.countdown_set(t, d, "clock")
assert t.rxtx_writes[0] == bytes([0xFF, 0x00, 0x20, 0x26, 0x12, 0x31])
assert t.rxtx_writes[-1] == bytes([0xE2])
@pytest.mark.asyncio
async def test_countdown_off(self, t):
await C.countdown_off(t)
assert t.rxtx_writes == [bytes([0xFA]), bytes([0xE2])]
@pytest.mark.asyncio
async def test_parking(self, t):
await C.parking(t, "13800138000")
assert t.rxtx_writes[0] == bytes([0xEF]) + bytes(
int(f"{d}{d}", 16) for d in "13800138000"
)
@pytest.mark.asyncio
async def test_sleep_on_off(self, t):
await C.sleep(t, True, 23, 7)
assert t.rxtx_writes[0] == bytes([0xFB, 0x01, 0x23, 0x07])
await C.sleep(t, False, 23, 7)
assert t.rxtx_writes[1] == bytes([0xFB, 0x00, 0x23, 0x07])
@pytest.mark.asyncio
async def test_rotation(self, t):
await C.rotation(t, count=4)
assert t.rxtx_writes[0] == bytes.fromhex("EA0003")
await C.rotation(t, interval=5, unit="min")
assert t.rxtx_writes[1] == bytes.fromhex("e9010501")
@pytest.mark.asyncio
async def test_activate(self, t):
await C.activate(t, "A1B2" * 8)
assert t.rxtx_writes[0] == bytes([0xEF]) + bytes.fromhex("A1B2" * 8)
assert t.rxtx_writes[-1] == bytes([0xE2])
@pytest.mark.asyncio
async def test_wifi(self, t):
await C.wifi(t, "MyAP", "pw", "101010100")
assert t.rxtx_writes[0] == b"WIFI_SSID:MyAP;WIFI_PASS:pw;CITY:101010100"
@pytest.mark.asyncio
async def test_lut(self, t):
await C.lut(t, 0x05)
assert t.rxtx_writes[0] == bytes([0xE6, 0x05])
@pytest.mark.asyncio
async def test_get_device_id(self, t):
dev_id = await C.get_device_id(t)
assert t.rxtx_writes[0] == bytes([0xEF, 0xEF])
assert dev_id == "DEVICE12345678"