facett-build-thing/tests/thin_door.rs
//! **What the thin door (facett's `cargo xtask build`) asks of this declaration.**
//!
//! Two LAW items, held from the CODE side (the xtask side is
//! `xtask/tests/build_is_a_thin_door.rs`):
//!
//! * every `[[build.variant]]` row carries a suite tag — untagged is not a third
//! flavour, it is a row `--suite ORIGINAL` cannot select — and the EMITTED toml
//! says so for every row, not just the declaration;
//! * every row cargo cannot build names the door that does, so the build verb can
//! refuse it BY NAME instead of skipping it.
use facett_build_thing::nornir_build_thing::variant::ArtifactKind;
use facett_build_thing::{declared, door_for, emitted_toml, SUITE};
#[test]
fn every_row_is_tagged_original_in_the_code() {
let set = declared();
// Twelve release rows (4 bundle groups + 2 wheels + 2 demo + panel fixture + 3 images)
// plus facett-flow's feature-verification rows (PR #3): plain, wgpu, every flow
// feature alone and with wgpu, all features, all features on wasm32. Held as a
// number, so a new row is a decision here as well as in the declaration.
let flow_rows = 2 + 2 * facett_build_thing::FLOW_FEATURES.len() + 2;
assert_eq!(facett_build_thing::FLOW_FEATURES.len(), 10, "facett-flow declares ten features");
assert_eq!(
set.variants.len(),
12 + flow_rows,
"facett declares twelve release rows + {flow_rows} facett-flow feature rows"
);
assert_eq!(set.variants.len(), 36);
for v in &set.variants {
assert_eq!(v.suites, vec![SUITE.to_string()], "row '{}' is not tagged {SUITE}", v.name);
}
assert_eq!(set.base_suite.as_deref(), Some(SUITE));
}
/// The emission, read as text: each `[[build.variant]]` block carries the tag.
/// Counting blocks against tags (rather than grepping for one tag) is what goes
/// red when ONE row loses it.
#[test]
fn every_row_is_tagged_original_in_the_emitted_toml() {
let toml = emitted_toml().expect("emits");
let blocks: Vec<&str> = toml.split("[[build.variant]]").skip(1).collect();
assert_eq!(blocks.len(), declared().variants.len(), "emission lost or grew a row");
let tag = format!("suites = [\"{SUITE}\"]");
for b in &blocks {
// A block ends where the next table starts.
let body = b.split("\n[").next().unwrap_or(b);
let name = body.lines().find(|l| l.starts_with("name = ")).unwrap_or("?");
assert!(body.contains(&tag), "emitted row {name} carries no `{tag}`:\n{body}");
}
}
#[test]
fn every_row_cargo_cannot_build_names_its_door() {
let set = declared();
let mut refused = 0;
for v in &set.variants {
match door_for(v) {
None => assert!(v.kind.is_cargo(), "non-cargo row '{}' has no door", v.name),
Some(door) => {
assert!(!v.kind.is_cargo(), "cargo row '{}' was given a door", v.name);
assert!(door.contains(&v.name), "door for '{}' does not name it: {door}", v.name);
refused += 1;
}
}
}
// 3 images + the two wheels. Held as a number so a new non-cargo row is a decision.
assert_eq!(refused, 5);
for name in [facett_build_thing::VARIANT, facett_build_thing::DEMO_PIP_VARIANT] {
let pkg = set.get(name).unwrap();
assert_eq!(pkg.kind, ArtifactKind::Package);
assert!(door_for(pkg).unwrap().contains("cargo ops publish-pip"));
}
}
/// **Every bundle group is a row, a cell and a routing line — from one list.**
/// Core is today's bundle unchanged: same row name, same package, no features,
/// defaults on, same dist dir, the wheel's `assets/` root. Every other group is
/// `facet-wrapped-group` with exactly one group feature (lane A's package: the
/// core package can carry no `[features]` table without its wasm moving).
#[test]
fn every_bundle_group_is_a_tagged_wasm_row_with_its_own_cell_and_dist() {
use facett_build_thing::{
bundle_group, BUNDLE_GROUPS, CORE_GROUP, GROUP_PACKAGE, WASM_DIST, WASM_OUTPUTS, WASM_PACKAGE, WASM_VARIANT,
};
let set = declared();
let core = bundle_group(CORE_GROUP).expect("core group");
assert_eq!(
(core.variant, core.package, core.dist_dir, core.wheel_dir),
(WASM_VARIANT, WASM_PACKAGE, WASM_DIST, "")
);
assert!(core.features.is_empty() && !core.no_default_features, "core must stay byte-identical");
assert!(core.entries.is_empty(), "core holds every entry no other group names");
assert_eq!(core.outputs(), WASM_OUTPUTS.map(str::to_string), "core's files keep their names");
assert_eq!(BUNDLE_GROUPS[0].name, CORE_GROUP, "core loads first");
let mut dists = std::collections::BTreeSet::new();
let mut entries = std::collections::BTreeSet::new();
for g in BUNDLE_GROUPS {
let v = set.get(g.variant).unwrap_or_else(|| panic!("group '{}' has no row", g.name));
assert_eq!(v.kind, ArtifactKind::Wasm);
assert_eq!(v.suites, vec![SUITE.to_string()]);
assert_eq!(v.package.as_deref(), Some(g.package));
assert_eq!(v.features, g.features.iter().map(|f| f.to_string()).collect::<Vec<_>>());
assert_eq!(v.no_default_features, g.no_default_features);
let cell = set.wasm(g.variant).expect("cell");
assert_eq!(cell.out_dir, g.dist_dir);
assert!(cell.manifest.is_some(), "group '{}' captures no manifest — the loader could not route to it", g.name);
// The files the routing table and the wheel name are the files edda's
// stages write — one derivation, checked against the other.
let written: Vec<String> = cell
.outputs(v)
.iter()
.map(|p| p.rsplit('/').next().unwrap().to_string())
.collect();
assert_eq!(written, g.outputs().to_vec(), "group '{}': edda writes {written:?}", g.name);
assert!(dists.insert(g.dist_dir), "two groups write {}", g.dist_dir);
for e in g.entries {
assert!(entries.insert(*e), "entry `{e}` is in two groups");
}
if g.name != CORE_GROUP {
assert_eq!(g.package, GROUP_PACKAGE, "group '{}' would rebuild the core package", g.name);
assert_eq!(g.features.len(), 1, "group '{}': exactly ONE group feature", g.name);
assert!(!g.entries.is_empty(), "group '{}' routes no entry", g.name);
assert!(!g.wheel_dir.is_empty(), "group '{}' would overwrite core in the wheel", g.name);
assert!(g.dist_dir.starts_with(&format!("{GROUP_PACKAGE}/dist-")), "{}", g.dist_dir);
}
}
}
/// Entry → group is the recipe's; the loader's routing names every grouped entry
/// once and sends the rest to the default group.
#[test]
fn every_entry_routes_to_exactly_one_group() {
use facett_build_thing::{group_of_entry, routing_json, BUNDLE_GROUPS, CORE_GROUP};
assert_eq!(group_of_entry("table").name, CORE_GROUP);
assert_eq!(group_of_entry("docview").name, "docs");
assert_eq!(group_of_entry("manual").name, "docs");
assert_eq!(group_of_entry("model3d").name, "model3d");
let json = routing_json();
assert!(json.contains("\"default\": \"core\""), "{json}");
// Only the `entries` lists route; every grouped entry appears in exactly one.
let routed: String = json
.split("\"entries\": [")
.skip(1)
.map(|s| s.split(']').next().unwrap_or(""))
.collect::<Vec<_>>()
.join(",");
for g in BUNDLE_GROUPS {
for e in g.entries {
assert_eq!(routed.matches(&format!("\"{e}\"")).count(), 1, "`{e}` routed more than once: {json}");
}
}
}
/// The routing table the loader reads is the EMISSION of `BUNDLE_GROUPS`, and the
/// committed copy is that emission byte for byte (re-run `-- emit` after editing).
#[test]
fn the_committed_routing_table_is_the_emission() {
use facett_build_thing::{repo_root, routing_json, BUNDLE_GROUPS, ROUTING_PATH};
let committed = std::fs::read_to_string(repo_root().join(ROUTING_PATH)).expect("routing table committed");
assert_eq!(committed, routing_json(), "{ROUTING_PATH} is not the emission — run `cargo run -p facett-build-thing -- emit`");
for g in BUNDLE_GROUPS {
assert!(committed.contains(&format!("\"name\": \"{}\"", g.name)), "routing lost group {}", g.name);
}
}