feat: 完善 N7 智能座舱交互与控制链路
This commit is contained in:
@@ -0,0 +1,759 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
import cognitive_agent.application.seat_service as seat_service_module
|
||||
from cognitive_agent.application.assistant_plan_guard import guard_assistant_plan
|
||||
from cognitive_agent.application.seat_service import SeatDemoService
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def _request(
|
||||
domain: str,
|
||||
capability: str,
|
||||
target: str,
|
||||
parameters: dict[str, object],
|
||||
*,
|
||||
operation: str = "set",
|
||||
duration_ms: int | None = None,
|
||||
) -> dict[str, object]:
|
||||
return {
|
||||
"domain": domain,
|
||||
"capability": capability,
|
||||
"target_scope": target,
|
||||
"operation": operation,
|
||||
"duration_ms": duration_ms,
|
||||
"parameters": [{"name": name, "value": value} for name, value in parameters.items()],
|
||||
"reason": "将用户明确表达的控制目标规范化为登记能力。",
|
||||
}
|
||||
|
||||
|
||||
def _plan(*requests: dict[str, object]) -> dict[str, object]:
|
||||
return {
|
||||
"detected_domains": list(dict.fromkeys(str(request["domain"]) for request in requests))
|
||||
or ["seat"],
|
||||
"requests": list(requests),
|
||||
"ambiguities": [],
|
||||
"decision_summary": ["仅规范化原始请求明确涉及的能力。"],
|
||||
"confidence": 0.95,
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def service(tmp_path_factory: pytest.TempPathFactory) -> SeatDemoService:
|
||||
instance = SeatDemoService(ROOT)
|
||||
instance.artifact_root = tmp_path_factory.mktemp("assistant-plan-runs")
|
||||
yield instance
|
||||
instance.close()
|
||||
|
||||
|
||||
def _executable_capabilities(service: SeatDemoService) -> set[str]:
|
||||
return {
|
||||
str(capability.get("name") or "")
|
||||
for domain in service.capability_context["domains"]
|
||||
for capability in domain.get("capabilities", [])
|
||||
if domain.get("availability") == "executable"
|
||||
or str(capability.get("name") or "") in service.native_can_runtime.supported_capabilities
|
||||
}
|
||||
|
||||
|
||||
def _guard(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
plan: dict[str, object],
|
||||
*,
|
||||
trusted_local: dict[str, object] | None = None,
|
||||
):
|
||||
return guard_assistant_plan(
|
||||
plan,
|
||||
fallback_text=text,
|
||||
capability_context=service.capability_context,
|
||||
executable_capabilities=_executable_capabilities(service),
|
||||
trusted_local=trusted_local,
|
||||
)
|
||||
|
||||
|
||||
def _operations(result: dict[str, object]) -> list[dict[str, object]]:
|
||||
return [
|
||||
operation
|
||||
for config in result.get("function_configs", {}).values()
|
||||
for operation in config.get("spec", {}).get("operations", [])
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "plan_request", "expected_capability", "expected_parameters"),
|
||||
[
|
||||
(
|
||||
"空调打开",
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_power",
|
||||
"vehicle",
|
||||
{"state": "on"},
|
||||
operation="activate",
|
||||
),
|
||||
"climate.set_power",
|
||||
{"state": "on"},
|
||||
),
|
||||
(
|
||||
"天幕透光率调到30%",
|
||||
_request(
|
||||
"roof",
|
||||
"roof.set_transmittance",
|
||||
"vehicle",
|
||||
{"transmittance_pct": 30},
|
||||
),
|
||||
"roof.set_transmittance",
|
||||
{"transmittance_pct": 30},
|
||||
),
|
||||
(
|
||||
"开启天幕自动调光",
|
||||
_request(
|
||||
"roof",
|
||||
"roof.set_automatic_dimming",
|
||||
"vehicle",
|
||||
{"state": "on"},
|
||||
operation="activate",
|
||||
),
|
||||
"roof.set_automatic_dimming",
|
||||
{"state": "on"},
|
||||
),
|
||||
(
|
||||
"氛围灯调成蓝色,亮度50%",
|
||||
_request(
|
||||
"ambient_light",
|
||||
"ambient_light.set_illumination",
|
||||
"vehicle",
|
||||
{"color_hex": "#0000FF", "brightness_pct": 50},
|
||||
),
|
||||
"ambient_light.set_illumination",
|
||||
{"color_hex": "#0000FF", "brightness_pct": 50},
|
||||
),
|
||||
(
|
||||
"氛围灯设置为影院模式",
|
||||
_request(
|
||||
"ambient_light",
|
||||
"ambient_light.set_mode",
|
||||
"vehicle",
|
||||
{"mode": "cinema"},
|
||||
),
|
||||
"ambient_light.set_mode",
|
||||
{"mode": "cinema"},
|
||||
),
|
||||
(
|
||||
"副驾腿托伸出到40%",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_legrest_extension",
|
||||
"passenger",
|
||||
{"position_pct": 40},
|
||||
),
|
||||
"seat.set_legrest_extension",
|
||||
{"position_pct": 40},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_explicit_registered_plan_executes_through_existing_pipeline(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
plan_request: dict[str, object],
|
||||
expected_capability: str,
|
||||
expected_parameters: dict[str, object],
|
||||
) -> None:
|
||||
with patch.object(
|
||||
service.openai,
|
||||
"interpret",
|
||||
side_effect=AssertionError("Codex plan must not invoke the legacy hosted parser"),
|
||||
):
|
||||
result = service.preview_native_can(
|
||||
text,
|
||||
provider="local",
|
||||
assistant_plan=_plan(plan_request),
|
||||
)
|
||||
|
||||
operations = _operations(result)
|
||||
assert result["status"] == "succeeded"
|
||||
assert result["provider_used"] == "local_rules+codex_app_server"
|
||||
assert [(item["capability"], item["parameters"]) for item in operations] == [
|
||||
(expected_capability, expected_parameters)
|
||||
]
|
||||
assert operations[0]["parse_source"] == "cloud_model"
|
||||
|
||||
|
||||
def test_named_preset_can_be_saved_then_applied_by_guarded_plan(
|
||||
service: SeatDemoService,
|
||||
) -> None:
|
||||
conversation_id = "conv-assistant-plan-preset"
|
||||
saved = service.preview_native_can(
|
||||
"保存当前座椅姿态为通勤",
|
||||
provider="local",
|
||||
conversation_id=conversation_id,
|
||||
assistant_plan=_plan(
|
||||
_request(
|
||||
"seat",
|
||||
"seat.save_posture_preset",
|
||||
"passenger",
|
||||
{"preset_name": "通勤"},
|
||||
operation="save",
|
||||
)
|
||||
),
|
||||
)
|
||||
applied = service.preview_native_can(
|
||||
"应用座椅预设通勤",
|
||||
provider="local",
|
||||
conversation_id=conversation_id,
|
||||
assistant_plan=_plan(
|
||||
_request(
|
||||
"seat",
|
||||
"seat.apply_posture_preset",
|
||||
"passenger",
|
||||
{"preset_name": "通勤"},
|
||||
operation="apply",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert saved["status"] == "succeeded"
|
||||
assert saved["saved_presets"] == [{"name": "通勤", "target": "passenger"}]
|
||||
assert applied["status"] == "succeeded"
|
||||
assert {item["capability"] for item in _operations(applied)} == {
|
||||
"seat.set_longitudinal_position",
|
||||
"seat.set_cushion_tilt",
|
||||
"seat.set_backrest_recline",
|
||||
"seat.set_legrest_height",
|
||||
"seat.set_legrest_extension",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "plan_request"),
|
||||
[
|
||||
(
|
||||
"关闭空调",
|
||||
_request("climate", "climate.set_power", "vehicle", {"state": "on"}),
|
||||
),
|
||||
(
|
||||
"打开遮阳帘",
|
||||
_request(
|
||||
"roof",
|
||||
"roof.set_shade_motion",
|
||||
"vehicle",
|
||||
{"motion": "close"},
|
||||
),
|
||||
),
|
||||
(
|
||||
"遮阳帘打开30%",
|
||||
_request(
|
||||
"roof",
|
||||
"roof.set_shade_position",
|
||||
"vehicle",
|
||||
{"position_pct": 70},
|
||||
),
|
||||
),
|
||||
(
|
||||
"空调温度调到23度",
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_temperature",
|
||||
"vehicle",
|
||||
{"temperature_c": 26},
|
||||
),
|
||||
),
|
||||
(
|
||||
"风量调到3档",
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_fan_level",
|
||||
"vehicle",
|
||||
{"level": 2},
|
||||
),
|
||||
),
|
||||
(
|
||||
"氛围灯亮度调到3档",
|
||||
_request(
|
||||
"ambient_light",
|
||||
"ambient_light.set_brightness_level",
|
||||
"vehicle",
|
||||
{"brightness_level": 5},
|
||||
),
|
||||
),
|
||||
(
|
||||
"智能天幕透光率调到30%",
|
||||
_request(
|
||||
"roof",
|
||||
"roof.set_transmittance",
|
||||
"vehicle",
|
||||
{"transmittance_pct": 70},
|
||||
),
|
||||
),
|
||||
(
|
||||
"后门上锁",
|
||||
_request("door", "door.set_rear_lock", "rear", {"state": "unlock"}),
|
||||
),
|
||||
(
|
||||
"把空调温度调低一点",
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_temperature",
|
||||
"vehicle",
|
||||
{"temperature_c": 23},
|
||||
operation="increase",
|
||||
),
|
||||
),
|
||||
(
|
||||
"把空调温度调低一点",
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_temperature",
|
||||
"vehicle",
|
||||
{"temperature_c": 23},
|
||||
operation="decrease",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_reversed_or_invented_value_is_filtered(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
plan_request: dict[str, object],
|
||||
) -> None:
|
||||
guarded = _guard(service, text, _plan(plan_request))
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert len(guarded.rejected_requests) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "plan_request"),
|
||||
[
|
||||
(
|
||||
"整车上锁",
|
||||
_request("door", "door.set_vehicle_lock", "vehicle", {"state": "lock"}),
|
||||
),
|
||||
(
|
||||
"打开壁灯",
|
||||
_request(
|
||||
"interior_light",
|
||||
"interior_light.set_wall_power",
|
||||
"vehicle",
|
||||
{"state": "on"},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_catalog_only_or_unimplemented_native_capability_is_filtered(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
plan_request: dict[str, object],
|
||||
) -> None:
|
||||
guarded = _guard(service, text, _plan(plan_request))
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert len(guarded.rejected_requests) == 1
|
||||
|
||||
|
||||
def test_model_cannot_expand_an_explicit_window_target(
|
||||
service: SeatDemoService,
|
||||
) -> None:
|
||||
guarded = _guard(
|
||||
service,
|
||||
"打开左前车窗",
|
||||
_plan(
|
||||
_request(
|
||||
"window",
|
||||
"window.set_motion",
|
||||
"rear_right",
|
||||
{"motion": "open"},
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert guarded.rejected_requests[0]["field"].endswith("target_scope")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("text", "state"), [("打开空调", "on"), ("关闭空调", "off")])
|
||||
def test_hvac_power_wording_does_not_authorize_compressor_control(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
state: str,
|
||||
) -> None:
|
||||
guarded = _guard(
|
||||
service,
|
||||
text,
|
||||
_plan(
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_ac",
|
||||
"vehicle",
|
||||
{"state": state},
|
||||
operation="activate" if state == "on" else "deactivate",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert guarded.rejected_requests[0]["field"].endswith("capability")
|
||||
|
||||
|
||||
def test_local_control_wins_and_plan_only_fills_unparsed_clause(
|
||||
service: SeatDemoService,
|
||||
) -> None:
|
||||
result = service.preview_native_can(
|
||||
"打开遮阳帘,空调打开",
|
||||
provider="local",
|
||||
assistant_plan=_plan(
|
||||
_request(
|
||||
"roof",
|
||||
"roof.set_shade_motion",
|
||||
"vehicle",
|
||||
{"motion": "close"},
|
||||
),
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_power",
|
||||
"vehicle",
|
||||
{"state": "on"},
|
||||
operation="activate",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
operations = _operations(result)
|
||||
by_capability = {item["capability"]: item for item in operations}
|
||||
assert by_capability["roof.set_shade_motion"]["parameters"] == {"motion": "open"}
|
||||
assert by_capability["roof.set_shade_motion"]["parse_source"] == "local_rule"
|
||||
assert by_capability["climate.set_power"]["parameters"] == {"state": "on"}
|
||||
assert by_capability["climate.set_power"]["parse_source"] == "cloud_model"
|
||||
|
||||
|
||||
def test_plan_still_passes_through_language_safety_guard(
|
||||
service: SeatDemoService,
|
||||
) -> None:
|
||||
original_guard = seat_service_module.apply_language_safety_guards
|
||||
with patch.object(
|
||||
seat_service_module,
|
||||
"apply_language_safety_guards",
|
||||
wraps=original_guard,
|
||||
) as safety_guard:
|
||||
result = service.preview_native_can(
|
||||
"空调打开",
|
||||
provider="local",
|
||||
assistant_plan=_plan(
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_power",
|
||||
"vehicle",
|
||||
{"state": "on"},
|
||||
operation="activate",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert result["status"] == "succeeded"
|
||||
safety_guard.assert_called_once()
|
||||
assert safety_guard.call_args.args[1] == "空调打开"
|
||||
|
||||
|
||||
def test_adapter_range_check_rejects_even_text_evidenced_value(
|
||||
service: SeatDemoService,
|
||||
) -> None:
|
||||
result = service.preview_native_can(
|
||||
"空调温度调到99度",
|
||||
provider="local",
|
||||
assistant_plan=_plan(
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_temperature",
|
||||
"vehicle",
|
||||
{"temperature_c": 99},
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert result["status"] == "no_action"
|
||||
assert _operations(result) == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message",
|
||||
(
|
||||
"为什么要打开空调",
|
||||
"请复述:打开空调",
|
||||
"写一个故事,主角打开空调",
|
||||
),
|
||||
)
|
||||
def test_non_execution_question_cannot_authorize_a_plan(
|
||||
service: SeatDemoService,
|
||||
message: str,
|
||||
) -> None:
|
||||
guarded = _guard(
|
||||
service,
|
||||
message,
|
||||
_plan(
|
||||
_request(
|
||||
"climate",
|
||||
"climate.set_power",
|
||||
"vehicle",
|
||||
{"state": "on"},
|
||||
operation="activate",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert len(guarded.rejected_requests) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "valid_request", "reversed_request"),
|
||||
[
|
||||
(
|
||||
"氛围灯颜色编号32",
|
||||
_request(
|
||||
"ambient_light",
|
||||
"ambient_light.set_color_index",
|
||||
"vehicle",
|
||||
{"color_index": 32},
|
||||
),
|
||||
_request(
|
||||
"ambient_light",
|
||||
"ambient_light.set_color_index",
|
||||
"vehicle",
|
||||
{"color_index": 70},
|
||||
),
|
||||
),
|
||||
(
|
||||
"主驾左风口水平标定值-20,垂直标定值30",
|
||||
_request(
|
||||
"outlet",
|
||||
"outlet.set_calibrated_position",
|
||||
"driver_left",
|
||||
{"horizontal_value": -20, "vertical_value": 30},
|
||||
),
|
||||
_request(
|
||||
"outlet",
|
||||
"outlet.set_calibrated_position",
|
||||
"driver_left",
|
||||
{"horizontal_value": 20, "vertical_value": 30},
|
||||
),
|
||||
),
|
||||
(
|
||||
"召回主驾座椅2号记忆位置",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.recall_driver_memory_native",
|
||||
"driver",
|
||||
{"slot": 2},
|
||||
),
|
||||
_request(
|
||||
"seat",
|
||||
"seat.recall_driver_memory_native",
|
||||
"driver",
|
||||
{"slot": 3},
|
||||
),
|
||||
),
|
||||
(
|
||||
"副驾靠背调到120度",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_backrest_recline",
|
||||
"passenger",
|
||||
{"angle_deg": 120},
|
||||
),
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_backrest_recline",
|
||||
"passenger",
|
||||
{"angle_deg": 130},
|
||||
),
|
||||
),
|
||||
(
|
||||
"副驾座椅向后移动20毫米",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_longitudinal_position",
|
||||
"passenger",
|
||||
{"distance_mm": 20},
|
||||
),
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_longitudinal_position",
|
||||
"passenger",
|
||||
{"distance_mm": 30},
|
||||
),
|
||||
),
|
||||
(
|
||||
"主驾座椅按摩强度开到3档",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_driver_massage_native",
|
||||
"driver",
|
||||
{"action": "strength", "strength": 3},
|
||||
),
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_driver_massage_native",
|
||||
"driver",
|
||||
{"action": "strength", "strength": 2},
|
||||
),
|
||||
),
|
||||
(
|
||||
"启动副驾木马模式",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.start_dynamic_mode",
|
||||
"passenger",
|
||||
{"mode_id": 1},
|
||||
operation="activate",
|
||||
),
|
||||
_request(
|
||||
"seat",
|
||||
"seat.start_dynamic_mode",
|
||||
"passenger",
|
||||
{"mode_id": 2},
|
||||
operation="activate",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_remaining_numeric_and_action_parameters_are_text_bound(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
valid_request: dict[str, object],
|
||||
reversed_request: dict[str, object],
|
||||
) -> None:
|
||||
accepted = _guard(service, text, _plan(valid_request))
|
||||
rejected = _guard(service, text, _plan(reversed_request))
|
||||
|
||||
assert len(accepted.plan["requests"]) == 1
|
||||
assert accepted.rejected_requests == ()
|
||||
assert rejected.plan["requests"] == []
|
||||
assert len(rejected.rejected_requests) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "plan_request"),
|
||||
[
|
||||
(
|
||||
"关闭副驾空调",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.stop_dynamic_mode",
|
||||
"passenger",
|
||||
{},
|
||||
operation="deactivate",
|
||||
),
|
||||
),
|
||||
(
|
||||
"打开副驾空调加热",
|
||||
_request(
|
||||
"seat",
|
||||
"seat.set_heating",
|
||||
"passenger",
|
||||
{"state": "on", "level": 2},
|
||||
operation="activate",
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_occupant_words_in_climate_requests_cannot_authorize_seat_controls(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
plan_request: dict[str, object],
|
||||
) -> None:
|
||||
guarded = _guard(service, text, _plan(plan_request))
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert len(guarded.rejected_requests) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sentinel", ("unknown", "unspecified", "default"))
|
||||
def test_placeholder_targets_are_never_treated_as_implicit_authorization(
|
||||
service: SeatDemoService,
|
||||
sentinel: str,
|
||||
) -> None:
|
||||
guarded = _guard(
|
||||
service,
|
||||
"打开左前车窗",
|
||||
_plan(
|
||||
_request(
|
||||
"window",
|
||||
"window.set_motion",
|
||||
sentinel,
|
||||
{"motion": "open"},
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert guarded.rejected_requests[0]["field"].endswith("target_scope")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("target", ("front_left", "all"))
|
||||
def test_local_reading_light_request_cannot_expand_to_another_scope(
|
||||
service: SeatDemoService,
|
||||
target: str,
|
||||
) -> None:
|
||||
guarded = _guard(
|
||||
service,
|
||||
"打开主驾阅读灯",
|
||||
_plan(
|
||||
_request(
|
||||
"interior_light",
|
||||
"interior_light.set_reading_power",
|
||||
target,
|
||||
{"state": "on"},
|
||||
operation="activate",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert guarded.plan["requests"] == []
|
||||
assert len(guarded.rejected_requests) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("text", "capability", "valid", "swapped"),
|
||||
[
|
||||
(
|
||||
"主驾左风口水平25%垂直75%",
|
||||
"outlet.set_position_percent",
|
||||
{"horizontal_pct": 25, "vertical_pct": 75},
|
||||
{"horizontal_pct": 75, "vertical_pct": 25},
|
||||
),
|
||||
(
|
||||
"主驾左风口水平-20垂直30标定坐标",
|
||||
"outlet.set_calibrated_position",
|
||||
{"horizontal_value": -20, "vertical_value": 30},
|
||||
{"horizontal_value": 30, "vertical_value": -20},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_outlet_axis_values_cannot_be_swapped_by_a_model(
|
||||
service: SeatDemoService,
|
||||
text: str,
|
||||
capability: str,
|
||||
valid: dict[str, object],
|
||||
swapped: dict[str, object],
|
||||
) -> None:
|
||||
accepted = _guard(
|
||||
service,
|
||||
text,
|
||||
_plan(_request("outlet", capability, "driver_left", valid)),
|
||||
)
|
||||
rejected = _guard(
|
||||
service,
|
||||
text,
|
||||
_plan(_request("outlet", capability, "driver_left", swapped)),
|
||||
)
|
||||
|
||||
assert len(accepted.plan["requests"]) == 1
|
||||
assert accepted.rejected_requests == ()
|
||||
assert rejected.plan["requests"] == []
|
||||
assert len(rejected.rejected_requests) == 1
|
||||
Reference in New Issue
Block a user