use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
fn write_src(name: &str, src: &str) -> std::path::PathBuf {
static COUNTER: AtomicU64 = AtomicU64::new(0);
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
let mut path = std::env::temp_dir();
path.push(format!(
"ilo_lambdas_xeng_{name}_{}_{n}.ilo",
std::process::id()
));
std::fs::write(&path, src).expect("write src");
path
}
fn run_ok(engine: &str, src: &str, entry: &str, args: &[&str]) -> String {
let path = write_src(entry, src);
let mut cmd = ilo();
cmd.arg(&path).arg(engine).arg(entry);
for a in args {
cmd.arg(a);
}
let out = cmd.output().expect("failed to run ilo");
let _ = std::fs::remove_file(&path);
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()
}
fn run_all(src: &str, entry: &str, args: &[&str], expected: &str) {
for engine in ["--vm", "--jit"] {
let actual = run_ok(engine, src, entry, args);
assert_eq!(
actual, expected,
"engine {engine} produced {actual:?}, expected {expected:?} for src `{src}`"
);
}
}
#[test]
fn lambda_map_2arg_square() {
let src = "main xs:L n>L n;map (x:n>n;*x x) xs";
run_all(src, "main", &["[1,2,3,4]"], "[1, 4, 9, 16]");
}
#[test]
fn lambda_map_3arg_ctx_bump() {
let src = "main bump:n xs:L n>L n;map (x:n c:n>n;+x c) bump xs";
run_all(src, "main", &["10", "[1,2,3]"], "[11, 12, 13]");
}
#[test]
fn lambda_flt_2arg_positive() {
let src = "main xs:L n>L n;flt (x:n>b;>x 0) xs";
run_all(src, "main", &["[-1,2,-3,4,-5,6]"], "[2, 4, 6]");
}
#[test]
fn lambda_flt_3arg_ctx_threshold() {
let src = "main thr:n xs:L n>L n;flt (x:n c:n>b;>x c) thr xs";
run_all(src, "main", &["3", "[1,2,3,4,5]"], "[4, 5]");
}
#[test]
fn lambda_fld_2arg_sum() {
let src = "main xs:L n>n;fld (a:n x:n>n;+a x) xs 0";
run_all(src, "main", &["[1,2,3,4,5]"], "15");
}
#[test]
fn lambda_fld_3arg_ctx_weighted_sum() {
let src = "main w:n xs:L n>n;fld (a:n x:n c:n>n;+a *x c) w xs 0";
run_all(src, "main", &["5", "[1,2,3,4]"], "50");
}
#[test]
fn lambda_srt_2arg_by_abs() {
let src = "main xs:L n>L n;srt (x:n>n;abs x) xs";
run_all(src, "main", &["[-3,1,-5,2]"], "[1, 2, -3, -5]");
}
#[test]
fn lambda_srt_3arg_ctx_distance() {
let src = "main t:n xs:L n>L n;srt (x:n c:n>n;abs -x c) t xs";
run_all(src, "main", &["8", "[1,5,10,20]"], "[10, 5, 1, 20]");
}
#[test]
fn lambda_grp_2arg_by_sign() {
let src = "main xs:L n>M t (L n);grp (x:n>t;>x 0{\"pos\"}{\"np\"}) xs";
run_all(src, "main", &["[-1,2,-3,4]"], "{np: [-1, -3]; pos: [2, 4]}");
}
#[test]
fn lambda_uniqby_2arg_by_parity() {
let src = "main xs:L n>L n;uniqby (x:n>n;mod x 2) xs";
run_all(src, "main", &["[1,3,2,4,5,6]"], "[1, 2]");
}
#[test]
fn lambda_partition_2arg_positive() {
let src = "main xs:L n>L (L n);partition (x:n>b;>x 0) xs";
run_all(src, "main", &["[-1,2,-3,4]"], "[[2, 4], [-1, -3]]");
}
#[test]
fn lambda_flatmap_2arg_duplicate_and_double() {
let src = "main xs:L n>L n;flatmap (x:n>L n;[x,*x 2]) xs";
run_all(src, "main", &["[1,2,3]"], "[1, 2, 2, 4, 3, 6]");
}
#[test]
fn lambda_map_empty_list() {
let src = "main xs:L n>L n;map (x:n>n;*x x) xs";
run_all(src, "main", &["[]"], "[]");
}
#[test]
fn lambda_flt_empty_list() {
let src = "main xs:L n>L n;flt (x:n>b;>x 0) xs";
run_all(src, "main", &["[]"], "[]");
}
#[test]
fn lambda_fld_empty_list_returns_seed() {
let src = "main xs:L n>n;fld (a:n x:n>n;+a x) xs 7";
run_all(src, "main", &["[]"], "7");
}
#[test]
fn lambda_map_then_srt_no_tls_desync() {
let src =
"main>L (L _);a=map (x:n>n;+x 1) [1 2 3];sk=srt (p:L _>n;p.0) [[2 \"a\"] [1 \"b\"]];sk";
run_all(src, "main", &[], "[[1, b], [2, a]]");
}
#[test]
fn lambda_flt_then_srt_no_tls_desync() {
let src =
"main>L (L _);a=flt (x:n>b;>x 1) [1 2 3];sk=srt (p:L _>n;p.0) [[2 \"a\"] [1 \"b\"]];sk";
run_all(src, "main", &[], "[[1, b], [2, a]]");
}
#[test]
fn lambda_fld_then_srt_no_tls_desync() {
let src = "main>L (L _);s=fld (a:n x:n>n;+a x) [1 2 3] 0;sk=srt (p:L _>n;p.0) [[2 \"a\"] [1 \"b\"]];sk";
run_all(src, "main", &[], "[[1, b], [2, a]]");
}
#[test]
fn lambda_flatmap_then_srt_no_tls_desync() {
let src = "main>L (L _);a=flatmap (x:n>L n;[x x]) [1 2];sk=srt (p:L _>n;p.0) [[2 \"a\"] [1 \"b\"]];sk";
run_all(src, "main", &[], "[[1, b], [2, a]]");
}
#[test]
fn lambda_map_then_srt_frq_mget_pairs() {
let src = "main>L (L _);ws=[\"apple\" \"apple\" \"banana\" \"apple\" \"cherry\" \"banana\"];dummy=map (w:t>n;len w) ws;fr=frq ws;ks=mkeys fr;pairs=[];@k ks{c=mget fr k;pairs=+=pairs [c k]};sk=srt (p:L _>n;p.0) pairs;sk";
run_all(src, "main", &[], "[[1, cherry], [2, banana], [3, apple]]");
}
#[test]
fn lambda_map_then_grp_no_tls_desync() {
let src = "main>L n;a=map (x:n>n;*x 2) [1 2 3];g=grp (x:n>t;?>x 5 \"big\" \"small\") [1 6 2 7 3 8];mget g \"big\"";
run_all(src, "main", &[], "[6, 7, 8]");
}
#[test]
fn lambda_map_then_uniqby_no_tls_desync() {
let src = "main>L n;a=map (x:n>n;+x 1) [1 2 3];uniqby (x:n>b;>x 3) [1 2 3 4 5]";
run_all(src, "main", &[], "[1, 4]");
}
#[test]
fn lambda_map_then_partition_no_tls_desync() {
let src = "main>L (L n);a=map (x:n>n;+x 1) [1 2 3];partition (x:n>b;>x 2) [1 2 3 4 5]";
run_all(src, "main", &[], "[[3, 4, 5], [1, 2]]");
}
#[test]
fn lambda_map_then_srt_then_map_no_tls_desync() {
let src = "main>L n;a=map (x:n>n;+x 1) [1 2 3];sk=srt (p:L _>n;p.0) [[2 \"a\"] [1 \"b\"]];map (x:n>n;*x 10) [4 5 6]";
run_all(src, "main", &[], "[40, 50, 60]");
}