1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Regression tests for `setunion`/`setinter`/`setdiff` — set operations on
// lists, backed by HashSet<String> with type-prefixed keys (`t:`/`n:`/`b:`)
// to keep Number(5) and Text("5") in separate domains.
//
// Output is sorted (stringwise on the type-prefixed key) for determinism.
// Verified across tree, vm, and cranelift engines.
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()
}
macro_rules! tri_engine_test {
($name:ident, $src:expr, $expect:expr) => {
mod $name {
use super::*;
const SRC: &str = $src;
const EXPECT: &str = $expect;
#[test]
fn tree() {
assert_eq!(run("--vm", SRC, "f"), EXPECT);
}
#[test]
fn vm() {
assert_eq!(run("--vm", SRC, "f"), EXPECT);
}
#[test]
#[cfg(feature = "cranelift")]
fn cranelift() {
assert_eq!(run("--jit", SRC, "f"), EXPECT);
}
}
};
}
// Basic union: combine two number lists, dedupe, sort.
tri_engine_test!(
union_basic,
"f>L n;setunion [1,2,3] [2,3,4]",
"[1, 2, 3, 4]"
);
// Basic intersection.
tri_engine_test!(inter_basic, "f>L n;setinter [1,2,3] [2,3,4]", "[2, 3]");
// Basic difference.
tri_engine_test!(diff_basic, "f>L n;setdiff [1,2,3] [2,3,4]", "[1]");
// Dedup within a single input.
tri_engine_test!(union_dedup, "f>L n;setunion [1,1,2] [2,2,3]", "[1, 2, 3]");
// Empty operand: intersection with anything is empty.
tri_engine_test!(inter_empty, "f>L n;setinter [] [1,2]", "[]");
// Strings: union dedupes and sorts.
tri_engine_test!(
union_strings,
"f>L t;setunion [\"a\",\"b\"] [\"b\",\"c\"]",
"[a, b, c]"
);
// Cross-type guard: Number(1) and Text("1") must NOT collapse.
// Output uses heterogeneous element type — declare as `L a`.
// `n:1` sorts before `t:1` stringwise, so 1 comes before "1".
// (Strings render without quotes; we assert length-2 by listing both.)
tri_engine_test!(union_cross_type, "f>L a;setunion [1] [\"1\"]", "[1, 1]");
// Cross-type guard with distinguishable text element.
tri_engine_test!(
union_cross_type_distinct,
"f>L a;setunion [1] [\"x\"]",
"[1, x]"
);
// Sort is *lexicographic* on the prefixed-string key, not numeric. So
// `setunion [10, 2] []` yields [10, 2] because "n:10" < "n:2" in string
// order. Use `srt` after the set op for numeric order. This test pins the
// documented caveat so any future change to numeric sort is intentional.
tri_engine_test!(
union_lexicographic_order,
"f>L n;setunion [10, 2] []",
"[10, 2]"
);