use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
const DEFAULT_MAX_LINES: usize = 3000;
const EXCEPTIONS: &[(&str, usize)] = &[
("stats.rs", 9856),
("vmm/freeze_coord/mod.rs", 8973), ("scenario/ops/mod.rs", 7463),
("monitor/reader.rs", 5608),
("scenario/payload_run.rs", 5598),
("test_support/eval.rs", 5504),
("vmm/virtio_console.rs", 4793),
("monitor/dump/tests.rs", 4645),
("monitor/bpf_map/tests.rs", 4013), ("vmm/virtio_blk/device.rs", 3826),
("workload/spawn/mod.rs", 3752),
("fetch.rs", 3727), ("workload/worker/mod.rs", 3635),
("bin/cargo_ktstr/parse_tests.rs", 3571),
("ctprof/mod.rs", 3568),
("vmm/rust_init.rs", 3510),
("vmm/host_topology/tests.rs", 3189), ("vmm/exit_dispatch.rs", 3091),
("vmm/initramfs.rs", 3074),
("monitor/scx_walker.rs", 3055),
("host_context.rs", 3041), ("test_support/probe.rs", 3027),
("monitor/tests.rs", 3015), ];
fn src_root() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect(
"CARGO_MANIFEST_DIR must be set (cargo sets it for cargo-test / cargo-nextest \
invocations; running this test outside of cargo is unsupported)",
);
PathBuf::from(manifest_dir).join("src")
}
fn rel_path(file: &Path, src_root: &Path) -> String {
let rel = file
.strip_prefix(src_root)
.expect("file must live under src_root");
rel.components()
.map(|c| c.as_os_str().to_string_lossy().into_owned())
.collect::<Vec<_>>()
.join("/")
}
fn count_lines(path: &Path) -> usize {
let bytes = std::fs::read(path).expect("read source file");
bytes.iter().filter(|&&b| b == b'\n').count()
}
#[test]
#[ignore]
fn no_src_file_exceeds_3000_lines_unless_grandfathered() {
let src = src_root();
assert!(
src.is_dir(),
"src directory does not exist at {src:?}; CARGO_MANIFEST_DIR may be wrong",
);
let exceptions: BTreeMap<&str, usize> = EXCEPTIONS.iter().copied().collect();
assert_eq!(
exceptions.len(),
EXCEPTIONS.len(),
"EXCEPTIONS contains a duplicate path key — each file must \
appear exactly once",
);
let mut new_overflows: Vec<(String, usize)> = Vec::new();
let mut grew_past_ceiling: Vec<(String, usize, usize)> = Vec::new();
let mut seen_exceptions: BTreeMap<&str, bool> =
exceptions.keys().map(|k| (*k, false)).collect();
for entry in walkdir::WalkDir::new(&src).into_iter() {
let entry = entry.expect("walkdir must succeed under src/");
let path = entry.path();
if !entry.file_type().is_file() {
continue;
}
if path.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let rel = rel_path(path, &src);
let lines = count_lines(path);
match exceptions.get(rel.as_str()) {
Some(&ceiling) => {
if let Some(seen) = seen_exceptions.get_mut(rel.as_str()) {
*seen = true;
}
if lines > ceiling {
grew_past_ceiling.push((rel, lines, ceiling));
}
}
None => {
if lines > DEFAULT_MAX_LINES {
new_overflows.push((rel, lines));
}
}
}
}
let mut stale_exceptions: Vec<(String, Option<usize>)> = Vec::new();
for key in exceptions.keys() {
let path = src.join(key);
if !path.is_file() {
stale_exceptions.push(((*key).to_string(), None));
continue;
}
let lines = count_lines(&path);
if lines <= DEFAULT_MAX_LINES {
stale_exceptions.push(((*key).to_string(), Some(lines)));
}
}
let unreached: Vec<&str> = seen_exceptions
.iter()
.filter_map(|(k, seen)| if *seen { None } else { Some(*k) })
.collect();
let any_failure = !new_overflows.is_empty()
|| !grew_past_ceiling.is_empty()
|| !stale_exceptions.is_empty()
|| !unreached.is_empty();
if any_failure {
let mut msg = String::from("src-file size guard failed:\n\n");
if !new_overflows.is_empty() {
msg.push_str("(1) Files NOT in EXCEPTIONS that exceed 3000 lines:\n");
for (path, lines) in &new_overflows {
msg.push_str(&format!(
" src/{path} = {lines} lines (limit {DEFAULT_MAX_LINES})\n"
));
}
msg.push_str(
" Fix: split the file into submodules, or add it to \
EXCEPTIONS with its current line count and a `// queued: \
<task>` comment naming the queued split task.\n\n",
);
}
if !grew_past_ceiling.is_empty() {
msg.push_str("(2) Grandfathered files that grew past their pinned ceiling:\n");
for (path, lines, ceiling) in &grew_past_ceiling {
msg.push_str(&format!(
" src/{path} = {lines} lines (grandfathered ceiling {ceiling})\n"
));
}
msg.push_str(
" Fix: shrink the file (preferred) OR refresh the \
EXCEPTIONS entry's count if the growth is genuinely \
unavoidable. Refreshing requires a reviewer sign-off — \
the entry is a ratchet, not a free pass.\n\n",
);
}
if !stale_exceptions.is_empty() {
msg.push_str(
"(3) EXCEPTIONS entries that are now stale (file ≤ 3000 \
lines or removed) — remove these entries:\n",
);
for (path, lines) in &stale_exceptions {
match lines {
Some(n) => msg.push_str(&format!(
" src/{path} now {n} lines (≤ {DEFAULT_MAX_LINES}); remove from EXCEPTIONS\n"
)),
None => msg.push_str(&format!(
" src/{path} no longer exists; remove from EXCEPTIONS\n"
)),
}
}
msg.push_str(
" Fix: delete the listed entries from EXCEPTIONS. \
The default 3000-line gate guards the file going forward.\n\n",
);
}
if !unreached.is_empty() {
msg.push_str(
"(4) EXCEPTIONS keys not visited by the walk (typo or \
removed file):\n",
);
for key in &unreached {
msg.push_str(&format!(" src/{key}\n"));
}
msg.push_str(
" Fix: correct the path string or delete the entry. \
Every EXCEPTIONS key must resolve to a real file under src/.\n\n",
);
}
panic!("{msg}");
}
}