add: main function

This commit is contained in:
2026-03-12 21:09:49 -07:00
parent c0951fc9d4
commit 90de2206db
9 changed files with 1062 additions and 671 deletions

80
tests/hello_rpg.rs Normal file
View File

@@ -0,0 +1,80 @@
//! Integration tests for the compiler binary against the Hello World program.
use std::process::Command;
/// `CARGO_BIN_EXE_rust-langrpg` is injected by Cargo for integration tests and
/// always points at the freshly-built binary under `target/`.
const BIN: &str = env!("CARGO_BIN_EXE_rust-langrpg");
/// Absolute path to hello.rpg, resolved at compile time relative to the crate
/// root so the test works regardless of the working directory.
const HELLO_RPG: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/hello.rpg");
// ─────────────────────────────────────────────────────────────────────────────
// Helper
// ─────────────────────────────────────────────────────────────────────────────
fn run(args: &[&str]) -> std::process::Output {
Command::new(BIN)
.args(args)
.output()
.unwrap_or_else(|e| panic!("failed to spawn '{}': {e}", BIN))
}
// ─────────────────────────────────────────────────────────────────────────────
// Tests
// ─────────────────────────────────────────────────────────────────────────────
/// The compiler should exit 0 when given hello.rpg (no -o flag — tree is
/// discarded but the parse must still succeed).
#[test]
fn hello_rpg_exits_ok() {
let out = run(&[HELLO_RPG]);
assert!(
out.status.success(),
"expected exit 0 for hello.rpg\nstderr: {}",
String::from_utf8_lossy(&out.stderr),
);
}
/// When -o is supplied the output file must be created and contain a non-empty
/// parse tree.
#[test]
fn hello_rpg_writes_tree() {
let out_path = std::env::temp_dir().join("hello_rpg_test_tree.txt");
let out = run(&["-o", out_path.to_str().unwrap(), HELLO_RPG]);
assert!(
out.status.success(),
"compiler failed with -o flag\nstderr: {}",
String::from_utf8_lossy(&out.stderr),
);
let tree = std::fs::read_to_string(&out_path)
.unwrap_or_else(|e| panic!("could not read output file '{}': {e}", out_path.display()));
assert!(
!tree.trim().is_empty(),
"output file is empty — expected a parse tree",
);
// The tree should reference at least the top-level <program> non-terminal.
assert!(
tree.contains("program"),
"parse tree does not mention <program>:\n{tree}",
);
}
/// The compiler must print the file name to stderr as "ok: hello.rpg" (or the
/// full path) when the parse succeeds.
#[test]
fn hello_rpg_reports_ok_on_stderr() {
let out = run(&[HELLO_RPG]);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
stderr.starts_with("ok:"),
"expected stderr to start with 'ok:'\ngot: {stderr}",
);
}