use std::path::{Path, PathBuf};
fn user_documents() -> Vec<PathBuf> {
let mut docs = vec![PathBuf::from("README.md")];
for dir in ["docs", "docs/for-users"] {
for entry in std::fs::read_dir(dir).expect("docs directory exists") {
let path = entry.expect("readable entry").path();
if path.extension().and_then(|e| e.to_str()) == Some("md") {
docs.push(path);
}
}
}
docs
}
fn link_targets(text: &str) -> Vec<String> {
let mut targets = Vec::new();
let mut rest = text;
while let Some(open) = rest.find("](") {
let after = &rest[open + 2..];
let Some(close) = after.find(')') else { break };
targets.push(after[..close].to_string());
rest = &after[close..];
}
targets
}
fn local_target(target: &str) -> Option<&str> {
let target = target.trim();
if target.is_empty()
|| target.starts_with('#')
|| target.contains("://")
|| target.starts_with("mailto:")
{
return None;
}
let path = target.split('#').next().unwrap_or(target);
if path.is_empty() {
return None;
}
Some(path)
}
#[test]
fn relative_doc_links_resolve() {
let mut missing = Vec::new();
for document in user_documents() {
let text = std::fs::read_to_string(&document)
.unwrap_or_else(|e| panic!("{}: {e}", document.display()));
let base: &Path = document.parent().unwrap_or_else(|| Path::new("."));
for target in link_targets(&text) {
let Some(local) = local_target(&target) else {
continue;
};
if !base.join(local).exists() {
missing.push(format!("{} -> {target}", document.display()));
}
}
}
assert!(
missing.is_empty(),
"these documented links point at files that do not exist:\n {}",
missing.join("\n ")
);
}
#[test]
fn every_mode_has_a_user_guide_referenced_from_the_readme() {
let readme = std::fs::read_to_string("README.md").expect("README exists");
for guide in [
"docs/for-users/navigation.md",
"docs/for-users/triage.md",
"docs/for-users/cycles.md",
"docs/for-users/new-issue.md",
"docs/for-users/config.md",
] {
assert!(Path::new(guide).exists(), "{guide} must exist");
assert!(readme.contains(guide), "the README must reference {guide}");
}
}