#![allow(clippy::single_element_loop)]
use std::process::Command;
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
fn run_ok(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()
}
const ENGINES: &[&str] = &[
"--vm",
"--vm",
#[cfg(feature = "cranelift")]
"--jit",
];
#[test]
fn dot_index_zero() {
let src = "f>n;xs=[10,20,30];xs.0";
for engine in ENGINES {
assert_eq!(run_ok(engine, src, "f"), "10", "engine={engine}");
}
}
#[test]
fn dot_index_two() {
let src = "f>n;xs=[10,20,30];xs.2";
for engine in ENGINES {
assert_eq!(run_ok(engine, src, "f"), "30", "engine={engine}");
}
}
#[test]
fn dot_index_out_of_range_tree_vm() {
let src = "f>n;xs=[10,20,30];xs.5";
for engine in ["--vm"] {
let out = ilo()
.args([src, engine, "f"])
.output()
.expect("failed to run ilo");
assert!(
!out.status.success(),
"engine={engine}: expected runtime error for xs.5, got stdout={}",
String::from_utf8_lossy(&out.stdout)
);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
stderr.contains("out of bounds")
|| stderr.contains("out of range")
|| stderr.contains("ILO-R006")
|| stderr.contains("ILO-R009"),
"engine={engine}: expected out-of-range error, got stderr={stderr}"
);
}
}
#[test]
#[cfg(feature = "cranelift")]
fn dot_index_out_of_range_cranelift() {
let src = "f>n;xs=[10,20,30];xs.5";
let out = ilo()
.args([src, "--jit", "f"])
.output()
.expect("failed to run ilo");
assert!(
!out.status.success(),
"cranelift: expected runtime error for xs.5, got stdout={}",
String::from_utf8_lossy(&out.stdout)
);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
stderr.contains("out of bounds") || stderr.contains("ILO-R004"),
"cranelift: expected out-of-bounds diagnostic, got stderr={stderr}"
);
}
#[test]
fn record_field_access_unaffected() {
let src = "type point{x:n;y:n}\nf>n;p=point x:10 y:20;p.y";
for engine in ENGINES {
assert_eq!(run_ok(engine, src, "f"), "20", "engine={engine}");
}
}
#[test]
fn record_numeric_dot_fails_verify() {
let src = "type point{x:n;y:n}\nf>n;p=point x:10 y:20;p.0";
let out = ilo()
.args([src, "--vm", "f"])
.output()
.expect("failed to run ilo");
assert!(
!out.status.success(),
"expected verify/type error for p.0, got stdout={}",
String::from_utf8_lossy(&out.stdout)
);
}
#[test]
fn dot_index_nested_list() {
let src = "f>n;xss=[[1,2],[3,4]];xss.0.1";
for engine in ENGINES {
assert_eq!(run_ok(engine, src, "f"), "2", "engine={engine}");
}
}
#[test]
fn dot_index_nested_list_deep() {
let src = "f>n;xss=[[[1,2]],[[3,4],[5,6]]];xss.1.1.0";
for engine in ENGINES {
assert_eq!(run_ok(engine, src, "f"), "5", "engine={engine}");
}
}
#[test]
fn float_literal_outside_dot_unchanged() {
let src = "f>n;1.5";
for engine in ENGINES {
assert_eq!(run_ok(engine, src, "f"), "1.5", "engine={engine}");
}
}