use crate::harness::*;
#[test]
fn pre_subcommand_global_flag_with_trailing_flags() {
let h = populated_home();
let claude_home = h.projects().parent().unwrap().to_path_buf();
let home_s = claude_home.to_str().unwrap().to_string();
let out = h.run(&[
"--claude-home",
home_s.as_str(),
"list",
ENC,
"--max-count",
"1",
]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(out.stdout.contains(SESS), "row listed:\n{}", out.stdout);
let out = h.run(&[
"--claude-home",
home_s.as_str(),
"search",
"xyzzy-no-such-text",
ENC,
"--format",
"json",
]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(
out.stdout.contains(r#""kind":"header""#),
"envelope present even on zero matches:\n{}",
out.stdout
);
let eq = format!("--claude-home={home_s}");
let out = h.run(&[eq.as_str(), "list", ENC, "--max-count", "1"]);
assert!(out.success, "stderr: {}", out.stderr);
assert!(out.stdout.contains(SESS));
let out = h.run(&["--bogus", "list"]);
assert!(!out.success);
assert!(out.stderr.contains("--bogus"), "stderr: {}", out.stderr);
}
#[test]
fn unknown_flag_reports_clean_error_not_project_dir_error() {
let h = populated_home();
let at_sess = at(SESS);
for args in [
vec!["files", at_sess.as_str(), "--by-fil"],
vec!["verbatim", at_sess.as_str(), "--budgett", "5000"],
vec!["recover", "--bogus-flag"],
vec!["agents", ENC, "--bogus"],
vec!["list", "--by-fil"],
] {
let out = h.run(&args);
assert!(!out.success, "a bad flag must exit nonzero: {args:?}");
assert!(
out.stderr.contains("unexpected argument"),
"expected an 'unexpected argument' message for {args:?}; got: {}",
out.stderr
);
assert!(
!out.stderr.contains("no Claude Code project dir named"),
"the misleading project-dir error must NOT appear for {args:?}; got: {}",
out.stderr
);
}
}
#[test]
fn help_exits_zero() {
let h = Home::new();
let out = h.run(&["--help"]);
assert!(out.success);
assert!(out.stdout.contains("ripgrep for Claude Code"));
}
#[test]
fn version_exits_zero() {
let h = Home::new();
let out = h.run(&["--version"]);
assert!(out.success);
assert!(out.stdout.contains("csift"));
}
#[test]
fn no_subcommand_errors() {
let h = Home::new();
let out = h.run(&[]);
assert!(!out.success, "missing subcommand must exit nonzero");
}
#[test]
fn short_value_flag_pairs_beyond_position_zero() {
let h = Home::new();
h.write(
"-Users-testuser-Projects-argv/0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d.jsonl",
"{\"type\":\"user\",\"uuid\":\"u0\",\"timestamp\":\"2026-06-07T05:00:00.000Z\",\"message\":{\"role\":\"user\",\"content\":\"zzargv payload\"}}\n",
);
let o = h.run(&[
"search",
"zzargv",
"-Users-testuser-Projects-argv",
"--no-truncate",
"--format",
"json",
"-t",
"user",
]);
assert!(o.success, "stderr: {}", o.stderr);
assert!(
o.stdout.contains("\"label\":\"user.message\""),
"-t user filter survived the reorder:\n{}",
o.stdout
);
}
#[test]
fn dangling_short_value_flag_is_not_paired_with_the_next_flag() {
let h = Home::new();
let o = h.run(&["search", "zz", ".", "-t", "--format"]);
assert!(!o.success);
assert!(
o.stderr.contains("a value is required") && o.stderr.contains("<SELECTOR>"),
"clap names the missing SELECTOR value (the -t flag stayed unpaired): {}",
o.stderr
);
}