use std::path::PathBuf;
use std::process::Command;
use pounce_cli::solve_report::SolveReport;
fn pounce_exe() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_pounce"))
}
fn fixture(name: &str) -> PathBuf {
let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
p.push("tests");
p.push("fixtures");
p.push(name);
p
}
fn tmp_json(tag: &str) -> PathBuf {
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
let seq = COUNTER.fetch_add(1, Ordering::Relaxed);
let mut p = std::env::temp_dir();
p.push(format!(
"pounce_m13_{}_{seq}_{tag}.json",
std::process::id()
));
p
}
fn run(extra: &[&str]) -> (SolveReport, String) {
let json_path = tmp_json("e2e");
let mut cmd = Command::new(pounce_exe());
cmd.arg(fixture("lp_afiro.nl"))
.arg("solver_selection=nlp")
.arg("--json-output")
.arg(&json_path)
.arg("--json-detail")
.arg("full");
for a in extra {
cmd.arg(a);
}
let output = cmd.output().expect("spawn pounce");
let mut combined = String::from_utf8_lossy(&output.stdout).into_owned();
combined.push_str(&String::from_utf8_lossy(&output.stderr));
assert!(
output.status.success(),
"pounce failed (exit {:?}); output:\n{combined}",
output.status.code(),
);
let text = std::fs::read_to_string(&json_path).unwrap();
let _ = std::fs::remove_file(&json_path);
let report = serde_json::from_str(&text).expect("parse SolveReport JSON");
(report, combined)
}
#[test]
fn presolve_dual_block_keeps_original_nl_length() {
let (baseline, _) = run(&["presolve=no"]);
let m_full = baseline.solution.lambda.len();
assert!(
m_full > 0,
"baseline produced no duals; fixture/route changed"
);
assert_eq!(
m_full, baseline.problem.n_constraints as usize,
"baseline lambda length disagrees with n_constraints"
);
let (presolved, stderr) = run(&["presolve=yes"]);
let dropped_some = stderr
.split("dropped ")
.nth(1)
.and_then(|s| s.split_whitespace().next())
.and_then(|n| n.parse::<u32>().ok())
.map(|n| n > 0)
.unwrap_or(false);
assert!(
dropped_some,
"presolve dropped no rows — test no longer exercises M13; output:\n{stderr}"
);
assert_eq!(
presolved.solution.lambda.len(),
m_full,
"presolve dual block length {} != original .nl m {m_full}",
presolved.solution.lambda.len(),
);
assert_eq!(
presolved.solution.lambda.len(),
presolved.problem.n_constraints as usize,
"presolve lambda length disagrees with reported n_constraints"
);
}