guardy 0.2.4

Fast, secure git hooks in Rust with secret scanning and protected file synchronization
Documentation
use guardy::{
    config::{CONFIG, sync::RepoConfig},
    sync::manager::SyncManager,
};

/// Test that SyncManager respects configuration settings
#[tokio::test]
async fn test_sync_manager_uses_config() {
    // Test that SyncManager uses the cache_dir from config
    let manager = SyncManager::new().expect("Failed to create SyncManager");

    // The cache directory should match the default config value
    let expected_cache = std::env::current_dir()
        .expect("Failed to get current dir")
        .join(&CONFIG.sync.cache_dir);

    assert_eq!(
        manager
            .get_cache_dir()
            .canonicalize()
            .unwrap_or_else(|_| manager.get_cache_dir().clone()),
        expected_cache.canonicalize().unwrap_or(expected_cache),
        "SyncManager should use cache_dir from config"
    );
}

/// Test repo name extraction
#[test]
fn test_repo_name_extraction() {
    let manager = SyncManager::new().expect("Failed to create SyncManager");

    // Test various repo URL formats
    assert_eq!(
        manager.extract_repo_name("https://github.com/user/repo.git"),
        "repo"
    );

    assert_eq!(
        manager.extract_repo_name("https://github.com/user/repo"),
        "repo"
    );

    assert_eq!(
        manager.extract_repo_name("git@github.com:user/repo.git"),
        "repo" // .git suffix is stripped from all URL formats
    );

    assert_eq!(
        manager.extract_repo_name("https://gitlab.com/group/subgroup/project"),
        "project"
    );
}

/// Test sync status with empty configuration
#[tokio::test]
async fn test_sync_status_no_config() {
    // Ensure we have empty repos config for this test
    if !CONFIG.sync.repolist.is_empty() {
        // Skip this test if there's actual config loaded
        return;
    }

    let manager = SyncManager::new().expect("Failed to create SyncManager");
    let status = manager
        .check_sync_status()
        .expect("Failed to check sync status");

    // Should return NotConfigured when no repos are configured
    matches!(status, guardy::sync::SyncStatus::NotConfigured);
}

/// Test that sync manager handles repo config structure correctly
#[test]
fn test_repo_config_structure() {
    let repo_config = RepoConfig {
        name: "test-repo".into(),
        repo: "https://github.com/user/test-repo.git".into(),
        version: "main".into(),
        source_path: "configs".into(),
        dest_path: ".".into(),
        include: vec!["*.yaml".to_string(), "*.toml".to_string()],
        exclude: vec!["*.tmp".to_string()],
        protected: true,
    };

    // Test serialization/deserialization
    let json = serde_json::to_string(&repo_config).expect("Failed to serialize RepoConfig");
    let deserialized: RepoConfig =
        serde_json::from_str(&json).expect("Failed to deserialize RepoConfig");

    assert_eq!(repo_config.name, deserialized.name);
    assert_eq!(repo_config.repo, deserialized.repo);
    assert_eq!(repo_config.version, deserialized.version);
    assert_eq!(repo_config.source_path, deserialized.source_path);
    assert_eq!(repo_config.dest_path, deserialized.dest_path);
    assert_eq!(repo_config.include, deserialized.include);
    assert_eq!(repo_config.exclude, deserialized.exclude);
    assert_eq!(repo_config.protected, deserialized.protected);
}

/// Test that RepoConfig has sensible defaults
#[test]
fn test_repo_config_defaults() {
    let minimal_json = r#"{
        "name": "test",
        "repo": "https://github.com/user/test.git",
        "version": "main",
        "source_path": "src",
        "dest_path": "."
    }"#;

    let config: RepoConfig =
        serde_json::from_str(minimal_json).expect("Failed to parse minimal RepoConfig");

    // Test that optional fields have correct defaults
    assert!(
        config.include.is_empty(),
        "include should default to empty vec"
    );
    assert!(
        config.exclude.is_empty(),
        "exclude should default to empty vec"
    );
    assert!(!config.protected, "protected should default to false");
}