//! Integration tests for the `asmapi` command. use std::path::PathBuf; use assert_cmd::Command; use predicates::prelude::*; use serde_json::Value; fn cargo_command() -> Command { Command::cargo_bin("asmapi").expect("binary") } fn workspace_root() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("..") .join("..") .canonicalize() .expect("workspace root") } fn managed_fixture_dir() -> PathBuf { workspace_root() .join("fixtures") .join("managed") .join("bin") } fn game_assembly() -> PathBuf { managed_fixture_dir().join("GameAssembly.dll") } fn fixture_support() -> PathBuf { managed_fixture_dir().join("FixtureSupport.dll") } fn diff_json(extra_args: &[&str]) -> Value { let mut command = cargo_command(); let output = command .arg("diff") .arg(game_assembly()) .arg(fixture_support()) .args(extra_args) .assert() .success() .get_output() .stdout .clone(); serde_json::from_slice::(&output).expect("json payload") } #[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( "missing subcommand; expected diff", )) .stderr(predicate::str::contains("asmapi")) .stderr(predicate::str::contains("Type 'asmapi --help'")); } #[test] fn help_mentions_diff_and_shared_output_flags() { let mut command = cargo_command(); command .arg("--help") .assert() .success() .stdout(predicate::str::contains("asmapi diff")) .stdout(predicate::str::contains("--format ")) .stdout(predicate::str::contains("--json")) .stdout(predicate::str::contains("--toon")); let mut command = cargo_command(); command .args(["diff", "--help"]) .assert() .success() .stdout(predicate::str::contains("--visibility ")) .stdout(predicate::str::contains("--include-special")) .stdout(predicate::str::contains("--no-missing-method-risks")); } #[test] fn diff_outputs_compact_text_sections() { let mut command = cargo_command(); command .arg(game_assembly()) .arg(fixture_support()) .arg("diff") .assert() .code(2); let mut command = cargo_command(); command .arg("diff") .arg(game_assembly()) .arg(fixture_support()) .assert() .success() .stdout(predicate::str::contains("removed_types=")) .stdout(predicate::str::contains("added_types:")) .stdout(predicate::str::contains("removed_methods:")) .stdout(predicate::str::contains("missing_method_risks:")); } #[test] fn diff_json_exposes_stable_top_level_fields() { let payload = diff_json(&["--json"]); assert_eq!(payload["visibility"], "public"); assert!(payload["old_assembly"].is_object()); assert!(payload["new_assembly"].is_object()); assert!(payload["summary"]["removed_types"].as_u64().is_some()); assert!(payload["missing_method_risks"].as_array().is_some()); } #[test] fn visibility_all_includes_more_or_equal_removed_methods() { let public_payload = diff_json(&["--json"]); let all_payload = diff_json(&["--visibility", "all", "--json"]); assert_eq!(all_payload["visibility"], "all"); assert!( all_payload["summary"]["removed_methods"] .as_u64() .expect("all visibility removed method count") >= public_payload["summary"]["removed_methods"] .as_u64() .expect("public visibility removed method count") ); } #[test] fn invalid_visibility_is_usage_error() { let mut command = cargo_command(); command .arg("diff") .arg(game_assembly()) .arg(fixture_support()) .arg("--visibility") .arg("private") .assert() .code(2) .stderr(predicate::str::contains("invalid --visibility value")); }