Skip to main content

nornir_testmatrix/
lib.rs

1//! # nornir-testmatrix
2//!
3//! The portable core of nornir's **multi-aspect test matrix** — extracted from
4//! `nornir` (EPIC L) so any leaf repo (znippy, skade, lbzip2-rs …) can run the
5//! same matrix with a *tiny* dep set: `std` + `serde`/`serde_json` + `anyhow`.
6//! No iceberg, arrow, eframe, tantivy, or skade.
7//!
8//! ## What it does
9//! 1. **Runner** ([`runner`]) — wrap a repo's *native* Rust test framework
10//!    (`cargo nextest run --message-format libtest-json` if nextest is on PATH,
11//!    else plain `cargo test`), parse each test's pass/fail + duration, enforce a
12//!    stall watchdog. Pure subprocess driving — no test registration.
13//! 2. **Multi-aspect engine** ([`aspect`]) — beyond unit tests, run MANY
14//!    *aspects* of a repo's health ([`Aspect`]): build, doctest, clippy, fmt,
15//!    audit, bench-smoke, coverage, feature-powerset, msrv, examples. Each
16//!    shells the right `cargo` subcommand, parses its result, and emits
17//!    [`TestResultRow`]s carrying an `aspect` tag + a numeric `metric` (coverage
18//!    %, warning count, advisory count …). A missing tool is a **skip**, never a
19//!    hard fail.
20//! 3. **Model** ([`model`]) — the pure row/summary types ([`TestResultRow`],
21//!    [`RunSummary`], [`TestSelector`], the [`status`] tags) + the renderers
22//!    ([`render_matrix`], [`summarize_runs`], [`rows_to_json`]).
23//! 4. **Sinks** ([`sink`]) — the [`TestSink`] trait + built-in [`JsonFileSink`]
24//!    and [`NullSink`] so a leaf repo with no warehouse can still persist its
25//!    matrix. nornir implements `TestSink` over its Iceberg warehouse.
26//! 5. **Discovery** ([`discover`]) — the autonom (AUT2) anti-drift core: pure
27//!    enumerators that build the testable [`Surface`] from data (facett
28//!    components, viz tabs × {thin,fat}, CLI subcommands, MCP tools, and the
29//!    unreached-function set from `symbol_facts − test-reachable(call_edges)`),
30//!    then [`compute_gap`] differences it against coverage so the gate can
31//!    enforce `Gap == ∅`. No warehouse here — the caller feeds the rows.
32//! 6. **Functional-status mode** ([`functional`]) — a component reports whether
33//!    it *actually works* (`functional_status(component, check, ok, detail)`)
34//!    from its own headless-render / self-test path. The
35//!    [`Aspect::Functional`] runner drains those into rows so a broken render is
36//!    a RED matrix row WITHOUT eyeballing a GUI. Gated behind the **`testmatrix`
37//!    cargo feature**: release builds (feature off) strip the emit to a no-op.
38//!
39//! ## How a leaf repo uses it
40//! ```no_run
41//! use nornir_testmatrix::{run_full_matrix, Aspect, JsonFileSink, TestSink};
42//! use std::path::Path;
43//!
44//! let aspects = [Aspect::Build, Aspect::Unit, Aspect::Doctest, Aspect::Clippy, Aspect::Fmt];
45//! let rows = run_full_matrix(Path::new("."), &aspects);
46//! let sink = JsonFileSink::new("target/nornir-testmatrix.json");
47//! sink.append(&rows).unwrap();
48//! ```
49
50pub mod aspect;
51pub mod coverage;
52pub mod discover;
53pub mod functional;
54pub mod model;
55pub mod runner;
56pub mod sink;
57
58// ─── flat re-exports (the crate's public façade) ───────────────────────────
59
60pub use aspect::{
61    aspect_label, parse_aspect, parse_funnel_decompose, run_aspect, run_full_matrix, Aspect,
62    AspectOutcome,
63};
64pub use coverage::{
65    rows_for, seed_allowlist, stale_allowlist_entries, AllowEntry, Allowlist, CoverageRow,
66    CoverageSummary, GateReport, Verdict,
67};
68pub use discover::{
69    cli_commands, compute_gap, facett_components, mcp_tools, test_reachable, unreached_functions,
70    viz_tabs, CallEdge, FacetRow, Gap, Mode, Surface, SurfaceKind, SurfaceNode, SymbolRow,
71};
72pub use functional::{drain_functional_rows, functional_row, functional_status};
73pub use model::{
74    listed_rows, new_run_id, parse_cargo_test_list, parse_nextest_list, render_matrix,
75    rows_to_json, short_run, status, summarize_runs, RunSummary, TestResultRow, TestSelector,
76};
77pub use runner::{
78    detect_runner, list_tests, run_matrix, stall_secs, MatrixRun, Runner, TestCase,
79    DEFAULT_STALL_SECS,
80};
81pub use sink::{JsonFileSink, NullSink, TestSink};