//! Integration test: drive the built `aura` binary as a downstream user would, //! asserting the `run` subcommand's stdout/exit contract and the bad-args path. use std::process::Command; /// Path to the freshly-built `aura` binary (Cargo sets this env var for the test /// crate; the binary is named `aura` in `Cargo.toml`). const BIN: &str = env!("CARGO_BIN_EXE_aura"); #[test] fn run_prints_json_and_exits_zero() { let out = Command::new(BIN).arg("run").output().expect("spawn aura run"); assert!(out.status.success(), "exit status: {:?}", out.status); let stdout = String::from_utf8(out.stdout).expect("utf-8 stdout"); // exactly one line (the JSON object + a trailing newline from println!). assert_eq!(stdout.lines().count(), 1, "stdout was: {stdout:?}"); let line = stdout.trim_end(); // canonical cycle-0009 JSON shape: nested manifest + metrics, stable keys. assert!(line.starts_with("{\"manifest\":{\"commit\":\"unknown\","), "got: {line}"); assert!(line.contains("\"broker\":\"sim-optimal(pip_size=0.0001)\""), "got: {line}"); assert!(line.contains("\"window\":[1,7]"), "got: {line}"); assert!(line.contains("\"metrics\":{\"total_pips\":"), "got: {line}"); // the integer sign-flip count is stable across float renderings. assert!(line.ends_with("\"exposure_sign_flips\":1}}"), "got: {line}"); } #[test] fn no_args_prints_usage_and_exits_two() { let out = Command::new(BIN).output().expect("spawn aura"); assert_eq!(out.status.code(), Some(2), "exit status: {:?}", out.status); assert!(out.stdout.is_empty(), "stdout should be empty on the usage path"); let stderr = String::from_utf8(out.stderr).expect("utf-8 stderr"); assert!(stderr.contains("usage"), "stderr was: {stderr:?}"); } /// Property: `--help`/`-h` is the success-path help affordance, not the error /// path. A newcomer's reflex first command (C22 first-contact ergonomics, #20) /// prints the usage to stdout and exits 0; the conventional `-h` alias behaves /// identically. An *unknown* subcommand keeps the error path (exit 2) so the /// help fix does not regress bad-args handling. #[test] fn help_flag_prints_usage_to_stdout_and_exits_zero() { for flag in ["--help", "-h"] { let out = Command::new(BIN).arg(flag).output().expect("spawn aura --help"); assert_eq!(out.status.code(), Some(0), "`aura {flag}` exit: {:?}", out.status); let stdout = String::from_utf8(out.stdout).expect("utf-8 stdout"); assert!( !stdout.trim().is_empty(), "`aura {flag}` should print help to stdout, got: {stdout:?}" ); // The usage names the only subcommand a newcomer can run. assert!( stdout.contains("run"), "`aura {flag}` help should mention the `run` subcommand, got: {stdout:?}" ); } // Negative-preservation: an unknown subcommand is still the error path. let out = Command::new(BIN).arg("frobnicate").output().expect("spawn aura frobnicate"); assert_eq!( out.status.code(), Some(2), "unknown subcommand must stay exit 2: {:?}", out.status ); }