"""
Tests for the error handling components.
This module tests the custom exception hierarchy, error handlers,
and response formatters in the errors package.
"""
import pytest
from unittest.mock import MagicMock, patch
from typing import Dict, Any
from commit_helper_mcp.errors import (
CommitHelperMCPError,
GitOperationError,
ValidationError,
ConfigurationError,
RepositoryError,
PluginError,
ServiceError,
handle_errors,
handle_git_errors,
handle_validation_errors,
handle_configuration_errors,
log_error_context,
ErrorResponse,
create_error_response,
create_success_response,
format_validation_error,
format_git_error,
)
class TestExceptions:
"""Test the custom exception hierarchy."""
def test_base_exception(self):
"""Test the base CommitHelperMCPError exception."""
error = CommitHelperMCPError("Test error message")
assert str(error) == "Test error message"
assert error.context.operation == "unknown"
assert error.context.component == "unknown"
assert error.cause is None
def test_exception_with_context(self):
"""Test exception with custom context."""
error = GitOperationError(
"Git operation failed", git_command="commit", repo_path="/path/to/repo"
)
assert str(error) == "Git operation failed"
assert error.context.operation == "git_operation"
assert error.context.component == "git_service"
assert error.context.details["git_command"] == "commit"
assert error.context.details["repo_path"] == "/path/to/repo"
assert len(error.context.suggestions) > 0
def test_exception_with_cause(self):
"""Test exception with cause."""
original_error = ValueError("Original error")
error = ValidationError(
"Validation failed", validation_type="commit_message", cause=original_error
)
assert str(error) == "Validation failed"
assert error.cause == original_error
assert error.context.details["validation_type"] == "commit_message"
def test_to_dict_serialization(self):
"""Test exception serialization to dictionary."""
error = ConfigurationError(
"Configuration error", config_file="config.toml", config_key="settings"
)
error_dict = error.to_dict()
assert error_dict["error_type"] == "ConfigurationError"
assert error_dict["message"] == "Configuration error"
assert error_dict["context"]["component"] == "config_service"
assert error_dict["context"]["details"]["config_file"] == "config.toml"
assert error_dict["context"]["details"]["config_key"] == "settings"
def test_get_user_message(self):
"""Test getting user-friendly message."""
error = RepositoryError("Repository error", repo_path="/path/to/repo")
assert error.get_user_message() == "Repository error"
# Test with custom user message
error.context.user_message = "User-friendly error message"
assert error.get_user_message() == "User-friendly error message"
def test_get_suggestions(self):
"""Test getting error suggestions."""
error = PluginError("Plugin error", plugin_name="test_plugin")
suggestions = error.get_suggestions()
assert isinstance(suggestions, list)
assert len(suggestions) > 0
def test_get_recovery_actions(self):
"""Test getting recovery actions."""
error = ServiceError("Service error", service_name="test_service")
# Add custom recovery actions
error.context.recovery_actions = ["Action 1", "Action 2"]
actions = error.get_recovery_actions()
assert isinstance(actions, list)
assert len(actions) == 2
assert "Action 1" in actions
assert "Action 2" in actions
class TestErrorHandlers:
"""Test the error handling decorators."""
def test_handle_errors_decorator_success(self):
"""Test handle_errors decorator with successful function."""
@handle_errors()
def successful_function():
return {"success": True, "data": "test"}
result = successful_function()
assert result["success"] is True
assert result["data"] == "test"
def test_handle_errors_decorator_with_custom_exception(self):
"""Test handle_errors decorator with custom exception."""
@handle_errors()
def failing_function():
raise ValidationError("Validation failed", validation_type="test")
result = failing_function()
assert result["success"] is False
assert result["error"] == "Validation failed"
assert result["error_type"] == "ValidationError"
def test_handle_errors_decorator_with_standard_exception(self):
"""Test handle_errors decorator with standard exception."""
@handle_errors()
def failing_function():
raise ValueError("Standard error")
result = failing_function()
assert result["success"] is False
assert "Standard error" in result["error"]
assert result["error_type"] == "ServiceError"
def test_handle_errors_decorator_with_reraise(self):
"""Test handle_errors decorator with reraise=True."""
@handle_errors(reraise=True)
def failing_function():
raise ValidationError("Validation failed", validation_type="test")
with pytest.raises(ValidationError):
failing_function()
def test_handle_git_errors_decorator(self):
"""Test handle_git_errors decorator."""
@handle_git_errors
def git_function():
raise ValueError("Git error")
with pytest.raises(GitOperationError):
git_function()
def test_handle_validation_errors_decorator(self):
"""Test handle_validation_errors decorator."""
@handle_validation_errors
def validation_function():
raise ValueError("Validation error")
with pytest.raises(ValidationError):
validation_function()
def test_handle_configuration_errors_decorator(self):
"""Test handle_configuration_errors decorator."""
@handle_configuration_errors
def config_function():
raise ValueError("Config error")
with pytest.raises(ConfigurationError):
config_function()
def test_log_error_context(self, caplog):
"""Test log_error_context function."""
error = ValidationError("Validation failed", validation_type="test")
log_error_context(error, "test_function")
assert "Error in test_function: Validation failed" in caplog.text
class TestResponseFormatters:
"""Test the response formatting functions."""
def test_error_response_dataclass(self):
"""Test ErrorResponse dataclass."""
response = ErrorResponse(
error="Test error",
error_type="TestError",
details={"key": "value"},
suggestions=["Suggestion 1", "Suggestion 2"],
recovery_actions=["Action 1"],
context={"component": "test"},
)
result = response.to_dict()
assert result["success"] is False
assert result["error"] == "Test error"
assert result["error_type"] == "TestError"
assert result["details"]["key"] == "value"
assert "Suggestion 1" in result["suggestions"]
assert "Action 1" in result["recovery_actions"]
assert result["context"]["component"] == "test"
def test_create_error_response(self):
"""Test create_error_response function."""
error = ValidationError("Validation failed", validation_type="test")
response = create_error_response(error)
assert response["success"] is False
assert response["error"] == "Validation failed"
assert response["error_type"] == "ValidationError"
assert "suggestions" in response
def test_create_success_response(self):
"""Test create_success_response function."""
data = {"key": "value"}
response = create_success_response(data, message="Success message")
assert response["success"] is True
assert response["key"] == "value"
assert response["message"] == "Success message"
def test_format_validation_error(self):
"""Test format_validation_error function."""
response = format_validation_error(
"Invalid format",
invalid_value="test",
expected_format="expected",
validation_rules=["Rule 1", "Rule 2"],
)
assert response["success"] is False
assert response["error"] == "Invalid format"
assert response["error_type"] == "ValidationError"
assert "Rule 1" in response["suggestions"]
assert "Rule 2" in response["suggestions"]
def test_format_git_error(self):
"""Test format_git_error function."""
response = format_git_error(
"Git error", git_command="commit", repo_path="/path/to/repo", exit_code=128
)
assert response["success"] is False
assert response["error"] == "Git error"
assert response["error_type"] == "GitOperationError"
assert response["details"]["git_command"] == "commit"
assert response["details"]["repo_path"] == "/path/to/repo"
assert response["details"]["exit_code"] == 128