use std::process::Command;
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
#[cfg(feature = "cranelift")]
const ENGINES_ALL: &[&str] = &["--vm", "--jit"];
#[cfg(not(feature = "cranelift"))]
const ENGINES_ALL: &[&str] = &["--vm"];
fn run_engine(engine: &str, src: &str) -> (String, String, i32) {
let out = ilo()
.args([src, engine])
.output()
.expect("failed to run ilo");
let code = out.status.code().unwrap_or(-1);
(
String::from_utf8_lossy(&out.stdout).trim().to_string(),
String::from_utf8_lossy(&out.stderr).trim().to_string(),
code,
)
}
fn run_default_inline(src: &str) -> (String, String, i32) {
let out = ilo().arg(src).output().expect("failed to run ilo");
let code = out.status.code().unwrap_or(-1);
(
String::from_utf8_lossy(&out.stdout).trim().to_string(),
String::from_utf8_lossy(&out.stderr).trim().to_string(),
code,
)
}
#[test]
fn bare_bang_on_number_errors_on_default_inline() {
let src = "main>R n t;x=42;x!";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 1, "expected exit 1, got {code}. stdout={stdout:?}");
assert!(
stdout.is_empty(),
"expected empty stdout (not 'nil'), got {stdout:?}"
);
assert!(
stderr.contains("ILO-T034"),
"expected ILO-T034 in stderr, got: {stderr}"
);
assert!(
stderr.contains("auto-unwrap operator"),
"expected explanatory message about auto-unwrap, got: {stderr}"
);
}
#[test]
fn bare_bang_on_number_errors_on_every_engine() {
let src = "main>R n t;x=42;x!";
for engine in ENGINES_ALL {
let (stdout, stderr, code) = run_engine(engine, src);
assert_eq!(code, 1, "{engine}: expected exit 1, got {code}");
assert!(stdout.is_empty(), "{engine}: stdout not empty: {stdout:?}");
assert!(
stderr.contains("ILO-T034"),
"{engine}: expected ILO-T034, got: {stderr}"
);
}
}
#[test]
fn bare_bang_on_text_local_errors_on_default_inline() {
let src = "main>R t t;s=\"hi\";s!";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 1, "expected exit 1, got {code}");
assert!(stdout.is_empty(), "expected empty stdout, got {stdout:?}");
assert!(stderr.contains("ILO-T034"), "stderr: {stderr}");
}
#[test]
fn bare_bang_on_param_errors_on_default_inline() {
let src = "f p:n>R n t;p!\nmain>R n t;f 1";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 1, "expected exit 1, got {code}");
assert!(stdout.is_empty(), "stdout: {stdout:?}");
assert!(stderr.contains("ILO-T034"), "stderr: {stderr}");
}
#[test]
fn bare_bangbang_on_number_errors_on_default_inline() {
let src = "main>n;x=42;x!!";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 1, "expected exit 1, got {code}");
assert!(stdout.is_empty(), "stdout: {stdout:?}");
assert!(stderr.contains("ILO-T034"), "stderr: {stderr}");
assert!(stderr.contains("!!"), "expected !! mention, got: {stderr}");
}
#[test]
fn bare_bang_inside_guard_body_errors() {
let src = "main>R n t;x=42;>x 0{x!};~x";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 1, "expected exit 1, got {code}");
assert!(stdout.is_empty(), "stdout: {stdout:?}");
assert!(stderr.contains("ILO-T034"), "stderr: {stderr}");
}
#[test]
fn bang_on_result_returning_fn_still_works_default_inline() {
let src = "helper>R n t;~42\nmain>R n t;v=helper!;~v";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 0, "expected exit 0, got {code}. stderr={stderr}");
assert_eq!(stdout, "42", "expected 42, got {stdout:?}");
}
#[test]
fn bang_on_result_returning_fn_still_works_every_engine() {
let src = "helper>R n t;~42\nmain>R n t;v=helper!;~v";
for engine in ENGINES_ALL {
let (stdout, stderr, code) = run_engine(engine, src);
assert_eq!(code, 0, "{engine}: exit {code}, stderr={stderr}");
assert_eq!(stdout, "42", "{engine}: got {stdout:?}");
}
}
#[test]
fn bangbang_on_result_returning_fn_still_works_default_inline() {
let src = "helper>R n t;~42\nmain>n;helper!!";
let (stdout, stderr, code) = run_default_inline(src);
assert_eq!(code, 0, "expected exit 0, got {code}. stderr={stderr}");
assert_eq!(stdout, "42", "expected 42, got {stdout:?}");
}
#[test]
fn explicit_ast_flag_still_dumps_without_verifying() {
let src = "main>R n t;x=42;x!";
let out = ilo()
.args(["--ast", src])
.output()
.expect("failed to run ilo");
let code = out.status.code().unwrap_or(-1);
let stdout = String::from_utf8_lossy(&out.stdout);
assert_eq!(code, 0, "expected exit 0, got {code}");
assert!(stdout.contains("\"declarations\""), "stdout: {stdout}");
assert!(stdout.contains("\"Propagate\""), "stdout: {stdout}");
}
#[test]
fn inline_multi_fn_no_main_still_ast_dumps() {
let src = "helper>n;1\nother>n;2";
let (stdout, _stderr, code) = run_default_inline(src);
assert_eq!(code, 0, "expected exit 0, got {code}");
assert!(
stdout.contains("\"declarations\""),
"expected AST JSON, got: {stdout}"
);
}