""" Tests for logger module. """ import os import logging import pytest from unittest.mock import patch import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) from src.logger import init_logger class TestLogger: """Test cases for the logger module.""" def test_init_logger_basic(self, temp_log_dir): """Test basic logger initialization.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) assert isinstance(logger, logging.Logger) assert logger.name == "test_logger" assert logger.level == logging.INFO def test_init_logger_testing_mode(self, temp_log_dir): """Test logger initialization in testing mode.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=True) assert logger.level == logging.DEBUG def test_init_logger_production_mode(self, temp_log_dir): """Test logger initialization in production mode.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) assert logger.level == logging.INFO def test_file_handlers_created(self, temp_log_dir): """Test that file handlers are created correctly.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) # Check that handlers were added assert len(logger.handlers) >= 3 # At least 3 file handlers def test_file_handler_levels(self, temp_log_dir): """Test that file handlers have correct log levels.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) handler_levels = [handler.level for handler in logger.handlers if isinstance(handler, logging.FileHandler)] # Should have handlers for DEBUG, WARNING, and ERROR levels assert logging.DEBUG in handler_levels assert logging.WARNING in handler_levels assert logging.ERROR in handler_levels def test_log_file_paths(self, temp_log_dir): """Test that log files are created with correct paths.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) # Log something to trigger file creation logger.debug("Test debug message") logger.warning("Test warning message") logger.error("Test error message") # Check that log files would be created (paths are correct) expected_files = [ os.path.join(temp_log_dir, "app.log"), os.path.join(temp_log_dir, "app.warning.log"), os.path.join(temp_log_dir, "app.error.log") ] # The files should exist or be ready to be created for handler in logger.handlers: if isinstance(handler, logging.FileHandler): assert handler.baseFilename in expected_files def test_formatter_format(self, temp_log_dir): """Test that formatters are set correctly.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) expected_format = "%(asctime)s - %(name)s - %(funcName)s - %(levelname)s - %(message)s" for handler in logger.handlers: if isinstance(handler, logging.FileHandler): assert handler.formatter._fmt == expected_format @patch('colorlog.basicConfig') def test_colorlog_configuration(self, mock_basicConfig, temp_log_dir): """Test that colorlog is configured correctly.""" with patch('logger.LOG_PATH', temp_log_dir): init_logger("test_logger", testing_mode=False) mock_basicConfig.assert_called_once() # Check that format includes color and bold formatting call_args = mock_basicConfig.call_args assert 'format' in call_args[1] format_string = call_args[1]['format'] assert '%(log_color)s' in format_string assert '\033[1m' in format_string # Bold sequence def test_multiple_logger_instances(self, temp_log_dir): """Test creating multiple logger instances.""" with patch('logger.LOG_PATH', temp_log_dir): logger1 = init_logger("logger1", testing_mode=False) logger2 = init_logger("logger2", testing_mode=True) assert logger1.name == "logger1" assert logger2.name == "logger2" assert logger1.level == logging.INFO assert logger2.level == logging.DEBUG def test_logger_inheritance(self, temp_log_dir): """Test that logger follows Python logging hierarchy.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test.module.logger", testing_mode=False) assert logger.name == "test.module.logger" @patch('logging.FileHandler') def test_file_handler_error_handling(self, mock_file_handler, temp_log_dir): """Test error handling when file handler creation fails.""" mock_file_handler.side_effect = PermissionError("Cannot create log file") with patch('logger.LOG_PATH', temp_log_dir): # Should not raise an exception, but handle gracefully try: logger = init_logger("test_logger", testing_mode=False) # Logger should still be created, just without file handlers assert isinstance(logger, logging.Logger) except PermissionError: pytest.fail("init_logger should handle file creation errors gracefully") def test_logger_name_parameter(self, temp_log_dir): """Test that logger name is set correctly from parameter.""" with patch('logger.LOG_PATH', temp_log_dir): test_name = "my.custom.logger.name" logger = init_logger(test_name, testing_mode=False) assert logger.name == test_name def test_testing_mode_boolean(self, temp_log_dir): """Test that testing_mode parameter accepts boolean values.""" with patch('logger.LOG_PATH', temp_log_dir): logger_true = init_logger("test1", testing_mode=True) logger_false = init_logger("test2", testing_mode=False) assert logger_true.level == logging.DEBUG assert logger_false.level == logging.INFO def test_log_format_contains_required_fields(self, temp_log_dir): """Test that log format contains all required fields.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) log_format = "%(asctime)s - %(name)s - %(funcName)s - %(levelname)s - %(message)s" # Check that format contains all expected fields expected_fields = ['%(asctime)s', '%(name)s', '%(funcName)s', '%(levelname)s', '%(message)s'] for field in expected_fields: assert field in log_format def test_handler_file_mode(self, temp_log_dir): """Test that file handlers use append mode by default.""" with patch('logger.LOG_PATH', temp_log_dir): logger = init_logger("test_logger", testing_mode=False) # File handlers should be in append mode by default for handler in logger.handlers: if isinstance(handler, logging.FileHandler): # FileHandler uses 'a' mode by default assert hasattr(handler, 'mode') # Basic check that it's a file handler