golden.rs
raw
//! Golden-image test harness, shared by every crate with rendering tests.
//!
//! `check` compares a rendered pixmap against `<dir>/<name>.png` exactly.
//! With `GUIDUCK_BLESS` set, it (re)writes the golden instead. On mismatch
//! the actual render lands in `target/golden-failures/` and the check
//! panics with the diff statistics.
use std::path::Path;
use crate::diff::{DiffTolerance, compare};
/// Goldens come from the same deterministic renderer, so they must
/// reproduce exactly.
const TOLERANCE: DiffTolerance = DiffTolerance::EXACT;
pub fn check(name: &str, actual: &tiny_skia::Pixmap, golden_dir: &Path) {
let golden_path = golden_dir.join(format!("{name}.png"));
if std::env::var_os("GUIDUCK_BLESS").is_some() {
std::fs::create_dir_all(golden_dir).expect("create goldens dir");
actual.save_png(&golden_path).expect("write golden");
return;
}
let golden = tiny_skia::Pixmap::load_png(&golden_path).unwrap_or_else(|e| {
panic!(
"missing or unreadable golden {golden_path:?} ({e}); \
run with GUIDUCK_BLESS=1 to create it"
)
});
// `<crate>/tests/goldens` → workspace root → `target/golden-failures`.
let failure_dir = golden_dir
.ancestors()
.nth(4)
.unwrap_or_else(|| Path::new("."))
.join("target/golden-failures");
match compare(&golden, actual, TOLERANCE) {
Some((_, true)) => {}
Some((stats, false)) => {
std::fs::create_dir_all(&failure_dir).ok();
let actual_path = failure_dir.join(format!("{name}-actual.png"));
actual.save_png(&actual_path).ok();
panic!(
"{name} differs from golden: {:.4}% of pixels (max channel diff {}); \
actual written to {actual_path:?}",
stats.differing_fraction * 100.0,
stats.max_channel_diff,
);
}
None => {
std::fs::create_dir_all(&failure_dir).ok();
let actual_path = failure_dir.join(format!("{name}-actual.png"));
actual.save_png(&actual_path).ok();
panic!(
"{name} has wrong dimensions: golden {}x{}, actual {}x{}; \
actual written to {actual_path:?}",
golden.width(),
golden.height(),
actual.width(),
actual.height(),
);
}
}
}