pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
#![cfg(feature = "mutation-testing")]

//! GREEN Phase Tests for PMAT-070-001: CargoMutantsWrapper Infrastructure
//!
//! Tests updated to use real implementation from server/src/services/mutation/cargo_mutants_wrapper.rs
//!
//! Test Categories:
//! 1. Wrapper initialization (new())
//! 2. PATH detection
//! 3. Version checking
//! 4. Error handling
//! 5. Basic subprocess execution

use pmat::services::mutation::cargo_mutants_wrapper::CargoMutantsWrapper;

// ============================================================================
// RED PHASE TESTS - Unit Tests
// ============================================================================

#[test]
fn test_wrapper_new_success_when_cargo_mutants_installed() {
    // RED Phase Test 1: Wrapper initialization when cargo-mutants is installed
    // Expected: Should detect cargo-mutants in PATH and initialize successfully

    let wrapper = CargoMutantsWrapper::new();

    // This should pass if cargo-mutants is installed
    assert!(
        wrapper.is_ok(),
        "Wrapper should initialize successfully when cargo-mutants is installed"
    );

    let wrapper = wrapper.unwrap();
    assert!(
        wrapper.is_installed(),
        "is_installed() should return true when cargo-mutants is in PATH"
    );
}

#[test]
fn test_wrapper_new_error_message_when_not_installed() {
    // RED Phase Test 2: Error handling when cargo-mutants is not installed
    // Expected: Should return graceful error with installation instructions

    // This test can only run when cargo-mutants is NOT installed
    // For now, we verify that initialization always succeeds (doesn't panic)

    let wrapper = CargoMutantsWrapper::new();

    // Should always initialize successfully (doesn't panic)
    assert!(
        wrapper.is_ok(),
        "Wrapper should initialize gracefully even when cargo-mutants not found"
    );

    // If cargo-mutants IS installed, we can't test the "not installed" scenario
    // This would require environment mocking (future enhancement)
    // For now, just verify wrapper initialized successfully
}

#[test]
fn test_detect_cargo_mutants_in_path() {
    // RED Phase Test 3: PATH detection functionality
    // Expected: Should correctly detect cargo-mutants binary location

    let wrapper = CargoMutantsWrapper::new().expect("Failed to create wrapper");

    if wrapper.is_installed() {
        assert!(
            wrapper.cargo_mutants_path().is_some(),
            "cargo_mutants_path should be Some when installed"
        );

        let path = wrapper.cargo_mutants_path().unwrap();
        // cargo-mutants is a cargo subcommand, so we store "cargo" as the path
        assert!(
            path.to_string_lossy().contains("cargo"),
            "Path should contain 'cargo'"
        );
    }
}

#[test]

fn test_execute_cargo_mutants_version() {
    // RED Phase Test 4: Basic subprocess execution (--version)
    // Expected: Should execute cargo-mutants --version and return output

    let wrapper = CargoMutantsWrapper::new().expect("Failed to create wrapper");

    if wrapper.is_installed() {
        let version = wrapper.version();
        assert!(
            version.is_ok(),
            "version() should succeed when cargo-mutants is installed"
        );

        let version_string = version.unwrap();
        assert!(
            !version_string.is_empty(),
            "Version string should not be empty"
        );
        assert!(
            version_string.contains("cargo-mutants"),
            "Version output should mention cargo-mutants"
        );
    }
}

#[test]

fn test_version_check_requires_24_7_0_minimum() {
    // RED Phase Test 5: Version validation
    // Expected: Should enforce minimum version v24.7.0

    let wrapper = CargoMutantsWrapper::new().expect("Failed to create wrapper");

    if wrapper.is_installed() {
        let version = wrapper.version().expect("Failed to get version");

        // Parse version (example: "cargo-mutants 24.7.1")
        let version_parts: Vec<&str> = version.split_whitespace().collect();
        assert!(
            version_parts.len() >= 2,
            "Version should have at least 2 parts"
        );

        let version_number = version_parts[1];
        let parts: Vec<&str> = version_number.split('.').collect();
        assert!(
            parts.len() >= 2,
            "Version should have major.minor at minimum"
        );

        let major: u32 = parts[0].parse().expect("Major version should be a number");
        let minor: u32 = parts[1].parse().expect("Minor version should be a number");

        // Enforce minimum v24.7.0
        assert!(major >= 24, "Major version should be at least 24");
        if major == 24 {
            assert!(minor >= 7, "Minor version should be at least 7 for v24.x");
        }
    }
}

#[test]

fn test_wrapper_initialization_is_idempotent() {
    // RED Phase Test 6: Idempotency check
    // Expected: Calling new() multiple times should return same PATH

    let wrapper1 = CargoMutantsWrapper::new().expect("First initialization failed");
    let wrapper2 = CargoMutantsWrapper::new().expect("Second initialization failed");

    assert_eq!(
        wrapper1.cargo_mutants_path(),
        wrapper2.cargo_mutants_path(),
        "Multiple calls to new() should detect same cargo-mutants path"
    );
}

#[test]

fn test_error_messages_include_installation_instructions() {
    // RED Phase Test 7: Error message quality
    // Expected: Errors should include actionable installation instructions

    // This test would need to mock PATH environment to simulate not installed
    // For now, we'll test the error message format when cargo-mutants is not found

    let error_message = "cargo-mutants not found in PATH\nInstall: cargo install cargo-mutants";

    assert!(
        error_message.contains("cargo install cargo-mutants"),
        "Error message should include installation command"
    );
    assert!(
        error_message.contains("PATH"),
        "Error message should mention PATH"
    );
}

// ============================================================================
// RED PHASE TESTS - Edge Cases
// ============================================================================

#[test]

fn test_wrapper_handles_multiple_cargo_mutants_in_path() {
    // RED Phase Test 8: Handle edge case of multiple installations
    // Expected: Should pick the first one in PATH (standard behavior)

    let result = CargoMutantsWrapper::new();

    // Should not panic even if multiple cargo-mutants exist in PATH
    assert!(result.is_ok());
}

#[test]

fn test_wrapper_handles_permission_denied() {
    // RED Phase Test 9: Handle permission errors
    // Expected: Should gracefully handle permission denied errors

    // This would require mocking file permissions
    // For now, just ensure initialization doesn't panic
    let wrapper = CargoMutantsWrapper::new();
    assert!(
        wrapper.is_ok(),
        "Should handle permission errors gracefully"
    );
}

#[test]

fn test_wrapper_handles_corrupted_binary() {
    // RED Phase Test 10: Handle corrupted/invalid binary
    // Expected: version() should fail with clear error message

    // This would require mocking a corrupted binary
    // For now, test that version() returns Result (can fail)
    let wrapper = CargoMutantsWrapper::new().expect("Failed to create wrapper");

    if wrapper.is_installed() {
        // version() should return Result<String, Error>, allowing for failure
        let version_result = wrapper.version();
        assert!(
            version_result.is_ok() || version_result.is_err(),
            "version() should return Result type"
        );
    }
}

// ============================================================================
// RED PHASE - Property Tests (Placeholder)
// ============================================================================
// Property tests will be added in a separate file: cargo_mutants_property_tests.rs

#[test]
#[ignore] // Property tests require proptest crate
fn proptest_wrapper_initialization_idempotent() {
    // Property: new() called N times should always return same path
    // Implementation: See cargo_mutants_property_tests.rs
    todo!("Property test: wrapper initialization idempotent (requires proptest)");
}

#[test]
#[ignore] // Property tests require proptest crate
fn proptest_version_parsing_handles_all_semver_formats() {
    // Property: Version parsing should handle all semver formats
    // Implementation: See cargo_mutants_property_tests.rs
    todo!("Property test: version parsing (requires proptest)");
}

#[test]
#[ignore] // Property tests require proptest crate
fn proptest_error_messages_always_include_installation_instructions() {
    // Property: All error messages should include installation instructions
    // Implementation: See cargo_mutants_property_tests.rs
    todo!("Property test: error messages (requires proptest)");
}

// ============================================================================
// RED PHASE - Integration Tests (Placeholder)
// ============================================================================
// Integration tests will be added in a separate file: cargo_mutants_integration_tests.rs

#[test]
#[ignore] // Integration test
fn integration_test_full_wrapper_workflow() {
    // Integration test: new() → version() → is_installed()
    // Implementation: See cargo_mutants_integration_tests.rs
    todo!("Integration test: full wrapper workflow");
}

// ============================================================================
// RED PHASE SUMMARY
// ============================================================================
// Total Tests: 13 unit tests + 3 property test placeholders + 1 integration test placeholder
// Expected Status: ALL SHOULD FAIL (unimplemented!)
//
// Next Phase: GREEN (implement minimal CargoMutantsWrapper to pass these tests)