sal-os 0.1.2

SAL OS - Operating system interaction utilities with cross-platform abstraction
Documentation
use sal_os::package::{PackHero, Platform};

#[test]
fn test_pack_hero_creation() {
    // Test that we can create a PackHero instance
    let hero = PackHero::new();

    // Test that platform detection works
    let platform = hero.platform();
    match platform {
        Platform::Ubuntu | Platform::MacOS | Platform::Unknown => {
            // All valid platforms
        }
    }
}

#[test]
fn test_platform_detection() {
    let hero = PackHero::new();
    let platform = hero.platform();

    // Platform should be deterministic
    let platform2 = hero.platform();
    assert_eq!(format!("{:?}", platform), format!("{:?}", platform2));

    // Test platform display
    match platform {
        Platform::Ubuntu => {
            assert_eq!(format!("{:?}", platform), "Ubuntu");
        }
        Platform::MacOS => {
            assert_eq!(format!("{:?}", platform), "MacOS");
        }
        Platform::Unknown => {
            assert_eq!(format!("{:?}", platform), "Unknown");
        }
    }
}

#[test]
fn test_debug_mode() {
    let mut hero = PackHero::new();

    // Test setting debug mode
    hero.set_debug(true);
    hero.set_debug(false);

    // Debug mode setting should not panic
}

#[test]
fn test_package_operations_error_handling() {
    let hero = PackHero::new();

    // Test with invalid package name
    let result = hero.is_installed("nonexistent-package-12345-xyz");
    // This should return a result (either Ok(false) or Err)
    // Validate that we get a proper result type
    match result {
        Ok(is_installed) => {
            // Should return false for non-existent package
            assert!(
                !is_installed,
                "Non-existent package should not be reported as installed"
            );
        }
        Err(_) => {
            // Error is also acceptable (e.g., no package manager available)
            // The important thing is it doesn't panic
        }
    }

    // Test install with invalid package
    let result = hero.install("nonexistent-package-12345-xyz");
    // This should return an error
    assert!(result.is_err());

    // Test remove with invalid package
    let result = hero.remove("nonexistent-package-12345-xyz");
    // This might succeed (if package wasn't installed) or fail
    // Validate that we get a proper result type
    match result {
        Ok(_) => {
            // Success is acceptable (package wasn't installed)
        }
        Err(err) => {
            // Error is also acceptable
            // Verify error message is meaningful
            let error_msg = err.to_string();
            assert!(!error_msg.is_empty(), "Error message should not be empty");
        }
    }
}

#[test]
fn test_package_search_basic() {
    let hero = PackHero::new();

    // Test search with empty query
    let result = hero.search("");
    // Should handle empty query gracefully
    // Validate that we get a proper result type
    match result {
        Ok(packages) => {
            // Empty search might return all packages or empty list
            // Verify the result is a valid vector
            assert!(
                packages.len() < 50000,
                "Empty search returned unreasonably large result"
            );
        }
        Err(err) => {
            // Error is acceptable for empty query
            let error_msg = err.to_string();
            assert!(!error_msg.is_empty(), "Error message should not be empty");
        }
    }

    // Test search with very specific query that likely won't match
    let result = hero.search("nonexistent-package-xyz-12345");
    if let Ok(packages) = result {
        // If search succeeded, it should return a vector
        // The vector should be valid (we can get its length)
        let _count = packages.len();
        // Search results should be reasonable (not absurdly large)
        assert!(
            packages.len() < 10000,
            "Search returned unreasonably large result set"
        );
    }
    // If search failed, that's also acceptable
}

#[test]
fn test_package_list_basic() {
    let hero = PackHero::new();

    // Test listing installed packages
    let result = hero.list_installed();
    if let Ok(packages) = result {
        // If listing succeeded, it should return a vector
        // On most systems, there should be at least some packages installed
        println!("Found {} installed packages", packages.len());
    }
    // If listing failed (e.g., no package manager available), that's acceptable
}

#[test]
fn test_package_update_basic() {
    let hero = PackHero::new();

    // Test package list update
    let result = hero.update();
    // This might succeed or fail depending on permissions and network
    // Validate that we get a proper result type
    match result {
        Ok(_) => {
            // Success is good - package list was updated
        }
        Err(err) => {
            // Error is acceptable (no permissions, no network, etc.)
            let error_msg = err.to_string();
            assert!(!error_msg.is_empty(), "Error message should not be empty");
            // Common error patterns we expect
            let error_lower = error_msg.to_lowercase();
            assert!(
                error_lower.contains("permission")
                    || error_lower.contains("network")
                    || error_lower.contains("command")
                    || error_lower.contains("not found")
                    || error_lower.contains("failed"),
                "Error message should indicate a reasonable failure cause: {}",
                error_msg
            );
        }
    }
}

#[test]
#[ignore] // Skip by default as this can take a very long time and modify the system
fn test_package_upgrade_basic() {
    let hero = PackHero::new();

    // Test package upgrade (this is a real system operation)
    let result = hero.upgrade();
    // Validate that we get a proper result type
    match result {
        Ok(_) => {
            // Success means packages were upgraded
            println!("Package upgrade completed successfully");
        }
        Err(err) => {
            // Error is acceptable (no permissions, no packages to upgrade, etc.)
            let error_msg = err.to_string();
            assert!(!error_msg.is_empty(), "Error message should not be empty");
            println!("Package upgrade failed as expected: {}", error_msg);
        }
    }
}

#[test]
fn test_package_upgrade_interface() {
    // Test that the upgrade interface works without actually upgrading
    let hero = PackHero::new();

    // Verify that PackHero has the upgrade method and it returns the right type
    // This tests the interface without performing the actual upgrade
    let _upgrade_fn = PackHero::upgrade;

    // Test that we can call upgrade (it will likely fail due to permissions/network)
    // but we're testing that the interface works correctly
    let result = hero.upgrade();

    // The result should be a proper Result type
    match result {
        Ok(_) => {
            // Upgrade succeeded (unlikely in test environment)
        }
        Err(err) => {
            // Expected in most test environments
            // Verify error is meaningful
            let error_msg = err.to_string();
            assert!(!error_msg.is_empty(), "Error should have a message");
            assert!(error_msg.len() > 5, "Error message should be descriptive");
        }
    }
}

// Platform-specific tests
#[cfg(target_os = "linux")]
#[test]
fn test_linux_platform_detection() {
    let hero = PackHero::new();
    let platform = hero.platform();

    // On Linux, should detect Ubuntu or Unknown (if not Ubuntu-based)
    match platform {
        Platform::Ubuntu | Platform::Unknown => {
            // Expected on Linux
        }
        Platform::MacOS => {
            panic!("Should not detect macOS on Linux system");
        }
    }
}

#[cfg(target_os = "macos")]
#[test]
fn test_macos_platform_detection() {
    let hero = PackHero::new();
    let platform = hero.platform();

    // On macOS, should detect MacOS
    match platform {
        Platform::MacOS => {
            // Expected on macOS
        }
        Platform::Ubuntu | Platform::Unknown => {
            panic!("Should detect macOS on macOS system, got {:?}", platform);
        }
    }
}

// Integration tests that require actual package managers
// These are marked with ignore so they don't run by default

#[test]
#[ignore]
fn test_real_package_check() {
    let hero = PackHero::new();

    // Test with a package that's commonly installed
    #[cfg(target_os = "linux")]
    let test_package = "bash";

    #[cfg(target_os = "macos")]
    let test_package = "bash";

    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
    let test_package = "unknown";

    let result = hero.is_installed(test_package);
    if let Ok(is_installed) = result {
        println!("Package '{}' is installed: {}", test_package, is_installed);
    } else {
        println!(
            "Failed to check if '{}' is installed: {:?}",
            test_package, result
        );
    }
}

#[test]
#[ignore]
fn test_real_package_search() {
    let hero = PackHero::new();

    // Search for a common package
    let result = hero.search("git");
    if let Ok(packages) = result {
        println!("Found {} packages matching 'git'", packages.len());
        if !packages.is_empty() {
            println!(
                "First few matches: {:?}",
                &packages[..std::cmp::min(5, packages.len())]
            );
        }
    } else {
        println!("Package search failed: {:?}", result);
    }
}

#[test]
#[ignore]
fn test_real_package_list() {
    let hero = PackHero::new();

    // List installed packages
    let result = hero.list_installed();
    if let Ok(packages) = result {
        println!("Total installed packages: {}", packages.len());
        if !packages.is_empty() {
            println!(
                "First few packages: {:?}",
                &packages[..std::cmp::min(10, packages.len())]
            );
        }
    } else {
        println!("Package listing failed: {:?}", result);
    }
}

#[test]
fn test_platform_enum_properties() {
    // Test that Platform enum can be compared
    assert_eq!(Platform::Ubuntu, Platform::Ubuntu);
    assert_eq!(Platform::MacOS, Platform::MacOS);
    assert_eq!(Platform::Unknown, Platform::Unknown);

    assert_ne!(Platform::Ubuntu, Platform::MacOS);
    assert_ne!(Platform::Ubuntu, Platform::Unknown);
    assert_ne!(Platform::MacOS, Platform::Unknown);
}

#[test]
fn test_pack_hero_multiple_instances() {
    // Test that multiple PackHero instances work correctly
    let hero1 = PackHero::new();
    let hero2 = PackHero::new();

    // Both should detect the same platform
    assert_eq!(
        format!("{:?}", hero1.platform()),
        format!("{:?}", hero2.platform())
    );

    // Both should handle debug mode independently
    let mut hero1_mut = hero1;
    let mut hero2_mut = hero2;

    hero1_mut.set_debug(true);
    hero2_mut.set_debug(false);

    // No assertions here since debug mode doesn't have observable effects in tests
    // But this ensures the API works correctly
}