94 lines
3.7 KiB
Python
94 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from cognitive_agent.application.native_can_runtime import NativeCanRuntime
|
|
from cognitive_agent.generated.can_semantic_protocol import (
|
|
CAN0_SUPPORTED_CAPABILITIES,
|
|
CAN1_SUPPORTED_CAPABILITIES,
|
|
PROTOCOL_SOURCE_SHA256,
|
|
frame,
|
|
match_semantic_command,
|
|
payload_variant,
|
|
)
|
|
from seat_domain import T2GSeatCompiler
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
class SharedCanSemanticProtocolTests(unittest.TestCase):
|
|
def test_checked_in_python_and_cpp_views_are_current(self) -> None:
|
|
completed = subprocess.run(
|
|
[sys.executable, "tools/generate_can_semantic_protocol.py", "--check"],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
self.assertEqual(completed.returncode, 0, completed.stderr)
|
|
self.assertEqual(len(PROTOCOL_SOURCE_SHA256), 64)
|
|
|
|
def test_generated_matcher_routes_both_channels_and_rejects_bad_axes(self) -> None:
|
|
cases = {
|
|
"seat passenger basin relative up 10": ("can0.seat.relative", 0),
|
|
"seat passenger legrest position 100": ("can0.seat.position", 0),
|
|
"ac fan 2": ("can1.climate.fan", 1),
|
|
"outlet passenger-right close": ("can1.outlet.switch", 1),
|
|
"seat driver horizontal forward 500": ("can1.seat.driver_axis", 1),
|
|
}
|
|
for command, expected in cases.items():
|
|
with self.subTest(command=command):
|
|
matched = match_semantic_command(command)
|
|
self.assertIsNotNone(matched)
|
|
assert matched is not None
|
|
self.assertEqual((matched["id"], matched["channel"]), expected)
|
|
for command in (
|
|
"seat passenger basin relative forward 10",
|
|
"seat driver height forward 500",
|
|
"ac fan 8",
|
|
"door vehicle lock",
|
|
):
|
|
with self.subTest(command=command):
|
|
self.assertIsNone(match_semantic_command(command))
|
|
|
|
def test_outlet_static_payload_and_transport_have_one_generated_source(self) -> None:
|
|
metadata = frame("can1.outlet.switch")
|
|
self.assertEqual(metadata["frame_id"], "0x4EF")
|
|
self.assertEqual(metadata["format"], "can_fd")
|
|
self.assertTrue(metadata["brs"])
|
|
self.assertEqual(metadata["repeat"], {"kind": "fixed", "count": 3, "period_ms": 100})
|
|
self.assertEqual(metadata["feedback_ids"], ["0x4BB", "0x37B"])
|
|
self.assertEqual(
|
|
payload_variant("can1.outlet.switch", "passenger-right:close"),
|
|
bytes.fromhex("03 FF FF FF FF 08 00 00"),
|
|
)
|
|
|
|
runtime = NativeCanRuntime(ROOT)
|
|
spec = runtime._outlet_switch_frame( # noqa: SLF001 - protocol contract test
|
|
"passenger_right", {"state": "close"}
|
|
)
|
|
self.assertEqual(spec.frame_id, 0x4EF)
|
|
self.assertEqual(spec.payload, bytes.fromhex("03 FF FF FF FF 08 00 00"))
|
|
self.assertEqual(spec.repeat_count, 3)
|
|
self.assertEqual(spec.period_ms, 100)
|
|
self.assertEqual(spec.feedback_ids, (0x4BB, 0x37B))
|
|
|
|
def test_python_capability_sets_and_can0_plan_contract_are_generated(self) -> None:
|
|
runtime = NativeCanRuntime(ROOT)
|
|
self.assertEqual(runtime.supported_capabilities, CAN1_SUPPORTED_CAPABILITIES)
|
|
self.assertIn("seat.set_longitudinal_position", CAN0_SUPPORTED_CAPABILITIES)
|
|
contract = T2GSeatCompiler._protocol_contract( # noqa: SLF001
|
|
"can0.seat.position", "move"
|
|
)
|
|
self.assertEqual(contract["frame_id"], "0x300")
|
|
self.assertEqual(contract["repeat"]["count"], 1)
|
|
self.assertEqual(contract["feedback_ids"], ["0x301", "0x302"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|