from __future__ import annotations import tempfile import unittest from pathlib import Path import yaml from cognitive_agent.application.mode_profile import ModeProfileRegistry from cognitive_agent.application.seat_service import REPOSITORY_ROOT class ModeProfileRegistryTests(unittest.TestCase): def test_zero_gravity_profile_matches_alias_and_builds_requests(self) -> None: registry = ModeProfileRegistry(REPOSITORY_ROOT / "config" / "modes") matched = registry.match_text("副驾驶进入零重力模式", vehicle_id="denza_n7") self.assertEqual([profile.id for profile in matched], ["zero_gravity"]) self.assertEqual(matched[0].vehicle_ids, ("denza_n7",)) requests = registry.requests_for_profiles(matched) self.assertGreaterEqual(len(requests), 4) self.assertEqual(requests[0]["domain"], "seat") self.assertEqual(requests[0]["capability"], "seat.set_longitudinal_position") self.assertEqual(requests[0]["target_scope"], "passenger") self.assertIn( {"name": "position_pct", "value": 100}, requests[0]["parameters"], ) by_capability = {request["capability"]: request for request in requests} self.assertEqual( by_capability["seat.set_cushion_tilt"]["parameters"], [{"name": "position_pct", "value": 100}], ) self.assertEqual( by_capability["seat.set_backrest_recline"]["parameters"], [ {"name": "position_pct", "value": 81}, {"name": "angle_deg", "value": 150}, ], ) self.assertEqual( by_capability["seat.set_legrest_height"]["parameters"], [ {"name": "position_pct", "value": 94}, {"name": "angle_deg", "value": 163}, ], ) public = registry.public_modes() self.assertIn("零重力模式", {item["name"] for item in public}) self.assertNotIn( "zero_gravity", {profile.id for profile in registry.match_text("副驾驶进入零重力模式", vehicle_id="other_vehicle")}, ) def test_reference_modes_are_denza_specific(self) -> None: registry = ModeProfileRegistry(REPOSITORY_ROOT / "config" / "modes") expected_ids = { "zero_gravity", "cruise_sofa", "leisure_lounger", "nap", "easy_entry_exit", "baby_nap", "office", "meditation_space", "electric_beach_chair", "queen_passenger_driving", "calf_decompression_float", "rocking_horse", "dynamic_cradle", } denza_modes = registry.public_modes(vehicle_id="denza_n7") denza_ids = {mode["id"] for mode in denza_modes} self.assertTrue(expected_ids.issubset(denza_ids)) self.assertTrue( expected_ids.isdisjoint( {mode["id"] for mode in registry.public_modes(vehicle_id="other_vehicle")} ) ) self.assertEqual( registry.match_text("进入办公模式", vehicle_id="denza_n7")[0].id, "office", ) self.assertEqual( registry.match_text("进入小腿解压悬浮模式", vehicle_id="denza_n7")[0].id, "calf_decompression_float", ) def test_dynamic_modes_preserve_exact_timelines_and_native_mode_ids(self) -> None: registry = ModeProfileRegistry(REPOSITORY_ROOT / "config" / "modes") profiles = { profile.id: profile for profile in registry.profiles() if profile.id in {"rocking_horse", "dynamic_cradle"} } horse = profiles["rocking_horse"] self.assertIsNotNone(horse.timeline) assert horse.timeline is not None self.assertEqual(horse.timeline.repeat, "until_stopped_or_timeout") self.assertEqual(horse.timeline.max_runtime_ms, 600_000) self.assertIsNone(horse.timeline.cycle_duration_ms) self.assertEqual( [(phase.id, phase.duration_ms) for phase in horse.timeline.phases], [("rock_forward", None), ("rock_backward", None)], ) self.assertEqual( horse.timeline.entry["targets"]["longitudinal"]["hall_pulse"], 320, ) self.assertEqual( [phase.completion for phase in horse.timeline.phases], ["all_targets_reached", "all_targets_reached"], ) self.assertEqual([phase.timeout_ms for phase in horse.timeline.phases], [15_000, 15_000]) self.assertEqual(horse.timeline.phases[0].motion["final_approach_hall_pulses"], 8) self.assertTrue(horse.timeline.phases[0].motion["continuous_four_axis_cruise"]) self.assertEqual( horse.timeline.phases[0].targets["cushion_tilt"]["hall_pulse"], 250, ) self.assertEqual( horse.timeline.phases[1].targets["cushion_tilt"]["hall_pulse"], 130, ) self.assertEqual( horse.timeline.phases[0].motion["cruise_duty_percent"]["cushion_tilt"], 90, ) self.assertEqual( horse.timeline.phases[0].targets["longitudinal"]["hall_pulse"], 270, ) self.assertEqual( horse.timeline.phases[1].targets["longitudinal"]["hall_pulse"], 370, ) self.assertEqual( horse.timeline.phases[0].motion["cruise_duty_percent"]["longitudinal"], 90, ) cradle = profiles["dynamic_cradle"] self.assertIsNotNone(cradle.timeline) assert cradle.timeline is not None self.assertEqual(cradle.timeline.repeat, "until_stopped_or_timeout") self.assertEqual(cradle.timeline.max_runtime_ms, 600_000) self.assertIsNone(cradle.timeline.cycle_duration_ms) self.assertEqual( [(phase.id, phase.duration_ms) for phase in cradle.timeline.phases], [("forward", None), ("return", None)], ) self.assertEqual( cradle.timeline.entry["targets"]["longitudinal"]["hall_pulse"], 391, ) self.assertEqual( [phase.completion for phase in cradle.timeline.phases], ["all_targets_reached", "all_targets_reached"], ) self.assertEqual( [phase.timeout_ms for phase in cradle.timeline.phases], [30_000, 30_000], ) self.assertEqual( cradle.timeline.phases[0].motion["final_approach_hall_pulses"], 12, ) self.assertTrue( cradle.timeline.phases[0].motion["continuous_four_axis_cruise"] ) self.assertNotIn("clearance_lead", cradle.timeline.phases[0].motion) requests = { profile.id: registry.requests_for_profiles([profile])[0] for profile in (horse, cradle) } self.assertEqual( requests["rocking_horse"]["parameters"], [{"name": "mode_id", "value": 1}], ) self.assertEqual( requests["dynamic_cradle"]["parameters"], [{"name": "mode_id", "value": 2}], ) def test_denza_mode_positions_use_corrected_n7_zero_points(self) -> None: registry = ModeProfileRegistry(REPOSITORY_ROOT / "config" / "modes") expected_positions = { "baby_nap": (81, 30, 41, 0), "calf_decompression_float": (51, 75, 0, 100), "cruise_sofa": (51, 30, 44, 53), "easy_entry_exit": (100, 0, 0, 0), "electric_beach_chair": (100, 0, 100, 60), "leisure_lounger": (51, 30, 66, 76), "meditation_space": (100, 44, 44, 58), "nap": (100, 100, 81, 94), "office": (72, 22, 22, 21), "queen_passenger_driving": (72, 38, 44, 31), "zero_gravity": (100, 100, 81, 94), } profiles = { profile.id: profile for profile in registry.profiles() if profile.id in expected_positions and profile.vehicle_ids == ("denza_n7",) } actual_positions = {} for profile_id, profile in profiles.items(): requests = { request["capability"]: request for request in registry.requests_for_profiles([profile]) } actual_positions[profile_id] = tuple( next( parameter["value"] for parameter in requests[capability]["parameters"] if parameter["name"] == "position_pct" ) for capability in ( "seat.set_longitudinal_position", "seat.set_cushion_tilt", "seat.set_backrest_recline", "seat.set_legrest_height", ) ) self.assertEqual(actual_positions, expected_positions) def test_common_modes_are_visible_with_vehicle_specific_overrides(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) common = root / "common" denza = root / "vehicles" / "denza_n7" other = root / "vehicles" / "other_vehicle" common.mkdir(parents=True) denza.mkdir(parents=True) other.mkdir(parents=True) (common / "relax.yaml").write_text( """ id: relax name: 放松模式 aliases: - relax description: 公共放松模式。 operations: - domain: roof capability: roof.set_transmittance target_scope: vehicle operation: set parameters: transmittance_pct: 45 """.strip() + "\n", encoding="utf-8", ) (denza / "relax.yaml").write_text( """ id: relax name: N7 放松模式 aliases: - relax description: N7 专属放松模式。 scope: vehicle_ids: - denza_n7 operations: - domain: roof capability: roof.set_transmittance target_scope: vehicle operation: set parameters: transmittance_pct: 20 """.strip() + "\n", encoding="utf-8", ) (other / "nap.yaml").write_text( """ id: nap name: 午休模式 description: 其他车型专属午休模式。 operations: - domain: roof capability: roof.set_transmittance target_scope: vehicle operation: set parameters: transmittance_pct: 10 """.strip() + "\n", encoding="utf-8", ) registry = ModeProfileRegistry(root) denza_matches = registry.match_text("进入放松模式", vehicle_id="denza_n7") other_matches = registry.match_text("进入放松模式", vehicle_id="other_vehicle") self.assertEqual([profile.name for profile in denza_matches], ["N7 放松模式"]) self.assertEqual([profile.name for profile in other_matches], ["放松模式"]) self.assertEqual( {profile.id for profile in registry.match_text("进入午休模式", vehicle_id="denza_n7")}, set(), ) self.assertEqual( {mode["id"] for mode in registry.public_modes(vehicle_id="denza_n7")}, {"relax"}, ) def test_save_mode_profile_persists_yaml_and_reloads(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) registry = ModeProfileRegistry(root) profile = registry.save_mode( "露营模式", [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": {"transmittance_pct": 20}, "reason": "保存最近一次天幕目标。", } ], vehicle_id="denza_n7", ) saved_path = Path(profile.source) self.assertTrue(saved_path.is_file()) self.assertEqual( saved_path.relative_to(root).parts[:3], ("vehicles", "denza_n7", "user"), ) document = yaml.safe_load(saved_path.read_text(encoding="utf-8")) self.assertEqual(document["name"], "露营模式") self.assertEqual(document["scope"]["vehicle_ids"], ["denza_n7"]) self.assertEqual(document["operations"][0]["domain"], "roof") reloaded = ModeProfileRegistry(root) matched = reloaded.match_text("进入露营模式", vehicle_id="denza_n7") self.assertEqual([item.name for item in matched], ["露营模式"]) self.assertEqual( reloaded.match_text("进入露营模式", vehicle_id="other_vehicle"), [], ) requests = reloaded.requests_for_profiles(matched) self.assertEqual(requests[0]["capability"], "roof.set_transmittance") self.assertEqual( requests[0]["parameters"], [{"name": "transmittance_pct", "value": 20}], ) def test_mode_card_override_persists_instruction_and_can_command_flow(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "presets" user_root = Path(directory) / "persistent-user-modes" preset = root / "vehicles" / "denza_n7" / "office.yaml" preset.parent.mkdir(parents=True) preset.write_text( """ id: office name: 办公模式 icon: briefcase scope: vehicle_ids: [denza_n7] operations: - domain: climate capability: climate.set_temperature target_scope: passenger parameters: temperature_c: 24 """.strip() + "\n", encoding="utf-8", ) registry = ModeProfileRegistry(root, user_root=user_root) flow = { "schema": "cognitive-agent-mode-command-flow/v1", "source_request_id": "req-mode-editor-001", "plans": { "native_climate": { "spec": { "commands": [ { "message": "Native_0x1DE", "signals": { "frame_id": "0x1DE", "data_hex": "00 00 00 00 18 00 00 00", }, } ] } } }, } registry.save_mode( "专注办公模式", [ { "domain": "climate", "capability": "climate.set_temperature", "target_scope": "passenger", "parameters": {"temperature_c": 24}, } ], mode_id="office", vehicle_id="denza_n7", icon="briefcase", instruction="副驾空调设置为24度", command_flow=flow, ) reloaded = ModeProfileRegistry(root, user_root=user_root) mode = next( item for item in reloaded.public_modes("denza_n7") if item["id"] == "office" ) self.assertEqual(mode["name"], "专注办公模式") self.assertEqual(mode["origin"], "customized") self.assertTrue(mode["preset_override"]) self.assertEqual(mode["instruction"], "副驾空调设置为24度") self.assertEqual( mode["command_flow"]["source_request_id"], "req-mode-editor-001", ) self.assertTrue( (user_root / "vehicles" / "denza_n7" / "user" / "office.yaml").is_file() ) def test_session_overlay_ignores_stale_repository_user_modes(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "profiles" session_root = Path(directory) / "session" stale = root / "vehicles" / "denza_n7" / "user" / "stale.yaml" stale.parent.mkdir(parents=True) stale.write_text( """ id: stale name: 上次运行模式 scope: vehicle_ids: [denza_n7] operations: - domain: roof capability: roof.set_transmittance target_scope: vehicle parameters: transmittance_pct: 20 """.strip() + "\n", encoding="utf-8", ) registry = ModeProfileRegistry(root, user_root=session_root) self.assertEqual(registry.public_modes("denza_n7"), []) created = registry.save_mode( "本次运行模式", [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "parameters": {"transmittance_pct": 35}, } ], vehicle_id="denza_n7", ) self.assertTrue(Path(created.source).is_relative_to(session_root)) self.assertEqual( {mode["id"] for mode in registry.public_modes("denza_n7")}, {created.id}, ) registry.delete_user_mode(created.id, "denza_n7") self.assertFalse(Path(created.source).exists()) self.assertEqual(registry.public_modes("denza_n7"), []) def test_delete_user_mode_removes_yaml_and_protects_presets(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) preset_path = root / "common" / "preset" / "office.yaml" preset_path.parent.mkdir(parents=True) preset_path.write_text( """ id: office name: 办公模式 operations: - domain: climate capability: climate.set_temperature target_scope: vehicle parameters: temperature_c: 24 """.strip() + "\n", encoding="utf-8", ) registry = ModeProfileRegistry(root) user_profile = registry.save_mode( "K歌模式", [ { "domain": "ambient_light", "capability": "ambient_light.set_power", "target_scope": "vehicle", "parameters": {"state": "on"}, } ], vehicle_id="denza_n7", ) public_modes = { mode["id"]: mode for mode in registry.public_modes(vehicle_id="denza_n7") } self.assertEqual(public_modes[user_profile.id]["origin"], "user") self.assertTrue(public_modes[user_profile.id]["deletable"]) self.assertEqual(public_modes["office"]["origin"], "preset") self.assertFalse(public_modes["office"]["deletable"]) deleted = registry.delete_user_mode(user_profile.id, "denza_n7") self.assertEqual(deleted.id, user_profile.id) self.assertFalse(Path(user_profile.source).exists()) self.assertNotIn( user_profile.id, {mode["id"] for mode in registry.public_modes("denza_n7")}, ) with self.assertRaises(PermissionError): registry.delete_user_mode("office", "denza_n7") def test_update_mode_profile_backs_up_initial_yaml_and_restores(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) registry = ModeProfileRegistry(root) profile = registry.save_mode( "露营模式", [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": {"transmittance_pct": 20}, "reason": "原始天幕目标。", } ], vehicle_id="denza_n7", ) updated = registry.update_mode( profile, [ { "domain": "roof", "capability": "roof.set_transmittance", "target_scope": "vehicle", "operation": "set", "parameters": {"transmittance_pct": 50}, "reason": "用户修改天幕目标。", } ], ) self.assertTrue(Path(profile.source).with_suffix(".yaml.initial.bak").is_file()) requests = registry.requests_for_profiles([updated]) self.assertEqual( requests[0]["parameters"], [{"name": "transmittance_pct", "value": 50}], ) restored = registry.restore_initial_mode(updated) restored_requests = registry.requests_for_profiles([restored]) self.assertEqual( restored_requests[0]["parameters"], [{"name": "transmittance_pct", "value": 20}], ) if __name__ == "__main__": unittest.main()