crates/gunnar-ui-recipe/tests/toml_parity.rs
//! **`.nornir/build-variants.toml` IS the code's emission — and this fails for
//! any reason it is not.**
//!
//! 1. the committed bytes are `emit`'s bytes (a row added to the code and not
//! re-emitted, a hand edit, a comment typed into the output: all red);
//! 2. the emission reads back, through the ONE loader, to the declaration;
//! 3. the file is inert — an edit is visible to a reader and invisible to the code;
//! 4. the comparison can go red at all (a set differing by one field is unequal).
use gunnar_ui_recipe::{declared, emitted_toml, repo_root, GunnarUiBuildThing};
use nornir_build_thing::emit::first_difference;
use nornir_build_thing::plugin::{BuildThing, Role};
use nornir_build_thing::variant::{ArtifactKind, BuildVariantSet, Profile, ServiceShape};
fn committed() -> String {
let path = BuildVariantSet::conventional_path(&repo_root());
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()))
}
#[test]
fn the_committed_toml_is_the_codes_emission_byte_for_byte() {
let emitted = emitted_toml().expect("the declaration emits");
if let Some(diff) = first_difference(&committed(), &emitted) {
panic!(
".nornir/build-variants.toml is not the code's emission — the code is the source. \
Run `cargo run -p gunnar-ui-build-thing -- emit` and commit the result; never edit \
the toml by hand. {diff}"
);
}
let back = BuildVariantSet::from_toml_str(&emitted).expect("the emission parses back");
assert_eq!(back, declared());
back.validate_all().expect("and every variant validates");
gunnar_ui_recipe::require_committed_is_emitted(&repo_root())
.expect("the door's own check agrees");
}
#[test]
fn an_edited_toml_has_zero_effect_on_what_the_code_declares() {
let before = declared();
let edited = emitted_toml().unwrap().replace(
"name = \"gunnar-ui-web\"",
"name = \"gunnar-ui-web-edited\"",
);
let read = BuildVariantSet::from_toml_str(&edited).expect("still parses");
assert_ne!(
read, before,
"the edit must be visible to a reader, else this proves nothing"
);
assert_eq!(
GunnarUiBuildThing.variants(),
before,
"the code read the file — it must not"
);
}
#[test]
fn the_comparison_reports_red_on_a_set_that_differs_by_one_field() {
let set =
BuildVariantSet::load_file(&BuildVariantSet::conventional_path(&repo_root())).unwrap();
assert_eq!(set.variants.len(), 5, "5 [[build.variant]] rows (the product gunnar-ui first)");
let mut p = set.clone();
p.variants[2].features.clear();
assert_ne!(p, set, "a variant losing its features must compare unequal");
let mut p = set.clone();
p.variants[1].target = None;
assert_ne!(p, set, "a variant losing its target must compare unequal");
}
/// **Every row is a build this repository already performs**, held to the
/// values the doors that perform it use.
#[test]
fn the_rows_describe_the_builds_that_already_happen() {
let set = declared();
// The BFF: static musl, release, a skidbladnir service under `gunnar-ui`.
// `deploy/deploy.sh`'s GUNNAR_UI_TRIPLE default and its ONE `cargo build`.
for name in ["gunnar-ui-server", "gunnar-ui-server-metered"] {
let v = set
.get(name)
.unwrap_or_else(|| panic!("{name} is declared"));
assert_eq!(v.package.as_deref(), Some("gunnar-ui-server"));
assert_eq!(v.bin.as_deref(), Some("gunnar-ui-server"));
assert_eq!(v.target.as_deref(), Some("x86_64-unknown-linux-musl"));
assert_eq!(v.profile, Profile::Release);
assert_eq!(v.kind, ArtifactKind::Service);
assert_eq!(v.member.as_deref(), Some("gunnar-ui"));
assert_eq!(v.role, Some(Role::Server));
assert_eq!(v.shape, ServiceShape::ThinStandalone);
assert!(v.embeds.is_empty(), "nothing here compiles a sibling in");
assert!(
v.reaches.contains("gunnar"),
"the BFF is useless without one"
);
}
// The console: a wasm32 bundle, release, driven against the BFF.
for name in ["gunnar-ui-web", "gunnar-ui-web-metered"] {
let v = set
.get(name)
.unwrap_or_else(|| panic!("{name} is declared"));
assert_eq!(v.package.as_deref(), Some("gunnar-ui-web"));
assert_eq!(v.target.as_deref(), Some("wasm32-unknown-unknown"));
assert_eq!(v.kind, ArtifactKind::Wasm);
assert_eq!(
v.role,
Some(Role::Client),
"a UI is a client, not a new role"
);
assert!(v.member.is_none(), "a browser bundle is no system service");
assert!(
v.reaches.contains("gunnar-ui"),
"it reaches the BFF that serves it"
);
}
// The metered/community split is the WHOLE feature universe, and it is
// gunnar's word rather than one invented here.
assert_eq!(
set.offers.iter().map(String::as_str).collect::<Vec<_>>(),
["metered"]
);
assert!(set.get("gunnar-ui-server").unwrap().features.is_empty());
assert_eq!(
set.get("gunnar-ui-server-metered").unwrap().features,
["metered"]
);
assert!(set.get("gunnar-ui-web").unwrap().features.is_empty());
assert_eq!(
set.get("gunnar-ui-web-metered").unwrap().features,
["metered"]
);
// Exactly one normal case per role group, and no suite axis to confuse it.
assert!(
set.check_defaults().is_empty(),
"{:?}",
set.check_defaults()
);
assert!(
set.get("gunnar-ui-server-metered").unwrap().is_default,
"the deploy's default"
);
assert!(
set.get("gunnar-ui-web").unwrap().is_default,
"what bare `trunk build --release` makes"
);
}
/// **NO `[[build.wasm]]` cell, and the absence is the declaration.**
///
/// The console's bundle is built by trunk, which runs the wasm row's cargo
/// build and then wasm-bindgen at the version `Trunk.toml` pins, `wasm-opt -Oz`
/// and the `index.html` asset pipeline — writing CONTENT-HASHED names
/// (`gunnar-ui-web-<hash>_bg.wasm`). `BindgenStage` DERIVES its outputs from the
/// package name, so a cell here would name `gunnar_ui_web_bg.wasm` and
/// `gunnar_ui_web.js`, two files trunk never writes, and anything chaining the
/// cell would be checked against a claim that is false.
///
/// This test exists so that adding a cell is a deliberate act that has to come
/// with the vocabulary to describe trunk, rather than a copy of facett's row.
#[test]
fn the_console_declares_no_wasm_cell_because_trunk_is_not_wasm_bindgen() {
let set = declared();
assert!(
set.wasms.is_empty(),
"a [[build.wasm]] cell would have to describe trunk, and BindgenStage cannot: \
trunk's outputs are content-hashed and it also runs wasm-opt and the index.html \
pipeline. See this test's doc comment."
);
let bundle = repo_root().join("crates/gunnar-ui-web/Trunk.toml");
assert!(
bundle.is_file(),
"the bundler this repository actually uses: {}",
bundle.display()
);
}