use std::collections::BTreeSet;
use std::path::Path;
const DECLARATION_FILE: &str = "src/cli/globals.rs";
const CLAP_ONLY_FIELDS: &[&str] = &["verbose", "quiet", "config_dir", "cache_dir"];
fn sources_excluding_declaration() -> String {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let mut joined = String::new();
let mut stack = vec![root.join("src")];
while let Some(dir) = stack.pop() {
let Ok(entries) = std::fs::read_dir(&dir) else {
continue;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
stack.push(path);
continue;
}
if path.extension().is_none_or(|e| e != "rs") {
continue;
}
if path.ends_with(Path::new(DECLARATION_FILE).file_name().unwrap())
&& path.to_string_lossy().contains("cli")
{
continue;
}
if let Ok(text) = std::fs::read_to_string(&path) {
joined.push_str(&text);
joined.push('\n');
}
}
}
joined
}
fn declared_cli_fields() -> BTreeSet<String> {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join(DECLARATION_FILE);
let text = std::fs::read_to_string(&path).expect("globals.rs must be readable");
let start = text
.find("pub struct Cli {")
.expect("the Cli struct must be declared in globals.rs");
let body = &text[start..];
let mut fields = BTreeSet::new();
for line in body.lines() {
let trimmed = line.trim();
let Some(rest) = trimmed.strip_prefix("pub ") else {
continue;
};
let Some((name, _)) = rest.split_once(':') else {
continue;
};
if name.chars().all(|c| c.is_ascii_lowercase() || c == '_') && !name.is_empty() {
fields.insert(name.to_string());
}
}
fields
}
#[test]
fn the_guard_actually_found_the_cli_fields() {
let fields = declared_cli_fields();
assert!(
fields.len() > 20,
"only {} fields parsed out of the Cli struct, so the extraction broke \
and every other assertion here would pass by not looking: {fields:?}",
fields.len()
);
assert!(
fields.contains("fail_on_degraded"),
"a known global flag is missing from the extraction: {fields:?}"
);
}
fn reaches_a_consumer(field: &str, sources: &str, declaration: &str) -> bool {
sources.contains(&format!("cli.{field}")) || declaration.contains(&format!("self.{field}"))
}
#[test]
fn every_global_flag_reaches_a_consumer() {
let fields = declared_cli_fields();
let sources = sources_excluding_declaration();
let declaration =
std::fs::read_to_string(Path::new(env!("CARGO_MANIFEST_DIR")).join(DECLARATION_FILE))
.expect("globals.rs must be readable");
let mut inert = Vec::new();
for field in &fields {
if CLAP_ONLY_FIELDS.contains(&field.as_str()) {
continue;
}
if !reaches_a_consumer(field, &sources, &declaration) {
inert.push(field.clone());
}
}
assert!(
inert.is_empty(),
"these global flags parse and are then discarded — nothing READS them \
off the parsed `Cli`. A flag that promises an effect it cannot have is \
worse than no flag: the operator gets no error and believes the setting \
took. Remove them, or wire them to a consumer.\n{inert:?}"
);
}
#[test]
fn a_parameter_named_after_a_field_is_not_a_consumer() {
let mention_only = "pub fn decide(fail_on_degraded: bool) -> bool { !fail_on_degraded }";
assert!(
!reaches_a_consumer("fail_on_degraded", mention_only, ""),
"a parameter named after the field is a mention, not a read; the guard \
accepted exactly this shape and let an inert flag ship"
);
assert!(
reaches_a_consumer("fail_on_degraded", "run(args, cli.fail_on_degraded)", ""),
"reading the value off the parsed Cli must count as a consumer"
);
assert!(
reaches_a_consumer("select", "", "let v = self.select.clone();"),
"an accessor on Cli must count: it is how the agent-surface knobs flow"
);
}
#[test]
fn the_removed_flags_stay_removed() {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join(DECLARATION_FILE);
let text = std::fs::read_to_string(&path).expect("globals.rs must be readable");
for gone in ["pub strict_env_clear", "pub extraction_backend"] {
assert!(
!text.contains(gone),
"{gone} was removed in v1.2.2 because nothing consumed it; \
re-adding it needs a consumer first"
);
}
}
#[test]
fn no_help_text_offers_a_mode_the_binary_does_not_have() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let args = std::fs::read_to_string(root.join("src/commands/enrich/args.rs"))
.expect("enrich args.rs must be readable");
let modes = args
.split("pub enum EnrichMode {")
.nth(1)
.and_then(|rest| rest.split('}').next())
.map(|body| body.matches("#[value(name =").count())
.expect("EnrichMode must be declared in enrich/args.rs");
if modes > 1 {
return;
}
let help = run_enrich_help();
for forbidden in ["subprocess mode", "subprocess modes"] {
assert!(
!help.to_lowercase().contains(forbidden),
"`enrich --help` names a `{forbidden}` while EnrichMode has a single \
variant, so no such mode can be selected. Either restore the mode \
or stop advertising it:\n{help}"
);
}
}
fn run_enrich_help() -> String {
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sqlite-graphrag"))
.args(["enrich", "--help"])
.output()
.expect("failed to run the built binary");
let mut text = String::from_utf8_lossy(&output.stdout).into_owned();
text.push_str(&String::from_utf8_lossy(&output.stderr));
text
}