Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/nornir-testmatrix/src/lib.rs

//! # nornir-testmatrix
//!
//! The portable core of nornir's **multi-aspect test matrix** — extracted from
//! `nornir` (EPIC L) so any leaf repo (znippy, skade, lbzip2-rs …) can run the
//! same matrix with a *tiny* dep set: `std` + `serde`/`serde_json` + `anyhow`.
//! No iceberg, arrow, eframe, tantivy, or skade.
//!
//! ## What it does
//! 1. **Runner** ([`runner`]) — wrap a repo's *native* Rust test framework
//!    (`cargo nextest run --message-format libtest-json` if nextest is on PATH,
//!    else plain `cargo test`), parse each test's pass/fail + duration, enforce a
//!    stall watchdog. Pure subprocess driving — no test registration.
//! 2. **Multi-aspect engine** ([`aspect`]) — beyond unit tests, run MANY
//!    *aspects* of a repo's health ([`Aspect`]): build, doctest, clippy, fmt,
//!    audit, bench-smoke, coverage, feature-powerset, msrv, examples. Each
//!    shells the right `cargo` subcommand, parses its result, and emits
//!    [`TestResultRow`]s carrying an `aspect` tag + a numeric `metric` (coverage
//!    %, warning count, advisory count …). A missing tool is a **skip**, never a
//!    hard fail.
//! 3. **Model** ([`model`]) — the pure row/summary types ([`TestResultRow`],
//!    [`RunSummary`], [`TestSelector`], the [`status`] tags) + the renderers
//!    ([`render_matrix`], [`summarize_runs`], [`rows_to_json`]).
//! 4. **Sinks** ([`sink`]) — the [`TestSink`] trait + built-in [`JsonFileSink`]
//!    and [`NullSink`] so a leaf repo with no warehouse can still persist its
//!    matrix. nornir implements `TestSink` over its Iceberg warehouse.
//! 5. **Discovery** ([`discover`]) — the autonom (AUT2) anti-drift core: pure
//!    enumerators that build the testable [`Surface`] from data (facett
//!    components, viz tabs × {thin,fat}, CLI subcommands, MCP tools, and the
//!    unreached-function set from `symbol_facts − test-reachable(call_edges)`),
//!    then [`compute_gap`] differences it against coverage so the gate can
//!    enforce `Gap == ∅`. No warehouse here — the caller feeds the rows.
//! 6. **Functional-status mode** ([`functional`]) — a component reports whether
//!    it *actually works* (`functional_status(component, check, ok, detail)`)
//!    from its own headless-render / self-test path. The
//!    [`Aspect::Functional`] runner drains those into rows so a broken render is
//!    a RED matrix row WITHOUT eyeballing a GUI. Gated behind the **`testmatrix`
//!    cargo feature**: release builds (feature off) strip the emit to a no-op.
//! 7b. **uiplane — UI-PLANE reachability (LAW 9)** ([`uiplane`]) — model a running
//!    app as **planes** ([`UiPlane`]) + a **navigation plan** ([`UiPlan`]: planes
//!    as nodes, transitions as edges), then [`RobotPlan::walk`] a [`PlaneDriver`]
//!    over it to REACH every plane and prove every declared surface is
//!    **present + RAN**. A surface that is unreachable (orphan plane / missing
//!    transition) or reachable-but-didn't-run is a **RED** row. Generic +
//!    UI-agnostic: a headless library has an empty plan (trivially green); the
//!    native robot-UI and the deployed-wasm headless-browser are two backends
//!    behind the same [`PlaneDriver`] seam.
//! 7c. **gatedtests — the silenced-test guard** ([`gatedtests`]) — a
//!    `tests/*.rs` carrying a crate-level `#![cfg(feature = "X")]` where `X` is
//!    not in that crate's `default` set compiles to an **empty test binary** and
//!    reports `0 tests ... ok`. [`audit_gated_tests`] walks every test target of
//!    every workspace member (`cargo metadata`), parses the leading `#![cfg]`
//!    (`all`/`any`/`not`, nested), resolves the crate's transitive `default`
//!    closure, and emits a RED [`TestResultRow`] on the `gated-tests` aspect for
//!    every file that neither compiles by default nor is re-invoked by a matrix
//!    arm the repo DECLARES in `.nornir/testmatrix-arms.json`. Silence is not
//!    success.
//! 8. **utfallsrum — outcome-space coverage** ([`utfallsrum`]) — declare a
//!    function's whole OUTCOME SPACE as equivalence partitions + boundary values
//!    ([`Outcome`]), record which classes a test exercised with the exact output,
//!    and score `utfallsrum_covered ∈ [0,1]` = exercised / declared. A single-value
//!    test scores low even when green; the gate requires ≥K classes swept before a
//!    surface counts as covered. Boundary-value + equivalence-partition analysis,
//!    made first-class and persistable next to the functional verdict.
//!
//! ## How a leaf repo uses it
//! ```no_run
//! use nornir_testmatrix::{run_full_matrix, Aspect, JsonFileSink, TestSink};
//! use std::path::Path;
//!
//! let aspects = [Aspect::Build, Aspect::Unit, Aspect::Doctest, Aspect::Clippy, Aspect::Fmt];
//! let rows = run_full_matrix(Path::new("."), &aspects);
//! let sink = JsonFileSink::new("target/nornir-testmatrix.json");
//! sink.append(&rows).unwrap();
//! ```

pub mod appliance;
pub mod aspect;
// The CHAIN MATRIX — the 7-stage road from a declared build thing to a server
// that answers, and the 4th verdict (`n/a`) the appliance rollup needed.
pub mod chain;
pub mod atom;
pub mod armcheck;
pub mod citations;
pub mod coverage;
pub mod discover;
pub mod functional;
pub mod gatedtests;
// The SHARED matrix-harness primitives (`run_cargo` + `stamp_row`) every repo's
// `*_matrix.rs` used to hand-roll byte-identically (holger, korp) — L5.
pub mod harness;
// **What does this constellation measure, and what does it claim?** — the
// discovery half of the two things that had no verb: every bench target
// (including the ones in detached manifests) and every declared matrix row
// against what actually emits it.
pub mod inventory;
pub mod model;
pub mod runner;
pub mod sink;
// **Does every declared test target COMPILE?** — the step before every other
// guard here: `cargo check` is not a proxy for `cargo test`, and a test target
// that does not compile is reported by nothing.
pub mod targetcheck;
// **Which features gate tests, and does anything declare a run of them?** — the
// question `gatedtests` cannot answer, because it walks test TARGETS and the
// ~850 measured dark tests live in the LIBRARY target behind a `#[cfg]` on a
// `mod`. Also the one place that resolves a feature turned on by a DEPENDENCY
// EDGE, the third source of "what is on" that makes a variants-only scan report
// a lit feature as dark.
pub mod testsurface;
pub mod uiplane;
pub mod utfallsrum;

// ─── flat re-exports (the crate's public façade) ───────────────────────────

pub use appliance::{
    appliance_boot_preset, appliance_product, ApplianceBootGrid, ApplianceRollup, BootPreset,
    BootReach, ProofVerdict, APPLIANCE_BOOT_COMPONENT, APPLIANCE_BOOT_PROOFS, APPLIANCE_PRODUCTS,
    APPLIANCE_PROOFS,
};
pub use aspect::{
    aspect_label, parse_aspect, parse_funnel_decompose, run_aspect, run_full_matrix, Aspect,
    AspectOutcome,
};
pub use atom::{
    atom_surface, verify_atoms, AtomFailReason, AtomFailure, AtomObservation, AtomSpec, AtomState,
    AtomVerdict,
};
pub use armcheck::{
    arm_args, arm_target_dir, count_listed_tests, test_artifacts, verify_arm, verify_arms,
    ArmCheck, ArmVerification,
};
pub use citations::{
    audit_citations, sibling_checkouts, CitationReport, PhantomCitation, ALLOW_FILE,
    PLACEHOLDER_STEMS,
};
pub use coverage::{
    covered_with_utfallsrum, rows_for, rows_for_with_utfallsrum, seed_allowlist,
    stale_allowlist_entries, AllowEntry, Allowlist, CoverageRow, CoverageSummary, GateReport,
    SurfaceUtfallsrum, Verdict, DEFAULT_UTFALLSRUM_THRESHOLD,
};
pub use discover::{
    cli_commands, compute_gap, facett_components, mcp_tools, test_reachable, unreached_functions,
    viz_tabs, workspace_keys, workspace_surface_key, CallEdge, FacetRow, Gap, Mode, Surface,
    SurfaceKind, SurfaceNode, SymbolRow, SERVED_WORKSPACES,
};
pub use functional::{
    functional_na, functional_na_row, NA_MARKER,
    drain_functional_file, drain_functional_rows, emit_rows, functional_row, functional_status,
    record_rows,
};
pub use harness::{now_micros, run_cargo, stamp_row};
pub use inventory::{
    declares_workspace, forbidden_vocabulary, manifest_roots, module_doc_first_line, parse_targets,
    mask_comments_and_strings, render as render_inventory, resolve_rows, scan_bench_arms,
    scan_emit_sites, scan_repo, ScannedEmit, ignore_requirement, EMIT_CALL_MAX_LINES,
    bare_literal, id_field, renderer_vocabulary, resolve_rows_with, scan_roots, scan_roots_with,
    to_json as inventory_to_json, top_level_args, unresolved_registrations,
    to_rows as inventory_to_rows, uses_criterion,
    workspace_targets, ArmDecl, BenchKind, BenchTarget, EmitSite, Inventory, MatrixRowDecl,
    MetaTarget, RepoInventory, State, ASPECT_INVENTORY, BENCH_EXAMPLE_LOCATIONS, EMIT_FNS, GATE_MARKER, NA_FN,
    FORBIDDEN_WORD,
};
pub use gatedtests::{
    assert_no_silenced_tests, audit_gated_tests, audit_repo, classify, count_test_fns,
    default_features, extract_crate_cfg,
    feature_closure, parse_cfg_expr, parse_metadata, workspace_crates, CfgExpr, CrateManifest,
    DepEdge, DepKind,
    GateVerdict, GatedTestFile, GatedTestReport, MatrixArm, MatrixArms, TestTarget, ARMS_FILE,
    ASPECT_GATED_TESTS,
};
pub use testsurface::{
    audit_test_surface, closure_split, config_for_arm, config_for_variant, default_config,
    dep_closure, depths_per_line, file_mod_decl, gated_surfaces, inline_mod_decl, module_file,
    outer_cfg_body, resolve, scan_unit_gates, surface_gaps, ConfigOrigin, GateSite, GatedSurface,
    Resolved, RunVerdict, SurfaceGap, SurfaceRow, TestConfig, TestSurfaceReport, UnitGate,
    ASPECT_TEST_SURFACE,
};
pub use model::{
    listed_rows, new_run_id, parse_cargo_test_list, parse_nextest_list, render_matrix,
    rows_to_json, short_run, status, summarize_runs, RunSummary, TestResultRow, TestSelector,
};
pub use runner::{
    detect_runner, heavy_enabled, list_tests, nextest_outcome_args, parse_output, run_arm, run_arms, run_matrix,
    stall_secs, suite_crate, ArmRun, MatrixRun, Runner, TestCase, DEFAULT_STALL_SECS,
    NEXTEST_LIBTEST_JSON_ARGS, NEXTEST_LIBTEST_JSON_ENV,
};
pub use functional::ASPECT_FUNCTIONAL;
pub use sink::{JsonFileSink, NullSink, TestSink};
pub use targetcheck::{
    assert_all_test_targets_compile, check_targets, compile_target_dir, configs_from_arms,
    configs_from_metadata, configs_from_variants, dedup_configs, outside_this_workspace,
    package_name_from_id,
    parse_build_stream, run_config, BuildOutcome, CompileConfig, CompileReport, ConfigOutcome,
    ConfigSource, Depth, TargetError, TargetState, TargetVerdict, VariantSpec,
    SILENTLY_FATAL_LINTS,
    ASPECT_TARGET_COMPILE,
};
pub use uiplane::{
    MockDriver, PlaneDriver, RobotPlan, RouteStep, SurfaceVerdict, Transition, UiPlan, UiPlane,
    UiSurface, WalkReport, WalkRow, UIPLANE_ASPECT,
};
pub use utfallsrum::{Outcome, OutcomeClass, UtfallsrumSummary, UTFALLSRUM_ASPECT};