facett-core/tests/ice_drip_kittest.rs
//! **Kittest PROOF for the ice-drip winter decor** (the Skaði "Skade Vinter"
//! scene) — the same shape as `facett-graph3d`'s clock-determinism kittest.
//!
//! 1. **Deterministic given `(seed, clock)`** — two drips at the same clock have
//! byte-identical observable `state_json()`; advancing the clock changes it.
//! 2. **It really paints in a real egui frame** — driven headlessly through
//! `egui_kittest` (no GPU): the icicles + falling melt-droplets + frost shimmer
//! are laid into a live `egui::Painter` without panicking.
//! 3. **The gate holds** — a disabled drip has zero active droplets.
//!
//! Run: `cargo test -p facett-core --test ice_drip_kittest`.
use egui_kittest::Harness;
use facett_core::effects::IceDrip;
#[test]
fn ice_drip_is_clock_deterministic_paints_headlessly_and_gates() {
// (1) Deterministic: same seed + clock ⇒ identical observable state.
let a = IceDrip::new(12, 7).enabled(true).at_clock(2.0);
let b = IceDrip::new(12, 7).enabled(true).at_clock(2.0);
assert_eq!(a.state_json(), b.state_json(), "same (seed,clock) ⇒ identical drip");
let later = IceDrip::new(12, 7).enabled(true).at_clock(2.4);
assert_ne!(a.state_json(), later.state_json(), "advancing the clock moves the drip");
// Every live droplet's fall is normalised into [0,1] (gravity curve), and the
// scene is non-empty — real winter motion, not a stub.
let s = a.state_json();
assert_eq!(s["enabled"], true);
assert!(s["active_droplets"].as_u64().unwrap() > 0, "live droplets: {s}");
for d in s["droplets"].as_array().unwrap() {
let y = d["y_norm"].as_f64().unwrap();
assert!((0.0..=1.0).contains(&y), "droplet fall is normalised: {d}");
}
// (2) It paints inside a real egui layout (headless kittest, no GPU): drive the
// drip off the harness clock and lay it onto the live painter.
let mut drip = IceDrip::new(12, 7).enabled(true);
let mut harness = Harness::builder()
.with_size(egui::vec2(420.0, 300.0))
.build_ui(move |ui| {
let r = ui.max_rect();
drip.set_clock(ui.input(|i| i.time) as f32);
drip.paint(ui.painter(), r);
ui.label("skaði · skade vinter");
});
harness.run();
// (3) The gate: a disabled drip is dark — nothing active.
let off = IceDrip::new(12, 7).at_clock(2.0); // enabled defaults false
assert_eq!(off.state_json()["active_droplets"], serde_json::json!(0), "disabled ⇒ no droplets");
#[cfg(feature = "testmatrix")]
facett_core::testmatrix::emit(
"IceDrip",
"ice_drip_clock_determinism_paint_gate",
a.state_json() == b.state_json()
&& a.state_json() != later.state_json()
&& off.state_json()["active_droplets"] == serde_json::json!(0),
"deterministic at a pinned clock, paints headlessly, disabled = no droplets",
);
}