use std::path::{Path, PathBuf};
use std::process::{Command, Output};
fn run_ripr(args: &[&str]) -> Output {
let bin = env!("CARGO_BIN_EXE_ripr");
Command::new(bin).args(args).output().unwrap()
}
fn workspace_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(Path::parent)
.unwrap()
.to_path_buf()
}
fn sample_diff() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/sample/example.diff")
}
fn assert_success(output: &Output) {
assert!(
output.status.success(),
"expected command to succeed\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn version_runs() {
let output = run_ripr(&["--version"]);
assert_success(&output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("ripr"));
}
#[test]
fn help_runs() {
let output = run_ripr(&["--help"]);
assert_success(&output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("static RIPR"));
}
#[test]
fn check_human_output_reports_sample_findings() {
let root = workspace_root().display().to_string();
let diff = sample_diff();
assert!(diff.exists());
let diff = diff.display().to_string();
let output = run_ripr(&["check", "--root", &root, "--diff", &diff]);
assert_success(&output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("Summary: 5 probe(s)"));
assert!(stdout.contains("Static exposure: weakly_exposed"));
assert!(stdout.contains("Static exposure: infection_unknown"));
assert!(stdout.contains("Recommended next step:"));
}
#[test]
fn check_json_output_has_stable_contract_fields() {
let root = workspace_root().display().to_string();
let diff = sample_diff().display().to_string();
let output = run_ripr(&["check", "--root", &root, "--diff", &diff, "--json"]);
assert_success(&output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains(r#""schema_version": "0.1""#));
assert!(stdout.contains(r#""classification": "weakly_exposed""#));
assert!(stdout.contains(r#""classification": "infection_unknown""#));
assert!(stdout.contains(r#""recommended_next_step""#));
}
#[test]
fn explain_returns_targeted_probe_details() {
let root = workspace_root().display().to_string();
let diff = sample_diff().display().to_string();
let output = run_ripr(&[
"explain",
"--root",
&root,
"--diff",
&diff,
"probe:crates_ripr_examples_sample_src_lib.rs:21:error_path",
]);
assert_success(&output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("Static exposure: weakly_exposed (error_path, value)"));
assert!(stdout.contains("No exact error variant discriminator was detected"));
}
#[test]
fn context_json_returns_probe_and_discriminator_guidance() {
let root = workspace_root().display().to_string();
let diff = sample_diff().display().to_string();
let output = run_ripr(&[
"context",
"--root",
&root,
"--diff",
&diff,
"--at",
"probe:crates_ripr_examples_sample_src_lib.rs:21:error_path",
"--json",
]);
assert_success(&output);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains(r#""id": "probe:crates_ripr_examples_sample_src_lib.rs:21:error_path""#)
);
assert!(stdout.contains(r#""discriminate": "weak""#));
assert!(stdout.contains(r#""missing""#));
}
#[test]
fn explain_unknown_probe_fails_with_clear_error() {
let root = workspace_root().display().to_string();
let diff = sample_diff().display().to_string();
let output = run_ripr(&[
"explain",
"--root",
&root,
"--diff",
&diff,
"probe:missing:0:not_real",
]);
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("no finding matched"));
}