crates/gunnar-recipe/tests/rows_equal_cargo_install.rs
//! **Every cargo row of the Build Thing builds what its `cargo install` line builds**
//! (owner order 2026-10-26, G-BOTH-2; Holger's H5 is the model).
//!
//! Each row that compiles a binary has exactly one line in [`gunnar_recipe::twins::TWINS`];
//! the line is a local `--locked` install of the row's package with the same effective
//! features, profile and target, and it leaves exactly the row's binary behind. The
//! README shows every line. The measured half (both resolutions through `cargo tree`,
//! the same crates, the binary per row) is `cargo xtask twins`, a step of `cargo xtask ci`.
use std::path::{Path, PathBuf};
use gunnar_recipe::twins::{
cargo_rows, point_of_install, point_of_row, twin_differences, twin_of, Manifest, TWINS,
};
use gunnar_recipe::variants::by_name;
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(2)
.expect("crates/gunnar-recipe has a repository root")
.to_path_buf()
}
/// The bin and feature facts of a package's own manifest.
fn manifest(dir: &str) -> Manifest {
let path = repo_root().join(dir).join("Cargo.toml");
let m: toml::Table = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("{}: {e}", path.display()))
.parse()
.unwrap_or_else(|e| panic!("{}: {e}", path.display()));
let strings = |v: &toml::Value| -> Vec<String> {
v.as_array()
.map(|a| {
a.iter()
.filter_map(|x| x.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
};
let features = m
.get("features")
.and_then(|f| f.as_table())
.cloned()
.unwrap_or_default();
let default_features = features
.get("default")
.map(strings)
.unwrap_or_default()
.into_iter()
.collect();
let local: Vec<(String, Vec<String>)> = features
.iter()
.filter(|(k, _)| k.as_str() != "default")
.map(|(k, v)| {
(
k.clone(),
strings(v)
.into_iter()
.filter(|f| !f.contains(':') && !f.contains('/'))
.collect(),
)
})
.collect();
let bins = m
.get("bin")
.and_then(|b| b.as_array())
.map(|a| {
a.iter()
.map(|b| {
(
b["name"].as_str().unwrap_or_default().to_string(),
b.get("required-features").map(strings).unwrap_or_default(),
)
})
.collect()
})
.unwrap_or_default();
Manifest {
default_features,
features: local,
bins,
}
}
#[test]
fn every_cargo_row_has_exactly_one_cargo_install_line() {
let rows: Vec<&str> = cargo_rows().iter().map(|v| v.name).collect();
assert!(rows.len() >= 15, "the cargo rows: {rows:?}");
let missing: Vec<&str> = rows
.iter()
.copied()
.filter(|r| twin_of(r).is_none())
.collect();
assert!(
missing.is_empty(),
"no `cargo install` line for the rows {missing:?}"
);
let stray: Vec<&str> = TWINS
.iter()
.map(|t| t.row)
.filter(|r| !rows.contains(r))
.collect();
assert!(
stray.is_empty(),
"lines for rows that are not cargo rows: {stray:?}"
);
let mut seen = std::collections::BTreeSet::new();
for t in TWINS {
assert!(seen.insert(t.row), "row {} has two lines", t.row);
}
}
#[test]
fn every_row_builds_what_its_cargo_install_line_builds() {
let mut bad = Vec::new();
for t in TWINS {
let Some(v) = by_name(t.row) else {
bad.push(format!("{}: no such row", t.row));
continue;
};
let row = point_of_row(v).unwrap_or_else(|e| panic!("{e}"));
let line = match point_of_install(t.install) {
Ok(p) => p,
Err(e) => {
bad.push(format!("{}: {e}", t.row));
continue;
}
};
// The console's crate is a sibling checkout's (`../gunnar-ui`); a lone clone has
// none, and the gunnar-ui repository holds that row to its line itself
// (gunnar-ui-recipe `tests/the_console_product.rs`).
if row.path.starts_with("../") && !repo_root().join(&row.path).join("Cargo.toml").is_file()
{
eprintln!(
"NOT RUN for {}: no {} checkout beside this one",
t.row, row.path
);
continue;
}
for d in twin_differences(&row, &line, &manifest(&row.path)) {
bad.push(format!("{} (`{}`): {d}", t.row, t.install));
}
}
assert!(
bad.is_empty(),
"a row is not its `cargo install` line:\n {}",
bad.join("\n ")
);
}
/// **The three products are rows, each its `cargo install` line** (GUN-PRODUCTS, owner
/// 2026-10-30): `cargo install gunnar` (the server), `cargo install gunnar-ui` (the console,
/// the gunnar-ui checkout's crate) and `cargo install gunnar-cli` (the command-line tool),
/// each with its crate's defaults and leaving the crate's one program.
#[test]
fn the_three_products_are_rows_and_their_lines() {
for (row, line) in [
("gunnar", "cargo install --locked --path crates/gunnar"),
(
"gunnar-ui",
"cargo install --locked --path ../gunnar-ui/crates/gunnar-ui",
),
(
"gunnar-cli",
"cargo install --locked --path crates/gunnar-cli",
),
] {
let v = by_name(row).unwrap_or_else(|| panic!("no Build Thing row `{row}`"));
assert_eq!(
(v.package, v.bin),
(Some(row), Some(row)),
"{row} builds the crate of its name and leaves its program"
);
assert!(
!v.features.contains(&"metered"),
"{row}: a product carries no money"
);
assert_eq!(v.target, None, "{row}: `cargo install` builds for the host");
let t = twin_of(row).unwrap_or_else(|| panic!("{row} has no `cargo install` line"));
assert_eq!(t.install, line, "{row}");
}
}
#[test]
fn the_readme_shows_every_line() {
let readme = std::fs::read_to_string(repo_root().join("crates/gunnar-recipe/README.md"))
.expect("crates/gunnar-recipe/README.md");
let missing: Vec<&str> = TWINS
.iter()
.filter(|t| !readme.contains(&format!("| `{}` | `{}` |", t.row, t.install)))
.map(|t| t.row)
.collect();
assert!(
missing.is_empty() && !TWINS.is_empty(),
"crates/gunnar-recipe/README.md does not show the rows {missing:?} as `| `row` | `line` |`"
);
}
/// **The crates.io server is the row `gunnar`** (OX-VARIANTS 2026-10-28, GUN-PRODUCTS
/// 2026-10-30): the README and `crates/gunnar/README.md` give `cargo install gunnar`.
#[test]
fn the_crates_io_install_is_a_row() {
let v = by_name("gunnar").expect("the row `gunnar`");
assert_eq!(v.package, Some("gunnar"));
assert_eq!(
twin_of("gunnar").map(|t| t.install),
Some("cargo install --locked --path crates/gunnar")
);
for doc in ["README.md", "crates/gunnar/README.md"] {
let text = std::fs::read_to_string(repo_root().join(doc)).unwrap();
assert!(
text.contains("cargo install gunnar\n"),
"{doc} names `cargo install gunnar`"
);
}
}
/// **`crates/gunnar/README.md`'s feature table is the manifest's** (OX-VARIANTS 2026-10-28):
/// it is the page crates.io shows for `cargo install gunnar`, so every feature of
/// `crates/gunnar/Cargo.toml` is a row, and `(default)` stands on exactly the manifest's
/// `default` (mimalloc and SSO left the default on 2026-10-22).
#[test]
fn the_gunnar_readme_feature_table_is_the_manifest() {
let m = manifest("crates/gunnar");
let readme = std::fs::read_to_string(repo_root().join("crates/gunnar/README.md")).unwrap();
let mut rows = std::collections::BTreeMap::new();
let table = readme
.split_once("| feature | what it adds |")
.expect("crates/gunnar/README.md has the feature table")
.1;
for line in table.lines().skip(2).take_while(|l| l.starts_with('|')) {
let Some(rest) = line.strip_prefix("| `") else {
continue;
};
let Some((name, what)) = rest.split_once("` |") else {
continue;
};
rows.insert(name.to_string(), what.contains("(default)"));
}
let mut bad = Vec::new();
for (f, _) in &m.features {
match rows.get(f) {
None => bad.push(format!("`{f}` has no row")),
Some(&d) if d != m.default_features.contains(f) => bad.push(format!(
"`{f}`: the README says default = {d}, the manifest {}",
m.default_features.contains(f)
)),
_ => {}
}
}
for name in rows.keys() {
if !m.features.iter().any(|(f, _)| f == name) {
bad.push(format!("`{name}` is no feature of crates/gunnar"));
}
}
assert!(
bad.is_empty(),
"crates/gunnar/README.md:\n {}",
bad.join("\n ")
);
}