xtask/tests/fmt.rs
//! The `cargo fmt --all` landmine, and the two things that keep it defused.
//!
//! The damage was real and recent: on 2026-08-04 the writing form of
//! `cargo fmt --all`, run from this repository, rewrote 680 files in facett, 76
//! in znippy and 167 in znippy-zoomies. Everything below exists so nobody loses
//! that afternoon again, and so the pieces cannot be removed quietly.
//!
//! Two claims are asserted here, and both were seen red before being believed:
//!
//! 1. **The interception is installed.** `.cargo/config.toml` aliases `fmt` to
//! `xtask fmt`, so `cargo fmt` inside this tree cannot reach the landmine.
//! 2. **Discovery is a filesystem walk, not the `members` list.** The list
//! misses four package trees, and this test names all four, so a future
//! "simplification" back to `members` goes red instead of silently dropping
//! 608 diffs' worth of files out of the format again.
//!
//! What is deliberately NOT here: an assertion that the whole tree is currently
//! formatted. That is `cargo xtask fmt` (and step one of `cargo xtask ci`), it
//! costs 21 `cargo-fmt` invocations, and putting it in the unit suite would make
//! every `cargo test --workspace` pay for it.
use std::path::{Path, PathBuf};
use xtask::fmt::{cargo_fmt_binary, package_manifests, Mode};
/// The repository root, from this test binary's own manifest.
fn root() -> PathBuf {
// CARGO_MANIFEST_DIR is `<root>/xtask`.
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("xtask has a parent")
.to_path_buf()
}
fn rel(root: &Path, p: &Path) -> String {
p.strip_prefix(root)
.unwrap_or(p)
.to_string_lossy()
.replace('\\', "/")
}
/// The `fmt` alias is the whole interception. Without it, `cargo fmt --all`
/// from this directory rewrites five other repositories.
#[test]
fn cargo_fmt_is_intercepted_by_the_alias() {
let cfg = root().join(".cargo").join("config.toml");
let text =
std::fs::read_to_string(&cfg).unwrap_or_else(|e| panic!("read {}: {e}", cfg.display()));
let alias = text
.lines()
.map(str::trim)
.find(|l| l.starts_with("fmt ") && l.contains('='))
.unwrap_or_else(|| {
panic!(
"{} has no `fmt` alias.\n\
Without it, `cargo fmt --all` in this repository walks local path \n\
dependencies out through the old znippy engine crate and rewrites facett, znippy, \n\
znippy-zoomies, Skidbladnir and nornir — 12556 diffs, MEASURED \n\
2026-08-04. If you removed it because cargo made the alias a hard \n\
error (rust-lang/cargo#10049), the landmine is still there: replace \n\
the protection, do not just delete it.",
cfg.display()
)
});
assert!(
alias.contains("xtask") && alias.contains("fmt"),
"the `fmt` alias must route to `xtask fmt`, got: {alias}"
);
}
/// The four package trees the root `members` list does not contain.
///
/// Each is here for its own reason, and all four hold real `.rs` files that had
/// never been formatted:
///
/// * the old znippy engine crate — in the workspace `exclude` list, because
/// znippy's path dependency is read at RESOLVE time and would break every
/// gunnar build on a machine with no sibling znippy checkout.
/// * the old znippy engine bench — a detached workspace one level deeper
/// still, inside an already-excluded crate.
/// * `bench/` — a detached workspace at the repository root.
/// * `installtest/` — simply not a member.
const NOT_IN_MEMBERS: &[&str] = &[
// the deleted engine crate’s manifest and its nested `bench/` were the first
// two entries here and are gone: the crate was DELETED on 2026-08-11. The
// root manifest's `exclude` block had already recorded it as deleted on
// 2026-08-10 while 5.0 GB of it — all build output, zero tracked files —
// sat on disk, so `cargo xtask fmt` was still walking into it.
//
// Same shape as the `gunnar-znippy` deletion the floor below records. A
// fixture that names a tree which no longer exists does not pin the gap it
// was written for; it just fails.
"bench/Cargo.toml",
"installtest/Cargo.toml",
];
/// Discovery must be a filesystem walk. The `members` list is not the tree, and
/// a fmt built on it silently skipped 608 diffs across three trees.
#[test]
fn discovery_finds_the_four_trees_the_members_list_misses() {
let root = root();
let found: Vec<String> = package_manifests(&root)
.iter()
.map(|p| rel(&root, p))
.collect();
// First prove the fixture: `members` really does not name these.
let manifest = std::fs::read_to_string(root.join("Cargo.toml")).expect("read root Cargo.toml");
let members_block = {
let a = manifest.find("members").expect("root has a members list");
let b = manifest[a..].find(']').expect("members list closes") + a;
&manifest[a..b]
};
for m in NOT_IN_MEMBERS {
let dir = m.trim_end_matches("/Cargo.toml");
assert!(
!members_block.contains(&format!("\"{dir}\"")),
"fixture is stale: `{dir}` IS in the members list now, so it no longer \
demonstrates the gap this test exists to pin"
);
}
// Now the claim.
for m in NOT_IN_MEMBERS {
assert!(
found.iter().any(|f| f == m),
"`{m}` is not in the discovered set, so `cargo xtask fmt` would skip it.\n\
The `members` list is NOT the tree. Discovery must stay a filesystem \
walk.\nFound: {found:#?}"
);
}
}
/// The virtual root manifest must never be handed to `cargo fmt
/// --manifest-path`: it exits with a usage error rather than doing nothing,
/// which is what made an earlier scoped fmt step fail for a reason that looked
/// like a formatting failure.
#[test]
fn discovery_skips_virtual_manifests_and_the_guard_fixtures() {
let root = root();
let found: Vec<String> = package_manifests(&root)
.iter()
.map(|p| rel(&root, p))
.collect();
assert!(
!found.iter().any(|f| f == "Cargo.toml"),
"the virtual root manifest must not be in the set: {found:#?}"
);
// The fixture workspaces under xtask/tests/fixtures are deliberately BROKEN
// — each is the red-first proof of a dependency-guard rule — and are in the
// root `exclude` list for that reason. They are asserted against, not
// styled.
let fixtures: Vec<&String> = found
.iter()
.filter(|f| f.contains("tests/fixtures"))
.collect();
assert!(
fixtures.is_empty(),
"guard fixtures must not be formatted, they are asserted against: {fixtures:#?}"
);
// Vendored third-party source is held VERBATIM. `vendor/gix-features` is
// gix-features 0.49.0 plus six lines, carried as a `[patch]` until the fix
// lands upstream; rustfmt would rewrite the other several thousand and the
// diff against upstream would be gone. It is edition 2024 where this repo is
// 2021, so it would even get a different import sort -- the exact
// cross-repository damage this whole mechanism exists to stop, reproduced
// inside our own tree.
let vendored: Vec<&String> = found.iter().filter(|f| f.starts_with("vendor/")).collect();
assert!(
vendored.is_empty(),
"vendored third-party source must never be reformatted: {vendored:#?}"
);
// **Other repositories parked inside this checkout.** Local tooling keeps
// full sibling checkouts (edda, draupnir, …) under `.idea/worktrees` and
// `.claude/worktrees`. A walk that descends into them formats other
// repositories from inside this one — the damage this module exists to
// stop, and it has arrived through BOTH directories now (`.idea`
// 2026-08-16, `.claude` 2026-09-12: the tooling moved and the skip list
// did not follow). Asserted by directory here, above the fixture check,
// because a sibling's fixtures are only the part that happened to be
// noticed — its ordinary crates were being swept in too.
let parked: Vec<&String> = found
.iter()
.filter(|f| f.starts_with(".idea/") || f.starts_with(".claude/"))
.collect();
assert!(
parked.is_empty(),
"these manifests belong to other repositories parked inside this checkout and must \
never be in this repository's fmt set: {parked:#?}"
);
// And the set must not be trivially empty, which would make both asserts
// above pass while covering nothing.
//
// The floor was 20 and went red on 2026-08-10 when `crates/gunnar-znippy`
// was deleted (the storage engine became a
// feature of `gunnar-server` rather than a crate of its own). One manifest
// fewer, and this is a floor, so the deletion is what moved it — not a
// discovery regression. It is deliberately a floor and not an equality:
// adding a crate must not fail a test whose subject is "the walk found
// something".
//
// 19 -> 17 on 2026-08-11, and for the same reason a second time:
// the old znippy engine crate was deleted, taking its own manifest AND the
// nested the deleted engine crate’s nested bench manifest with it. Two deletions
// have now moved this number and both are written down, because a floor
// nobody explains is a floor the next person raises back.
assert!(
found.len() >= 17,
"expected ~17 package manifests, found {}: {found:#?}",
found.len()
);
}
/// `xtask fmt` shells out to `cargo-fmt`, NOT to `cargo fmt` — because
/// `cargo fmt` is now the alias that lands back here, and that loop would not
/// terminate.
#[test]
fn the_formatter_invoked_is_cargo_fmt_itself_not_the_alias() {
let bin = cargo_fmt_binary();
let name = bin.file_name().and_then(|n| n.to_str()).unwrap_or("");
assert_eq!(
name, "cargo-fmt",
"must invoke the `cargo-fmt` binary directly; going through `cargo fmt` \
re-enters the alias and recurses"
);
assert_ne!(
name, "cargo",
"that is the alias, and it points back at this task"
);
}
/// Mode is an argument, not a default that happens to be right. `Check` and
/// `Write` must be distinguishable — an enum whose variants compare equal would
/// make every "did we check or did we write?" assertion vacuous.
#[test]
fn check_and_write_are_distinguishable() {
assert_ne!(Mode::Check, Mode::Write);
}