This commit is contained in:
Fahad
2025-06-15 15:32:41 +04:00
parent 3bc7956239
commit 86728a1442
13 changed files with 1261 additions and 1178 deletions

View File

@@ -28,10 +28,11 @@ class TestServerTools:
assert "precommit" in tool_names
assert "testgen" in tool_names
assert "refactor" in tool_names
assert "tracer" in tool_names
assert "version" in tool_names
# Should have exactly 9 tools (including refactor)
assert len(tools) == 9
# Should have exactly 10 tools (including refactor and tracer)
assert len(tools) == 10
# Check descriptions are verbose
for tool in tools:

View File

@@ -321,3 +321,83 @@ class TestAbsolutePathValidation:
response = json.loads(result[0].text)
assert response["status"] == "success"
assert "Analysis complete" in response["content"]
class TestSpecialStatusModels:
"""Test SPECIAL_STATUS_MODELS registry and structured response handling"""
def test_trace_complete_status_in_registry(self):
"""Test that trace_complete status is properly registered"""
from tools.models import SPECIAL_STATUS_MODELS, TraceComplete
assert "trace_complete" in SPECIAL_STATUS_MODELS
assert SPECIAL_STATUS_MODELS["trace_complete"] == TraceComplete
def test_trace_complete_model_validation(self):
"""Test TraceComplete model validation"""
from tools.models import TraceComplete
# Test precision mode
precision_data = {
"status": "trace_complete",
"trace_type": "precision",
"entry_point": {
"file": "/path/to/file.py",
"class_or_struct": "MyClass",
"method": "myMethod",
"signature": "def myMethod(self, param1: str) -> bool",
"parameters": {"param1": "test"},
},
"call_path": [
{
"from": {"file": "/path/to/file.py", "class": "MyClass", "method": "myMethod", "line": 10},
"to": {"file": "/path/to/other.py", "class": "OtherClass", "method": "otherMethod", "line": 20},
"reason": "direct call",
"condition": None,
"ambiguous": False,
}
],
}
model = TraceComplete(**precision_data)
assert model.status == "trace_complete"
assert model.trace_type == "precision"
assert model.entry_point.file == "/path/to/file.py"
assert len(model.call_path) == 1
# Test dependencies mode
dependencies_data = {
"status": "trace_complete",
"trace_type": "dependencies",
"target": {
"file": "/path/to/file.py",
"class_or_struct": "MyClass",
"method": "myMethod",
"signature": "def myMethod(self, param1: str) -> bool",
},
"incoming_dependencies": [
{
"from_file": "/path/to/caller.py",
"from_class": "CallerClass",
"from_method": "callerMethod",
"line": 15,
"type": "direct_call",
}
],
"outgoing_dependencies": [
{
"to_file": "/path/to/dependency.py",
"to_class": "DepClass",
"to_method": "depMethod",
"line": 25,
"type": "method_call",
}
],
}
model = TraceComplete(**dependencies_data)
assert model.status == "trace_complete"
assert model.trace_type == "dependencies"
assert model.target.file == "/path/to/file.py"
assert len(model.incoming_dependencies) == 1
assert len(model.outgoing_dependencies) == 1

View File

@@ -1,410 +0,0 @@
"""
Tests for the tracepath tool functionality
"""
from unittest.mock import Mock, patch
import pytest
from tools.models import ToolModelCategory
from tools.tracepath import TracePathRequest, TracePathTool
class TestTracePathTool:
"""Test suite for the TracePath tool"""
@pytest.fixture
def tracepath_tool(self):
"""Create a tracepath tool instance for testing"""
return TracePathTool()
@pytest.fixture
def mock_model_response(self):
"""Create a mock model response for call path analysis"""
def _create_response(content=None):
if content is None:
content = """## Call Path Summary
1. 🟢 `BookingManager::finalizeInvoice()` at booking.py:45 → calls `PaymentProcessor.process()`
2. 🟢 `PaymentProcessor::process()` at payment.py:123 → calls `validation.validate_payment()`
3. 🟡 `validation.validate_payment()` at validation.py:67 → conditionally calls `Logger.log()`
## Value-Driven Flow Analysis
**Scenario 1**: `invoice_id=123, payment_method="credit_card"`
- Path: BookingManager → PaymentProcessor → CreditCardValidator → StripeGateway
- Key decision at payment.py:156: routes to Stripe integration
## Side Effects & External Dependencies
### Database Interactions
- **Transaction.save()** at models.py:234 → inserts payment record
### Network Calls
- **StripeGateway.charge()** → HTTPS POST to Stripe API
## Code Anchors
- Entry point: `BookingManager::finalizeInvoice` at booking.py:45
- Critical branch: Payment method selection at payment.py:156
"""
return Mock(
content=content,
usage={"input_tokens": 150, "output_tokens": 300, "total_tokens": 450},
model_name="test-model",
metadata={"finish_reason": "STOP"},
)
return _create_response
def test_get_name(self, tracepath_tool):
"""Test that the tool returns the correct name"""
assert tracepath_tool.get_name() == "tracepath"
def test_get_description(self, tracepath_tool):
"""Test that the tool returns a comprehensive description"""
description = tracepath_tool.get_description()
assert "STATIC CALL PATH ANALYSIS" in description
assert "control flow" in description
assert "confidence levels" in description
assert "polymorphism" in description
assert "side effects" in description
def test_get_input_schema(self, tracepath_tool):
"""Test that the input schema includes all required fields"""
schema = tracepath_tool.get_input_schema()
assert schema["type"] == "object"
assert "entry_point" in schema["properties"]
assert "files" in schema["properties"]
# Check required fields
required_fields = schema["required"]
assert "entry_point" in required_fields
assert "files" in required_fields
# Check optional parameters
assert "parameters" in schema["properties"]
assert "analysis_depth" in schema["properties"]
assert "language" in schema["properties"]
assert "confidence_threshold" in schema["properties"]
# Check enum values for analysis_depth
depth_enum = schema["properties"]["analysis_depth"]["enum"]
expected_depths = ["shallow", "medium", "deep"]
assert all(depth in depth_enum for depth in expected_depths)
# Check enum values for language
language_enum = schema["properties"]["language"]["enum"]
expected_languages = ["python", "javascript", "typescript", "csharp", "java"]
assert all(lang in language_enum for lang in expected_languages)
def test_get_model_category(self, tracepath_tool):
"""Test that the tool uses extended reasoning category"""
category = tracepath_tool.get_model_category()
assert category == ToolModelCategory.EXTENDED_REASONING
def test_request_model_validation(self):
"""Test request model validation"""
# Valid request
request = TracePathRequest(
entry_point="BookingManager::finalizeInvoice",
files=["/test/booking.py", "/test/payment.py"],
parameters={"invoice_id": 123, "payment_method": "credit_card"},
analysis_depth="medium",
)
assert request.entry_point == "BookingManager::finalizeInvoice"
assert len(request.files) == 2
assert request.analysis_depth == "medium"
assert request.confidence_threshold == 0.7 # default value
# Test validation with invalid confidence threshold
with pytest.raises(ValueError):
TracePathRequest(
entry_point="test::method", files=["/test/file.py"], confidence_threshold=1.5 # Invalid: > 1.0
)
# Invalid request (missing required fields)
with pytest.raises(ValueError):
TracePathRequest(files=["/test/file.py"]) # Missing entry_point
def test_language_detection_python(self, tracepath_tool):
"""Test language detection for Python files"""
files = ["/test/booking.py", "/test/payment.py", "/test/utils.py"]
language = tracepath_tool.detect_primary_language(files)
assert language == "python"
def test_language_detection_javascript(self, tracepath_tool):
"""Test language detection for JavaScript files"""
files = ["/test/app.js", "/test/component.jsx", "/test/utils.js"]
language = tracepath_tool.detect_primary_language(files)
assert language == "javascript"
def test_language_detection_typescript(self, tracepath_tool):
"""Test language detection for TypeScript files"""
files = ["/test/app.ts", "/test/component.tsx", "/test/utils.ts"]
language = tracepath_tool.detect_primary_language(files)
assert language == "typescript"
def test_language_detection_csharp(self, tracepath_tool):
"""Test language detection for C# files"""
files = ["/test/BookingService.cs", "/test/PaymentProcessor.cs"]
language = tracepath_tool.detect_primary_language(files)
assert language == "csharp"
def test_language_detection_java(self, tracepath_tool):
"""Test language detection for Java files"""
files = ["/test/BookingManager.java", "/test/PaymentService.java"]
language = tracepath_tool.detect_primary_language(files)
assert language == "java"
def test_language_detection_mixed(self, tracepath_tool):
"""Test language detection for mixed language files"""
files = ["/test/app.py", "/test/service.js", "/test/model.java"]
language = tracepath_tool.detect_primary_language(files)
assert language == "mixed"
def test_language_detection_unknown(self, tracepath_tool):
"""Test language detection for unknown extensions"""
files = ["/test/config.xml", "/test/readme.txt"]
language = tracepath_tool.detect_primary_language(files)
assert language == "unknown"
def test_parse_entry_point_class_method_double_colon(self, tracepath_tool):
"""Test parsing entry point with double colon syntax"""
result = tracepath_tool.parse_entry_point("BookingManager::finalizeInvoice", "python")
assert result["raw"] == "BookingManager::finalizeInvoice"
assert result["class_or_module"] == "BookingManager"
assert result["method_or_function"] == "finalizeInvoice"
assert result["type"] == "method"
def test_parse_entry_point_module_function_dot(self, tracepath_tool):
"""Test parsing entry point with dot syntax"""
result = tracepath_tool.parse_entry_point("utils.validate_input", "python")
assert result["raw"] == "utils.validate_input"
assert result["class_or_module"] == "utils"
assert result["method_or_function"] == "validate_input"
assert result["type"] == "function"
def test_parse_entry_point_nested_module(self, tracepath_tool):
"""Test parsing entry point with nested module syntax"""
result = tracepath_tool.parse_entry_point("payment.services.process_payment", "python")
assert result["raw"] == "payment.services.process_payment"
assert result["class_or_module"] == "payment.services"
assert result["method_or_function"] == "process_payment"
assert result["type"] == "function"
def test_parse_entry_point_function_only(self, tracepath_tool):
"""Test parsing entry point with function name only"""
result = tracepath_tool.parse_entry_point("validate_payment", "python")
assert result["raw"] == "validate_payment"
assert result["class_or_module"] == ""
assert result["method_or_function"] == "validate_payment"
assert result["type"] == "function"
def test_parse_entry_point_camelcase_class(self, tracepath_tool):
"""Test parsing entry point with CamelCase class (method detection)"""
result = tracepath_tool.parse_entry_point("PaymentProcessor.process", "java")
assert result["raw"] == "PaymentProcessor.process"
assert result["class_or_module"] == "PaymentProcessor"
assert result["method_or_function"] == "process"
assert result["type"] == "method" # CamelCase suggests class method
@pytest.mark.asyncio
async def test_generate_structural_summary_phase1(self, tracepath_tool):
"""Test structural summary generation (Phase 1 returns empty)"""
files = ["/test/booking.py", "/test/payment.py"]
summary = await tracepath_tool._generate_structural_summary(files, "python")
# Phase 1 implementation should return empty string
assert summary == ""
@pytest.mark.asyncio
async def test_prepare_prompt_basic(self, tracepath_tool):
"""Test basic prompt preparation"""
request = TracePathRequest(
entry_point="BookingManager::finalizeInvoice",
files=["/test/booking.py"],
parameters={"invoice_id": 123},
analysis_depth="medium",
)
# Mock file content preparation
with patch.object(tracepath_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "def finalizeInvoice(self, invoice_id):\n pass"
with patch.object(tracepath_tool, "_validate_token_limit"):
prompt = await tracepath_tool.prepare_prompt(request)
assert "ANALYSIS REQUEST" in prompt
assert "BookingManager::finalizeInvoice" in prompt
assert "medium" in prompt
assert "CODE TO ANALYZE" in prompt
@pytest.mark.asyncio
async def test_prepare_prompt_with_parameters(self, tracepath_tool):
"""Test prompt preparation with parameter values"""
request = TracePathRequest(
entry_point="payment.process_payment",
files=["/test/payment.py"],
parameters={"amount": 100.50, "method": "credit_card"},
analysis_depth="deep",
include_db=True,
include_network=True,
include_fs=False,
)
with patch.object(tracepath_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "def process_payment(amount, method):\n pass"
with patch.object(tracepath_tool, "_validate_token_limit"):
prompt = await tracepath_tool.prepare_prompt(request)
assert "Parameter Values: {'amount': 100.5, 'method': 'credit_card'}" in prompt
assert "Analysis Depth: deep" in prompt
assert "Include Side Effects: database, network" in prompt
@pytest.mark.asyncio
async def test_prepare_prompt_with_context(self, tracepath_tool):
"""Test prompt preparation with additional context"""
request = TracePathRequest(
entry_point="UserService::authenticate",
files=["/test/auth.py"],
context="Focus on security implications and potential vulnerabilities",
focus_areas=["security", "error_handling"],
)
with patch.object(tracepath_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "def authenticate(self, username, password):\n pass"
with patch.object(tracepath_tool, "_validate_token_limit"):
prompt = await tracepath_tool.prepare_prompt(request)
assert "Additional Context: Focus on security implications" in prompt
assert "Focus Areas: security, error_handling" in prompt
def test_format_response_markdown(self, tracepath_tool):
"""Test response formatting for markdown output"""
request = TracePathRequest(
entry_point="BookingManager::finalizeInvoice", files=["/test/booking.py"], export_format="markdown"
)
response = "## Call Path Summary\n1. BookingManager::finalizeInvoice..."
model_info = {"model_response": Mock(friendly_name="Gemini Pro")}
formatted = tracepath_tool.format_response(response, request, model_info)
assert response in formatted
assert "Analysis Complete" in formatted
assert "Gemini Pro" in formatted
assert "confidence assessments" in formatted
def test_format_response_json(self, tracepath_tool):
"""Test response formatting for JSON output"""
request = TracePathRequest(entry_point="payment.process", files=["/test/payment.py"], export_format="json")
response = '{"call_path": [...], "confidence": "high"}'
formatted = tracepath_tool.format_response(response, request)
assert response in formatted
assert "structured JSON analysis" in formatted
assert "confidence levels" in formatted
def test_format_response_plantuml(self, tracepath_tool):
"""Test response formatting for PlantUML output"""
request = TracePathRequest(entry_point="service.execute", files=["/test/service.py"], export_format="plantuml")
response = "@startuml\nBooking -> Payment\n@enduml"
formatted = tracepath_tool.format_response(response, request)
assert response in formatted
assert "PlantUML diagram" in formatted
assert "Render the PlantUML" in formatted
def test_get_default_temperature(self, tracepath_tool):
"""Test that the tool uses analytical temperature"""
from config import TEMPERATURE_ANALYTICAL
assert tracepath_tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
def test_wants_line_numbers_by_default(self, tracepath_tool):
"""Test that line numbers are enabled by default"""
# The base class should enable line numbers by default for precise references
# We test that this isn't overridden to disable them
assert hasattr(tracepath_tool, "wants_line_numbers_by_default")
def test_side_effects_configuration(self):
"""Test side effects boolean configuration"""
request = TracePathRequest(
entry_point="test.function",
files=["/test/file.py"],
include_db=True,
include_network=False,
include_fs=True,
)
assert request.include_db is True
assert request.include_network is False
assert request.include_fs is True
def test_confidence_threshold_bounds(self):
"""Test confidence threshold validation bounds"""
# Valid thresholds
request1 = TracePathRequest(entry_point="test.function", files=["/test/file.py"], confidence_threshold=0.0)
assert request1.confidence_threshold == 0.0
request2 = TracePathRequest(entry_point="test.function", files=["/test/file.py"], confidence_threshold=1.0)
assert request2.confidence_threshold == 1.0
# Invalid thresholds should raise ValidationError
with pytest.raises(ValueError):
TracePathRequest(entry_point="test.function", files=["/test/file.py"], confidence_threshold=-0.1)
with pytest.raises(ValueError):
TracePathRequest(entry_point="test.function", files=["/test/file.py"], confidence_threshold=1.1)
def test_signature_parameter(self):
"""Test signature parameter for overload resolution"""
request = TracePathRequest(
entry_point="Calculator.add",
files=["/test/calc.cs"],
signature="public int Add(int a, int b)",
language="csharp",
)
assert request.signature == "public int Add(int a, int b)"
assert request.language == "csharp"
@pytest.mark.asyncio
async def test_prepare_prompt_with_language_override(self, tracepath_tool):
"""Test prompt preparation with language override"""
request = TracePathRequest(
entry_point="Calculator::Add",
files=["/test/calc.py"], # Python extension
language="csharp", # Override to C#
)
with patch.object(tracepath_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "public class Calculator { }"
with patch.object(tracepath_tool, "_validate_token_limit"):
prompt = await tracepath_tool.prepare_prompt(request)
assert "Language: csharp" in prompt # Should use override, not detected
def test_export_format_options(self):
"""Test all export format options"""
formats = ["markdown", "json", "plantuml"]
for fmt in formats:
request = TracePathRequest(entry_point="test.function", files=["/test/file.py"], export_format=fmt)
assert request.export_format == fmt
# Invalid format should raise ValidationError
with pytest.raises(ValueError):
TracePathRequest(entry_point="test.function", files=["/test/file.py"], export_format="invalid_format")

420
tests/test_tracer.py Normal file
View File

@@ -0,0 +1,420 @@
"""
Tests for the tracer tool functionality
"""
from unittest.mock import Mock, patch
import pytest
from tools.models import ToolModelCategory
from tools.tracer import TracerRequest, TracerTool
class TestTracerTool:
"""Test suite for the Tracer tool"""
@pytest.fixture
def tracer_tool(self):
"""Create a tracer tool instance for testing"""
return TracerTool()
@pytest.fixture
def mock_model_response(self):
"""Create a mock model response for call path analysis"""
def _create_response(content=None):
if content is None:
content = """## Call Path Summary
1. 🟢 `BookingManager::finalizeInvoice()` at booking.py:45 → calls `PaymentProcessor.process()`
2. 🟢 `PaymentProcessor::process()` at payment.py:123 → calls `validation.validate_payment()`
3. 🟡 `validation.validate_payment()` at validation.py:67 → conditionally calls `Logger.log()`
## Value-Driven Flow Analysis
**Scenario 1**: `invoice_id=123, payment_method="credit_card"`
- Path: BookingManager → PaymentProcessor → CreditCardValidator → StripeGateway
- Key decision at payment.py:156: routes to Stripe integration
## Side Effects & External Dependencies
### Database Interactions
- **Transaction.save()** at models.py:234 → inserts payment record
### Network Calls
- **StripeGateway.charge()** → HTTPS POST to Stripe API
## Code Anchors
- Entry point: `BookingManager::finalizeInvoice` at booking.py:45
- Critical branch: Payment method selection at payment.py:156
"""
return Mock(
content=content,
usage={"input_tokens": 150, "output_tokens": 300, "total_tokens": 450},
model_name="test-model",
metadata={"finish_reason": "STOP"},
)
return _create_response
def test_get_name(self, tracer_tool):
"""Test that the tool returns the correct name"""
assert tracer_tool.get_name() == "tracer"
def test_get_description(self, tracer_tool):
"""Test that the tool returns a comprehensive description"""
description = tracer_tool.get_description()
assert "STATIC CODE ANALYSIS" in description
assert "execution flow" in description
assert "dependency mappings" in description
assert "precision" in description
assert "dependencies" in description
def test_get_input_schema(self, tracer_tool):
"""Test that the input schema includes all required fields"""
schema = tracer_tool.get_input_schema()
assert schema["type"] == "object"
assert "prompt" in schema["properties"]
assert "files" in schema["properties"]
assert "trace_mode" in schema["properties"]
# Check required fields
required_fields = schema["required"]
assert "prompt" in required_fields
assert "files" in required_fields
assert "trace_mode" in required_fields
# Check enum values for trace_mode
trace_mode_enum = schema["properties"]["trace_mode"]["enum"]
assert "precision" in trace_mode_enum
assert "dependencies" in trace_mode_enum
def test_get_model_category(self, tracer_tool):
"""Test that the tool uses extended reasoning category"""
category = tracer_tool.get_model_category()
assert category == ToolModelCategory.EXTENDED_REASONING
def test_request_model_validation(self):
"""Test request model validation"""
# Valid request
request = TracerRequest(
prompt="Trace BookingManager::finalizeInvoice method with invoice_id=123",
files=["/test/booking.py", "/test/payment.py"],
trace_mode="precision",
)
assert request.prompt == "Trace BookingManager::finalizeInvoice method with invoice_id=123"
assert len(request.files) == 2
assert request.trace_mode == "precision"
# Invalid request (missing required fields)
with pytest.raises(ValueError):
TracerRequest(files=["/test/file.py"]) # Missing prompt and trace_mode
# Invalid trace_mode value
with pytest.raises(ValueError):
TracerRequest(prompt="Test", files=["/test/file.py"], trace_mode="invalid_type")
def test_language_detection_python(self, tracer_tool):
"""Test language detection for Python files"""
files = ["/test/booking.py", "/test/payment.py", "/test/utils.py"]
language = tracer_tool.detect_primary_language(files)
assert language == "python"
def test_language_detection_javascript(self, tracer_tool):
"""Test language detection for JavaScript files"""
files = ["/test/app.js", "/test/component.jsx", "/test/utils.js"]
language = tracer_tool.detect_primary_language(files)
assert language == "javascript"
def test_language_detection_typescript(self, tracer_tool):
"""Test language detection for TypeScript files"""
files = ["/test/app.ts", "/test/component.tsx", "/test/utils.ts"]
language = tracer_tool.detect_primary_language(files)
assert language == "typescript"
def test_language_detection_csharp(self, tracer_tool):
"""Test language detection for C# files"""
files = ["/test/BookingService.cs", "/test/PaymentProcessor.cs"]
language = tracer_tool.detect_primary_language(files)
assert language == "csharp"
def test_language_detection_java(self, tracer_tool):
"""Test language detection for Java files"""
files = ["/test/BookingManager.java", "/test/PaymentService.java"]
language = tracer_tool.detect_primary_language(files)
assert language == "java"
def test_language_detection_mixed(self, tracer_tool):
"""Test language detection for mixed language files"""
files = ["/test/app.py", "/test/service.js", "/test/model.java"]
language = tracer_tool.detect_primary_language(files)
assert language == "mixed"
def test_language_detection_unknown(self, tracer_tool):
"""Test language detection for unknown extensions"""
files = ["/test/config.xml", "/test/readme.txt"]
language = tracer_tool.detect_primary_language(files)
assert language == "unknown"
# Removed parse_entry_point tests as method no longer exists in simplified interface
@pytest.mark.asyncio
async def test_prepare_prompt_basic(self, tracer_tool):
"""Test basic prompt preparation"""
request = TracerRequest(
prompt="Trace BookingManager::finalizeInvoice method with invoice_id=123",
files=["/test/booking.py"],
trace_mode="precision",
)
# Mock file content preparation
with patch.object(tracer_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "def finalizeInvoice(self, invoice_id):\n pass"
with patch.object(tracer_tool, "check_prompt_size") as mock_check:
mock_check.return_value = None
prompt = await tracer_tool.prepare_prompt(request)
assert "ANALYSIS REQUEST" in prompt
assert "Trace BookingManager::finalizeInvoice method" in prompt
assert "precision" in prompt
assert "CODE TO ANALYZE" in prompt
@pytest.mark.asyncio
async def test_prepare_prompt_with_dependencies(self, tracer_tool):
"""Test prompt preparation with dependencies type"""
request = TracerRequest(
prompt="Analyze dependencies for payment.process_payment function with amount=100.50",
files=["/test/payment.py"],
trace_mode="dependencies",
)
with patch.object(tracer_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "def process_payment(amount, method):\n pass"
with patch.object(tracer_tool, "check_prompt_size") as mock_check:
mock_check.return_value = None
prompt = await tracer_tool.prepare_prompt(request)
assert "Analyze dependencies for payment.process_payment" in prompt
assert "Trace Mode: dependencies" in prompt
@pytest.mark.asyncio
async def test_prepare_prompt_with_security_context(self, tracer_tool):
"""Test prompt preparation with security context"""
request = TracerRequest(
prompt="Trace UserService::authenticate method focusing on security implications and potential vulnerabilities",
files=["/test/auth.py"],
trace_mode="precision",
)
with patch.object(tracer_tool, "_prepare_file_content_for_prompt") as mock_prep:
mock_prep.return_value = "def authenticate(self, username, password):\n pass"
with patch.object(tracer_tool, "check_prompt_size") as mock_check:
mock_check.return_value = None
prompt = await tracer_tool.prepare_prompt(request)
assert "security implications and potential vulnerabilities" in prompt
assert "Trace Mode: precision" in prompt
def test_format_response_precision(self, tracer_tool):
"""Test response formatting for precision trace"""
request = TracerRequest(
prompt="Trace BookingManager::finalizeInvoice method", files=["/test/booking.py"], trace_mode="precision"
)
response = '{"status": "trace_complete", "trace_type": "precision"}'
model_info = {"model_response": Mock(friendly_name="Gemini Pro")}
formatted = tracer_tool.format_response(response, request, model_info)
assert response in formatted
assert "Analysis Complete" in formatted
assert "Gemini Pro" in formatted
assert "precision analysis" in formatted
assert "CALL FLOW DIAGRAM" in formatted
assert "BRANCHING & SIDE EFFECT TABLE" in formatted
def test_format_response_dependencies(self, tracer_tool):
"""Test response formatting for dependencies trace"""
request = TracerRequest(
prompt="Analyze dependencies for payment.process function",
files=["/test/payment.py"],
trace_mode="dependencies",
)
response = '{"status": "trace_complete", "trace_type": "dependencies"}'
formatted = tracer_tool.format_response(response, request)
assert response in formatted
assert "dependencies analysis" in formatted
assert "DEPENDENCY FLOW GRAPH" in formatted
assert "DEPENDENCY TABLE" in formatted
# Removed PlantUML test as export_format is no longer a parameter
def test_get_default_temperature(self, tracer_tool):
"""Test that the tool uses analytical temperature"""
from config import TEMPERATURE_ANALYTICAL
assert tracer_tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
def test_wants_line_numbers_by_default(self, tracer_tool):
"""Test that line numbers are enabled by default"""
# The base class should enable line numbers by default for precise references
# We test that this isn't overridden to disable them
assert hasattr(tracer_tool, "wants_line_numbers_by_default")
def test_trace_mode_validation(self):
"""Test trace mode validation"""
# Valid trace modes
request1 = TracerRequest(prompt="Test precision", files=["/test/file.py"], trace_mode="precision")
assert request1.trace_mode == "precision"
request2 = TracerRequest(prompt="Test dependencies", files=["/test/file.py"], trace_mode="dependencies")
assert request2.trace_mode == "dependencies"
# Invalid trace mode should raise ValidationError
with pytest.raises(ValueError):
TracerRequest(prompt="Test", files=["/test/file.py"], trace_mode="invalid_type")
def test_get_rendering_instructions(self, tracer_tool):
"""Test the main rendering instructions dispatcher method"""
# Test precision mode
precision_instructions = tracer_tool._get_rendering_instructions("precision")
assert "MANDATORY RENDERING INSTRUCTIONS FOR PRECISION TRACE" in precision_instructions
assert "CALL FLOW DIAGRAM" in precision_instructions
assert "BRANCHING & SIDE EFFECT TABLE" in precision_instructions
# Test dependencies mode
dependencies_instructions = tracer_tool._get_rendering_instructions("dependencies")
assert "MANDATORY RENDERING INSTRUCTIONS FOR DEPENDENCIES TRACE" in dependencies_instructions
assert "DEPENDENCY FLOW GRAPH" in dependencies_instructions
assert "DEPENDENCY TABLE" in dependencies_instructions
def test_get_precision_rendering_instructions(self, tracer_tool):
"""Test precision mode rendering instructions"""
instructions = tracer_tool._get_precision_rendering_instructions()
# Check for required sections
assert "MANDATORY RENDERING INSTRUCTIONS FOR PRECISION TRACE" in instructions
assert "1. CALL FLOW DIAGRAM (TOP-DOWN)" in instructions
assert "2. BRANCHING & SIDE EFFECT TABLE" in instructions
# Check for specific formatting requirements
assert "[Class::Method] (file: /path, line: ##)" in instructions
assert "Chain each call using ↓ or → for readability" in instructions
assert "If ambiguous, mark with `⚠️ ambiguous branch`" in instructions
assert "Side Effects:" in instructions
assert "[database] description (File.ext:##)" in instructions
# Check for critical rules
assert "CRITICAL RULES:" in instructions
assert "Use exact filenames, class names, and line numbers from JSON" in instructions
assert "DO NOT invent function names or examples" in instructions
def test_get_dependencies_rendering_instructions(self, tracer_tool):
"""Test dependencies mode rendering instructions"""
instructions = tracer_tool._get_dependencies_rendering_instructions()
# Check for required sections
assert "MANDATORY RENDERING INSTRUCTIONS FOR DEPENDENCIES TRACE" in instructions
assert "1. DEPENDENCY FLOW GRAPH" in instructions
assert "2. DEPENDENCY TABLE" in instructions
# Check for specific formatting requirements
assert "Called by:" in instructions
assert "[CallerClass::callerMethod] ← /path/file.ext:##" in instructions
assert "Calls:" in instructions
assert "[Logger::logAction] → /utils/log.ext:##" in instructions
assert "Type Dependencies:" in instructions
assert "State Access:" in instructions
# Check for arrow rules
assert "`←` for incoming (who calls this)" in instructions
assert "`→` for outgoing (what this calls)" in instructions
# Check for dependency table format
assert "| Type | From/To | Method | File | Line |" in instructions
assert "| direct_call | From: CallerClass | callerMethod |" in instructions
# Check for critical rules
assert "CRITICAL RULES:" in instructions
assert "Use exact filenames, class names, and line numbers from JSON" in instructions
assert "Show directional dependencies with proper arrows" in instructions
def test_format_response_uses_private_methods(self, tracer_tool):
"""Test that format_response correctly uses the refactored private methods"""
# Test precision mode
precision_request = TracerRequest(prompt="Test precision", files=["/test/file.py"], trace_mode="precision")
precision_response = tracer_tool.format_response('{"test": "response"}', precision_request)
# Should contain precision-specific instructions
assert "CALL FLOW DIAGRAM" in precision_response
assert "BRANCHING & SIDE EFFECT TABLE" in precision_response
assert "precision analysis" in precision_response
# Test dependencies mode
dependencies_request = TracerRequest(
prompt="Test dependencies", files=["/test/file.py"], trace_mode="dependencies"
)
dependencies_response = tracer_tool.format_response('{"test": "response"}', dependencies_request)
# Should contain dependencies-specific instructions
assert "DEPENDENCY FLOW GRAPH" in dependencies_response
assert "DEPENDENCY TABLE" in dependencies_response
assert "dependencies analysis" in dependencies_response
def test_rendering_instructions_consistency(self, tracer_tool):
"""Test that private methods return consistent instructions"""
# Get instructions through both paths
precision_direct = tracer_tool._get_precision_rendering_instructions()
precision_via_dispatcher = tracer_tool._get_rendering_instructions("precision")
dependencies_direct = tracer_tool._get_dependencies_rendering_instructions()
dependencies_via_dispatcher = tracer_tool._get_rendering_instructions("dependencies")
# Should be identical
assert precision_direct == precision_via_dispatcher
assert dependencies_direct == dependencies_via_dispatcher
def test_rendering_instructions_completeness(self, tracer_tool):
"""Test that rendering instructions contain all required elements"""
precision_instructions = tracer_tool._get_precision_rendering_instructions()
dependencies_instructions = tracer_tool._get_dependencies_rendering_instructions()
# Both should have mandatory sections
for instructions in [precision_instructions, dependencies_instructions]:
assert "MANDATORY RENDERING INSTRUCTIONS" in instructions
assert "You MUST render" in instructions
assert "exactly two views" in instructions
assert "CRITICAL RULES:" in instructions
assert "ALWAYS render both views unless data is missing" in instructions
assert "Use exact filenames, class names, and line numbers from JSON" in instructions
assert "DO NOT invent function names or examples" in instructions
def test_rendering_instructions_mode_specific_content(self, tracer_tool):
"""Test that each mode has unique content"""
precision_instructions = tracer_tool._get_precision_rendering_instructions()
dependencies_instructions = tracer_tool._get_dependencies_rendering_instructions()
# Precision-specific content should not be in dependencies
assert "CALL FLOW DIAGRAM" in precision_instructions
assert "CALL FLOW DIAGRAM" not in dependencies_instructions
assert "BRANCHING & SIDE EFFECT TABLE" in precision_instructions
assert "BRANCHING & SIDE EFFECT TABLE" not in dependencies_instructions
# Dependencies-specific content should not be in precision
assert "DEPENDENCY FLOW GRAPH" in dependencies_instructions
assert "DEPENDENCY FLOW GRAPH" not in precision_instructions
assert "DEPENDENCY TABLE" in dependencies_instructions
assert "DEPENDENCY TABLE" not in precision_instructions
# Mode-specific symbols and patterns
assert "" in precision_instructions # Flow arrows
assert "" in dependencies_instructions # Incoming arrow
assert "" in dependencies_instructions # Outgoing arrow
assert "Side Effects:" in precision_instructions
assert "Called by:" in dependencies_instructions