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 ENGINES: &[&str] = &[
"--run-tree",
"--run-vm",
#[cfg(feature = "cranelift")]
"--jit",
];
#[test]
fn text_key_mget() {
let src = r#"f>n;m=mmap;m=mset m "a" 7;r=mget m "a";?r{n v:v;_:-1}"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "7", "engine={e}");
}
}
#[test]
fn text_key_mhas() {
let src = r#"f>b;m=mmap;m=mset m "k" 1;mhas m "k""#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "true", "engine={e}");
}
}
#[test]
fn text_key_mdel_then_miss() {
let src = r#"f>n;m=mmap;m=mset m "k" 1;m=mdel m "k";r=mget m "k";?r{n v:v;_:0}"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "0", "engine={e}");
}
}
#[test]
fn int_key_mset_mget() {
let src = r#"f>n;m=mmap;m=mset m 7 100;r=mget m 7;?r{n v:v;_:-1}"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "100", "engine={e}");
}
}
#[test]
fn int_key_mhas_present() {
let src = r#"f>b;m=mmap;m=mset m 42 0;mhas m 42"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "true", "engine={e}");
}
}
#[test]
fn int_key_mhas_missing() {
let src = r#"f>b;m=mmap;m=mset m 42 0;mhas m 99"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "false", "engine={e}");
}
}
#[test]
fn int_key_mdel_removes_entry() {
let src = r#"f>n;m=mmap;m=mset m 1 10;m=mset m 2 20;m=mdel m 1;len (mkeys m)"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "1", "engine={e}");
}
}
#[test]
fn int_key_mget_missing_returns_nil() {
let src = r#"f>n;m=mmap;m=mset m 1 99;r=mget m 2;?r{n v:v;_:-1}"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "-1", "engine={e}");
}
}
#[test]
fn int_key_mkeys_sorted_deterministic() {
let src = r#"f>n;m=mmap;m=mset m 3 0;m=mset m 1 0;m=mset m 2 0;ks=srt (mkeys m);hd ks"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "1", "engine={e}");
}
}
#[test]
fn int_key_mvals_count() {
let src = r#"f>n;m=mmap;m=mset m 1 10;m=mset m 2 20;m=mset m 3 30;len (mvals m)"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "3", "engine={e}");
}
}
#[test]
fn int_key_len_via_mkeys() {
let src = r#"f>n;m=mmap;m=mset m 10 0;m=mset m 20 0;m=mset m 30 0;len (mkeys m)"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "3", "engine={e}");
}
}
#[test]
fn int_key_distinct_from_text_key_via_frq() {
let src_num = r#"f>n;m=frq [1, "1"];r=mget m 1;?r{n v:v;_:-1}"#;
let src_txt = r#"f>n;m=frq [1, "1"];r=mget m "1";?r{n v:v;_:-1}"#;
for e in ENGINES {
assert_eq!(run(e, src_num, "f"), "1", "engine={e} numeric key");
assert_eq!(run(e, src_txt, "f"), "1", "engine={e} text key");
}
}
#[test]
fn float_key_floors_to_int() {
let src = r#"f>n;m=mmap;m=mset m 0.7 42;r=mget m 0;?r{n v:v;_:-1}"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "42", "engine={e}");
}
}
#[test]
fn jdmp_int_key_stringifies() {
let src = r#"f>t;m=mmap;m=mset m 7 42;jdmp m"#;
for e in ENGINES {
let out = run(e, src, "f");
assert!(
out.contains("\"7\":42"),
"engine={e} expected key \"7\":42, got: {out}"
);
}
}
#[test]
fn int_key_iteration_deterministic_across_engines() {
let src = r#"f>t;m=mmap;m=mset m 5 0;m=mset m 1 0;m=mset m 3 0;m=mset m 2 0;m=mset m 4 0;ks=srt (mkeys m);fmt "{},{},{},{},{}" (str (at ks 0)) (str (at ks 1)) (str (at ks 2)) (str (at ks 3)) (str (at ks 4))"#;
for e in ENGINES {
assert_eq!(run(e, src, "f"), "1,2,3,4,5", "engine={e}");
}
}