Docs added to show how a new tool is created All tools should add numbers to code for models to be able to reference if needed Enabled line numbering for code for all tools to use Additional tests to validate line numbering is not added to git diffs
166 lines
6.3 KiB
Python
166 lines
6.3 KiB
Python
"""
|
|
Test to verify that precommit tool handles line numbers correctly:
|
|
- Diffs should NOT have line numbers (they have their own diff markers)
|
|
- Additional context files SHOULD have line numbers
|
|
"""
|
|
|
|
import os
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from tools.precommit import Precommit, PrecommitRequest
|
|
|
|
|
|
class TestPrecommitLineNumbers:
|
|
"""Test that precommit correctly handles line numbers for diffs vs context files."""
|
|
|
|
@pytest.fixture
|
|
def tool(self):
|
|
"""Create a Precommit tool instance."""
|
|
return Precommit()
|
|
|
|
@pytest.fixture
|
|
def mock_provider(self):
|
|
"""Create a mock provider."""
|
|
provider = MagicMock()
|
|
provider.get_provider_type.return_value.value = "test"
|
|
|
|
# Mock the model response
|
|
model_response = MagicMock()
|
|
model_response.content = "Test review response"
|
|
model_response.usage = {"total_tokens": 100}
|
|
model_response.metadata = {"finish_reason": "stop"}
|
|
model_response.friendly_name = "test-model"
|
|
|
|
provider.generate_content = AsyncMock(return_value=model_response)
|
|
provider.get_capabilities.return_value = MagicMock(
|
|
context_window=200000,
|
|
temperature_constraint=MagicMock(
|
|
validate=lambda x: True, get_corrected_value=lambda x: x, get_description=lambda: "0.0 to 1.0"
|
|
),
|
|
)
|
|
provider.supports_thinking_mode.return_value = False
|
|
|
|
return provider
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_diffs_have_no_line_numbers_but_context_files_do(self, tool, mock_provider, tmp_path):
|
|
"""Test that git diffs don't have line numbers but context files do."""
|
|
# Use the workspace root for test files
|
|
import tempfile
|
|
|
|
test_workspace = tempfile.mkdtemp(prefix="test_precommit_")
|
|
|
|
# Create a context file in the workspace
|
|
context_file = os.path.join(test_workspace, "context.py")
|
|
with open(context_file, "w") as f:
|
|
f.write(
|
|
"""# This is a context file
|
|
def context_function():
|
|
return "This should have line numbers"
|
|
"""
|
|
)
|
|
|
|
# Mock git commands to return predictable output
|
|
def mock_run_git_command(repo_path, command):
|
|
if command == ["status", "--porcelain"]:
|
|
return True, " M example.py"
|
|
elif command == ["diff", "--name-only"]:
|
|
return True, "example.py"
|
|
elif command == ["diff", "--", "example.py"]:
|
|
# Return a sample diff - this should NOT have line numbers added
|
|
return (
|
|
True,
|
|
"""diff --git a/example.py b/example.py
|
|
index 1234567..abcdefg 100644
|
|
--- a/example.py
|
|
+++ b/example.py
|
|
@@ -1,5 +1,8 @@
|
|
def hello():
|
|
- print("Hello, World!")
|
|
+ print("Hello, Universe!") # Changed this line
|
|
|
|
def goodbye():
|
|
print("Goodbye!")
|
|
+
|
|
+def new_function():
|
|
+ print("This is new")
|
|
""",
|
|
)
|
|
else:
|
|
return True, ""
|
|
|
|
# Create request with context file
|
|
request = PrecommitRequest(
|
|
path=test_workspace,
|
|
prompt="Review my changes",
|
|
files=[context_file], # This should get line numbers
|
|
include_staged=False,
|
|
include_unstaged=True,
|
|
)
|
|
|
|
# Mock the tool's provider and git functions
|
|
with (
|
|
patch.object(tool, "get_model_provider", return_value=mock_provider),
|
|
patch("tools.precommit.run_git_command", side_effect=mock_run_git_command),
|
|
patch("tools.precommit.find_git_repositories", return_value=[test_workspace]),
|
|
patch(
|
|
"tools.precommit.get_git_status",
|
|
return_value={
|
|
"branch": "main",
|
|
"ahead": 0,
|
|
"behind": 0,
|
|
"staged_files": [],
|
|
"unstaged_files": ["example.py"],
|
|
"untracked_files": [],
|
|
},
|
|
),
|
|
):
|
|
|
|
# Prepare the prompt
|
|
prompt = await tool.prepare_prompt(request)
|
|
|
|
# Print prompt sections for debugging if test fails
|
|
# print("\n=== PROMPT OUTPUT ===")
|
|
# print(prompt)
|
|
# print("=== END PROMPT ===\n")
|
|
|
|
# Verify that diffs don't have line numbers
|
|
assert "--- BEGIN DIFF:" in prompt
|
|
assert "--- END DIFF:" in prompt
|
|
|
|
# Check that the diff content doesn't have line number markers (│)
|
|
# Find diff section
|
|
diff_start = prompt.find("--- BEGIN DIFF:")
|
|
diff_end = prompt.find("--- END DIFF:", diff_start) + len("--- END DIFF:")
|
|
if diff_start != -1 and diff_end > diff_start:
|
|
diff_section = prompt[diff_start:diff_end]
|
|
assert "│" not in diff_section, "Diff section should NOT have line number markers"
|
|
|
|
# Verify the diff has its own line markers
|
|
assert "@@ -1,5 +1,8 @@" in diff_section
|
|
assert '- print("Hello, World!")' in diff_section
|
|
assert '+ print("Hello, Universe!") # Changed this line' in diff_section
|
|
|
|
# Verify that context files DO have line numbers
|
|
if "--- BEGIN FILE:" in prompt:
|
|
# Extract context file section
|
|
file_start = prompt.find("--- BEGIN FILE:")
|
|
file_end = prompt.find("--- END FILE:", file_start) + len("--- END FILE:")
|
|
if file_start != -1 and file_end > file_start:
|
|
context_section = prompt[file_start:file_end]
|
|
|
|
# Context files should have line number markers
|
|
assert "│" in context_section, "Context file section SHOULD have line number markers"
|
|
|
|
# Verify specific line numbers in context file
|
|
assert "1│ # This is a context file" in context_section
|
|
assert "2│ def context_function():" in context_section
|
|
assert '3│ return "This should have line numbers"' in context_section
|
|
|
|
def test_base_tool_wants_line_numbers_by_default(self, tool):
|
|
"""Verify that the base tool configuration wants line numbers by default."""
|
|
# The precommit tool should inherit the base behavior
|
|
assert tool.wants_line_numbers_by_default(), "Base tool should want line numbers by default"
|