//! CLI contract tests for PE analysis commands. use assert_cmd::Command; use predicates::prelude::*; use serde_json::Value; const COMMANDS: &[&str] = &[ "peexports", "peimports", "pecalls", "pesig", "pestrrefs", "drvshape", "ioctlscan", ]; fn peimports_command() -> Command { Command::cargo_bin("peimports").expect("binary") } fn peexports_command() -> Command { Command::cargo_bin("peexports").expect("binary") } #[test] fn help_mentions_shared_flags_and_examples() { for command_name in COMMANDS { let mut command = Command::cargo_bin(command_name).expect("binary"); command .arg("--help") .assert() .success() .stdout(predicate::str::contains("Examples")) .stdout(predicate::str::contains("--json")) .stdout(predicate::str::contains("--toon")) .stdout(predicate::str::contains("--input-format")); } } #[test] fn non_pe_input_is_runtime_error() { let temp = tempfile::NamedTempFile::new().expect("temp file"); std::fs::write(temp.path(), b"not a pe").expect("write fixture"); let mut command = peimports_command(); command .arg(temp.path()) .arg("--json") .assert() .code(3) .stderr(predicate::str::contains("not a PE")); } #[test] fn imports_json_includes_guided_triage_metadata() { let sample = assert_cmd::cargo::cargo_bin("peimports"); let mut command = peimports_command(); let output = command .arg(sample) .arg("--json") .assert() .success() .get_output() .stdout .clone(); let json = serde_json::from_slice::(&output).expect("json output"); assert_eq!(json["report_quality"]["confidence"], "high"); assert_eq!(json["report_quality"]["completeness"], "complete"); assert!( json["report_quality"]["evidence"] .as_array() .is_some_and(|items| { items .iter() .any(|item| item == "PE headers and import table parsed") }) ); assert!(json["next_actions"].as_array().is_some_and(|items| { items.iter().any(|item| { item["label"] == "Hunt imported API callsites" && item["command"].as_str().is_some_and(|command| { command.contains("pecalls") && command.contains("--category") }) }) })); } #[test] fn imports_text_is_answer_first_and_actionable() { let sample = assert_cmd::cargo::cargo_bin("peimports"); let mut command = peimports_command(); command .arg(sample) .assert() .success() .stdout(predicate::str::contains("answer=")) .stdout(predicate::str::contains( "trust confidence=high completeness=complete", )) .stdout(predicate::str::contains( "next_action label=\"Hunt imported API callsites\" command=\"pecalls", )); } #[test] fn exports_ordinal_filter_matches_the_real_export_ordinal() { let mut command = peexports_command(); let output = command .arg(r"C:\Windows\System32\kernel32.dll") .arg("--ordinal") .arg("126") .arg("--json") .assert() .success() .get_output() .stdout .clone(); let json = serde_json::from_slice::(&output).expect("json output"); let export = json["files"][0]["exports"][0].clone(); assert_eq!(export["ordinal"], 126); assert_eq!(export["name"], "BuildIoRingCancelRequest"); }