Files
Cognitive_Agent/tests/unit/test_self_calibration.py
2026-08-14 15:01:29 +08:00

119 lines
4.0 KiB
Python

from __future__ import annotations
import tempfile
import time
from pathlib import Path
import pytest
from cognitive_agent.application.calibration import protocol
from cognitive_agent.application.calibration.service import ApiError, CalibrationService
def test_protocol_matches_android_golden_vectors() -> None:
assert protocol.crc8(b"123456789") == 0x4B
vectors = (
(
protocol.command(0x00, protocol.OP_HELLO, protocol.AXIS_ALL),
"A1 00 01 FF 00 00 00 55",
),
(
protocol.command(0x01, protocol.OP_ARM, protocol.AXIS_ALL, 0x4E37),
"A1 01 02 FF 37 4E 00 0A",
),
(
protocol.command(0x23, protocol.OP_CALIBRATE, protocol.AXIS_ALL),
"A1 23 10 FF 00 00 00 33",
),
(
protocol.command(0x24, protocol.OP_MOVE_PERMILLE, 0, 1000),
"A1 24 11 00 E8 03 00 78",
),
(
protocol.command(0x25, protocol.OP_STOP, protocol.AXIS_ALL),
"A1 25 12 FF 00 00 00 6E",
),
)
for actual, expected in vectors:
assert actual == bytes.fromhex(expected)
def test_protocol_parses_status_and_rejects_bad_crc() -> None:
ack = protocol.parse(0x621, bytes.fromhex("B1 22 10 02 00 07 01 A9"))
assert isinstance(ack, protocol.Ack)
assert ack.accepted
controller = protocol.parse(0x622, bytes.fromhex("C1 01 00 17 07 FF 02 4E"))
assert isinstance(controller, protocol.ControllerStatus)
assert controller.can_ready
assert controller.motor_ready
assert controller.armed
frame = bytearray.fromhex("D1 00 F0 00 E0 01 17 40")
frame[2] ^= 1
with pytest.raises(protocol.ProtocolError):
protocol.parse(0x630, bytes(frame))
def test_simulation_uses_real_wire_boundary_and_generates_pose() -> None:
with tempfile.TemporaryDirectory() as directory:
service = CalibrationService(Path(directory))
service.start()
try:
initial = service.snapshot()
assert initial["transport"] == {
"mode": "hardware",
"state": "disconnected",
"detail": "尚未连接",
}
connected = service.connect_can({"mode": "simulation"})
assert connected["transport"]["state"] == "online"
assert connected["controller"]["can_ready"]
assert connected["controller"]["motor_ready"]
assert [axis["range"] for axis in connected["axes"]] == [480, 647, 917, 373]
service.move(0, 800)
time.sleep(0.2)
moving = service.snapshot()
assert moving["controller"]["armed"]
assert moving["axes"][0]["moving"]
time.sleep(0.45)
pose = service.snapshot()["mqtt"]
assert pose["state"] == "simulated"
assert pose["count"] >= 1
assert "Seat_cushion" in pose["areas"]
stopped = service.stop()
assert not stopped["controller"]["armed"]
finally:
service.close()
def test_virtual_session_restart_resets_axes_without_touching_hardware() -> None:
with tempfile.TemporaryDirectory() as directory:
service = CalibrationService(Path(directory))
service.start()
try:
service.connect_can({"mode": "simulation"})
service.move(1, 720)
time.sleep(0.15)
reset = service.reset_virtual_session()
assert reset["transport"]["mode"] == "simulation"
assert reset["transport"]["state"] == "disconnected"
assert reset["controller"]["armed"] is False
assert [axis["permille"] for axis in reset["axes"]] == [0, 0, 0, 0]
assert reset["operation"]["phase"] == protocol.PHASE_IDLE
finally:
service.close()
def test_virtual_session_restart_rejects_real_bench_state() -> None:
with tempfile.TemporaryDirectory() as directory:
service = CalibrationService(Path(directory))
with pytest.raises(ApiError, match="真实台架会话"):
service.reset_virtual_session()