use std::path::{Path, PathBuf};
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(Path::parent)
.expect("crates/frink-cli has two ancestors")
.to_path_buf()
}
fn read(rel: &str) -> String {
let p = repo_root().join(rel);
std::fs::read_to_string(&p).unwrap_or_else(|e| panic!("reading {}: {e}", p.display()))
}
fn long_flags(source: &str) -> Vec<String> {
let mut out = Vec::new();
for (i, _) in source.match_indices("long = \"") {
let rest = &source[i + "long = \"".len()..];
if let Some(end) = rest.find('"') {
let f = rest[..end].to_string();
if !out.contains(&f) {
out.push(f);
}
}
}
out
}
#[test]
fn every_run_flag_is_documented() {
let flags = long_flags(&read("crates/frink-cli/src/run.rs"));
assert!(flags.len() > 30, "only {} flags parsed", flags.len());
let docs = read("docs/CLI.md");
let missing: Vec<&String> = flags.iter().filter(|f| !documents(&docs, f)).collect();
assert!(
missing.is_empty(),
"these `frink run` flags are accepted and undocumented in docs/CLI.md: {missing:?}"
);
}
#[test]
fn every_server_flag_is_documented() {
let flags = long_flags(&read("crates/frink-server/src/cli.rs"));
assert!(flags.len() > 20, "only {} flags parsed", flags.len());
let docs = ["docs/CLI.md", "docs/API.md", "docs/CONFIG.md", "README.md"]
.iter()
.map(|p| read(p))
.collect::<Vec<_>>()
.join("\n");
let missing: Vec<&String> = flags.iter().filter(|f| !documents(&docs, f)).collect();
assert!(
missing.is_empty(),
"these `frink-server` flags are accepted and undocumented: {missing:?}"
);
}
fn documents(docs: &str, flag: &str) -> bool {
let needle = format!("--{flag}");
docs.match_indices(&needle).any(|(i, _)| {
docs[i + needle.len()..]
.chars()
.next()
.is_none_or(|c| !c.is_ascii_alphanumeric() && c != '-' && c != '_')
})
}
#[cfg(test)]
mod tests {
use super::documents;
#[test]
fn a_longer_flag_does_not_document_a_shorter_one() {
assert!(documents("| `--draft-max N` | ...", "draft-max"));
assert!(
!documents("| `--draft-max N` | ...", "draft"),
"--draft-max must not stand in for --draft"
);
assert!(
!documents("`--draft-p-minSABOTAGE`", "draft-p-min"),
"a mangled entry must not match the name it mangled"
);
assert!(documents("`--ctk` selects", "ctk"));
assert!(documents("use --jinja.", "jinja"));
}
}