facett-sdp/tests/matrix.rs
//! **The functional matrix cell for facett-sdp** — the pane emitted NO testmatrix
//! row of either aspect before this file (see
//! `.nornir/docs/test-matrix-inventory-history.md`, "~10 panes emit no cell").
//!
//! ONE call through the shared generic-`Facet` probe (L5) — no bespoke harness.
use facett_sdp::SdpEditor;
#[test]
fn sdp_probe_emits_render_and_input_cells() {
let mut view = SdpEditor::local();
let script = [
r#""graph""#, // flip to the DAG preview lane
r#"{"add_flow":{"name":"marts","deps":["clean"],"query":"SELECT * FROM clean"}}"#,
r#"{"add_flow":{"name":"broken","deps":["ghost"],"query":"SELECT 1"}}"#, // dangling dep
r#"{"remove_flow":3}"#,
];
let probe = facett_core::testmatrix::probe_and_emit("facett-sdp", &mut view, &script);
assert!(probe.drew(), "the flow editor must tessellate to vertices");
assert!(probe.cardinality() > 0, "state_json reports the flows");
assert!(probe.responded(), "update_json must drive state — a dead seam is a regression");
assert_eq!(probe.initial_state["mode"], "Edit");
assert_eq!(probe.initial_state["valid"], true);
assert_eq!(probe.steps[0].state["mode"], "Graph");
assert_eq!(probe.steps[1].state["flows"].as_array().unwrap().len(), 3);
assert_eq!(probe.steps[1].state["valid"], true);
// EXACT validation contract: a dangling dep must turn the pipeline RED, and
// removing the offending flow must turn it green again. A `drew()`-only or
// "count changed" oracle would not see either.
assert_eq!(probe.steps[2].state["valid"], false, "a dangling dep invalidates");
let errs = probe.steps[2].state["errors"].as_array().unwrap();
assert!(errs.iter().any(|e| e.as_str().unwrap().contains("ghost")), "{errs:?}");
assert_eq!(probe.steps[3].state["valid"], true, "removing it heals the pipeline");
assert_eq!(probe.steps[3].state["flows"].as_array().unwrap().len(), 3);
}
/// RED-when-broken: `remove_flow` with an out-of-range index must be a no-op
/// (not a panic, not a silent removal of the last flow).
#[test]
fn remove_flow_out_of_range_is_a_no_op() {
let mut ed = SdpEditor::local();
assert_eq!(ed.len(), 2);
ed.remove_flow(99);
assert_eq!(ed.len(), 2);
ed.remove_flow(0);
assert_eq!(ed.len(), 1);
assert_eq!(ed.flows()[0].name, "clean");
}