//! Tests for hooks system. use std::path::PathBuf; use std::time::Duration; use gitks::hooks::manager::{HookLevel, HookManager}; use gitks::hooks::sanitize::{validate_hook_content, validate_hook_name}; fn temp_repo() -> PathBuf { let dir = tempfile::tempdir().unwrap().path().to_path_buf(); // Create a bare git repo let _ = std::process::Command::new("git") .args(["init", "--bare"]) .arg(&dir) .output(); dir } #[test] fn test_validate_hook_name() { assert!(validate_hook_name("pre-receive").is_ok()); assert!(validate_hook_name("update").is_ok()); assert!(validate_hook_name("post-receive").is_ok()); assert!(validate_hook_name("commit-msg").is_ok()); assert!(validate_hook_name("invalid-hook").is_err()); assert!(validate_hook_name("").is_err()); assert!(validate_hook_name("random-name").is_err()); } #[test] fn test_validate_hook_content_safe() { assert!(validate_hook_content("#!/bin/sh\nexit 0").is_ok()); assert!(validate_hook_content("#!/bin/sh\necho 'hello'").is_ok()); } #[test] fn test_validate_hook_content_dangerous() { assert!(validate_hook_content("rm -rf /").is_err()); assert!(validate_hook_content("shutdown now").is_err()); assert!(validate_hook_content("chmod 777 /etc/passwd").is_err()); } #[test] fn test_validate_hook_content_size() { let large_content = "x".repeat(70000); assert!(validate_hook_content(&large_content).is_err()); } #[test] fn test_validate_hook_content_null_bytes() { assert!(validate_hook_content("test\0content").is_err()); } #[test] fn test_hook_manager_install_hooks() { let repo = temp_repo(); let prefix = repo.parent().unwrap().to_path_buf(); let hm = HookManager::new(prefix, None, None, Duration::from_secs(30), true); // Install hooks let result = hm.install_hooks(&repo); if result.is_ok() { // Check that hook files were created assert!(repo.join("hooks/pre-receive").exists()); assert!(repo.join("hooks/update").exists()); assert!(repo.join("hooks/post-receive").exists()); } // Installation may fail if git is not available; just check no panic } #[test] fn test_hook_manager_custom_hooks() { let repo = temp_repo(); let prefix = repo.parent().unwrap().to_path_buf(); let hm = HookManager::new(prefix, None, None, Duration::from_secs(30), true); // Set a custom hook let result = hm.set_custom_hook(&repo, "pre-receive", "#!/bin/sh\nexit 0"); if result.is_ok() { assert!(repo.join("custom_hooks/pre-receive/d").exists()); } // Remove custom hook let result = hm.remove_custom_hook(&repo, "pre-receive"); assert!(result.is_ok() || result.is_err()); // Just no panic } #[test] fn test_hook_manager_disallow_custom() { let repo = temp_repo(); let prefix = repo.parent().unwrap().to_path_buf(); let hm = HookManager::new( prefix, None, None, Duration::from_secs(30), false, // Disallow custom hooks ); let result = hm.set_custom_hook(&repo, "pre-receive", "#!/bin/sh\nexit 0"); assert!(result.is_err()); } #[test] fn test_hook_level_display() { assert_eq!(HookLevel::Server.to_string(), "server"); assert_eq!(HookLevel::Custom.to_string(), "custom"); }