"""Tests for error handling system.""" import pytest from unittest.mock import MagicMock, patch import time import logging from src.error_handler import ErrorHandler, OperationTimer class TestErrorHandler: """Test cases for ErrorHandler class.""" def setup_method(self): """Set up test fixtures before each test method.""" self.mock_logger = MagicMock() self.mock_ui_manager = MagicMock() self.error_handler = ErrorHandler(self.mock_logger, self.mock_ui_manager) def test_error_handler_initialization(self): """Test ErrorHandler initializes correctly.""" assert self.error_handler.logger == self.mock_logger assert self.error_handler.ui_manager == self.mock_ui_manager assert self.error_handler.error_counts == {} assert self.error_handler.last_error_time == {} def test_handle_error_basic(self): """Test basic error handling.""" error = ValueError("Test error") self.error_handler.handle_error(error, "Test context") # Verify logging self.mock_logger.error.assert_called_once() # Verify UI feedback if show_dialog is True self.mock_ui_manager.show_error_dialog.assert_called_once() def test_handle_error_without_dialog(self): """Test error handling without showing dialog.""" error = ValueError("Test error") self.error_handler.handle_error(error, "Test context", show_dialog=False) # Verify logging self.mock_logger.error.assert_called_once() # Verify no UI dialog self.mock_ui_manager.show_error_dialog.assert_not_called() def test_handle_error_with_custom_message(self): """Test error handling with custom user message.""" error = ValueError("Test error") custom_message = "Custom error message" self.error_handler.handle_error(error, "Test context", user_message=custom_message) # Verify custom message is used self.mock_ui_manager.show_error_dialog.assert_called_once() args = self.mock_ui_manager.show_error_dialog.call_args[0] assert custom_message in args[0] def test_error_frequency_tracking(self): """Test that error frequency is tracked correctly.""" error = ValueError("Test error") context = "Test context" # Handle same error multiple times self.error_handler.handle_error(error, context) self.error_handler.handle_error(error, context) self.error_handler.handle_error(error, context) # Check error counting error_key = f"{type(error).__name__}:{context}" assert self.error_handler.error_counts[error_key] == 3 def test_log_performance_warning(self): """Test performance warning logging.""" operation = "test_operation" duration = 5.0 self.error_handler.log_performance_warning(operation, duration) # Verify warning is logged self.mock_logger.warning.assert_called_once() log_call = self.mock_logger.warning.call_args[0][0] assert "Performance warning" in log_call assert operation in log_call assert str(duration) in log_call def test_operation_timer_context_manager(self): """Test operation timer context manager.""" timer = OperationTimer(self.error_handler, "test_operation") with timer: time.sleep(0.1) # Short sleep to simulate work # With default threshold, this should not trigger a warning self.mock_logger.warning.assert_not_called() def test_operation_timer_with_warning(self): """Test operation timer triggers warning for slow operations.""" # Use very low threshold to trigger warning timer = OperationTimer(self.error_handler, "test_operation", warning_threshold=0.01) with timer: time.sleep(0.1) # Sleep longer than threshold # Should trigger performance warning self.mock_logger.warning.assert_called_once() def test_multiple_error_types(self): """Test handling different types of errors.""" errors = [ ValueError("Value error"), FileNotFoundError("File not found"), RuntimeError("Runtime error"), ] for error in errors: self.error_handler.handle_error(error, "Test context") # Verify all errors were logged assert self.mock_logger.error.call_count == len(errors) assert self.mock_ui_manager.show_error_dialog.call_count == len(errors) class TestErrorHandlerEdgeCases: """Test edge cases and error conditions.""" def setup_method(self): """Set up test fixtures.""" self.mock_logger = MagicMock() self.error_handler = ErrorHandler(self.mock_logger) # No UI manager def test_error_handler_without_ui_manager(self): """Test error handling when UI manager is not available.""" error = ValueError("Test error") # Should not raise exception even without UI manager self.error_handler.handle_error(error, "Test context") # Should still log the error self.mock_logger.error.assert_called_once() def test_handle_none_error(self): """Test handling when error is None.""" # Should handle gracefully self.error_handler.handle_error(None, "Test context") # Should still attempt to log self.mock_logger.error.assert_called_once() def test_operation_timer_without_error_handler(self): """Test operation timer with None error handler.""" timer = OperationTimer(None, "test_operation") # Should not raise exception with timer: time.sleep(0.1) def test_empty_context(self): """Test error handling with empty context.""" error = ValueError("Test error") self.error_handler.handle_error(error, "") # Should still work with empty context self.mock_logger.error.assert_called_once() if __name__ == "__main__": pytest.main([__file__])