use std::path::Path;
use std::process::Command;
const BED: &str = "/tmp/bed/bed_v0.2.8_linux_amd64/bed";
const RSLEIGH_BIN: &str = env!("CARGO_BIN_EXE_rsleigh");
fn bed_available() -> bool {
if Path::new(BED).exists() {
return true;
}
if std::env::var_os("RSLEIGH_REQUIRE_BED_FIXTURE").is_some() {
panic!("bed fixture missing at {BED}");
}
eprintln!("[skip] bed fixture missing at {BED}");
false
}
fn decompile(addr: &str) -> String {
let out = Command::new(RSLEIGH_BIN)
.args([BED, addr])
.output()
.expect("rsleigh invocation");
assert!(
out.status.success(),
"rsleigh failed:\n{}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8(out.stdout).expect("UTF-8")
}
#[test]
fn no_phi_function_leaks_in_output() {
if !bed_available() {
return;
}
for addr in ["0x42d620", "0x455b60", "0x46b020", "0x46c7e0"] {
let text = decompile(addr);
assert!(
!text.contains("phi("),
"{addr}: raw `phi(...)` leaked into output\n{text}"
);
}
}
#[test]
fn conditional_merge_emits_ternary_on_bed() {
if !bed_available() {
return;
}
let text = decompile("0x46b020");
assert!(
text.contains(") ? ") && text.contains(" : "),
"no ternary found in output — rewrite not firing\n{text}"
);
}
#[test]
fn same_var_ternary_collapses_to_bare_var() {
if !bed_available() {
return;
}
let text = decompile("0x42d620");
for line in text.lines() {
let t = line.trim();
if let Some(qpos) = t.find(") ? ") {
let after_q = &t[qpos + 4..];
if let Some(colon) = after_q.find(" : ") {
let then_tok = after_q[..colon].trim();
let else_tok_end =
after_q[colon + 3..].find(|c: char| !c.is_ascii_alphanumeric() && c != '_');
let else_tok = match else_tok_end {
Some(n) => after_q[colon + 3..colon + 3 + n].trim(),
None => after_q[colon + 3..].trim_end_matches(';').trim(),
};
assert!(
then_tok != else_tok || then_tok.is_empty(),
"self-identity ternary leaked: `{t}` (both arms = `{then_tok}`)"
);
}
}
}
}