use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
fn write_src(tag: &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_fnarg_{tag}_{}_{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()
}
const PRNT_STR_SRC: &str = "f nc:n>n;prnt str nc;nc";
fn check_prnt_str(engine: &str) {
let out = run_ok(engine, PRNT_STR_SRC, "f", &["5"]);
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines.first().copied(), Some("5"), "engine={engine}");
}
#[test]
fn prnt_str_tree() {
check_prnt_str("--run-tree");
}
#[test]
fn prnt_str_vm() {
check_prnt_str("--run-vm");
}
const HD_TL_SRC: &str = "f xs:L n>n;hd tl xs";
fn check_hd_tl(engine: &str) {
assert_eq!(
run_ok(engine, HD_TL_SRC, "f", &["[10,20,30]"]),
"20",
"engine={engine}"
);
}
#[test]
fn hd_tl_tree() {
check_hd_tl("--run-tree");
}
#[test]
fn hd_tl_vm() {
check_hd_tl("--run-vm");
}
const PCT_SRC: &str = "pct a:n b:n>n;*/ a b 100\nf s:n>n;prnt pct s 10;s\n";
fn check_pct(engine: &str) {
let out = run_ok(engine, PCT_SRC, "f", &["5"]);
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines.first().copied(), Some("50"), "engine={engine}");
}
#[test]
fn pct_tree() {
check_pct("--run-tree");
}
#[test]
fn pct_vm() {
check_pct("--run-vm");
}
const FLR_SRC: &str = "f n:n>n;flr +*n 0.25 0";
fn check_flr(engine: &str) {
assert_eq!(
run_ok(engine, FLR_SRC, "f", &["10"]),
"2",
"engine={engine}"
);
}
#[test]
fn flr_tree() {
check_flr("--run-tree");
}
#[test]
fn flr_vm() {
check_flr("--run-vm");
}
const SLC_SRC: &str = "f>L n;ls=[10,20,30];i=0;slc ls i +i 1";
fn check_slc(engine: &str) {
assert_eq!(run_ok(engine, SLC_SRC, "f", &[]), "[10]", "engine={engine}");
}
#[test]
fn slc_prefix_arg_still_works_tree() {
check_slc("--run-tree");
}
#[test]
fn slc_prefix_arg_still_works_vm() {
check_slc("--run-vm");
}
const DBL_SRC: &str = "dbl x:n>n;*x 2\ng>n;prnt dbl 5;0\n";
fn check_dbl(engine: &str) {
let out = run_ok(engine, DBL_SRC, "g", &[]);
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines.first().copied(), Some("10"), "engine={engine}");
}
#[test]
fn user_fn_inner_tree() {
check_dbl("--run-tree");
}
#[test]
fn user_fn_inner_vm() {
check_dbl("--run-vm");
}
const FLD_MAX_SRC: &str = "f xs:L n>n;fld max xs 0";
fn check_fld_max(engine: &str) {
assert_eq!(
run_ok(engine, FLD_MAX_SRC, "f", &["[3,1,4,1,5,9,2,6]"]),
"9",
"engine={engine}"
);
}
#[test]
fn fld_max_hof_tree() {
check_fld_max("--run-tree");
}
const FILTER_SRC: &str = "pos x:n>b;>x 0\nmain xs:L n>L n;filter pos xs\n";
fn check_filter(engine: &str) {
assert_eq!(
run_ok(engine, FILTER_SRC, "main", &["[-3,0,2,4]"]),
"[2, 4]",
"engine={engine}"
);
}
#[test]
fn filter_alias_tree() {
check_filter("--run-tree");
}