facett-helix/tests/tube_render.rs
//! **CPU render-proof for the 3D TubeView.** Run a real [`TubeView`] through
//! `egui_kittest` so the tube painter executes (project → depth-sort → shade → paint),
//! then prove the render is **non-blank with depth**: the pure projection produces many
//! visible, on-pane, multi-shaded faces, and driving it through `ui()` never panics.
use egui_kittest::Harness;
use facett_core::Facet;
use facett_helix::{TubeMsg, TubeView};
#[test]
fn tube_paints_non_blank_with_depth() {
// Inject-assert the mesh first: a real tube, deterministically.
let probe = TubeView::demo().with_clock(0.0);
let st = probe.state_json();
assert!(st["triangle_count"].as_u64().unwrap() > 200, "a real tube mesh");
assert_eq!(st["valid"], true);
// The pure render core: many visible, on-pane, multi-shaded faces (non-blank).
let faces = probe.faces(640.0, 640.0);
assert!(faces.len() > 200, "the tube projects many visible faces (got {})", faces.len());
let mut shades = std::collections::HashSet::new();
for f in &faces {
let k = ((f.color.r() as u32 >> 3) << 10) | ((f.color.g() as u32 >> 3) << 5) | (f.color.b() as u32 >> 3);
shades.insert(k);
}
assert!(shades.len() >= 8, "the lit, data-coloured tube shows many shades (got {})", shades.len());
// Drive it through the egui immediate-mode surface — the painter must execute
// without panicking (the headless CPU path, no wgpu adapter needed).
let mut view = TubeView::demo().with_clock(0.0);
let mut harness = Harness::builder().with_size(egui::vec2(640.0, 640.0)).build_ui(move |ui| {
view.ui(ui);
});
harness.run();
}
#[test]
fn tube_state_is_data_and_deterministic() {
// Two views at the same pinned clock produce identical observable state (FC-7).
let a = TubeView::demo().with_clock(3.0);
let b = TubeView::demo().with_clock(3.0);
assert_eq!(a.state_json(), b.state_json(), "pinned clock ⇒ byte-identical state");
}
#[test]
fn tube_controls_are_addressable() {
let mut v = TubeView::demo();
assert!(v.update(TubeMsg::ToggleSpin(false)));
assert_eq!(v.state_json()["spin"], false);
assert!(v.update(TubeMsg::SetClock(2.5)));
assert_eq!(v.state_json()["clock_s"], 2.5);
}