refactor(tests): adjust formatting for consistency and readability
- Updated line breaks and indentation across test modules to enhance clarity and maintain consistent style. - Applied changes to workspace, provider, server, and GitWrapper-related test cases. No functional changes introduced.
This commit is contained in:
@@ -3,17 +3,22 @@ Tests for the git_wrapper module.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from git import GitCommandError
|
||||
|
||||
from exceptions import (
|
||||
BranchExistsError,
|
||||
BranchNotFoundError,
|
||||
CheckoutError,
|
||||
CloneError,
|
||||
CommitError,
|
||||
GitError,
|
||||
PullError,
|
||||
PushError,
|
||||
)
|
||||
from git_wrapper import GitWrapper
|
||||
from git_wrapper import GitWrapper, run_in_executor
|
||||
from models import FileChangeType
|
||||
|
||||
|
||||
@@ -116,7 +121,9 @@ class TestGitWrapperBranch:
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_branch_without_checkout(self, git_wrapper_with_repo):
|
||||
"""Test creating branch without checkout."""
|
||||
result = await git_wrapper_with_repo.create_branch("feature-no-checkout", checkout=False)
|
||||
result = await git_wrapper_with_repo.create_branch(
|
||||
"feature-no-checkout", checkout=False
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert result.branch == "feature-no-checkout"
|
||||
@@ -432,3 +439,505 @@ class TestGitWrapperStash:
|
||||
result = await git_wrapper_with_repo.stash()
|
||||
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stash_pop(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test popping a stash."""
|
||||
# Make changes and stash them
|
||||
readme = Path(git_repo.working_dir) / "README.md"
|
||||
original_content = readme.read_text()
|
||||
readme.write_text("Modified for stash pop test")
|
||||
git_repo.index.add(["README.md"])
|
||||
|
||||
stash_ref = await git_wrapper_with_repo.stash("Test stash for pop")
|
||||
|
||||
if stash_ref:
|
||||
# Pop the stash
|
||||
result = await git_wrapper_with_repo.stash_pop()
|
||||
assert result is True
|
||||
|
||||
|
||||
class TestGitWrapperRepoProperty:
|
||||
"""Tests for repo property edge cases."""
|
||||
|
||||
def test_repo_property_path_not_exists(self, test_settings):
|
||||
"""Test that accessing repo on non-existent path raises error."""
|
||||
wrapper = GitWrapper(
|
||||
Path("/nonexistent/path/that/does/not/exist"), test_settings
|
||||
)
|
||||
with pytest.raises(GitError, match="Path does not exist"):
|
||||
_ = wrapper.repo
|
||||
|
||||
def test_refresh_repo(self, git_wrapper_with_repo):
|
||||
"""Test _refresh_repo clears cached repo."""
|
||||
# Access repo to cache it
|
||||
_ = git_wrapper_with_repo.repo
|
||||
assert git_wrapper_with_repo._repo is not None
|
||||
|
||||
# Refresh should clear it
|
||||
git_wrapper_with_repo._refresh_repo()
|
||||
assert git_wrapper_with_repo._repo is None
|
||||
|
||||
|
||||
class TestGitWrapperBranchAdvanced:
|
||||
"""Advanced tests for branch operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_branch_from_ref(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test creating branch from specific ref."""
|
||||
# Get current HEAD SHA
|
||||
head_sha = git_repo.head.commit.hexsha
|
||||
|
||||
result = await git_wrapper_with_repo.create_branch(
|
||||
"feature-from-ref",
|
||||
from_ref=head_sha,
|
||||
checkout=False,
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert result.branch == "feature-from-ref"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_branch_force(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test force deleting a branch."""
|
||||
# Create branch and add unmerged commit
|
||||
await git_wrapper_with_repo.create_branch("unmerged-branch", checkout=True)
|
||||
new_file = Path(git_repo.working_dir) / "unmerged.txt"
|
||||
new_file.write_text("unmerged content")
|
||||
git_repo.index.add(["unmerged.txt"])
|
||||
git_repo.index.commit("Unmerged commit")
|
||||
|
||||
# Switch back to main
|
||||
await git_wrapper_with_repo.checkout("main")
|
||||
|
||||
# Force delete
|
||||
result = await git_wrapper_with_repo.delete_branch(
|
||||
"unmerged-branch", force=True
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
|
||||
|
||||
class TestGitWrapperListBranchesRemote:
|
||||
"""Tests for listing remote branches."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_branches_with_remote(self, git_wrapper_with_repo):
|
||||
"""Test listing branches including remote."""
|
||||
# Even without remotes, this should work
|
||||
result = await git_wrapper_with_repo.list_branches(include_remote=True)
|
||||
|
||||
assert result.current_branch == "main"
|
||||
# Remote branches list should be empty for local repo
|
||||
assert len(result.remote_branches) == 0
|
||||
|
||||
|
||||
class TestGitWrapperCheckoutAdvanced:
|
||||
"""Advanced tests for checkout operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_checkout_create_existing_error(self, git_wrapper_with_repo):
|
||||
"""Test error when creating branch that already exists."""
|
||||
with pytest.raises(BranchExistsError):
|
||||
await git_wrapper_with_repo.checkout("main", create_branch=True)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_checkout_force(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test force checkout discards local changes."""
|
||||
# Create branch
|
||||
await git_wrapper_with_repo.create_branch("force-test", checkout=False)
|
||||
|
||||
# Make local changes
|
||||
readme = Path(git_repo.working_dir) / "README.md"
|
||||
readme.write_text("local changes")
|
||||
|
||||
# Force checkout should work
|
||||
result = await git_wrapper_with_repo.checkout("force-test", force=True)
|
||||
|
||||
assert result.success is True
|
||||
|
||||
|
||||
class TestGitWrapperCommitAdvanced:
|
||||
"""Advanced tests for commit operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_commit_specific_files(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test committing specific files only."""
|
||||
# Create multiple files
|
||||
file1 = Path(git_repo.working_dir) / "commit_specific1.txt"
|
||||
file2 = Path(git_repo.working_dir) / "commit_specific2.txt"
|
||||
file1.write_text("content 1")
|
||||
file2.write_text("content 2")
|
||||
|
||||
result = await git_wrapper_with_repo.commit(
|
||||
"Commit specific file",
|
||||
files=["commit_specific1.txt"],
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert result.files_changed == 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_commit_with_partial_author(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test commit with only author name."""
|
||||
new_file = Path(git_repo.working_dir) / "partial_author.txt"
|
||||
new_file.write_text("content")
|
||||
|
||||
result = await git_wrapper_with_repo.commit(
|
||||
"Partial author commit",
|
||||
author_name="Test Author",
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_commit_allow_empty(self, git_wrapper_with_repo):
|
||||
"""Test allowing empty commits."""
|
||||
result = await git_wrapper_with_repo.commit(
|
||||
"Empty commit allowed",
|
||||
allow_empty=True,
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
|
||||
|
||||
class TestGitWrapperUnstageAdvanced:
|
||||
"""Advanced tests for unstaging operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unstage_specific_files(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test unstaging specific files."""
|
||||
# Create and stage files
|
||||
file1 = Path(git_repo.working_dir) / "unstage1.txt"
|
||||
file2 = Path(git_repo.working_dir) / "unstage2.txt"
|
||||
file1.write_text("content 1")
|
||||
file2.write_text("content 2")
|
||||
git_repo.index.add(["unstage1.txt", "unstage2.txt"])
|
||||
|
||||
count = await git_wrapper_with_repo.unstage(["unstage1.txt"])
|
||||
|
||||
assert count == 1
|
||||
|
||||
|
||||
class TestGitWrapperResetAdvanced:
|
||||
"""Advanced tests for reset operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reset_hard(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test hard reset."""
|
||||
# Create a commit
|
||||
file1 = Path(git_repo.working_dir) / "reset_hard.txt"
|
||||
file1.write_text("content")
|
||||
git_repo.index.add(["reset_hard.txt"])
|
||||
git_repo.index.commit("Commit for hard reset")
|
||||
|
||||
result = await git_wrapper_with_repo.reset("HEAD~1", mode="hard")
|
||||
|
||||
assert result is True
|
||||
# File should be gone after hard reset
|
||||
assert not file1.exists()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reset_specific_files(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test resetting specific files."""
|
||||
# Create and stage a file
|
||||
file1 = Path(git_repo.working_dir) / "reset_file.txt"
|
||||
file1.write_text("content")
|
||||
git_repo.index.add(["reset_file.txt"])
|
||||
|
||||
result = await git_wrapper_with_repo.reset("HEAD", files=["reset_file.txt"])
|
||||
|
||||
assert result is True
|
||||
|
||||
|
||||
class TestGitWrapperDiffAdvanced:
|
||||
"""Advanced tests for diff operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_diff_between_refs(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test diff between two refs."""
|
||||
# Create initial commit
|
||||
file1 = Path(git_repo.working_dir) / "diff_ref.txt"
|
||||
file1.write_text("initial")
|
||||
git_repo.index.add(["diff_ref.txt"])
|
||||
commit1 = git_repo.index.commit("First commit for diff")
|
||||
|
||||
# Create second commit
|
||||
file1.write_text("modified")
|
||||
git_repo.index.add(["diff_ref.txt"])
|
||||
commit2 = git_repo.index.commit("Second commit for diff")
|
||||
|
||||
result = await git_wrapper_with_repo.diff(
|
||||
base=commit1.hexsha,
|
||||
head=commit2.hexsha,
|
||||
)
|
||||
|
||||
assert result.files_changed > 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_diff_specific_files(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test diff for specific files only."""
|
||||
# Create files
|
||||
file1 = Path(git_repo.working_dir) / "diff_specific1.txt"
|
||||
file2 = Path(git_repo.working_dir) / "diff_specific2.txt"
|
||||
file1.write_text("content 1")
|
||||
file2.write_text("content 2")
|
||||
|
||||
result = await git_wrapper_with_repo.diff(files=["diff_specific1.txt"])
|
||||
|
||||
# Should only show changes for specified file
|
||||
for f in result.files:
|
||||
assert "diff_specific2.txt" not in f.get("path", "")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_diff_base_only(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test diff with base ref only (vs HEAD)."""
|
||||
# Create commit
|
||||
file1 = Path(git_repo.working_dir) / "diff_base.txt"
|
||||
file1.write_text("content")
|
||||
git_repo.index.add(["diff_base.txt"])
|
||||
commit = git_repo.index.commit("Commit for diff base test")
|
||||
|
||||
# Get parent commit
|
||||
parent = commit.parents[0] if commit.parents else commit
|
||||
|
||||
result = await git_wrapper_with_repo.diff(base=parent.hexsha)
|
||||
|
||||
assert isinstance(result.files_changed, int)
|
||||
|
||||
|
||||
class TestGitWrapperLogAdvanced:
|
||||
"""Advanced tests for log operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_log_with_ref(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test log starting from specific ref."""
|
||||
# Create branch with commits
|
||||
await git_wrapper_with_repo.create_branch("log-test", checkout=True)
|
||||
file1 = Path(git_repo.working_dir) / "log_ref.txt"
|
||||
file1.write_text("content")
|
||||
git_repo.index.add(["log_ref.txt"])
|
||||
git_repo.index.commit("Commit on log-test branch")
|
||||
|
||||
result = await git_wrapper_with_repo.log(ref="log-test", limit=5)
|
||||
|
||||
assert result.total_commits > 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_log_with_path(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test log filtered by path."""
|
||||
# Create file and commit
|
||||
file1 = Path(git_repo.working_dir) / "log_path.txt"
|
||||
file1.write_text("content")
|
||||
git_repo.index.add(["log_path.txt"])
|
||||
git_repo.index.commit("Commit for path log")
|
||||
|
||||
result = await git_wrapper_with_repo.log(path="log_path.txt")
|
||||
|
||||
assert result.total_commits >= 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_log_with_skip(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test log with skip parameter."""
|
||||
# Create multiple commits
|
||||
for i in range(3):
|
||||
file_path = Path(git_repo.working_dir) / f"skip_test{i}.txt"
|
||||
file_path.write_text(f"content {i}")
|
||||
git_repo.index.add([f"skip_test{i}.txt"])
|
||||
git_repo.index.commit(f"Skip test commit {i}")
|
||||
|
||||
result = await git_wrapper_with_repo.log(skip=1, limit=2)
|
||||
|
||||
# Should have skipped first commit
|
||||
assert len(result.commits) <= 2
|
||||
|
||||
|
||||
class TestGitWrapperRemoteUrl:
|
||||
"""Tests for remote URL operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_remote_url_nonexistent(self, git_wrapper_with_repo):
|
||||
"""Test getting URL for non-existent remote."""
|
||||
url = await git_wrapper_with_repo.get_remote_url("nonexistent")
|
||||
|
||||
assert url is None
|
||||
|
||||
|
||||
class TestGitWrapperConfig:
|
||||
"""Tests for git config operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_set_and_get_config(self, git_wrapper_with_repo):
|
||||
"""Test setting and getting config value."""
|
||||
await git_wrapper_with_repo.set_config("test.key", "test_value")
|
||||
|
||||
value = await git_wrapper_with_repo.get_config("test.key")
|
||||
|
||||
assert value == "test_value"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_config_nonexistent(self, git_wrapper_with_repo):
|
||||
"""Test getting non-existent config value."""
|
||||
value = await git_wrapper_with_repo.get_config("nonexistent.key")
|
||||
|
||||
assert value is None
|
||||
|
||||
|
||||
class TestGitWrapperClone:
|
||||
"""Tests for clone operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clone_success(self, temp_workspace, test_settings):
|
||||
"""Test successful clone."""
|
||||
wrapper = GitWrapper(temp_workspace, test_settings)
|
||||
|
||||
# Mock the clone operation
|
||||
with patch("git_wrapper.GitRepo") as mock_repo_class:
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.active_branch.name = "main"
|
||||
mock_repo.head.commit.hexsha = "abc123"
|
||||
mock_repo_class.clone_from.return_value = mock_repo
|
||||
|
||||
result = await wrapper.clone("https://github.com/test/repo.git")
|
||||
|
||||
assert result.success is True
|
||||
assert result.branch == "main"
|
||||
assert result.commit_sha == "abc123"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clone_with_auth_token(self, temp_workspace, test_settings):
|
||||
"""Test clone with auth token."""
|
||||
wrapper = GitWrapper(temp_workspace, test_settings)
|
||||
|
||||
with patch("git_wrapper.GitRepo") as mock_repo_class:
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.active_branch.name = "main"
|
||||
mock_repo.head.commit.hexsha = "abc123"
|
||||
mock_repo_class.clone_from.return_value = mock_repo
|
||||
|
||||
result = await wrapper.clone(
|
||||
"https://github.com/test/repo.git",
|
||||
auth_token="test-token",
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
# Verify token was injected in URL
|
||||
call_args = mock_repo_class.clone_from.call_args
|
||||
assert "test-token@" in call_args.kwargs["url"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clone_with_branch_and_depth(self, temp_workspace, test_settings):
|
||||
"""Test clone with branch and depth parameters."""
|
||||
wrapper = GitWrapper(temp_workspace, test_settings)
|
||||
|
||||
with patch("git_wrapper.GitRepo") as mock_repo_class:
|
||||
mock_repo = MagicMock()
|
||||
mock_repo.active_branch.name = "develop"
|
||||
mock_repo.head.commit.hexsha = "def456"
|
||||
mock_repo_class.clone_from.return_value = mock_repo
|
||||
|
||||
result = await wrapper.clone(
|
||||
"https://github.com/test/repo.git",
|
||||
branch="develop",
|
||||
depth=1,
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
call_args = mock_repo_class.clone_from.call_args
|
||||
assert call_args.kwargs["branch"] == "develop"
|
||||
assert call_args.kwargs["depth"] == 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clone_failure(self, temp_workspace, test_settings):
|
||||
"""Test clone failure raises CloneError."""
|
||||
wrapper = GitWrapper(temp_workspace, test_settings)
|
||||
|
||||
with patch("git_wrapper.GitRepo") as mock_repo_class:
|
||||
mock_repo_class.clone_from.side_effect = GitCommandError(
|
||||
"git clone", 128, stderr="Authentication failed"
|
||||
)
|
||||
|
||||
with pytest.raises(CloneError):
|
||||
await wrapper.clone("https://github.com/test/repo.git")
|
||||
|
||||
|
||||
class TestGitWrapperPush:
|
||||
"""Tests for push operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_push_force_disabled(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test force push is disabled by default."""
|
||||
git_repo.create_remote("origin", "https://github.com/test/repo.git")
|
||||
|
||||
with pytest.raises(PushError, match="Force push is disabled"):
|
||||
await git_wrapper_with_repo.push(force=True)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_push_remote_not_found(self, git_wrapper_with_repo):
|
||||
"""Test push to non-existent remote."""
|
||||
with pytest.raises(PushError, match="Remote not found"):
|
||||
await git_wrapper_with_repo.push(remote="nonexistent")
|
||||
|
||||
|
||||
class TestGitWrapperPull:
|
||||
"""Tests for pull operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pull_remote_not_found(self, git_wrapper_with_repo):
|
||||
"""Test pull from non-existent remote."""
|
||||
with pytest.raises(PullError, match="Remote not found"):
|
||||
await git_wrapper_with_repo.pull(remote="nonexistent")
|
||||
|
||||
|
||||
class TestGitWrapperFetch:
|
||||
"""Tests for fetch operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_remote_not_found(self, git_wrapper_with_repo):
|
||||
"""Test fetch from non-existent remote."""
|
||||
with pytest.raises(GitError, match="Remote not found"):
|
||||
await git_wrapper_with_repo.fetch(remote="nonexistent")
|
||||
|
||||
|
||||
class TestGitWrapperDiffHeadOnly:
|
||||
"""Tests for diff with head ref only."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_diff_head_only(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test diff with head ref only (working tree vs ref)."""
|
||||
# Make some changes
|
||||
readme = Path(git_repo.working_dir) / "README.md"
|
||||
readme.write_text("modified content")
|
||||
|
||||
# This tests the head-only branch (base=None, head=specified)
|
||||
result = await git_wrapper_with_repo.diff(head="HEAD")
|
||||
|
||||
assert isinstance(result.files_changed, int)
|
||||
|
||||
|
||||
class TestGitWrapperRemoteWithUrl:
|
||||
"""Tests for getting remote URL when remote exists."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_remote_url_exists(self, git_wrapper_with_repo, git_repo):
|
||||
"""Test getting URL for existing remote."""
|
||||
git_repo.create_remote("origin", "https://github.com/test/repo.git")
|
||||
|
||||
url = await git_wrapper_with_repo.get_remote_url("origin")
|
||||
|
||||
assert url == "https://github.com/test/repo.git"
|
||||
|
||||
|
||||
class TestRunInExecutor:
|
||||
"""Tests for run_in_executor utility."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_in_executor(self):
|
||||
"""Test running function in executor."""
|
||||
|
||||
def blocking_func(x, y):
|
||||
return x + y
|
||||
|
||||
result = await run_in_executor(blocking_func, 1, 2)
|
||||
|
||||
assert result == 3
|
||||
|
||||
Reference in New Issue
Block a user