facett-brokkr/tests/matrix.rs
//! **The functional matrix cell for facett-brokkr** — the pipeline builder
//! 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_brokkr::PipelineBuilder;
#[test]
fn brokkr_probe_emits_render_and_input_cells() {
let mut view = PipelineBuilder::demo("brokkr");
let before = view.state_json();
let script = [
r#""graph""#, // the interactive DAG lane
r#"{"add_stage":"deploy"}"#,
r#"{"set_text":"= not toml ="}"#, // an unparseable buffer
];
let probe = facett_core::testmatrix::probe_and_emit("facett-brokkr", &mut view, &script);
assert!(
probe.drew(),
"the pipeline builder must tessellate to vertices"
);
assert!(probe.cardinality() > 0, "state_json reports stages/steps");
assert!(
probe.responded(),
"update_json must drive state — a dead seam is a regression"
);
let stages0 = before["stage_count"].as_u64().unwrap();
assert!(stages0 >= 2, "the demo pipeline has real stages: {stages0}");
assert_eq!(probe.initial_state["valid"], true);
assert_eq!(probe.steps[0].state["mode"], "Graph");
assert_eq!(
probe.steps[1].state["stage_count"],
stages0 + 1,
"add_stage added exactly one"
);
// EXACT parse contract: garbage in the TOML buffer must surface a
// `parse_error`, not silently keep the old model. A `drew()`-only oracle
// would never see this.
assert!(
!probe.steps[2].state["parse_error"].is_null(),
"an unparseable buffer must report parse_error, got {}",
probe.steps[2].state["parse_error"]
);
}
/// RED-when-broken: `remove_stage` out of range must be a no-op, and the TOML the
/// pane hands the clipboard must round-trip back through `set_text` to the SAME
/// pipeline (the builder's own serialise/parse pair is its correctness contract).
#[test]
fn toml_round_trips_and_out_of_range_removal_is_a_no_op() {
let mut a = PipelineBuilder::demo("brokkr");
let n = a.stage_count();
a.remove_stage(999);
assert_eq!(a.stage_count(), n);
let toml = a.pipeline_toml();
let mut b = PipelineBuilder::new("brokkr");
b.set_text(&toml);
assert!(
b.state_json()["parse_error"].is_null(),
"our own TOML must re-parse"
);
assert_eq!(
b.state_json()["pipeline"],
a.state_json()["pipeline"],
"round trip is lossless"
);
}
#[test]
fn graph_editor_robot_messages_replay_connect_move_and_history() {
let mut view = PipelineBuilder::demo("brokkr");
let script = [
r#""graph""#,
r#"{"disconnect":["compile","unit"]}"#,
r#"{"connect":["compile","unit"]}"#,
r#"{"move":["compile",40,80]}"#,
r#""undo""#,
r#""redo""#,
r#"{"connect":["unit","compile"]}"#,
];
let probe = facett_core::testmatrix::probe_and_emit("facett-brokkr", &mut view, &script);
assert!(probe.drew());
assert_eq!(
probe.steps[2].state["pipeline"]["stage"][1]["step"][0]["needs"],
serde_json::json!(["compile"])
);
assert_eq!(
probe.steps[3].state["layout_overrides"]["compile"],
serde_json::json!([40.0, 80.0])
);
assert_eq!(
probe.steps[4].state["layout_overrides"],
serde_json::json!({})
);
assert_eq!(
probe.steps[5].state["layout_overrides"]["compile"],
serde_json::json!([40.0, 80.0])
);
assert!(
probe.steps[6].state["last_refusal"]
.as_str()
.unwrap()
.contains("cycle")
);
assert_eq!(probe.steps[6].state["toml"], probe.steps[5].state["toml"]);
}