//! Integration tests for the `unityprobe` command. use std::fs; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; use assert_cmd::Command; use predicates::prelude::*; use serde_json::Value; fn cargo_command() -> Command { Command::cargo_bin("unityprobe").expect("binary") } #[test] fn no_args_prints_quick_help_card() { let mut command = cargo_command(); command .assert() .code(2) .stdout(predicate::str::is_empty()) .stderr(predicate::str::contains( "error: unityprobe requires a subcommand", )) .stderr(predicate::str::contains("unityprobe - Mercury Toolbox")) .stderr(predicate::str::contains("Usage:")) .stderr(predicate::str::contains( "unityprobe [OPTIONS] [ARGS...]", )) .stderr(predicate::str::contains("install ")) .stderr(predicate::str::contains( "Type 'unityprobe --help' for the full command reference.", )); } fn unique_temp_dir(prefix: &str) -> PathBuf { let suffix = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("epoch") .as_nanos(); let path = std::env::temp_dir().join(format!("{prefix}-{suffix}")); fs::create_dir_all(&path).expect("temp dir"); path } #[test] fn help_calls_out_windows_only_bridge_workflow() { let mut command = cargo_command(); command .arg("--help") .assert() .success() .stdout(predicate::str::contains("Windows only")) .stdout(predicate::str::contains("named pipe JSON")) .stdout(predicate::str::contains("BepInEx\\plugins")) .stdout(predicate::str::contains("unityprobe status --game-root")) .stdout(predicate::str::contains("unityprobe --json find")) .stdout(predicate::str::contains("unityprobe inspect -- -938")); } #[cfg(windows)] #[test] fn status_reports_uninstalled_game_root_install_state_as_json() { let game_root = unique_temp_dir("unityprobe-status"); let mut command = cargo_command(); let output = command .arg("--json") .arg("status") .arg("--game-root") .arg(&game_root) .assert() .success() .stdout(predicate::str::contains("\"windows_supported\":true")) .get_output() .stdout .clone(); let report: Value = serde_json::from_slice(&output).expect("status json"); assert_eq!( report.get("game_root").and_then(Value::as_str), Some(game_root.to_string_lossy().as_ref()) ); assert_eq!( report.get("installed").and_then(Value::as_bool), Some(false) ); assert!( report .get("pipe_reachable") .and_then(Value::as_bool) .is_some() ); assert!(report.get("runtime_status").is_some()); } #[cfg(windows)] #[test] fn install_requires_explicit_bepinex_and_managed_layout() { let game_root = unique_temp_dir("unityprobe-install"); let mut command = cargo_command(); command .arg("install") .arg(&game_root) .assert() .code(3) .stderr(predicate::str::contains("BepInEx")) .stderr(predicate::str::contains("Managed")); }