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_flatmap_{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_err(engine: &str, src: &str, entry: &str) -> String {
let path = write_src(entry, src);
let out = ilo()
.arg(&path)
.arg(engine)
.arg(entry)
.output()
.expect("failed to run ilo");
let _ = std::fs::remove_file(&path);
assert!(
!out.status.success(),
"expected failure for `{src}` on {engine}, stdout={}",
String::from_utf8_lossy(&out.stdout)
);
String::from_utf8_lossy(&out.stderr).into_owned()
}
const PAIR_SRC: &str = "pr x:n>L n;[x, x] f xs:L n>L n;flatmap pr xs";
#[test]
fn flatmap_pair_tree() {
assert_eq!(
run_ok("--run-tree", PAIR_SRC, "f", &["[1,2,3]"]),
"[1, 1, 2, 2, 3, 3]"
);
}
#[test]
fn flatmap_empty_input_tree() {
assert_eq!(run_ok("--run-tree", PAIR_SRC, "f", &["[]"]), "[]");
}
const NONE_SRC: &str = "none x:n>L n;[] f xs:L n>L n;flatmap none xs";
#[test]
fn flatmap_fn_returns_empty_tree() {
assert_eq!(run_ok("--run-tree", NONE_SRC, "f", &["[1,2,3]"]), "[]");
}
const SPLIT_SRC: &str = "sp s:t>L t;spl s \":\" f xs:L t>L t;flatmap sp xs";
#[test]
fn flatmap_split_tree() {
assert_eq!(
run_ok("--run-tree", SPLIT_SRC, "f", &["[\"a:b\",\"c\"]"]),
"[a, b, c]"
);
}
const BAD_FN_SRC: &str = "f xs:L n>L n;flatmap 42 xs";
#[test]
fn flatmap_wrong_fn_arg_vm() {
let err = run_err("--run-vm", BAD_FN_SRC, "f");
assert!(
err.contains("flatmap") || err.contains("fn") || err.contains("function"),
"got: {err}"
);
}