use std::path::PathBuf;
use std::process::Command;
fn binary() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_keyhog"))
}
#[test]
fn explain_valid_detector_returns_exit_zero_with_spec() {
let output = Command::new(binary())
.arg("explain")
.arg("aws-access-key")
.output()
.expect("spawn keyhog explain aws-access-key");
assert_eq!(
output.status.code(),
Some(0),
"explain aws-access-key should exit 0; stderr={}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("aws-access-key") || stdout.contains("AWS Access Key"),
"explain output must include the detector id or name; got: {stdout}"
);
assert!(
stdout.contains("severity") || stdout.contains("regex") || stdout.contains("pattern"),
"explain output must include detector spec (severity/regex); got: {stdout}"
);
}
#[test]
fn explain_github_pat_detector_includes_rotation_guide() {
let output = Command::new(binary())
.arg("explain")
.arg("github-pat")
.output()
.expect("spawn keyhog explain github-pat");
assert_eq!(
output.status.code(),
Some(0),
"explain github-pat should exit 0"
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("github") || stdout.contains("GitHub"),
"explain github-pat must mention github; got: {stdout}"
);
assert!(
stdout.to_lowercase().contains("revoke")
|| stdout.to_lowercase().contains("rotate")
|| stdout.to_lowercase().contains("github"),
"explain must include rotation guidance or service info; got: {stdout}"
);
}
#[test]
fn explain_invalid_detector_id_exits_two_with_actionable_error() {
let output = Command::new(binary())
.arg("explain")
.arg("detector-does-not-exist-xyz")
.output()
.expect("spawn keyhog explain <invalid>");
assert_eq!(
output.status.code(),
Some(2),
"explain with invalid detector ID should exit 2 (user error)"
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.to_lowercase().contains("not found")
|| stderr.to_lowercase().contains("unknown")
|| stderr.contains("detector-does-not-exist"),
"error message must name the invalid detector so operator knows why; got: {stderr}"
);
}
#[test]
fn explain_help_documents_detector_id_argument() {
let output = Command::new(binary())
.arg("explain")
.arg("--help")
.output()
.expect("spawn keyhog explain --help");
assert_eq!(
output.status.code(),
Some(0),
"explain --help should exit 0"
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("DETECTOR_ID") || stdout.contains("detector"),
"help must document the required detector-id argument; got: {stdout}"
);
assert!(
stdout.contains("--detectors"),
"help must mention the --detectors directory override flag; got: {stdout}"
);
}