from __future__ import annotations from pathlib import Path from sync_state_machine.engine import StateMachineConfig, StateMachineRuntime CFG_PATH = Path(__file__).resolve().parents[2] / "sync_state_machine" / "config" / "node_state_machine.yaml" def test_all_event_outcomes_are_dispatchable() -> None: cfg = StateMachineConfig.load(CFG_PATH) runtime = StateMachineRuntime(cfg) covered_events: set[str] = set() for event_id, transition in cfg.transitions.items(): if not transition.outcomes: continue for idx, outcome in enumerate(transition.outcomes): if outcome.to is None: continue src = next((s for s in transition.from_states if s != "*"), "*") decision = runtime.dispatch(current_state=src, event_id=event_id, context=dict(outcome.when)) assert decision is not None, f"{event_id}[{idx}] did not dispatch" assert decision.to_state == outcome.to, f"{event_id}[{idx}] target mismatch" assert decision.outcome_index == idx, f"{event_id}[{idx}] wrong branch matched" covered_events.add(event_id) assert covered_events == set(cfg.transitions.keys())