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

nordisk/nornir

crates/nornir-introspect/src/selftest.rs

//! # Functional-status emit bridge — `nornir-introspect` → test matrix
//!
//! The single internal call site this crate uses to push a *functional* row
//! into the [`nornir_testmatrix`] matrix, so `nornir test --features testmatrix`
//! records whether `nornir-introspect`'s introspection surfaces (graph SVG/text
//! rendering, DWARF-symbol lookup, path-dep resolution) ACTUALLY work.
//!
//! ## Release strips everything
//! The `testmatrix` cargo feature gates the whole bridge: with it OFF (the
//! release default) [`emit`] is an `#[inline]` no-op and `nornir-testmatrix` is
//! not even linked. Lit ONLY under `cargo … --features testmatrix`.

/// The aspect tag every self-emitted row carries (matches `functional_row`).
pub const ASPECT_FUNCTIONAL: &str = "functional";

/// Push ONE functional-status row for a single real check (feature ON).
#[cfg(feature = "testmatrix")]
#[inline]
pub fn emit(component: &str, check: &str, ok: bool, detail: &str) {
    nornir_testmatrix::functional_status(component, check, ok, detail);
}

/// No-op stub when the `testmatrix` feature is OFF (release builds).
#[cfg(not(feature = "testmatrix"))]
#[inline]
pub fn emit(_component: &str, _check: &str, _ok: bool, _detail: &str) {}

/// `assert!`-with-emit: assert on the real return value AND record the verdict
/// as a matrix row.
#[macro_export]
macro_rules! assert_emit {
    ($component:expr, $check:expr, $ok:expr, $($detail:tt)+) => {{
        let __ok: bool = $ok;
        let __detail = ::std::format!($($detail)+);
        $crate::selftest::emit($component, $check, __ok, &__detail);
        ::std::assert!(__ok, "{}::{} — {}", $component, $check, __detail);
    }};
}

// ─── inject-and-assert wiring test (feature ON only) ─────────────────────────
#[cfg(all(test, feature = "testmatrix"))]
mod wiring {
    use crate::{artifact, pathdeps, Edge, EdgeKind, Graph};

    fn sym(name: &str, file: &str) -> artifact::Symbol {
        artifact::Symbol {
            name: name.to_string(),
            name_demangled: name.to_string(),
            name_mangled: format!("_ZN{name}"),
            file: file.to_string(),
            line: Some(1),
            size_bytes: Some(16),
            krate: "demo".to_string(),
        }
    }

    /// Exercise `nornir-introspect`'s real introspection surfaces, emit an honest
    /// row per surface (the scaffold AST call-graph is a deliberate RED), then
    /// drain the process-global functional buffer and assert the rows landed.
    #[test]
    fn emits_honest_rows_for_introspection_surfaces() {
        // Surface: graph → self-contained SVG.
        let g = Graph {
            nodes: vec!["a".into(), "b".into()],
            edges: vec![Edge {
                from: "a".into(),
                to: "b".into(),
                kind: EdgeKind::Calls,
            }],
        };
        let svg = g.to_svg();
        let svg_ok = svg.starts_with("<svg") && svg.contains("</svg>") && !svg.contains("mermaid");
        assert_emit!(
            "nornir-introspect",
            "graph_renders_self_contained_svg",
            svg_ok,
            "len={}",
            svg.len()
        );

        // Surface: graph → plain-text adjacency list.
        let text = g.to_text();
        let text_ok = text.contains("a → b (calls)");
        assert_emit!(
            "nornir-introspect",
            "graph_renders_text_adjacency",
            text_ok,
            "text_ok={text_ok}"
        );

        // Surface: DWARF-symbol lookup + defined_in over a synthetic symbol set.
        let syms = vec![
            sym("foo::bar", "crates/x/src/a.rs"),
            sym("foo::baz", "crates/x/src/b.rs"),
        ];
        let hits = artifact::lookup(&syms, "bar");
        let lookup_ok = hits.len() == 1 && hits[0].name == "foo::bar";
        assert_emit!(
            "nornir-introspect",
            "symbol_lookup_matches",
            lookup_ok,
            "hits={}",
            hits.len()
        );
        let in_a = artifact::defined_in(&syms, "a.rs");
        let defined_ok = in_a.len() == 1;
        assert_emit!(
            "nornir-introspect",
            "symbol_defined_in_filters_by_file",
            defined_ok,
            "in_a={}",
            in_a.len()
        );

        // Surface: path-dep resolution runs deterministically on a repo with none.
        let dir = tempfile::tempdir().unwrap();
        let unresolved = pathdeps::unresolved_path_dep_siblings(dir.path(), dir.path());
        assert_emit!(
            "nornir-introspect",
            "unresolved_path_deps_reports_none_for_bare_repo",
            unresolved.is_empty(),
            "unresolved={}",
            unresolved.len()
        );

        let rows = nornir_testmatrix::drain_functional_rows();
        for want in [
            "graph_renders_self_contained_svg",
            "graph_renders_text_adjacency",
            "symbol_lookup_matches",
            "symbol_defined_in_filters_by_file",
            "unresolved_path_deps_reports_none_for_bare_repo",
        ] {
            assert!(
                rows.iter().any(|r| r.suite == "nornir-introspect"
                    && r.test_name == want
                    && r.status == "pass"),
                "missing green row {want}: {rows:?}"
            );
        }
        assert!(
            rows.iter().all(|r| r.aspect == "functional"),
            "rows={rows:?}"
        );
    }
}