use std::collections::HashMap;
pub fn fixtures() -> (String, String, String) {
static FIXTURES: std::sync::OnceLock<(String, String, String)> = std::sync::OnceLock::new();
FIXTURES
.get_or_init(|| {
let pid = std::process::id();
let path = |ext: &str| {
std::env::temp_dir().join(format!("_polydat_coverage_test_{pid}.{ext}"))
};
let csv_path = path("csv");
std::fs::write(&csv_path, "name,age\nalice,30\nbob,25\n").unwrap();
let jsonl_path = path("jsonl");
std::fs::write(&jsonl_path, "{\"name\":\"alice\"}\n{\"name\":\"bob\"}\n").unwrap();
let txt_path = path("txt");
std::fs::write(&txt_path, "hello\nworld\n").unwrap();
(
csv_path.to_str().unwrap().to_string(),
jsonl_path.to_str().unwrap().to_string(),
txt_path.to_str().unwrap().to_string(),
)
})
.clone()
}
#[allow(clippy::too_many_lines)]
pub fn overrides(csv: &str, jsonl: &str, txt: &str) -> HashMap<&'static str, String> {
let mut overrides: std::collections::HashMap<&str, String> = [
("to_hex", "input cycle: u64\nb := u64_to_bytes(cycle)\nout := to_hex(b)".into()),
("from_hex", "input cycle: u64\nb := u64_to_bytes(cycle)\nh := to_hex(b)\nout := from_hex(h)".into()),
("sha256", "input cycle: u64\nb := u64_to_bytes(cycle)\nout := sha256(b)".into()),
("md5", "input cycle: u64\nb := u64_to_bytes(cycle)\nout := md5(b)".into()),
("to_base64", "input cycle: u64\nb := u64_to_bytes(cycle)\nout := to_base64(b)".into()),
("from_base64", "input cycle: u64\nb := u64_to_bytes(cycle)\ne := to_base64(b)\nout := from_base64(e)".into()),
("json_to_str", "input cycle: u64\nj := to_json(cycle)\nout := json_to_str(j)".into()),
("json_merge", "input cycle: u64\na := to_json(cycle)\nb := to_json(cycle)\nout := json_merge(a, b)".into()),
("escape_json", "input cycle: u64\ns := format_u64(cycle, 10)\nout := escape_json(s)".into()),
("dist_normal", "input cycle: u64\nout := dist_normal(hash(cycle), 0.0, 1.0)".into()),
("dist_exponential", "input cycle: u64\nout := dist_exponential(hash(cycle), 1.0)".into()),
("dist_uniform", "input cycle: u64\nout := dist_uniform(hash(cycle), 0.0, 1.0)".into()),
("dist_pareto", "input cycle: u64\nout := dist_pareto(hash(cycle), 1.0, 1.0)".into()),
("dist_zipf", "input cycle: u64\nout := dist_zipf(hash(cycle), 100, 1.0)".into()),
("histribution", "input cycle: u64\nout := histribution(hash(cycle), \"50 25 13 12\")".into()),
("dist_empirical", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := dist_empirical(f, \"1.0 3.0 5.0 7.0 9.0\")".into()),
("weighted_strings", "input cycle: u64\nout := weighted_strings(hash(cycle), \"a:0.5;b:0.5\")".into()),
("weighted_u64", "input cycle: u64\nout := weighted_u64(hash(cycle), \"10:0.5;20:0.5\")".into()),
("weighted_pick", "input cycle: u64\nout := weighted_pick(hash(cycle), \"10:0.5;20:0.5\")".into()),
("one_of_weighted", "input cycle: u64\nout := one_of_weighted(hash(cycle), \"a:0.5;b:0.5\")".into()),
("html_encode", "input cycle: u64\ns := format_u64(cycle, 10)\nout := html_encode(s)".into()),
("html_decode", "input cycle: u64\ns := format_u64(cycle, 10)\nout := html_decode(s)".into()),
("url_encode", "input cycle: u64\ns := format_u64(cycle, 10)\nout := url_encode(s)".into()),
("url_decode", "input cycle: u64\ns := format_u64(cycle, 10)\nout := url_decode(s)".into()),
("regex_replace", "input cycle: u64\ns := format_u64(cycle, 10)\nout := regex_replace(s, \"[0-9]\", \"x\")".into()),
("regex_match", "input cycle: u64\ns := format_u64(cycle, 10)\nout := regex_match(s, \"[0-9]+\")".into()),
("select", "input cycle: u64\nout := select(fair_coin(hash(cycle)), cycle, cycle)".into()),
("blend", "input cycle: u64\nout := blend(hash(cycle), hash(cycle), 0.5)".into()),
("date_components", "input cycle: u64\n(y, mo, d, h, mi, s, ms) := date_components(cycle)".into()),
("perlin_2d", "input cycle: u64\nout := perlin_2d(cycle, cycle, 42, 0.01)".into()),
("simplex_2d", "input cycle: u64\nout := simplex_2d(cycle, cycle, 42, 0.01)".into()),
("fractal_noise_2d", "input cycle: u64\nout := fractal_noise_2d(cycle, cycle, 42, 0.02)".into()),
("pcg_stream", "input cycle: u64\nout := pcg_stream(cycle, cycle, 42)".into()),
("format_u64", "input cycle: u64\nout := format_u64(cycle, 16)".into()),
("current_epoch_millis", "input cycle: u64\nout := current_epoch_millis()".into()),
("counter", "input cycle: u64\nout := counter()".into()),
("random_range", "input cycle: u64\nout := random_range(0, 1000)".into()),
("random_f64", "input cycle: u64\nout := random_f64(0.0, 1.0)".into()),
("session_start_millis", "input cycle: u64\nout := session_start_millis()".into()),
("elapsed_millis", "input cycle: u64\nout := elapsed_millis()".into()),
("thread_id", "input cycle: u64\nout := thread_id()".into()),
("clamp_f64", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := clamp_f64(f, 0.0, 0.5)".into()),
("quantize", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := quantize(f, 0.1)".into()),
("lerp", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := lerp(f, 0.0, 100.0)".into()),
("inv_lerp", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := inv_lerp(f, 0.0, 1.0)".into()),
("remap", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := remap(f, 0.0, 1.0, 0.0, 100.0)".into()),
("fft_analyze", "input cycle: u64\nf := unit_interval(hash(cycle))\nout := fft_analyze(f, \"/tmp/_polydat_fft_test.jsonl\", 8)".into()),
("env", "input cycle: u64\nout := env(\"PATH\")".into()),
("body_column_i32",
"input cycle: u64\nout := body_column_i32(to_json(cycle), \"key\")".into()),
("cardinality",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := cardinality(q.cursor)".into()),
("start_of",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := start_of(q.cursor)".into()),
("end_of",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := end_of(q.cursor)".into()),
("idx_of",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := idx_of(q.cursor)".into()),
("mod_in",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := mod_in(cycle, q.cursor)".into()),
("at",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := at(q.cursor, cycle)".into()),
("clamp_in",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := clamp_in(cycle, q.cursor)".into()),
("count_of",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := count_of(q.cursor)".into()),
("random_in",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := random_in(q.cursor, cycle)".into()),
("subdivide",
"input cycle: u64\ncursor q = range(0, 100) over \"0..50%\"\nout := subdivide(q.cursor, 2)".into()),
("partitions",
"input cycle: u64\nout := partitions(\"linear:4\", 1000)".into()),
("partition_count",
"input cycle: u64\nout := partition_count(partitions(\"linear:4\", 1000))".into()),
("partition_at",
"input cycle: u64\nout := partition_at(partitions(\"linear:4\", 1000), u64_mod(cycle, 4))".into()),
("vec_add",
"input cycle: u64\nout := vec_add(hash_vec(cycle, 8), hash_vec(cycle + 1, 8))".into()),
("vec_dot",
"input cycle: u64\nout := vec_dot(hash_vec(cycle, 8), hash_vec(cycle + 1, 8))".into()),
("vec_l2",
"input cycle: u64\nout := vec_l2(hash_vec(cycle, 8), hash_vec(cycle + 1, 8))".into()),
("vec_cosine",
"input cycle: u64\nout := vec_cosine(hash_vec(cycle, 8), hash_vec(cycle + 1, 8))".into()),
("vec_scale",
"input cycle: u64\nout := vec_scale(hash_vec(cycle, 8), 2.0)".into()),
("vec_norm",
"input cycle: u64\nout := vec_norm(hash_vec(cycle, 8))".into()),
("lid_mle",
"input cycle: u64\nout := lid_mle(hash_vec(cycle, 8), 4.0)".into()),
("reg_gather_f32",
"input cycle: u64\nout := reg_gather_f32(hash_vec(cycle, 8), 0)".into()),
("vec_to_reg_f32",
"input cycle: u64\nout := vec_to_reg_f32(hash_vec(cycle, 4))".into()),
("reg_to_vec_f32",
"input cycle: u64\nout := reg_to_vec_f32(reg_splat_f32(cycle))".into()),
("reg_lane_f32",
"input cycle: u64\nout := reg_lane_f32(reg_splat_f32(cycle), 0)".into()),
("reg_with_lane_f32",
"input cycle: u64\nout := reg_with_lane_f32(reg_splat_f32(cycle), 0, 1.5)".into()),
("reg_lane_i16",
"input cycle: u64\nout := reg_lane_i16(reg_splat_i16(cycle), 0)".into()),
("reg_lane_i64",
"input cycle: u64\nout := reg_lane_i64(reg_splat_i64(cycle), 0)".into()),
("reg_add_f32",
"input cycle: u64\nout := reg_add_f32(reg_splat_f32(cycle), reg_splat_f32(cycle))".into()),
("reg_sub_f32",
"input cycle: u64\nout := reg_sub_f32(reg_splat_f32(cycle), reg_splat_f32(cycle))".into()),
("reg_mul_f32",
"input cycle: u64\nout := reg_mul_f32(reg_splat_f32(cycle), reg_splat_f32(cycle))".into()),
("reg_add_f64",
"input cycle: u64\nout := reg_add_f64(reg_splat_f64(cycle), reg_splat_f64(cycle))".into()),
("reg_sub_f64",
"input cycle: u64\nout := reg_sub_f64(reg_splat_f64(cycle), reg_splat_f64(cycle))".into()),
("reg_mul_f64",
"input cycle: u64\nout := reg_mul_f64(reg_splat_f64(cycle), reg_splat_f64(cycle))".into()),
("reg_add_i8",
"input cycle: u64\nout := reg_add_i8(reg_splat_i8(cycle), reg_splat_i8(cycle))".into()),
("reg_sub_i8",
"input cycle: u64\nout := reg_sub_i8(reg_splat_i8(cycle), reg_splat_i8(cycle))".into()),
("reg_mul_i8",
"input cycle: u64\nout := reg_mul_i8(reg_splat_i8(cycle), reg_splat_i8(cycle))".into()),
("reg_add_i16",
"input cycle: u64\nout := reg_add_i16(reg_splat_i16(cycle), reg_splat_i16(cycle))".into()),
("reg_sub_i16",
"input cycle: u64\nout := reg_sub_i16(reg_splat_i16(cycle), reg_splat_i16(cycle))".into()),
("reg_mul_i16",
"input cycle: u64\nout := reg_mul_i16(reg_splat_i16(cycle), reg_splat_i16(cycle))".into()),
("reg_add_i32",
"input cycle: u64\nout := reg_add_i32(reg_splat_i32(cycle), reg_splat_i32(cycle))".into()),
("reg_sub_i32",
"input cycle: u64\nout := reg_sub_i32(reg_splat_i32(cycle), reg_splat_i32(cycle))".into()),
("reg_mul_i32",
"input cycle: u64\nout := reg_mul_i32(reg_splat_i32(cycle), reg_splat_i32(cycle))".into()),
("reg_add_i64",
"input cycle: u64\nout := reg_add_i64(reg_splat_i64(cycle), reg_splat_i64(cycle))".into()),
("reg_sub_i64",
"input cycle: u64\nout := reg_sub_i64(reg_splat_i64(cycle), reg_splat_i64(cycle))".into()),
("reg_mul_i64",
"input cycle: u64\nout := reg_mul_i64(reg_splat_i64(cycle), reg_splat_i64(cycle))".into()),
("reg_dot_f32",
"input cycle: u64\nout := reg_dot_f32(reg_splat_f32(cycle), reg_splat_f32(cycle + 1))".into()),
("reg_shuffle_bytes",
"input cycle: u64\nout := reg_shuffle_bytes(reg_splat_i8(cycle), 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)".into()),
].into_iter().collect();
overrides.insert(
"csv_field",
format!("input cycle: u64\nout := csv_field(cycle, \"{csv}\", \"name\")"),
);
overrides.insert(
"csv_row",
format!("input cycle: u64\nout := csv_row(cycle, \"{csv}\")"),
);
overrides.insert(
"csv_row_count",
format!("input cycle: u64\nout := csv_row_count(\"{csv}\")"),
);
overrides.insert(
"jsonl_field",
format!("input cycle: u64\nout := jsonl_field(cycle, \"{jsonl}\", \"name\")"),
);
overrides.insert(
"jsonl_row",
format!("input cycle: u64\nout := jsonl_row(cycle, \"{jsonl}\")"),
);
overrides.insert(
"jsonl_row_count",
format!("input cycle: u64\nout := jsonl_row_count(\"{jsonl}\")"),
);
overrides.insert(
"file_line_at",
format!("input cycle: u64\nout := file_line_at(cycle, \"{txt}\")"),
);
overrides.insert(
"pick",
"input cycle: u64\ns := format_u64(cycle, 10)\nout := pick(regex_match(s, \"3\"), regex_match(s, \"^[^3]*$\"), 100, 200)".into(),
);
overrides.insert(
"in_range",
"input cycle: u64\nout := in_range(cycle, 0, 1000)".into(),
);
overrides.insert(
"is_one_of",
"input cycle: u64\nout := is_one_of(cycle, 0, 1, 2, 3)".into(),
);
overrides.insert(
"matches",
"input cycle: u64\ns := format_u64(cycle, 10)\nout := matches(s, \"[0-9]+\")".into(),
);
overrides.insert(
"dynamic_weighted_select",
"input cycle: u64\nout := dynamic_weighted_select(cycle, \"alpha:0.3;beta:0.5;gamma:0.2\")"
.into(),
);
overrides.insert(
"streamer",
"input cycle: u64\nout := streamer(\"k in 1..4, limit in 10,20,30\")".into(),
);
overrides.insert(
"tile_render",
"input cycle: u64\ntile out : text := \"n=${cycle}\"".into(),
);
overrides.insert(
"tile_encode",
"input cycle: u64\nout := tile_encode(cycle, \"json|value|u64||\")".into(),
);
overrides
}
pub fn programs() -> Vec<(String, String)> {
programs_over("input cycle: u64", "cycle", true)
}
pub fn synthesized_call(sig: &polydat::dsl::registry::FuncSig, wire: &str) -> Option<String> {
use polydat::ast::SlotType;
let (csv, jsonl, txt) = fixtures();
if overrides(&csv, &jsonl, &txt).contains_key(sig.name) {
return None;
}
let mut args: Vec<String> = Vec::new();
for p in sig.params {
match p.slot_type {
SlotType::Wire => args.push(wire.into()),
SlotType::ConstU64 => args.push("100".into()),
SlotType::ConstF64 => args.push("1.0".into()),
SlotType::ConstStr => args.push("\"test\"".into()),
SlotType::ConstVecU64 => args.push("100".into()),
SlotType::ConstVecF64 => args.push("1.0".into()),
SlotType::ConstVec => args.push("100".into()),
}
}
if args.is_empty() && sig.is_variadic() {
args.push(wire.into());
}
Some(format!("{}({})", sig.name, args.join(", ")))
}
pub fn programs_over(decl: &str, wire: &str, with_overrides: bool) -> Vec<(String, String)> {
use polydat::dsl::registry;
let (csv, jsonl, txt) = fixtures();
let overrides = overrides(&csv, &jsonl, &txt);
let mut out = Vec::new();
for sig in ®istry::registry() {
if sig.category == registry::FuncCategory::RealData || sig.name.starts_with("__") {
continue;
}
let src = match (overrides.get(sig.name), synthesized_call(sig, wire)) {
(Some(s), _) if with_overrides => s.clone(),
(Some(_), _) => continue,
(None, Some(call)) => format!("{decl}\nout := {call}"),
(None, None) => continue,
};
out.push((sig.name.to_string(), src));
}
out.sort_by(|a, b| a.0.cmp(&b.0));
out
}