use std::path::PathBuf;
use std::process::Command;
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 run(fixture_name: &str, tag: &str, opts: &[&str]) -> (Option<i32>, String) {
let dir = std::env::temp_dir().join(format!("pounce_linsolsel_{tag}"));
std::fs::create_dir_all(&dir).expect("scratch dir");
let nl = dir.join(fixture_name);
std::fs::copy(fixture(fixture_name), &nl).expect("copy fixture");
let out = Command::new(pounce_exe())
.arg(&nl)
.args(opts)
.arg("print_level=0")
.output()
.expect("run pounce");
let _ = std::fs::remove_dir_all(&dir);
(
out.status.code(),
String::from_utf8_lossy(&out.stderr).into_owned(),
)
}
#[test]
fn unimplemented_backends_are_refused() {
for (i, name) in [
"ma27",
"ma77",
"ma86",
"ma97",
"mumps",
"pardiso",
"pardisomkl",
"spral",
"wsmp",
"custom",
]
.into_iter()
.enumerate()
{
let (code, err) = run(
"user_scaling_suffix.nl",
&format!("bad{i}"),
&[&format!("linear_solver={name}")],
);
assert_eq!(code, Some(2), "linear_solver={name} should fail; {err}");
assert!(
err.contains(&format!("linear_solver={name} is not implemented")),
"the refusal must name the backend; stderr:\n{err}",
);
assert!(
err.contains("linear_solver=feral"),
"the refusal must say what to use instead; stderr:\n{err}",
);
}
}
#[test]
fn the_refusal_is_case_insensitive() {
let (code, err) = run("user_scaling_suffix.nl", "upper", &["linear_solver=MUMPS"]);
assert_eq!(code, Some(2), "stderr:\n{err}");
}
#[test]
fn implemented_backends_are_accepted() {
for name in ["feral", "ma57"] {
let (code, err) = run(
"user_scaling_suffix.nl",
name,
&[&format!("linear_solver={name}")],
);
assert_eq!(code, Some(0), "linear_solver={name} should solve; {err}");
}
}
#[test]
fn the_registered_default_solves() {
let (code, err) = run("user_scaling_suffix.nl", "default", &[]);
assert_eq!(code, Some(0), "a default run must not be refused; {err}");
assert!(
!err.contains("not implemented"),
"a default run must not warn either; stderr:\n{err}",
);
}
#[test]
fn the_registered_default_is_feral() {
let dir = std::env::temp_dir().join("pounce_linsolsel_bannerdefault");
std::fs::create_dir_all(&dir).expect("scratch dir");
let nl = dir.join("user_scaling_suffix.nl");
std::fs::copy(fixture("user_scaling_suffix.nl"), &nl).expect("copy fixture");
let out = Command::new(pounce_exe())
.arg(&nl)
.output()
.expect("run pounce");
let _ = std::fs::remove_dir_all(&dir);
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("running with linear solver FERAL"),
"default banner should name FERAL; stdout:\n{stdout}",
);
}
#[test]
fn the_refusal_covers_the_convex_route() {
let (code, err) = run("boxed_qp_min.nl", "convex", &["linear_solver=mumps"]);
assert_eq!(code, Some(2), "stderr:\n{err}");
assert!(err.contains("not implemented"), "stderr:\n{err}");
}