Files
thechart/tests/test_logger.py
William Valentin 21dd1fc9c8
Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
refactor: Update import statements to include 'src' prefix for module paths
2025-07-29 16:52:46 -07:00

181 lines
7.6 KiB
Python

"""
Tests for logger module.
"""
import os
import logging
import tempfile
import pytest
from unittest.mock import patch, Mock
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