use clap::Parser;
use std::process::Command;
const RFX: &str = env!("CARGO_BIN_EXE_rfx");
fn on_small_stack<F: FnOnce() + Send + 'static>(mib: usize, f: F) -> bool {
std::thread::Builder::new()
.stack_size(mib * 1024 * 1024)
.spawn(f)
.expect("spawn")
.join()
.is_ok()
}
#[test]
fn argument_parsing_fits_in_a_windows_sized_stack() {
assert!(
on_small_stack(2, || {
let r = reflex::cli::Cli::try_parse_from(["rfx", "index", ".", "--quiet"]);
assert!(r.is_ok(), "parse should succeed");
}),
"clap parsing overflowed a 2 MiB stack — main.rs must size the worker thread"
);
}
#[test]
fn every_subcommand_parses_within_that_stack() {
let cases: Vec<Vec<&str>> = vec![
vec!["rfx", "index", "."],
vec!["rfx", "query", "pattern"],
vec!["rfx", "query", "pattern", "--symbols", "--json"],
vec!["rfx", "deps", "src/main.rs"],
vec!["rfx", "serve", "--port", "7878"],
vec!["rfx", "mcp"],
vec!["rfx", "watch"],
];
for args in cases {
let label = args.join(" ");
assert!(
on_small_stack(2, move || {
let _ = reflex::cli::Cli::try_parse_from(args);
}),
"`{label}` overflowed a 2 MiB stack"
);
}
}
#[test]
fn clap_exit_codes_survive_running_off_the_main_thread() {
for (args, want, what) in [
(vec!["--version"], 0, "--version"),
(vec!["--help"], 0, "--help"),
(vec!["--definitely-not-a-flag"], 2, "unknown flag"),
(vec!["query"], 1, "missing pattern"),
] {
let out = Command::new(RFX).args(&args).output().expect("spawn rfx");
assert_eq!(
out.status.code(),
Some(want),
"{what}: expected exit {want}, got {:?}\nstderr: {}",
out.status.code(),
String::from_utf8_lossy(&out.stderr)
);
}
}
#[test]
fn clap_output_survives_running_off_the_main_thread() {
let v = Command::new(RFX).arg("--version").output().unwrap();
let text = String::from_utf8_lossy(&v.stdout);
assert!(text.contains("rfx"), "--version printed: {text:?}");
let h = Command::new(RFX).arg("--help").output().unwrap();
let text = String::from_utf8_lossy(&h.stdout);
assert!(text.contains("index"), "--help should list subcommands");
assert!(text.contains("query"), "--help should list subcommands");
}