Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 31 additions & 71 deletions e2e/test_git_tools.py
Original file line number Diff line number Diff line change
@@ -1,94 +1,47 @@
#!/usr/bin/env python3

import os
import shutil
import tempfile
import unittest
from unittest import mock

import pytest

from codemcp.shell import run_command
from codemcp.testing import MCPEndToEndTestCase
from codemcp.tools.git_blame import git_blame
from codemcp.tools.git_diff import git_diff
from codemcp.tools.git_log import git_log
from codemcp.tools.git_show import git_show


@pytest.mark.asyncio
class TestGitTools(unittest.TestCase):
class TestGitTools(MCPEndToEndTestCase):
"""Test the git tools functionality."""

async def asyncSetUp(self):
# Create a temporary directory
self.temp_dir = tempfile.mkdtemp()

# Initialize a git repository
await run_command(
cmd=["git", "init"], cwd=self.temp_dir, capture_output=True, text=True
)
# Use the parent class's asyncSetUp to set up test environment
await super().asyncSetUp()

# Create a sample file
self.sample_file = os.path.join(self.temp_dir, "sample.txt")
self.sample_file = os.path.join(self.temp_dir.name, "sample.txt")
with open(self.sample_file, "w") as f:
f.write("Sample content\nLine 2\nLine 3\n")

# Add and commit the file
await run_command(
cmd=["git", "config", "user.name", "Test User"],
cwd=self.temp_dir,
capture_output=True,
text=True,
)
await run_command(
cmd=["git", "config", "user.email", "test@example.com"],
cwd=self.temp_dir,
capture_output=True,
text=True,
)
await run_command(
cmd=["git", "add", "sample.txt"],
cwd=self.temp_dir,
capture_output=True,
text=True,
)
await run_command(
cmd=["git", "commit", "-m", "Initial commit"],
cwd=self.temp_dir,
capture_output=True,
text=True,
)
# Add and commit the file (the base class already has git initialized)
await self.git_run(["add", "sample.txt"])
await self.git_run(["commit", "-m", "Initial commit"])

# Modify the file and create another commit
with open(self.sample_file, "a") as f:
f.write("Line 4\nLine 5\n")

await run_command(
cmd=["git", "add", "sample.txt"],
cwd=self.temp_dir,
capture_output=True,
text=True,
)
await run_command(
cmd=["git", "commit", "-m", "Second commit"],
cwd=self.temp_dir,
capture_output=True,
text=True,
)

async def asyncTearDown(self):
# Clean up the temporary directory
shutil.rmtree(self.temp_dir)
await self.git_run(["add", "sample.txt"])
await self.git_run(["commit", "-m", "Second commit"])

async def test_git_log(self):
"""Test the git_log tool."""
# Test with no arguments
result = await git_log(path=self.temp_dir)
result = await git_log(path=self.temp_dir.name)
self.assertIn("Initial commit", result["output"])
self.assertIn("Second commit", result["output"])

# Test with arguments
result = await git_log(arguments="--oneline -n 1", path=self.temp_dir)
result = await git_log(arguments="--oneline -n 1", path=self.temp_dir.name)
self.assertIn("Second commit", result["output"])
self.assertNotIn("Initial commit", result["output"])

Expand All @@ -99,61 +52,68 @@ async def test_git_diff(self):
f.write("Uncommitted change\n")

# Test with no arguments
result = await git_diff(path=self.temp_dir)
result = await git_diff(path=self.temp_dir.name)
self.assertIn("Uncommitted change", result["output"])

# Test with arguments
result = await git_diff(arguments="HEAD~1 HEAD", path=self.temp_dir)
result = await git_diff(arguments="HEAD~1 HEAD", path=self.temp_dir.name)
self.assertIn("Line 4", result["output"])

async def test_git_show(self):
"""Test the git_show tool."""
# Test with no arguments (should show the latest commit)
result = await git_show(path=self.temp_dir)
result = await git_show(path=self.temp_dir.name)
self.assertIn("Second commit", result["output"])

# Test with arguments
result = await git_show(arguments="HEAD~1", path=self.temp_dir)
result = await git_show(arguments="HEAD~1", path=self.temp_dir.name)
self.assertIn("Initial commit", result["output"])

async def test_git_blame(self):
"""Test the git_blame tool."""
# Test with file argument
result = await git_blame(arguments="sample.txt", path=self.temp_dir)
self.assertIn("Test User", result["output"])
result = await git_blame(arguments="sample.txt", path=self.temp_dir.name)
self.assertIn(
"A U Thor", result["output"]
) # MCPEndToEndTestCase sets this author
self.assertIn("Line 2", result["output"])

# Test with line range
result = await git_blame(arguments="-L 4,5 sample.txt", path=self.temp_dir)
result = await git_blame(arguments="-L 4,5 sample.txt", path=self.temp_dir.name)
self.assertIn("Line 4", result["output"])
self.assertNotIn("Line 2", result["output"])

async def test_invalid_path(self):
"""Test that tools handle invalid paths."""
with mock.patch("codemcp.git.is_git_repository", return_value=False):
with mock.patch("codemcp.tools.git_log.is_git_repository", return_value=False):
with self.assertRaises(ValueError):
await git_log(path="/invalid/path")

with mock.patch("codemcp.tools.git_diff.is_git_repository", return_value=False):
with self.assertRaises(ValueError):
await git_diff(path="/invalid/path")

with mock.patch("codemcp.tools.git_show.is_git_repository", return_value=False):
with self.assertRaises(ValueError):
await git_show(path="/invalid/path")

with mock.patch(
"codemcp.tools.git_blame.is_git_repository", return_value=False
):
with self.assertRaises(ValueError):
await git_blame(path="/invalid/path")

async def test_command_failure(self):
"""Test that tools handle command failures."""
# Test with invalid arguments
result = await git_log(arguments="--invalid-option", path=self.temp_dir)
result = await git_log(arguments="--invalid-option", path=self.temp_dir.name)
self.assertIn("Error", result["resultForAssistant"])

result = await git_diff(arguments="--invalid-option", path=self.temp_dir)
result = await git_diff(arguments="--invalid-option", path=self.temp_dir.name)
self.assertIn("Error", result["resultForAssistant"])

result = await git_show(arguments="--invalid-option", path=self.temp_dir)
result = await git_show(arguments="--invalid-option", path=self.temp_dir.name)
self.assertIn("Error", result["resultForAssistant"])

result = await git_blame(arguments="--invalid-option", path=self.temp_dir)
result = await git_blame(arguments="--invalid-option", path=self.temp_dir.name)
self.assertIn("Error", result["resultForAssistant"])