#[cfg(test)]
mod tests {
use crate::geometry::shapes::{Circle, Ellipse, Square};
use crate::geometry::traits::DiagramShape;
use crate::test_utils::corpus::{all, CorpusEntry, Fittable, TEST_SEEDS};
use crate::Fitter;
struct Row {
name: &'static str,
seed: u64,
diag: Option<f64>,
ceiling: f64,
ok: bool,
note: &'static str,
}
fn run<S>(
shape_name: &str,
ceiling_fn: fn(&CorpusEntry) -> f64,
fittable_fn: fn(&CorpusEntry) -> Fittable,
) where
S: DiagramShape + Copy + 'static,
{
let mut rows = Vec::new();
for entry in all() {
for &seed in &TEST_SEEDS {
let ceiling = ceiling_fn(entry);
let fittable = fittable_fn(entry);
if let Fittable::Skip(reason) = fittable {
rows.push(Row {
name: entry.name,
seed,
diag: None,
ceiling,
ok: true,
note: reason,
});
continue;
}
let spec = (entry.build)();
let result = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
Fitter::<S>::new(&spec).seed(seed).fit()
})) {
Ok(r) => r,
Err(_) => {
rows.push(Row {
name: entry.name,
seed,
diag: None,
ceiling,
ok: false,
note: "PANIC during fit",
});
continue;
}
};
match (fittable, result) {
(Fittable::Normal, Ok(layout)) => {
let diag = layout.diag_error();
let ok = diag.is_finite() && diag <= ceiling;
rows.push(Row {
name: entry.name,
seed,
diag: Some(diag),
ceiling,
ok,
note: if ok { "" } else { "OVER CEILING" },
});
}
(Fittable::Normal, Err(e)) => {
rows.push(Row {
name: entry.name,
seed,
diag: None,
ceiling,
ok: false,
note: leak_msg(format!("ERR: {e}")),
});
}
(Fittable::SanityOnly, Ok(layout)) => {
let ok = layout.loss().is_finite();
rows.push(Row {
name: entry.name,
seed,
diag: None,
ceiling,
ok,
note: if ok { "sanity-ok" } else { "sanity-loss-nan" },
});
}
(Fittable::SanityOnly, Err(_)) => {
rows.push(Row {
name: entry.name,
seed,
diag: None,
ceiling,
ok: true,
note: "sanity-err",
});
}
(Fittable::Skip(_), _) => unreachable!("Skip handled above the fit"),
}
}
}
print_report(shape_name, &rows);
let failures: Vec<&Row> = rows.iter().filter(|r| !r.ok).collect();
if !failures.is_empty() {
panic!(
"{} corpus quality: {} of {} (spec, seed) rows exceeded ceiling — see table above",
shape_name,
failures.len(),
rows.len()
);
}
}
fn print_report(shape_name: &str, rows: &[Row]) {
eprintln!();
eprintln!("# Corpus quality report ({shape_name})");
eprintln!("| spec | seed | diag_error | ceiling | status |");
eprintln!("|------|------|------------|---------|--------|");
for r in rows {
let diag = r
.diag
.map(|d| format!("{d:.3e}"))
.unwrap_or_else(|| "—".to_string());
let status = if r.ok { "OK" } else { "FAIL" };
let note = if r.note.is_empty() {
String::new()
} else {
format!(" ({})", r.note)
};
eprintln!(
"| {} | {} | {} | {:.1e} | {}{} |",
r.name, r.seed, diag, r.ceiling, status, note
);
}
eprintln!();
}
fn leak_msg(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
#[test]
fn corpus_circles_diag_error() {
run::<Circle>("circle", |e| e.ceiling_circle(), |e| e.fittable_circle);
}
#[test]
fn corpus_ellipses_diag_error() {
run::<Ellipse>("ellipse", |e| e.ceiling_ellipse(), |e| e.fittable_ellipse);
}
#[test]
fn corpus_squares_diag_error() {
run::<Square>("square", |e| e.ceiling_square(), |e| e.fittable_square);
}
}