//! cb-sim — scenario runner binary (GameKernel K17; precursor of `cb sim`). //! Parses scenario files, dispatches each to its game by the `/` //! prefix of its `scenario` field, and executes it. Exit codes: 0 all //! passed, 1 any failure — including a scenario whose game prefix is not //! registered, and a run in which nothing executed. There is deliberately //! no "tolerable" non-zero exit: a silent skip is the failure mode this //! binary exists to catch. use cb_game_runtime::{scenario, RunOutcome, ScenarioFile}; use games_ground::GroundState; fn main() { let args: Vec = std::env::args().skip(1).collect(); if args.is_empty() { eprintln!("usage: cb-sim ..."); std::process::exit(64); } let mut failed = false; let mut passed = 0usize; let mut covered: Vec = Vec::new(); for path in &args { let text = match std::fs::read_to_string(path) { Ok(t) => t, Err(e) => { eprintln!("{path}: read error: {e}"); failed = true; continue; } }; let sc = match ScenarioFile::from_yaml(&text) { Err(e) => { eprintln!("{path}: parse error: {e}"); failed = true; continue; } Ok(sc) => sc, }; let outcome = match sc.scenario.split('/').next() { Some("ground") => scenario::run::(&sc), _ => { // A renamed or typo'd prefix would otherwise skip every // scenario while the run still looked clean. eprintln!( "FAIL {} — no game registered for prefix {:?}", sc.scenario, sc.scenario.split('/').next().unwrap_or("") ); failed = true; continue; } }; match outcome { RunOutcome::Passed { covers } => { println!( "PASS {} covers={}{}", sc.scenario, covers.join(","), if sc.provisional { " provisional" } else { "" } ); covered.extend(covers); passed += 1; } RunOutcome::Failed { reason } => { println!("FAIL {} — {reason}", sc.scenario); failed = true; } } } covered.sort(); covered.dedup(); println!("{passed} passed, {} rules covered", covered.len()); // Positive control: a run that executed nothing must not pass. This // is the same class of error as a benchmark timing rejected work. if passed == 0 { eprintln!("FAIL — no scenario executed; refusing to report success"); failed = true; } if failed { std::process::exit(1); } }