sal-git 0.1.0

SAL Git - Git repository management and operations
Documentation
use sal_git::*;
use std::env;

#[test]
fn test_git_executor_initialization() {
    let mut executor = GitExecutor::new();

    // Test that executor can be initialized without panicking
    // Even if Redis is not available, init should handle it gracefully
    let result = executor.init();
    assert!(
        result.is_ok(),
        "GitExecutor init should handle Redis unavailability gracefully"
    );
}

#[test]
fn test_redis_connection_fallback() {
    // Test that GitExecutor handles Redis connection failures gracefully
    // Set an invalid Redis URL to force connection failure
    env::set_var("REDIS_URL", "redis://invalid-host:9999/0");

    let mut executor = GitExecutor::new();
    let result = executor.init();

    // Should succeed even with invalid Redis URL (graceful fallback)
    assert!(
        result.is_ok(),
        "GitExecutor should handle Redis connection failures gracefully"
    );

    // Cleanup
    env::remove_var("REDIS_URL");
}

#[test]
fn test_environment_variable_precedence() {
    // Test REDIS_URL takes precedence over SAL_REDIS_URL
    env::set_var("REDIS_URL", "redis://primary:6379/0");
    env::set_var("SAL_REDIS_URL", "redis://fallback:6379/1");

    // Create executor - should use REDIS_URL (primary)
    let mut executor = GitExecutor::new();
    let result = executor.init();

    // Should succeed (even if connection fails, init handles it gracefully)
    assert!(
        result.is_ok(),
        "GitExecutor should handle environment variables correctly"
    );

    // Test with only SAL_REDIS_URL
    env::remove_var("REDIS_URL");
    let mut executor2 = GitExecutor::new();
    let result2 = executor2.init();
    assert!(
        result2.is_ok(),
        "GitExecutor should use SAL_REDIS_URL as fallback"
    );

    // Cleanup
    env::remove_var("SAL_REDIS_URL");
}

#[test]
fn test_git_command_argument_validation() {
    let executor = GitExecutor::new();

    // Test with empty arguments
    let result = executor.execute(&[]);
    assert!(result.is_err(), "Empty git command should fail");

    // Test with invalid git command
    let result = executor.execute(&["invalid-command"]);
    assert!(result.is_err(), "Invalid git command should fail");

    // Test with malformed URL (should fail due to URL validation, not injection)
    let result = executor.execute(&["clone", "not-a-url"]);
    assert!(result.is_err(), "Invalid URL should be rejected");
}

#[test]
fn test_git_executor_with_valid_commands() {
    let executor = GitExecutor::new();

    // Test git version command (should work if git is available)
    let result = executor.execute(&["--version"]);

    match result {
        Ok(output) => {
            // If git is available, version should be in output
            let output_str = String::from_utf8_lossy(&output.stdout);
            assert!(
                output_str.contains("git version"),
                "Git version output should contain 'git version'"
            );
        }
        Err(_) => {
            // If git is not available, that's acceptable in test environment
            println!("Note: Git not available in test environment");
        }
    }
}

#[test]
fn test_credential_helper_environment_setup() {
    use std::process::Command;

    // Test that we can create and execute a simple credential helper script
    let temp_dir = std::env::temp_dir();
    let helper_script = temp_dir.join("test_git_helper");

    // Create a test credential helper script
    let script_content = "#!/bin/bash\necho username=testuser\necho password=testpass\n";

    // Write the helper script
    let write_result = std::fs::write(&helper_script, script_content);
    assert!(
        write_result.is_ok(),
        "Should be able to write credential helper script"
    );

    // Make it executable (Unix only)
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let mut perms = std::fs::metadata(&helper_script).unwrap().permissions();
        perms.set_mode(0o755);
        let perm_result = std::fs::set_permissions(&helper_script, perms);
        assert!(
            perm_result.is_ok(),
            "Should be able to set script permissions"
        );
    }

    // Test that the script can be executed
    #[cfg(unix)]
    {
        let output = Command::new(&helper_script).output();
        match output {
            Ok(output) => {
                let stdout = String::from_utf8_lossy(&output.stdout);
                assert!(
                    stdout.contains("username=testuser"),
                    "Script should output username"
                );
                assert!(
                    stdout.contains("password=testpass"),
                    "Script should output password"
                );
            }
            Err(_) => {
                println!("Note: Could not execute credential helper script (shell not available)");
            }
        }
    }

    // Clean up
    let _ = std::fs::remove_file(&helper_script);
}

#[test]
fn test_redis_url_masking() {
    // Test that sensitive Redis URLs are properly masked for logging
    // This tests the internal URL masking functionality

    // Test URLs with passwords
    let test_cases = vec![
        ("redis://user:password@localhost:6379/0", true),
        ("redis://localhost:6379/0", false),
        ("redis://user@localhost:6379/0", false),
        ("invalid-url", false),
    ];

    for (url, has_password) in test_cases {
        // Set the Redis URL and create executor
        std::env::set_var("REDIS_URL", url);

        let mut executor = GitExecutor::new();
        let result = executor.init();

        // Should always succeed (graceful handling of connection failures)
        assert!(result.is_ok(), "GitExecutor should handle URL: {}", url);

        // The actual masking happens internally during logging
        // We can't easily test the log output, but we verify the executor handles it
        if has_password {
            println!(
                "Note: Tested URL with password (should be masked in logs): {}",
                url
            );
        }
    }

    // Cleanup
    std::env::remove_var("REDIS_URL");
}