crates/knut-build-thing/tests/the_rows_are_the_matrix.rs
//! **The rows ARE the matrix** — knut's fourteen build points, asserted as a set and
//! not as a count.
//!
//! Every arm here is a property the hand-written file could not state: which rows
//! exist (exactly, in both directions), that each is tagged with a delivery, that
//! the repo names its base suite, that exactly one row per role is the normal
//! case, that the `required-features` trap is enforced rather than described, and
//! that the excluded wasm package is reachable at all.
use std::collections::BTreeSet;
use knut_build_thing::{KnutBuild, REQUIRED_FEATURES, SUITE};
use nornir_build_thing::plugin::{BuildRequest, BuildThing, Role};
use nornir_build_thing::variant::{ArtifactKind, ServiceShape};
/// **The fourteen atoms are exactly the fourteen** — both inclusions, so neither a new row
/// nobody mentioned nor a deleted row nobody missed can pass.
#[test]
fn the_fourteen_rows_are_exactly_these_fourteen() {
let declared: BTreeSet<String> = KnutBuild
.variants()
.variants
.iter()
.map(|v| v.name.clone())
.collect();
let expected: BTreeSet<String> = [
"bifrost",
"bifrost-doris",
"bifrost-falkordb",
"bifrost-falkordb-aistor",
"bifrost-falkordb-gravitino",
"bifrost-falkordb-grpc",
"bifrost-falkordb-polaris",
"bifrost-falkordb-unity",
"bifrost-full",
"graphar-flight",
"knut-bifrost-wasm-guest",
"knut-popviz",
"knut-spark-server",
"knutpipe",
]
.into_iter()
.map(str::to_string)
.collect();
assert_eq!(
declared, expected,
"the declared rows are not the fourteen knut ships"
);
}
/// **Every row carries a delivery tag, and the repo names its base suite.**
///
/// All six were UNTAGGED until 2026-09-20 — six of the 27 rows the 2026-09-17
/// census counted across the constellation. Untagged is not a third flavour; it
/// is a row `--suite ORIGINAL` cannot select, and a build verb that needs a
/// different flag per repo is not one verb.
#[test]
fn every_row_is_tagged_and_the_base_suite_is_declared() {
let set = KnutBuild.variants();
assert_eq!(
set.base_suite.as_deref(),
Some(SUITE),
"the repo must name the delivery `--suite ORIGINAL` resolves to"
);
for v in &set.variants {
assert_eq!(
v.suites,
vec![SUITE.to_string()],
"variant '{}' is not tagged {SUITE}",
v.name
);
}
assert!(set.declares_suites(), "the suite axis must be live");
assert_eq!(set.suites(), vec![SUITE]);
assert_eq!(
set.in_suite(SUITE).len(),
14,
"all fourteen rows must be selectable by delivery"
);
}
/// **Exactly one normal case per role.**
///
/// The hand-written file marked TWO tools default (`knutpipe` and `bifrost`) and
/// NO client at all, and nothing anywhere read the file closely enough to say so:
/// `validate_all` does not call `check_defaults`. `knutpipe` keeps the tool
/// default (it is the binary a plain `cargo build` produces) and `knut-popviz`
/// takes the client default as the only client row.
#[test]
fn each_role_names_exactly_one_normal_case() {
let set = KnutBuild.variants();
let problems = set.check_defaults();
assert!(
problems.is_empty(),
"the declaration cannot say which row is normal: {problems:#?}"
);
let menu = KnutBuild.menu();
assert_eq!(menu.default_for(Role::Tool), Some("knutpipe"));
assert_eq!(menu.default_for(Role::Server), Some("graphar-flight"));
assert_eq!(menu.default_for(Role::Client), Some("knut-popviz"));
}
/// The whole declaration passes the generic shape rules — kind × target × bin ×
/// linkage, the offers closure, the exclusive groups and the required-features
/// mirror.
#[test]
fn the_declaration_validates() {
KnutBuild.variants().validate_all().expect("shape-valid");
}
/// **The `--all-targets` trap, as data and as enforcement.**
///
/// Each entry of `REQUIRED_FEATURES` must have a row that builds its bin WITH the
/// feature — a hand-kept copy nothing compares is how a table drifts — and the
/// set's own `required` table must contain it, so the emitted file carries the
/// same trap the code enforces.
#[test]
fn required_table_matches_declaration() {
let set = KnutBuild.variants();
for (bin, need) in REQUIRED_FEATURES {
let v = set
.variants
.iter()
.find(|v| v.bin.as_deref() == Some(*bin))
.unwrap_or_else(|| panic!("no variant builds bin '{bin}'"));
assert!(
v.features.iter().any(|f| f == need),
"variant '{}' builds bin '{bin}' but does not enable its required feature \
'{need}' — the declaration would produce no binary",
v.name
);
assert_eq!(
set.required.get(*bin).map(Vec::as_slice),
Some(&[need.to_string()][..]),
"[build.required] and REQUIRED_FEATURES disagree about '{bin}'"
);
}
// The fifth required-features bin: declared, built by nothing, excused BY
// NAME. The hand-written file did not know it existed.
assert_eq!(
set.required.get("export-iceberg").map(Vec::as_slice),
Some(&["skade".to_string()][..])
);
assert!(
set.allow_unbuilt_bins
.get("export-iceberg")
.and_then(|e| e.reason())
.is_some_and(|r| !r.trim().is_empty()),
"an unbuilt bin with no written reason is a gap, not a decision"
);
}
/// The trap, as a test: asking for a `required-features` binary without its
/// feature must be REFUSED, not silently accepted. Without this rule cargo exits
/// 0 and emits nothing.
#[test]
fn refuses_a_required_features_bin_without_its_feature() {
let mut set = KnutBuild.variants();
let v = set
.variants
.iter_mut()
.find(|v| v.bin.as_deref() == Some("bifrost"))
.unwrap();
v.features.retain(|f| f != "cli");
let name = v.name.clone();
// The REAL rule, run against a deliberately-broken declaration — knut's own
// declaration is correct, so the failing case has to be constructed, and
// constructing it must not mean re-implementing the rule.
let verdict = knut_build_thing::validate_against(
&set,
&BuildRequest {
variant: Some(name),
..Default::default()
},
);
assert!(
!verdict.ok,
"a variant building `bifrost` without `cli` must be refused"
);
let why = verdict.reasons.join(" ");
assert!(
why.contains("cli") && why.contains("required-features"),
"the refusal must name the missing feature and why: {why}"
);
}
/// …and the same request WITH the feature must pass, or the rule is just a
/// blanket ban and the test above proves nothing.
#[test]
fn accepts_a_required_features_bin_with_its_feature() {
assert!(
KnutBuild
.validate(&BuildRequest {
variant: Some("bifrost".to_string()),
..Default::default()
})
.ok,
"`bifrost` as declared (with `cli`) must build"
);
}
/// An undeclared variant is refused by name, with the roster.
#[test]
fn an_undeclared_variant_is_refused_with_the_roster() {
let v = KnutBuild.validate(&BuildRequest {
variant: Some("knut-does-not-exist".to_string()),
..Default::default()
});
assert!(!v.ok);
let why = v.reasons.join(" ");
assert!(why.contains("knut-does-not-exist") && why.contains("knutpipe"), "{why}");
}
/// **The excluded wasm guest is reachable.**
///
/// It is `exclude`d from the root workspace on purpose, so `-p
/// knut-bifrost-wasm-guest` from the repo root reaches NOTHING. The row therefore
/// has to carry `manifest_dir`, which `cargo_args` renders as `--manifest-path`;
/// without it the row named a build cargo could not run, and that is how it stood
/// from 2026-07-23 until today.
#[test]
fn the_wasm_guest_row_names_the_manifest_that_can_build_it() {
let set = KnutBuild.variants();
let v = set.get("knut-bifrost-wasm-guest").expect("the guest row");
assert_eq!(v.kind, ArtifactKind::Wasm);
assert_eq!(v.target.as_deref(), Some("wasm32-unknown-unknown"));
assert_eq!(v.manifest_dir.as_deref(), Some("crates/knut-bifrost/wasm-guest"));
let argv = v.cargo_args();
assert!(
argv.iter().any(|a| a == "--manifest-path"),
"the guest's argv does not carry --manifest-path: {argv:?}"
);
assert!(
argv.iter()
.any(|a| a.ends_with("crates/knut-bifrost/wasm-guest/Cargo.toml")),
"{argv:?}"
);
// And the directory it names is really in this checkout.
assert!(knut_build_thing::emit::repo_root()
.join("crates/knut-bifrost/wasm-guest/Cargo.toml")
.is_file());
}
/// **Every row is a cargo row, and each says its linkage out loud.**
///
/// knut declares no `container`/`iso`/`installer` row, so `cargo xtask build`
/// would have nothing to refuse — the day one appears, `--list` must name the
/// door that builds it rather than skipping it. An omitted `linkage` reads as
/// `fat`, a positive claim of self-containment, so every row states it; and
/// `embeds`/`reaches` stay EMPTY because no symbol count was ever taken here.
#[test]
fn every_row_is_cargo_and_declares_its_linkage() {
for v in KnutBuild.variants().variants {
assert!(
v.kind.is_cargo(),
"variant '{}' is kind {} — a non-cargo row must be listed and refused by name \
with the door that builds it",
v.name,
v.kind.as_str()
);
assert_eq!(v.shape, ServiceShape::FatService, "variant '{}'", v.name);
assert!(
v.embeds.is_empty() && v.reaches.is_empty(),
"variant '{}' claims a composition nobody measured",
v.name
);
}
}
/// **The pinned environment.** `CargoToolchain::validate` refuses an empty
/// `image_sha256` BY NAME, and the wasm target the guest (and this recipe's own
/// plugin module) needs must be one the image carries.
#[test]
fn the_toolchain_is_pinned_by_digest_and_carries_every_declared_target() {
let set = KnutBuild.variants();
let tc = set.toolchain.as_ref().expect("knut pins its build image");
tc.validate().expect("the pin is well-formed");
assert_eq!(
tc.image_sha256,
"668468e775ad80f32d700cbc9709d41cac726f40d00649461a0932f30d1b2067"
);
assert!(tc.targets.iter().any(|t| t == "wasm32-unknown-unknown"));
for v in &set.variants {
if let Some(t) = v.target.as_deref() {
assert!(
tc.targets.iter().any(|x| x == t),
"variant '{}' targets '{t}', which the pinned image does not carry",
v.name
);
}
}
}
/// A GUI build is allowed, and must SAY that it starts a database — the
/// transitive `gui → autostart → graphar-falkordb/autostart` chain is the thing a
/// reader misses.
#[test]
fn gui_is_allowed_but_discloses_the_autostart() {
let v = KnutBuild.validate(&BuildRequest {
variant: Some("knut-popviz".to_string()),
..Default::default()
});
assert!(v.ok, "the popviz GUI is a legitimate build");
assert!(
v.reasons.join(" ").to_lowercase().contains("falkordb"),
"a build that starts a database must say so: {:?}",
v.reasons
);
}
#[test]
fn wasm_guest_may_not_link_a_native_graph_client() {
use nornir_build_thing::plugin::ArtifactFacts;
let facts = ArtifactFacts {
file_name: "knut_bifrost_wasm_guest.wasm".to_string(),
linked_crates: vec!["arrow-ipc".to_string(), "redis".to_string()],
..Default::default()
};
assert!(!KnutBuild.judge_artifact(&facts).ok);
let clean = ArtifactFacts {
file_name: "knut_bifrost_wasm_guest.wasm".to_string(),
linked_crates: vec!["arrow-ipc".to_string()],
..Default::default()
};
assert!(KnutBuild.judge_artifact(&clean).ok);
}