use egui::Color32;
use facett_core::harness;
use nornir_testmatrix::discover::FacetRow;
use facett_docview::{DocPage, DocView, Msg as DocMsg};
use facett_graph3d::{Graph3D, Layout3D, Msg as G3Msg};
use facett_graphview::metro::{demo_map, Msg as MetroMsg};
use facett_graphview::MetroView;
use facett_helix::{HelixView, Msg as HelixMsg};
use facett_jobview::{JobEntry, JobList, JobStatus, Msg as JobMsg};
use facett_warehousedeck::{DeckLayout, Msg as WhMsg, WarehouseDeck};
fn drive_elm<C>(comp: &mut C, msgs: Vec<C::Msg>) -> Result<(bool, String), String>
where
C: facett_core::Elm + facett_core::Facet,
{
let n_msgs = msgs.len();
let state = harness::snapshot_json(comp, msgs);
if !state.is_object() {
return Err(format!("snapshot is not a JSON object: {state}"));
}
let keys = state.as_object().map(|o| o.len()).unwrap_or(0);
let report = harness::headless_render(comp);
Ok((
report.drew(),
format!(
"msgs={n_msgs} state_keys={keys} verts={} drew={}",
report.vertices,
report.drew()
),
))
}
fn record(
rows: &mut Vec<FacetRow>,
component: &str,
caps: &[&str],
probe: impl FnOnce() -> Result<(bool, String), String>,
) {
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(probe));
let (driven, detail) = match outcome {
Ok(Ok((drew, d))) => (true, format!("clean headless drive ({d}, drew_proof={drew})")),
Ok(Err(e)) => (false, format!("dirty headless drive: {e}")),
Err(_) => (false, "panicked during headless drive".to_string()),
};
nornir_testmatrix::functional_status(component, "headless_drive", driven, &detail);
rows.push(FacetRow {
component: component.to_string(),
in_registry: true,
has_local_ctor: false,
has_remote_ctor: false,
caps: caps.iter().map(|s| s.to_string()).collect(),
driven,
});
}
pub fn probe_facett_components() -> Vec<FacetRow> {
let mut rows = Vec::with_capacity(6);
record(&mut rows, "facett-jobview", &["interactive", "hierarchical"], || {
let mut v = JobList::new("facett-jobview");
let parent = JobEntry::new("p1", "build", JobStatus::Done);
let child = JobEntry {
parent_id: Some("p1".to_string()),
..JobEntry::new("c1", "compile", JobStatus::Running)
};
drive_elm(
&mut v,
vec![
JobMsg::SetJobs(vec![parent, child]),
JobMsg::ToggleFold("p1".to_string()),
JobMsg::Select("c1".to_string()),
],
)
});
record(&mut rows, "facett-docview", &["interactive", "reads_docs"], || {
let svg = br##"<svg xmlns="http://www.w3.org/2000/svg" width="120" height="160"><rect width="120" height="160" fill="#ffffff"/><rect x="10" y="10" width="100" height="20" fill="#3355aa"/></svg>"##;
let pages: Vec<DocPage> = DocPage::from_svg_bytes(svg).into_iter().collect();
let toc = if pages.is_empty() {
Vec::new()
} else {
vec![("Intro".to_string(), 0usize)]
};
let mut v = DocView::new("facett-docview", pages, toc);
drive_elm(
&mut v,
vec![DocMsg::ZoomIn, DocMsg::ZoomIn, DocMsg::ToggleSidebar, DocMsg::JumpTo(0)],
)
});
record(&mut rows, "facett-graphview", &["interactive", "graph"], || {
let mut v = MetroView::new("facett-graphview");
v.set_map(demo_map());
drive_elm(
&mut v,
vec![
MetroMsg::SelectLine("bench_run→Bench.Submit".to_string()),
MetroMsg::ClearSelection,
],
)
});
record(&mut rows, "facett-graph3d", &["interactive", "graph", "3d"], || {
let nodes = vec![
("alpha".to_string(), Color32::RED),
("beta".to_string(), Color32::GREEN),
("gamma".to_string(), Color32::LIGHT_BLUE),
];
let edges = vec![(0usize, 1usize), (1, 2)];
let mut v = Graph3D::new(nodes, edges, Layout3D::Sphere);
drive_elm(
&mut v,
vec![
G3Msg::SetYaw(0.5),
G3Msg::Tick(0.1),
G3Msg::SelectNode(1),
G3Msg::SetLayout(Layout3D::Helix),
G3Msg::Fit,
],
)
});
record(
&mut rows,
"facett-warehousedeck",
&["interactive", "deck", "reads_warehouse"],
|| {
let mut v = WarehouseDeck::new("facett-warehousedeck").with_cols(2);
drive_elm(
&mut v,
vec![
WhMsg::IncCols,
WhMsg::SetLayout(DeckLayout::Focus),
WhMsg::FocusNext,
WhMsg::BackToWall,
],
)
},
);
record(&mut rows, "facett-helix", &["interactive", "dag", "time"], || {
let mut v = HelixView::demo();
drive_elm(
&mut v,
vec![
HelixMsg::Tick(0.2),
HelixMsg::Seek(0.5),
HelixMsg::ToggleTraverse(true),
HelixMsg::SetLevel(1),
HelixMsg::SetYaw(0.3),
],
)
});
rows
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_six_embedded_components_drive_green() {
let rows = probe_facett_components();
assert_eq!(rows.len(), 6, "one FacetRow per embedded component");
for r in &rows {
assert!(r.in_registry, "{} must be a registered surface", r.component);
assert!(
r.driven,
"{} must drive clean through the harness (its update() + render)",
r.component
);
}
let covered = nornir_testmatrix::discover::covered_facetts(&rows);
assert_eq!(covered.len(), 6, "each driven NA component → one covered key");
assert!(covered.contains("facett_component:facett-helix@na"));
}
}