105 lines
4.1 KiB
Python
Executable File
105 lines
4.1 KiB
Python
Executable File
from __future__ import annotations
|
|
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
from cognitive_agent.runtime.contracts import ContractValidator
|
|
from seat_domain.generator import build_function_config
|
|
from seat_domain.intent import parse_local_intent
|
|
from seat_domain.matrix import SeatCanMatrix
|
|
from seat_domain.source_matrix import read_source_signals
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[4]
|
|
DOMAIN_ROOT = ROOT / "domains" / "seat"
|
|
|
|
|
|
class SeatContractTests(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.validator = ContractValidator(ROOT)
|
|
|
|
def test_generated_function_config_matches_both_schemas(self) -> None:
|
|
parsed = parse_local_intent("打开副驾座椅加热")
|
|
config = build_function_config(parsed, "req-contract-001", "local_rules")
|
|
|
|
self.assertEqual(self.validator.validate(config), [])
|
|
|
|
def test_inferred_level_function_config_matches_both_schemas(self) -> None:
|
|
parsed = parse_local_intent("主驾有点热,有点闷")
|
|
config = build_function_config(parsed, "req-contract-002", "local_rules")
|
|
|
|
self.assertEqual(config["spec"]["operations"][0]["parameters"]["level"], 1)
|
|
self.assertEqual(self.validator.validate(config), [])
|
|
|
|
def test_motion_function_config_matches_both_schemas(self) -> None:
|
|
parsed = {
|
|
"detected_domains": ["seat"],
|
|
"actions": [
|
|
{
|
|
"action_type": "position",
|
|
"target": "passenger",
|
|
"axis": "legrest_extension",
|
|
"position_pct": 70,
|
|
}
|
|
],
|
|
"deferred_requests": [],
|
|
"ambiguities": [],
|
|
"decision_summary": ["Extend passenger leg rest."],
|
|
"confidence": 1.0,
|
|
}
|
|
|
|
config = build_function_config(parsed, "req-contract-motion", "test")
|
|
|
|
self.assertEqual(config["spec"]["operations"][0]["parameters"], {"position_pct": 70})
|
|
self.assertEqual(self.validator.validate(config), [])
|
|
|
|
def test_all_active_presets_match_both_schemas(self) -> None:
|
|
for path in (DOMAIN_ROOT / "config" / "presets").glob("*.yaml"):
|
|
with self.subTest(path=path.name):
|
|
document = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
self.assertEqual(self.validator.validate(document), [])
|
|
|
|
def test_normalized_matrix_matches_source_scope(self) -> None:
|
|
matrix = SeatCanMatrix(DOMAIN_ROOT / "can" / "seat-thermal-matrix.yaml")
|
|
|
|
self.assertEqual(len(matrix.data["messages"]), 6)
|
|
self.assertEqual(sum(len(item["signals"]) for item in matrix.data["messages"]), 23)
|
|
self.assertFalse(matrix.hardware_execution_allowed)
|
|
|
|
def test_synthetic_motion_matrix_is_explicitly_non_hardware(self) -> None:
|
|
matrix = SeatCanMatrix(DOMAIN_ROOT / "can" / "seat-motion-virtual-matrix.yaml")
|
|
|
|
self.assertTrue(matrix.data["synthetic"])
|
|
self.assertFalse(matrix.hardware_execution_allowed)
|
|
self.assertEqual(len(matrix.data["messages"]), 4)
|
|
self.assertEqual(sum(len(item["signals"]) for item in matrix.data["messages"]), 34)
|
|
|
|
def test_normalized_signal_layout_matches_supplied_xlsx(self) -> None:
|
|
source = {
|
|
item["name"]: item
|
|
for item in read_source_signals(ROOT / "座椅部分功能CAN矩阵表.xlsx")
|
|
}
|
|
matrix = SeatCanMatrix(DOMAIN_ROOT / "can" / "seat-thermal-matrix.yaml")
|
|
normalized = {
|
|
signal["name"]: {
|
|
"frame_id": int(message["frame_id"]),
|
|
"start_bit": int(signal["start_bit"]),
|
|
"bit_length": int(signal["bit_length"]),
|
|
}
|
|
for message in matrix.data["messages"]
|
|
for signal in message["signals"]
|
|
}
|
|
|
|
self.assertEqual(set(source), set(normalized))
|
|
for name, layout in normalized.items():
|
|
with self.subTest(signal=name):
|
|
self.assertEqual(layout["frame_id"], source[name]["frame_id"])
|
|
self.assertEqual(layout["start_bit"], source[name]["start_bit"])
|
|
self.assertEqual(layout["bit_length"], source[name]["bit_length"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|