//! Named success/violation replays per category (TRAFFIC-06/08 gate). //! //! Headless and deterministic: tick-indexed normalized input through the //! production `TrafficWorld::tick` path. Every production scenario must //! build, tick without panic, and keep a stable terminal result. Practice //! honesty is pinned: finish-marker completion never claims an assessed //! behaviour, and every hazard scenario spawns its actor. use nigig_traffic::traffic::road::spawns_for; use nigig_traffic::traffic::scenario::{all, Category}; use nigig_traffic::traffic::{Phase, TrafficWorld}; fn drive_until_settled(index: usize, ticks: u64) -> TrafficWorld { let mut w = TrafficWorld::new(); w.load_scenario(index); let input = makepad_game_blocks::DriveInput::default(); for _ in 0..ticks { w.tick(&input); } w } #[test] fn every_scenario_builds_ticks_and_settles_deterministically() { let scenarios = all(); assert!(scenarios.len() >= 47, "catalog has {}", scenarios.len()); for (i, s) in scenarios.iter().enumerate() { let a = drive_until_settled(i, 600); let b = drive_until_settled(i, 600); assert_eq!(a.run.tick, 600, "{}", s.id); assert_eq!(a.run.phase, b.run.phase, "{}: nondeterministic", s.id); assert_eq!( a.verdict_counts(), b.verdict_counts(), "{}: nondeterministic", s.id ); // Idle input never completes or fails: the finish marker is far and // no input was given. (A scenario that self-completes with no // driving would be finish-circle laundering of nothing.) assert!( matches!(a.run.phase, Phase::Driving), "{}: idle run left Driving ({:?})", s.id, a.run.phase ); } } #[test] fn hazard_scenarios_spawn_their_actor() { for s in all().iter().filter(|s| s.category == Category::Hazards) { let spawns = spawns_for(s); assert_eq!(spawns.len(), 1, "{}: hazard lesson with no hazard", s.id); } } #[test] fn priority_scenarios_field_a_crossing_car() { for s in all().iter().filter(|s| s.category == Category::Priority) { let spawns = spawns_for(s); assert_eq!(spawns.len(), 1, "{}: priority lesson with no traffic", s.id); } } #[test] fn same_input_replay_gives_same_result_twice() { // Deterministic attempts (invariant 10): fixed scenario + seeded start // + tick-indexed input ⇒ same trace/result. fn replay() -> (Phase, [u64; 4], i32, u32) { let mut w = TrafficWorld::new(); w.load_scenario(0); for i in 0..600 { let input = makepad_game_blocks::DriveInput { steer: if i % 120 < 60 { 0.5 } else { -0.5 }, throttle: if i < 400 { 1.0 } else { 0.0 }, brake: if i >= 400 { 1.0 } else { 0.0 }, ..makepad_game_blocks::DriveInput::default() }; w.tick(&input); } ( w.run.phase, w.verdict_counts(), w.run.score.total_points, w.run.score.mistakes, ) } assert_eq!(replay(), replay()); }