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

nordisk/facett

facett-build-thing/tests/build_gate.rs

//! **⚒ Build Thing's BUILD GATE, asserted where a test run sees it.**
//!
//! The forge's door (`dwarves buildthing` / ⚒ Build) ends every delivery with
//! `nornir_build_thing::buildgate::tally_bins`: every `[[bin]]` cargo can see in this
//! tree must come out of a declared row, or be named in `[build.allow_unbuilt_bins]`
//! with the reason it has no row — and no excuse may name a bin a row builds.
//! MEASURED 2026-10-16 (the build-thing sweep on loki): this repo's declaration was
//! RED on that gate and no test here asked the question, so the first place it
//! showed was the forge, after a whole build. This is the same function over the
//! same declaration, with the bins the declared cargo rows name.
//!
//! A new `[[bin]]` lands RED here until it gets a row or a written reason.

use std::collections::BTreeSet;
use std::path::PathBuf;

use nornir_build_thing::buildgate::tally_bins;
use nornir_build_thing::variant::{ArtifactKind, BuildVariantSet};

/// The checkout this crate lives in: the nearest ancestor that declares a build space.
fn repo_root() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .ancestors()
        .find(|d| BuildVariantSet::conventional_path(d).is_file())
        .expect("an ancestor declares .nornir/build-variants.toml")
        .to_path_buf()
}

/// What `cargo build -p <package>` (no `--bin`) emits: every bin of the package
/// whose `required-features` the row turns on. facett's native `facett-demo` row is
/// such a row — it builds the six demo bins, never `facett_robot` (`robotui`).
fn package_bins(root: &std::path::Path, package: Option<&str>, features: &[String]) -> Vec<String> {
    let Some(package) = package else { return Vec::new() };
    let dir = root.join(package);
    let all = BuildVariantSet::cargo_bin_targets(&dir).expect("walk the package's bins");
    let manifest: toml::Table = std::fs::read_to_string(dir.join("Cargo.toml"))
        .expect("the package manifest")
        .parse()
        .expect("it parses");
    let gated: Vec<String> = manifest
        .get("bin")
        .and_then(toml::Value::as_array)
        .into_iter()
        .flatten()
        .filter(|b| {
            b.get("required-features")
                .and_then(toml::Value::as_array)
                .is_some_and(|rf| rf.iter().filter_map(toml::Value::as_str).any(|f| !features.iter().any(|x| x == f)))
        })
        .filter_map(|b| b.get("name").and_then(toml::Value::as_str).map(str::to_string))
        .collect();
    all.into_iter().filter(|b| !gated.contains(b)).collect()
}

#[test]
fn every_bin_is_built_by_a_row_or_excused_with_a_reason() {
    let root = repo_root();
    let set = BuildVariantSet::discover(&root)
        .expect("the declaration loads")
        .expect("this repo declares a build space");
    let produced: BTreeSet<String> = set
        .variants
        .iter()
        .filter(|v| matches!(v.kind, ArtifactKind::Exe | ArtifactKind::Service))
        .flat_map(|v| match &v.bin {
            Some(b) => vec![b.clone()],
            None => package_bins(&root, v.package.as_deref(), &v.features),
        })
        .collect();
    let (tally, problems) = tally_bins(&root, produced, false).expect("the gate runs");
    // NON-VACUOUS: a walker that found no bins would pass any declaration.
    assert!(!tally.declared.is_empty(), "the gate saw no [[bin]] at all under {}", root.display());
    assert!(problems.is_empty(), "[build.allow_unbuilt_bins] problems: {problems:#?}");
    tally.verdict().unwrap_or_else(|e| panic!("{e}\n{}", tally.headline()));
}