crates/nornir-hash/src/selftest.rs
//! # Functional-status emit bridge — `nornir-hash` → 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-hash`'s real surfaces (the known SHA-256 vectors, the
//! hex round-trip, streaming-vs-oneshot agreement) ACTUALLY behave — without
//! eyeballing anything.
//!
//! ## 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).
///
/// * `component` — the unit under test (becomes the row's `suite`).
/// * `check` — the specific assertion's name (becomes the row's `test_name`).
/// * `ok` — the **real** verdict.
/// * `detail` — the **measured** value.
#[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). Inlined and
/// empty so the call — and, with the wrap-the-call-site pattern, the detail
/// string-building — is stripped entirely.
#[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. The `assert!` is the test's actual gate; the emit is the matrix
/// observation.
#[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::{hex_decode, hex_encode, sha256_hex, Sha256Hasher};
const EMPTY: &str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
const ABC: &str = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
/// Exercise `nornir-hash`'s real surfaces, emit an honest row per surface,
/// then drain the process-global functional buffer and assert the rows
/// landed — proving the emit bridge is wired end to end.
#[test]
fn emits_honest_rows_for_hash_surfaces() {
let empty = sha256_hex(b"");
assert_emit!(
"nornir-hash",
"empty_vector",
empty == EMPTY,
"sha256(\"\")={empty}"
);
let abc = sha256_hex(b"abc");
assert_emit!("nornir-hash", "abc_vector", abc == ABC, "sha256(abc)={abc}");
let mut h = Sha256Hasher::new();
h.update(b"a");
h.update(b"bc");
let streamed = h.finalize_hex();
assert_emit!(
"nornir-hash",
"streaming_matches_oneshot",
streamed == abc,
"streamed={streamed}"
);
let round = hex_decode(&hex_encode(&[0xde, 0xad, 0xbe, 0xef])).unwrap();
assert_emit!(
"nornir-hash",
"hex_round_trip",
round == vec![0xde, 0xad, 0xbe, 0xef],
"round={round:?}"
);
// RED surface: a corrupted digit must NOT match the true vector.
let mut wrong = EMPTY.to_string();
wrong.replace_range(0..1, "f");
crate::selftest::emit(
"nornir-hash",
"corrupted_digest_is_rejected",
wrong != empty,
&format!("wrong={wrong}"),
);
let rows = nornir_testmatrix::drain_functional_rows();
let has = |t: &str, pass: bool| {
rows.iter().any(|r| {
r.suite == "nornir-hash" && r.test_name == t && (r.status == "pass") == pass
})
};
assert!(has("empty_vector", true), "rows={rows:?}");
assert!(has("abc_vector", true), "rows={rows:?}");
assert!(has("streaming_matches_oneshot", true), "rows={rows:?}");
assert!(has("hex_round_trip", true), "rows={rows:?}");
assert!(has("corrupted_digest_is_rejected", true), "rows={rows:?}");
assert!(rows.iter().all(|r| r.aspect == "functional"), "rows={rows:?}");
}
}