//! Integration tests for the `binmeta` command. use std::path::{Path, PathBuf}; use assert_cmd::Command; use predicates::prelude::*; use serde_json::Value; fn cargo_command() -> Command { Command::cargo_bin("binmeta").expect("binary") } fn fixture(path: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("..") .join("..") .join("fixtures") .join(path) } fn inspect_json(path: &Path) -> Value { let mut command = cargo_command(); let output = command .arg(path) .arg("--json") .assert() .success() .get_output() .stdout .clone(); serde_json::from_slice::(&output).expect("json payload") } #[test] fn help_includes_examples_and_json_pipeline_usage() { let mut command = cargo_command(); command .arg("--help") .assert() .success() .stdout(predicate::str::contains( "binmeta .\\fixtures\\binmeta\\plain.txt", )) .stdout(predicate::str::contains("ConvertFrom-Json")) .stdout(predicate::str::contains("--input-format")); } #[test] fn inspects_plain_text_fixture_as_not_pe() { let input = fixture("binmeta/plain.txt"); let payload = inspect_json(&input); let entries = payload.as_array().expect("array payload"); assert_eq!(entries.len(), 1); assert_eq!(entries[0]["kind"], "not_pe"); assert_eq!(entries[0]["extension"], "txt"); assert_eq!(entries[0]["sha256"].as_str().map(str::len), Some(64)); assert!( entries[0]["size_bytes"] .as_u64() .is_some_and(|value| value > 0) ); assert!(entries[0]["pe"].is_null()); assert!(entries[0]["version"].is_null()); assert!(entries[0]["signature"].is_null()); } #[test] fn supports_powershell_pipeline_input() { let binary = assert_cmd::cargo::cargo_bin("binmeta"); let input = fixture("binmeta/plain.txt"); let script = format!("'{}' | & '{}' --json", input.display(), binary.display()); let mut command = Command::new("pwsh"); command .arg("-NoProfile") .arg("-Command") .arg(script) .assert() .success() .stdout(predicate::str::contains("\"kind\":\"not_pe\"")); } #[cfg(windows)] #[test] fn inspects_current_test_binary_as_pe() { let current_exe = std::env::current_exe().expect("current exe"); let payload = inspect_json(¤t_exe); let entry = &payload.as_array().expect("array payload")[0]; assert_eq!(entry["kind"], "pe"); assert_eq!(entry["path"], current_exe.display().to_string()); assert_eq!(entry["sha256"].as_str().map(str::len), Some(64)); assert!( entry["pe"]["machine"] .as_str() .is_some_and(|value| !value.is_empty()) ); assert!( entry["pe"]["architecture"] .as_str() .is_some_and(|value| !value.is_empty()) ); assert!( entry["pe"]["section_count"] .as_u64() .is_some_and(|value| value > 0) ); assert!( entry["pe"]["sections"] .as_array() .is_some_and(|value| !value.is_empty()) ); assert!(entry["pe"]["library_count"].as_u64().is_some()); assert!(entry.get("version").is_some()); assert!(entry.get("signature").is_some()); assert_eq!(entry["signature"]["status"], "not_signed"); assert_eq!(entry["signature"]["signature_type"], "none"); } #[cfg(windows)] #[test] fn inspects_windows_binary_version_and_catalog_signature() { let notepad = PathBuf::from(r"C:\Windows\System32\notepad.exe"); if !notepad.is_file() { eprintln!( "skipping notepad signature smoke: {} missing", notepad.display() ); return; } let payload = inspect_json(¬epad); let entry = &payload.as_array().expect("array payload")[0]; assert_eq!(entry["kind"], "pe"); assert!( entry["version"]["company_name"] .as_str() .is_some_and(|value| !value.is_empty()) ); assert!( entry["version"]["file_version"] .as_str() .is_some_and(|value| !value.is_empty()) ); assert_eq!(entry["signature"]["status"], "valid"); assert_eq!(entry["signature"]["catalog_signed"], true); assert_eq!(entry["signature"]["signature_type"], "catalog"); assert!( entry["signature"]["signer"]["subject"] .as_str() .is_some_and(|value| value.contains("Microsoft")) ); } #[cfg(windows)] #[test] fn malformed_version_resource_still_reports_pe_identity_when_reference_exists() { let nuitka_exe = PathBuf::from(r"C:\Users\example\Desktop\SampleTool.exe"); if !nuitka_exe.is_file() { eprintln!( "skipping Nuitka resource compatibility smoke: {} missing", nuitka_exe.display() ); return; } let payload = inspect_json(&nuitka_exe); let entry = &payload.as_array().expect("array payload")[0]; assert_eq!(entry["kind"], "pe"); assert_eq!(entry["version"]["company_name"], "Example Corp"); assert_eq!( entry["version"]["file_description"], "Codex Thread Importer" ); assert_eq!(entry["version"]["product_name"], "Codex Thread Importer"); assert!( entry["parse_error"] .as_str() .is_some_and(|message| message.contains("ResourceString value_len")) ); }