use std::fs;
use std::path::{Path, PathBuf};
fn root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}
fn read(rel: &str) -> String {
fs::read_to_string(root().join(rel)).unwrap_or_else(|e| panic!("cannot read {rel}: {e}"))
}
fn count_lines_containing(dir: &Path, needle: &str) -> usize {
let mut count = 0;
let mut stack = vec![dir.to_path_buf()];
while let Some(d) = stack.pop() {
for entry in fs::read_dir(&d).unwrap() {
let p = entry.unwrap().path();
if p.is_dir() {
stack.push(p);
} else if p.extension().is_some_and(|x| x == "rs") {
count += fs::read_to_string(&p).unwrap().lines().filter(|l| l.trim_start().starts_with(needle)).count();
}
}
}
count
}
fn leading_int(text: &str, marker: &str) -> usize {
let idx = text.find(marker).unwrap_or_else(|| panic!("doc missing marker '{marker}'"));
let digits: String = text[..idx].chars().rev().skip_while(|c| c.is_whitespace()).take_while(|c| c.is_ascii_digit()).collect();
digits.chars().rev().collect::<String>().parse().unwrap_or_else(|_| panic!("no integer before '{marker}'"))
}
#[test]
fn agents_md_structure_lists_every_module() {
let lib = read("src/lib.rs");
let agents = read("AGENTS.md");
let missing: Vec<String> = lib
.lines()
.filter_map(|l| {
let t = l.trim();
t.strip_prefix("pub mod ")?.strip_suffix(';').map(str::to_owned)
})
.filter(|m| !agents.contains(&format!("{m}.rs")))
.collect();
assert!(missing.is_empty(), "modules missing from the AGENTS.md project structure: {missing:?}");
}
fn documented_in(module: &str, doc: &str) -> bool {
doc.contains(&format!("{module}.rs")) || doc.contains(&format!("{module}::")) || doc.contains(&format!("`{module}`"))
}
#[test]
fn architecture_md_mentions_every_module() {
let lib = read("src/lib.rs");
let arch = read("ARCHITECTURE.md");
let missing: Vec<String> = lib
.lines()
.filter_map(|l| {
let t = l.trim();
t.strip_prefix("pub mod ")?.strip_suffix(';').map(str::to_owned)
})
.filter(|m| !documented_in(m, &arch))
.collect();
assert!(missing.is_empty(), "modules missing from ARCHITECTURE.md: {missing:?}");
}
#[test]
fn todo_md_unit_test_count_matches_code() {
let actual = count_lines_containing(&root().join("src"), "#[test]");
let claimed = leading_int(&read("TODO.md"), "inline unit tests");
assert_eq!(claimed, actual, "TODO.md unit-test count is stale (run `cargo test`, then update the Done section)");
}
#[test]
fn todo_md_integration_test_count_matches_code() {
let actual = count_lines_containing(&root().join("tests"), "#[test]");
let claimed = leading_int(&read("TODO.md"), "integration tests");
assert_eq!(claimed, actual, "TODO.md integration-test count is stale (run `cargo test`, then update the Done section)");
}