use std::path::{Path, PathBuf};
use std::process::Command;
mod common;
use common::bin_path;
fn corpus_root() -> PathBuf {
common::workspace_root().join("tests")
}
fn programs(dir: &Path) -> Vec<PathBuf> {
let mut found = Vec::new();
let entries = std::fs::read_dir(dir).unwrap_or_else(|e| panic!("read {}: {e}", dir.display()));
let mut entries: Vec<_> = entries.map(|e| e.expect("dir entry").path()).collect();
entries.sort();
for path in entries {
if path.is_dir() {
found.extend(programs(&path));
} else if path.extension().is_some_and(|e| e == "px") {
found.push(path);
}
}
found
}
#[test]
fn every_corpus_program_runs_and_prints_the_answer_it_documents() {
let root = corpus_root();
let programs = programs(&root);
assert!(
programs.len() >= 47,
"expected at least 47 programs in the corpus under {}, found {}. \
If you added one, raise this floor; if you removed one, say why.",
root.display(),
programs.len()
);
for px in programs {
let expected = std::fs::read_to_string(px.with_extension("out")).unwrap_or_else(|e| {
panic!(
"{}: every corpus program needs a `.out` naming its expected \
stdout ({e}). Add one; do not skip the program.",
px.display()
)
});
let mut cmd = Command::new(bin_path());
cmd.arg("run").arg(&px);
let input = px.with_extension("in");
if input.exists() {
cmd.arg("--input").arg(&input);
}
cmd.stdin(std::process::Stdio::null());
let output = cmd.output().expect("failed to run praxis");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert_eq!(
output.status.code(),
Some(0),
"`{}` should run clean\nstdout: {stdout}\nstderr: {stderr}",
px.display()
);
assert_eq!(
stdout.trim(),
expected.trim(),
"`{}` printed the wrong answer\nstderr: {stderr}",
px.display()
);
}
}