facett-demo/tests/pop_graph_blob.rs
//! **PNG-blob proof for the `Sverige · Population` showcase** (LAW: emit a
//! final-picture blob per graph view; the test reads it back, asserts non-blank +
//! contained). Renders each of the three linked views (full / debt / kommun) of the
//! knut-popsim population graph to a straight-RGBA frame through the L0 + glow
//! kernel, writes a PNG so a human can LOOK, and asserts on the read-back picture.
//!
//! Run: `cargo test -p facett-demo --test pop_graph_blob -- --nocapture`
use facett_demo::pop_model::{ColorMode, PopView};
use facett_demo::pop_tab::{PANE_H, PANE_W, PopGraphTab, TITLE};
/// Where the blobs land (a stable temp dir a human / the matrix can open).
fn blob_dir() -> std::path::PathBuf {
let d = std::env::temp_dir().join("facett-demo");
std::fs::create_dir_all(&d).ok();
d
}
/// Count pixels that differ from the dark ground — the real non-blank oracle (the
/// frame is fully opaque, so `lit_px` saturates; "drew something over the ground" is
/// the signal that matters).
fn drawn_px(rgba: &[u8]) -> usize {
rgba.as_chunks::<4>().0.iter().filter(|p| p[0] > 16 || p[1] > 18 || p[2] > 30).count()
}
/// Save a frame as a PNG and return its path + drawn-pixel count (over the ground).
fn save_view(tab: &PopGraphTab, view: PopView, suffix: &str) -> (std::path::PathBuf, usize) {
let f = tab.frame_for(view);
let drawn = drawn_px(&f.rgba);
let img =
image::RgbaImage::from_raw(PANE_W, PANE_H, f.rgba.clone()).expect("frame → image");
let path = blob_dir().join(format!("pop_{}_{}.png", view.label(), suffix));
image::DynamicImage::ImageRgba8(img).save(&path).ok();
eprintln!(
"[pop-blob] {} ({}): {} → {} drawn px (over ground)",
view.label(),
suffix,
path.display(),
drawn
);
(path, drawn)
}
#[test]
fn each_linked_view_emits_a_nonblank_contained_blob() {
let tab = PopGraphTab::new(TITLE);
for view in [PopView::Full, PopView::Debt, PopView::Kommun] {
let (path, drawn) = save_view(&tab, view, "bylabel");
// The blob exists on disk (so a human can LOOK).
assert!(path.exists(), "{} blob written", view.label());
// Non-blank: a real, substantial picture drew OVER the dark ground.
assert!(drawn > 2_000, "{} view drew over the ground: {drawn} px", view.label());
// Read the PNG back and assert it's CONTAINED (a dark-ground corner) + that
// the picture survives the round-trip.
let back = image::open(&path).expect("read back").to_rgba8();
assert_eq!(back.dimensions(), (PANE_W, PANE_H), "{} blob is full-size", view.label());
let corner = back.get_pixel(1, 1).0;
assert!(corner[3] == 255 && corner[0] < 40 && corner[1] < 40, "{} corner is the dark ground", view.label());
let full = PANE_W as usize * PANE_H as usize;
let lit_back = back.pixels().filter(|p| p.0[3] != 0).count();
assert_eq!(lit_back, full, "PNG is fully opaque (ground + orbs)");
let drawn_back = drawn_px(&back.into_raw());
assert!(drawn_back > 2_000, "{} drawn pixels survive the PNG round-trip: {drawn_back}", view.label());
// The interior carries real, bright colour (the glowing orbs), not just ground.
let f2 = tab.frame_for(view);
let bright = f2.rgba.as_chunks::<4>().0.iter().filter(|p| p[0] as u32 + p[1] as u32 + p[2] as u32 > 300).count();
assert!(bright > 200, "{} has bright glowing nodes, got {bright} bright px", view.label());
}
}
#[test]
fn debt_heat_blob_differs_from_label_blob() {
// The debt-heat lens must produce a visibly different blob than by-label — proof
// the colour-by toggle reaches the rendered PNG, not just state.
let mut tab = PopGraphTab::new(TITLE);
let (label_path, _) = save_view(&tab, PopView::Full, "bylabel2");
tab.query.color = ColorMode::ByDebtHeat;
tab.rebuild();
let (heat_path, _) = save_view(&tab, PopView::Full, "debtheat");
let a = image::open(&label_path).unwrap().to_rgba8();
let b = image::open(&heat_path).unwrap().to_rgba8();
let diff = a.pixels().zip(b.pixels()).filter(|(x, y)| x.0 != y.0).count();
assert!(diff > 2_000, "debt-heat blob differs from by-label blob: {diff} px");
}