use std::path::{Path, PathBuf};
use std::process::Command;
const BIN: &str = env!("CARGO_BIN_EXE_microscope-mem");
const NOT_SUBCOMMANDS: &[&str] = &[
"cargo", "build", "check", "clippy", "doc", "fmt", "install", "package", "publish", "run",
"test", "tree", "update", "add", "deny", "help", "version", "bash", "sh",
];
fn markdown_files(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
let name = entry.file_name();
let name = name.to_string_lossy();
if name == "target" || name == "node_modules" || name == ".git" {
continue;
}
if path.is_dir() {
markdown_files(&path, out);
} else if name.ends_with(".md") {
out.push(path);
}
}
}
#[test]
fn documented_commands_all_exist() {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let mut files = Vec::new();
markdown_files(&root, &mut files);
assert!(
files.len() > 5,
"expected to find the docs, found {}",
files.len()
);
let mut missing: Vec<(String, String)> = Vec::new();
for file in &files {
let Ok(text) = std::fs::read_to_string(file) else {
continue;
};
for line in text.lines() {
let line = line.trim_start();
let Some(rest) = line
.strip_prefix("microscope-memory")
.or_else(|| line.strip_prefix("microscope-mem"))
else {
continue;
};
let rest = rest.trim_start();
if rest.len() == line.len() - line.trim_start().len() && !rest.is_empty() {
continue; }
let name: String = rest
.chars()
.take_while(|c| c.is_ascii_lowercase() || *c == '-')
.collect();
let name = name.trim_end_matches('-').to_string();
if name.len() < 3 || NOT_SUBCOMMANDS.contains(&name.as_str()) {
continue;
}
let out = Command::new(BIN)
.args([name.as_str(), "--help"])
.output()
.expect("run the binary");
let text = format!(
"{}{}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
if text.contains("unrecognized subcommand") {
let rel = file
.strip_prefix(&root)
.unwrap_or(file)
.display()
.to_string();
missing.push((name, rel));
}
}
}
missing.sort();
missing.dedup();
assert!(
missing.is_empty(),
"these commands are documented but do not exist:\n{}",
missing
.iter()
.map(|(cmd, file)| format!(" {cmd} ({file})"))
.collect::<Vec<_>>()
.join("\n")
);
}