use std::process::Command;
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
fn run(engine: &str, src: &str, entry: &str) -> String {
let out = ilo()
.args([src, engine, entry])
.output()
.expect("failed to run ilo");
assert!(
out.status.success(),
"ilo {engine} failed for `{src}`: stderr={}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8_lossy(&out.stdout).trim().to_string()
}
const ASCII_FIRST_SRC: &str = "f>t;at \"hello\" 0";
const ASCII_LAST_SRC: &str = "f>t;at \"hello\" 4";
const ASCII_NEG_LAST_SRC: &str = "f>t;at \"hello\" -1";
const ASCII_NEG_FIRST_SRC: &str = "f>t;at \"hello\" -5";
fn check_eq(engine: &str, src: &str, expected: &str) {
assert_eq!(run(engine, src, "f"), expected, "engine={engine} src={src}");
}
#[test]
fn at_text_ascii_tree() {
check_eq("--run-tree", ASCII_FIRST_SRC, "h");
check_eq("--run-tree", ASCII_LAST_SRC, "o");
check_eq("--run-tree", ASCII_NEG_LAST_SRC, "o");
check_eq("--run-tree", ASCII_NEG_FIRST_SRC, "h");
}
#[test]
fn at_text_ascii_vm() {
check_eq("--run-vm", ASCII_FIRST_SRC, "h");
check_eq("--run-vm", ASCII_LAST_SRC, "o");
check_eq("--run-vm", ASCII_NEG_LAST_SRC, "o");
check_eq("--run-vm", ASCII_NEG_FIRST_SRC, "h");
}
#[test]
#[cfg(feature = "cranelift")]
fn at_text_ascii_cranelift() {
check_eq("--jit", ASCII_FIRST_SRC, "h");
check_eq("--jit", ASCII_LAST_SRC, "o");
check_eq("--jit", ASCII_NEG_LAST_SRC, "o");
check_eq("--jit", ASCII_NEG_FIRST_SRC, "h");
}
const UNI_MID_SRC: &str = "f>t;at \"naïve\" 2";
const UNI_LAST_SRC: &str = "f>t;at \"naïve\" 4";
const UNI_NEG_MID_SRC: &str = "f>t;at \"naïve\" -3";
const UNI_NEG_LAST_SRC: &str = "f>t;at \"naïve\" -1";
#[test]
fn at_text_unicode_tree() {
check_eq("--run-tree", UNI_MID_SRC, "ï");
check_eq("--run-tree", UNI_LAST_SRC, "e");
check_eq("--run-tree", UNI_NEG_MID_SRC, "ï");
check_eq("--run-tree", UNI_NEG_LAST_SRC, "e");
}
#[test]
fn at_text_unicode_vm() {
check_eq("--run-vm", UNI_MID_SRC, "ï");
check_eq("--run-vm", UNI_LAST_SRC, "e");
check_eq("--run-vm", UNI_NEG_MID_SRC, "ï");
check_eq("--run-vm", UNI_NEG_LAST_SRC, "e");
}
#[test]
#[cfg(feature = "cranelift")]
fn at_text_unicode_cranelift() {
check_eq("--jit", UNI_MID_SRC, "ï");
check_eq("--jit", UNI_LAST_SRC, "e");
check_eq("--jit", UNI_NEG_MID_SRC, "ï");
check_eq("--jit", UNI_NEG_LAST_SRC, "e");
}
const TEXT_OOR_SRC: &str = "f>t;at \"abc\" 99";
fn check_text_oor_error(engine: &str) {
let out = ilo()
.args([TEXT_OOR_SRC, engine, "f"])
.output()
.expect("failed to run ilo");
assert!(
!out.status.success(),
"engine={engine}: expected error, got stdout={}",
String::from_utf8_lossy(&out.stdout)
);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
stderr.contains("range") || stderr.contains("ILO-R009") || stderr.contains("ILO-R004"),
"engine={engine}: expected range/ILO-R009/ILO-R004 in stderr, got stderr={stderr}"
);
}
#[test]
fn at_text_oor_tree() {
check_text_oor_error("--run-tree");
}
#[test]
fn at_text_oor_vm() {
check_text_oor_error("--run-vm");
}
#[test]
#[cfg(feature = "cranelift")]
fn at_text_oor_cranelift() {
check_text_oor_error("--jit");
}
const AT_LOOP_SRC: &str = "f>n;\
s=\"\";@k 0..2000{s=+s \"A\"};\
l=len s;n=0;\
@i 0..l{c=at s i;n=+n 1};\
n";
fn check_at_loop(engine: &str) {
assert_eq!(run(engine, AT_LOOP_SRC, "f"), "2000", "engine={engine}");
}
#[test]
fn at_loop_over_built_string_tree() {
check_at_loop("--run-tree");
}
#[test]
fn at_loop_over_built_string_vm() {
check_at_loop("--run-vm");
}
#[test]
#[cfg(feature = "cranelift")]
fn at_loop_over_built_string_cranelift() {
check_at_loop("--jit");
}