use std::path::Path;
use std::process::Command;
use tempfile::TempDir;
fn run_with_db(subcommand_args: &[&str], db_path: &Path) -> (i32, String, String) {
let mut cmd = Command::new(env!("CARGO"));
cmd.arg("run")
.arg("--quiet")
.arg("--bin")
.arg("sqlite-graphrag")
.arg("--");
for a in subcommand_args {
cmd.arg(a);
}
cmd.arg("--db").arg(db_path);
let output = cmd
.output()
.expect("spawn cargo run for cli_db_flag_parity_regression");
let status = output.status.code().unwrap_or(-1);
let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
(status, stdout, stderr)
}
fn init_db(db_path: &Path) -> i32 {
let output = Command::new(env!("CARGO"))
.arg("run")
.arg("--quiet")
.arg("--bin")
.arg("sqlite-graphrag")
.arg("--")
.arg("init")
.arg("--db")
.arg(db_path)
.output()
.expect("spawn cargo run for init");
output.status.code().unwrap_or(-1)
}
fn with_initialised_db<F: FnOnce(&Path)>(body: F) {
let tmp = TempDir::new().expect("tempdir for cli_db_flag_parity_regression");
let db_path = tmp.path().join("parity.sqlite");
let init_status = init_db(&db_path);
assert!(
init_status == 0,
"FATAL: `init --db {}` returned status={}; cannot run parity checks. \
Test setup requires a bootstrapped database.",
db_path.display(),
init_status
);
body(&db_path);
}
fn assert_db_flag_accepted(label: &str, subcommand_args: &[&str], db_path: &Path) {
let (status, stdout, stderr) = run_with_db(subcommand_args, db_path);
let clap_rejected = stderr.contains("error:")
|| stderr.contains("unrecognized")
|| stderr.contains("unexpected argument")
|| stderr.contains("unknown option");
assert!(
!clap_rejected,
"REGRESSION GAP-E2E-008: subcommand `{label}` rejected `--db` flag.\n\
stderr: {stderr}\nstdout: {stdout}\nstatus: {status}\n\
Expected: clap accepts `--db <PATH>` as a valid argument.\n\
The Args struct for this subcommand is missing the standard \
`#[arg(long, env = \"SQLITE_GRAPHRAG_DB_PATH\")] pub db: Option<String>` field.",
);
}
#[test]
fn assert_db_flag_on_embedding_status() {
with_initialised_db(|db_path| {
assert_db_flag_accepted("embedding status", &["embedding", "status"], db_path);
});
}
#[test]
fn assert_db_flag_on_embedding_list() {
with_initialised_db(|db_path| {
assert_db_flag_accepted(
"embedding list",
&["embedding", "list", "--limit", "10"],
db_path,
);
});
}
#[test]
fn assert_db_flag_on_embedding_abandon() {
with_initialised_db(|db_path| {
assert_db_flag_accepted(
"embedding abandon <id>",
&["embedding", "abandon", "999999", "--yes"],
db_path,
);
});
}
#[test]
fn assert_db_flag_on_pending_list() {
with_initialised_db(|db_path| {
assert_db_flag_accepted(
"pending list",
&["pending", "list", "--limit", "10"],
db_path,
);
});
}
#[test]
fn assert_db_flag_on_pending_show() {
with_initialised_db(|db_path| {
assert_db_flag_accepted("pending show <id>", &["pending", "show", "0"], db_path);
});
}
#[test]
fn assert_db_flag_on_all_namespace_subcommands() {
with_initialised_db(|db_path| {
assert_db_flag_accepted("embedding status", &["embedding", "status"], db_path);
assert_db_flag_accepted(
"embedding list",
&["embedding", "list", "--limit", "10"],
db_path,
);
assert_db_flag_accepted(
"embedding abandon <id>",
&["embedding", "abandon", "999999", "--yes"],
db_path,
);
assert_db_flag_accepted(
"pending list",
&["pending", "list", "--limit", "10"],
db_path,
);
assert_db_flag_accepted("pending show <id>", &["pending", "show", "0"], db_path);
});
}