Files
headquarter/apps/api/tests/unit/test_git_operations.py
T
Developer c26e9eacfa feat: complete workspace-first-ui cleanup and tests
- Delete dead repo-workspace code: RepoWorkspacePage, useRepoWorkspace,
  WorkspaceLayout, FileBrowser, old git components (git-toolbar, file-editor,
  commit-panel), and repo-workspace.css.
- Fix stale backend test imports for moved models/services.
- Add GitOperations unit tests.
- Add integration tests for workspace files, git, and instances endpoints.
- Add frontend tests for WorkspaceDetailPage and ProjectCard.
- Update OpenSpec workspace-first-ui tasks and mark change completed.
- Regenerate project maps.

Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed),
python3 -m py_compile on changed backend files, pytest backend workspace tests.
2026-06-12 17:25:09 +00:00

134 lines
4.3 KiB
Python

"""Unit tests for GitOperations."""
import asyncio
import os
import subprocess
import tempfile
import pytest
from src.models import Workspace
from src.services.git.git_operations import GitOperations
def _run_git(*args: str, cwd: str) -> None:
subprocess.run(["git", *args], cwd=cwd, check=True, capture_output=True)
@pytest.fixture
def temp_workspace():
"""Create a temporary git workspace."""
with tempfile.TemporaryDirectory() as tmpdir:
_run_git("init", cwd=tmpdir)
_run_git("config", "user.email", "test@test.com", cwd=tmpdir)
_run_git("config", "user.name", "Test User", cwd=tmpdir)
readme = os.path.join(tmpdir, "README.md")
with open(readme, "w") as f:
f.write("# Test\n")
_run_git("add", "README.md", cwd=tmpdir)
_run_git("commit", "-m", "Initial commit", cwd=tmpdir)
ws = Workspace(
id="00000000-0000-0000-0000-000000000001",
name="test-ws",
repo_id="00000000-0000-0000-0000-000000000002",
user_id="00000000-0000-0000-0000-000000000003",
branch="main",
path=tmpdir,
)
yield ws
class TestGitOperationsStatus:
"""Tests for GitOperations.status."""
def test_status_clean(self, temp_workspace: Workspace):
git = GitOperations(temp_workspace)
status = asyncio.run(git.status())
assert status.branch == "main"
assert status.modified == []
assert status.added == []
assert status.deleted == []
assert status.untracked == []
def test_status_modified(self, temp_workspace: Workspace):
with open(os.path.join(temp_workspace.path, "README.md"), "a") as f:
f.write("modified\n")
git = GitOperations(temp_workspace)
status = asyncio.run(git.status())
assert "README.md" in status.modified
def test_status_untracked(self, temp_workspace: Workspace):
with open(os.path.join(temp_workspace.path, "new.py"), "w") as f:
f.write("print('hello')\n")
git = GitOperations(temp_workspace)
status = asyncio.run(git.status())
assert "new.py" in status.untracked
class TestGitOperationsCommit:
"""Tests for GitOperations.commit."""
def test_commit_stages_and_commits(self, temp_workspace: Workspace):
with open(os.path.join(temp_workspace.path, "new.py"), "w") as f:
f.write("print('hello')\n")
git = GitOperations(temp_workspace)
asyncio.run(git.commit("Add new file"))
status = asyncio.run(git.status())
assert "new.py" not in status.untracked
assert "new.py" not in status.added
history = asyncio.run(git.history())
assert history[0].message == "Add new file"
def test_commit_fails_without_changes(self, temp_workspace: Workspace):
git = GitOperations(temp_workspace)
with pytest.raises(RuntimeError):
asyncio.run(git.commit("Nothing to commit"))
class TestGitOperationsHistory:
"""Tests for GitOperations.history."""
def test_history_returns_commits(self, temp_workspace: Workspace):
git = GitOperations(temp_workspace)
history = asyncio.run(git.history())
assert len(history) >= 1
assert history[0].message == "Initial commit"
def test_history_filters_by_path(self, temp_workspace: Workspace):
with open(os.path.join(temp_workspace.path, "new.py"), "w") as f:
f.write("print('hello')\n")
git = GitOperations(temp_workspace)
asyncio.run(git.commit("Add new file"))
history = asyncio.run(git.history(path="new.py"))
assert len(history) == 1
assert history[0].message == "Add new file"
class TestGitOperationsBranches:
"""Tests for GitOperations.branches."""
def test_branches_lists_main(self, temp_workspace: Workspace):
git = GitOperations(temp_workspace)
branches, current = asyncio.run(git.branches())
assert "main" in branches
assert current == "main"
def test_checkout_switches_branch(self, temp_workspace: Workspace):
_run_git("checkout", "-b", "feature", cwd=temp_workspace.path)
_run_git("checkout", "main", cwd=temp_workspace.path)
git = GitOperations(temp_workspace)
asyncio.run(git.checkout("feature"))
status = asyncio.run(git.status())
assert status.branch == "feature"