"""Tests for hooks.py - git hook install/uninstall.""" import subprocess from pathlib import Path import pytest from graphify.hooks import install, uninstall, status, _HOOK_MARKER, _CHECKOUT_MARKER def _make_git_repo(tmp_path: Path) -> Path: subprocess.run(["git", "init", str(tmp_path)], check=True, capture_output=True) return tmp_path def test_install_creates_hook(tmp_path): repo = _make_git_repo(tmp_path) result = install(repo) hook = repo / ".git" / "hooks" / "post-commit" assert hook.exists() assert _HOOK_MARKER in hook.read_text() assert "installed" in result def test_install_is_executable(tmp_path): repo = _make_git_repo(tmp_path) install(repo) hook = repo / ".git" / "hooks" / "post-commit" assert hook.stat().st_mode & 0o111 # executable bit set def test_install_idempotent(tmp_path): repo = _make_git_repo(tmp_path) install(repo) result = install(repo) assert "already installed" in result # marker appears only once hook = repo / ".git" / "hooks" / "post-commit" assert hook.read_text().count(_HOOK_MARKER) == 1 def test_install_appends_to_existing_hook(tmp_path): repo = _make_git_repo(tmp_path) hook = repo / ".git" / "hooks" / "post-commit" hook.write_text("#!/bin/bash\necho existing\n") hook.chmod(0o755) install(repo) content = hook.read_text() assert "existing" in content assert _HOOK_MARKER in content def test_uninstall_removes_hook(tmp_path): repo = _make_git_repo(tmp_path) install(repo) result = uninstall(repo) hook = repo / ".git" / "hooks" / "post-commit" assert not hook.exists() assert "removed" in result.lower() def test_uninstall_no_hook(tmp_path): repo = _make_git_repo(tmp_path) result = uninstall(repo) assert "nothing to remove" in result def test_status_installed(tmp_path): repo = _make_git_repo(tmp_path) install(repo) result = status(repo) assert "installed" in result def test_status_not_installed(tmp_path): repo = _make_git_repo(tmp_path) result = status(repo) assert "not installed" in result def test_no_git_repo_raises(tmp_path): with pytest.raises(RuntimeError, match="No git repository"): install(tmp_path / "not_a_repo") def test_install_creates_post_checkout_hook(tmp_path): repo = _make_git_repo(tmp_path) install(repo) hook = repo / ".git" / "hooks" / "post-checkout" assert hook.exists() assert _CHECKOUT_MARKER in hook.read_text() def test_install_post_checkout_is_executable(tmp_path): repo = _make_git_repo(tmp_path) install(repo) hook = repo / ".git" / "hooks" / "post-checkout" assert hook.stat().st_mode & 0o111 def test_uninstall_removes_post_checkout_hook(tmp_path): repo = _make_git_repo(tmp_path) install(repo) uninstall(repo) hook = repo / ".git" / "hooks" / "post-checkout" assert not hook.exists() def test_status_shows_both_hooks(tmp_path): repo = _make_git_repo(tmp_path) install(repo) result = status(repo) assert "post-commit" in result assert "post-checkout" in result assert result.count("installed") >= 2