use std::process::Command;
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
fn run(engine: &str, src: &str, entry: &str) -> (bool, String) {
let out = ilo()
.args([src, engine, entry])
.output()
.expect("failed to run ilo");
(
out.status.success(),
String::from_utf8_lossy(&out.stderr).into_owned(),
)
}
const FLD_BINDING_IN_BODY: &str = "f>n;fld=5;fld";
fn check_fld_binding(engine: &str) {
let (ok, stderr) = run(engine, FLD_BINDING_IN_BODY, "f");
assert!(!ok, "engine={engine}: expected parse failure");
assert!(
stderr.contains("ILO-P011"),
"engine={engine}: missing ILO-P011, stderr={stderr}"
);
assert!(
stderr.contains("`fld` is reserved for the fold builtin"),
"engine={engine}: missing friendly message, stderr={stderr}"
);
assert!(
stderr.contains("field") || stderr.contains("folder"),
"engine={engine}: hint should suggest field/folder, stderr={stderr}"
);
assert!(
!stderr.contains("ILO-T006"),
"engine={engine}: arity cascade leaked, stderr={stderr}"
);
assert!(
!stderr.contains("arity mismatch"),
"engine={engine}: arity cascade leaked, stderr={stderr}"
);
}
#[test]
fn fld_binding_in_body_tree() {
check_fld_binding("--vm");
}
#[test]
fn fld_binding_in_body_vm() {
check_fld_binding("--vm");
}
#[test]
#[cfg(feature = "cranelift")]
fn fld_binding_in_body_cranelift() {
check_fld_binding("--jit");
}
const FLD_BINDING_IN_LOOP: &str = "f a:n>n;@i 0..a{fld=i};1";
fn check_fld_binding_loop(engine: &str) {
let (ok, stderr) = run(engine, FLD_BINDING_IN_LOOP, "f");
assert!(!ok, "engine={engine}: expected parse failure");
assert!(
stderr.contains("ILO-P011"),
"engine={engine}: missing ILO-P011, stderr={stderr}"
);
assert!(
stderr.contains("`fld` is reserved for the fold builtin"),
"engine={engine}: missing friendly message, stderr={stderr}"
);
assert!(
!stderr.contains("ILO-T006"),
"engine={engine}: arity cascade leaked, stderr={stderr}"
);
}
#[test]
fn fld_binding_in_loop_tree() {
check_fld_binding_loop("--vm");
}
#[test]
fn fld_binding_in_loop_vm() {
check_fld_binding_loop("--vm");
}
#[test]
#[cfg(feature = "cranelift")]
fn fld_binding_in_loop_cranelift() {
check_fld_binding_loop("--jit");
}
#[test]
fn fld_as_builtin_still_works() {
let out = ilo()
.args(["add x:n y:n>n;+x y;f>n;fld add [1 2 3 4] 0", "--vm", "f"])
.output()
.expect("failed to run ilo");
assert!(
out.status.success(),
"fld builtin broken: stderr={}",
String::from_utf8_lossy(&out.stderr)
);
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(stdout.contains("10"), "expected 10, got: {stdout}");
}