"""Tests for git utilities."""
import subprocess
from pathlib import Path
import pytest
from ccsession.parsers.git import GitUtils, GitState
def test_git_utils_is_git_repo(mock_git_repo):
"""Test detection of git repository."""
git = GitUtils(mock_git_repo)
assert git.is_git_repo() is True
# Non-git directory
git_non_repo = GitUtils("/tmp")
assert git_non_repo.is_git_repo() is False
def test_git_utils_get_current_branch(mock_git_repo):
"""Test getting current branch name."""
git = GitUtils(mock_git_repo)
branch = git.get_current_branch()
assert branch == "feat-auth"
def test_git_utils_get_project_root(mock_git_repo):
"""Test getting project root."""
git = GitUtils(mock_git_repo)
root = git.get_project_root()
assert root == mock_git_repo
def test_git_utils_get_state_clean(mock_git_repo):
"""Test getting git state with clean working directory."""
git = GitUtils(mock_git_repo)
state = git.get_state()
assert state.is_git_repo is True
assert state.branch == "feat-auth"
assert state.has_uncommitted_changes is False
assert state.uncommitted_file_count == 0
def test_git_utils_get_state_with_changes(mock_git_repo_with_changes):
"""Test getting git state with uncommitted changes."""
git = GitUtils(mock_git_repo_with_changes)
state = git.get_state()
assert state.is_git_repo is True
assert state.branch == "feat-auth"
assert state.has_uncommitted_changes is True
assert state.uncommitted_file_count == 1
def test_git_utils_get_state_non_git(tmp_path):
"""Test getting git state in non-git directory."""
git = GitUtils(tmp_path)
state = git.get_state()
assert state.is_git_repo is False
assert state.branch is None
assert state.has_uncommitted_changes is False
def test_git_utils_get_recent_commits(mock_git_repo):
"""Test getting recent commits."""
# Add more commits
test_file = mock_git_repo / "test.txt"
test_file.write_text("updated content")
subprocess.run(["git", "add", "."], cwd=mock_git_repo, capture_output=True)
subprocess.run(
["git", "commit", "-m", "Second commit"],
cwd=mock_git_repo,
capture_output=True,
)
git = GitUtils(mock_git_repo)
commits = git.get_recent_commits(n=5)
assert len(commits) >= 2
assert commits[0].message == "Second commit"
assert commits[1].message == "Initial commit"
assert len(commits[0].sha) == 40 # Full SHA
def test_git_utils_get_recent_commits_with_since(mock_git_repo):
"""Test filtering commits by time."""
from datetime import datetime, timezone, timedelta
# Get commits since future (should be empty)
future = datetime.now(timezone.utc) + timedelta(days=1)
git = GitUtils(mock_git_repo)
commits = git.get_recent_commits(since=future)
assert len(commits) == 0
# Get commits since past (should include all)
past = datetime.now(timezone.utc) - timedelta(days=1)
commits = git.get_recent_commits(since=past)
assert len(commits) >= 1
def test_git_utils_get_context_dir(mock_git_repo, sample_plan_path):
"""Test getting .context directory path."""
git = GitUtils(mock_git_repo)
context_dir = git.get_context_dir()
expected = mock_git_repo / ".context" / "dev" / "feat-auth"
assert context_dir == expected
def test_git_utils_get_context_plan_path(mock_git_repo, sample_plan_path):
"""Test getting planning doc path."""
git = GitUtils(mock_git_repo)
plan_path = git.get_context_plan_path()
expected = mock_git_repo / ".context" / "dev" / "feat-auth" / "feat-auth-detailed-plan.md"
assert plan_path == expected
assert plan_path.exists()
def test_git_utils_get_context_plan_path_no_file(mock_git_repo):
"""Test getting planning doc path when file doesn't exist."""
git = GitUtils(mock_git_repo)
plan_path = git.get_context_plan_path()
# Should return None since file doesn't exist
assert plan_path is None
def test_git_utils_non_git_operations(tmp_path):
"""Test that git operations fail gracefully in non-git directory."""
git = GitUtils(tmp_path)
assert git.get_current_branch() is None
assert git.get_project_root() is None
assert git.get_recent_commits() == []
assert git.get_context_dir() is None
assert git.get_context_plan_path() is None