use assert_cmd::prelude::*;
use std::collections::BTreeSet;
use std::process::Command;
use std::sync::OnceLock;
const BIN: &str = "net-mesh";
const INTERNAL_REFERENCES: &[&str] = &[
"NET_CLI_PLAN",
"MESHOS_SDK_PLAN",
"DECK_SDK_PLAN",
"SUBNET_AUTH_SDK_PLAN",
"CAPABILITY_SYSTEM_SDK_PLAN",
"MCP_BRIDGE_SDK_PLAN",
"SDK_COMPUTE_SURFACE_PLAN",
"TEST_COVERAGE_PLAN",
"PERF_AUDIT",
"review-10",
];
const VERBS: &[&str] = &[
"version",
"identity",
"admin",
"ice",
"snapshot",
"audit",
"log",
"failures",
"cap",
"peer",
"daemon",
"netdb",
"org",
"db",
"mcp",
"wrap",
"forwarding",
"node",
"port",
"rpc",
"channel",
"aggregator",
"blob",
"subnet",
"gateway",
"transfer",
"typegen",
"completion",
"man",
];
fn help_for(path: &[String]) -> String {
let output = Command::cargo_bin(BIN)
.unwrap()
.args(path)
.arg("--help")
.output()
.unwrap_or_else(|e| panic!("failed to run {BIN} {path:?} --help: {e}"));
assert!(
output.status.success(),
"`{BIN} {} --help` failed: {}",
path.join(" "),
String::from_utf8_lossy(&output.stderr),
);
String::from_utf8_lossy(&output.stdout).into_owned()
}
fn children_of(help: &str) -> Vec<String> {
let mut rows: Vec<(usize, String)> = Vec::new();
let mut in_commands = false;
for line in help.lines() {
if line.starts_with("Commands:") {
in_commands = true;
continue;
}
if !in_commands {
continue;
}
if !line.starts_with(' ') {
break;
}
let indent = line.len() - line.trim_start().len();
if let Some(name) = line.split_whitespace().next() {
rows.push((indent, name.to_owned()));
}
}
let Some(name_column) = rows.iter().map(|(indent, _)| *indent).min() else {
return Vec::new();
};
rows.into_iter()
.filter(|(indent, _)| *indent == name_column)
.filter(|(_, name)| name != "help")
.map(|(_, name)| name)
.collect()
}
fn every_help_page() -> &'static [(String, String)] {
static PAGES: OnceLock<Vec<(String, String)>> = OnceLock::new();
PAGES.get_or_init(|| {
let mut pages = Vec::new();
let mut queue: Vec<Vec<String>> = vec![Vec::new()];
let mut seen: BTreeSet<Vec<String>> = BTreeSet::new();
while let Some(path) = queue.pop() {
if !seen.insert(path.clone()) {
continue;
}
let help = help_for(&path);
for child in children_of(&help) {
let mut next = path.clone();
next.push(child);
queue.push(next);
}
let label = if path.is_empty() {
BIN.to_owned()
} else {
format!("{BIN} {}", path.join(" "))
};
pages.push((label, help));
}
pages
})
}
#[test]
fn the_help_walk_reaches_the_whole_tree() {
let pages = every_help_page();
assert!(
pages.len() > 30,
"walked only {} help pages — the `Commands:` parser is probably \
broken, and a checker that visits nothing passes forever",
pages.len(),
);
}
#[test]
fn help_never_points_at_a_repository_file() {
let mut problems = Vec::new();
for (label, help) in every_help_page() {
for needle in INTERNAL_REFERENCES {
if help.to_lowercase().contains(&needle.to_lowercase()) {
let line = help
.lines()
.find(|l| l.to_lowercase().contains(&needle.to_lowercase()))
.unwrap_or("")
.trim();
problems.push(format!(" `{label} --help` mentions {needle}: {line}"));
}
}
}
assert!(
problems.is_empty(),
"help text points at {} repository-internal name(s). An installed \
user has no checkout, so this is a dead end:\n{}",
problems.len(),
problems.join("\n"),
);
}
#[test]
fn help_spells_the_binary_the_way_it_is_installed() {
let mut problems = Vec::new();
for (label, help) in every_help_page() {
for line in help.lines() {
for verb in VERBS {
let needle = format!("net {verb}");
let mut from = 0;
while let Some(at) = line[from..].find(&needle) {
let start = from + at;
let preceded_by_hyphen = start > 0 && line.as_bytes()[start - 1] == b'-';
let mid_word = start > 0 && line.as_bytes()[start - 1].is_ascii_alphanumeric();
if !preceded_by_hyphen && !mid_word {
problems.push(format!(
" `{label} --help` says `{needle}`; the installed \
executable is `{BIN}`: {}",
line.trim()
));
}
from = start + needle.len();
}
}
}
}
assert!(
problems.is_empty(),
"{} help line(s) name a program that is not what gets installed:\n{}",
problems.len(),
problems.join("\n"),
);
}