""" Unit tests for the Logger module. """ import pytest import sys import tempfile import os from pathlib import Path from unittest.mock import patch, MagicMock from loguru import logger from src.logger import setup_logger, get_logger, LoggerMixin class TestLoggerSetup: """Test cases for logger setup functionality.""" def test_setup_logger_default(self): """Test logger setup with default parameters.""" with patch('loguru.logger.remove') as mock_remove, \ patch('loguru.logger.add') as mock_add: setup_logger() # Verify default logger was removed mock_remove.assert_called_once() # Verify console logger was added assert mock_add.call_count == 1 console_call = mock_add.call_args_list[0] assert console_call[0][0] == sys.stderr assert "level" in console_call[1] assert console_call[1]["colorize"] is True def test_setup_logger_with_file(self): """Test logger setup with file output.""" with tempfile.NamedTemporaryFile(delete=False) as tmp_file: log_file = tmp_file.name try: with patch('loguru.logger.remove') as mock_remove, \ patch('loguru.logger.add') as mock_add: setup_logger(log_file=log_file) # Verify both console and file loggers were added assert mock_add.call_count == 2 # Check file logger call file_call = mock_add.call_args_list[1] assert file_call[0][0] == log_file assert "rotation" in file_call[1] assert "retention" in file_call[1] assert "compression" in file_call[1] finally: # Clean up if os.path.exists(log_file): os.unlink(log_file) def test_setup_logger_verbose(self): """Test logger setup with verbose mode.""" with patch('loguru.logger.remove') as mock_remove, \ patch('loguru.logger.add') as mock_add: setup_logger(verbose=True) # Verify DEBUG level was set console_call = mock_add.call_args_list[0] assert console_call[1]["level"] == "DEBUG" def test_setup_logger_custom_level(self): """Test logger setup with custom log level.""" with patch('loguru.logger.remove') as mock_remove, \ patch('loguru.logger.add') as mock_add: setup_logger(log_level="WARNING") # Verify WARNING level was set console_call = mock_add.call_args_list[0] assert console_call[1]["level"] == "WARNING" def test_setup_logger_custom_rotation(self): """Test logger setup with custom rotation settings.""" with tempfile.NamedTemporaryFile(delete=False) as tmp_file: log_file = tmp_file.name try: with patch('loguru.logger.remove') as mock_remove, \ patch('loguru.logger.add') as mock_add: setup_logger(log_file=log_file, rotation="100 MB") # Verify custom rotation was set file_call = mock_add.call_args_list[1] assert file_call[1]["rotation"] == "100 MB" finally: # Clean up if os.path.exists(log_file): os.unlink(log_file) def test_setup_logger_exception_handler(self): """Test that exception handler is set up.""" with patch('loguru.logger.remove') as mock_remove, \ patch('loguru.logger.add') as mock_add, \ patch('sys.excepthook') as mock_excepthook: setup_logger() # Verify exception handler was set assert mock_excepthook is not None assert callable(mock_excepthook) class TestGetLogger: """Test cases for get_logger function.""" def test_get_logger_no_name(self): """Test getting logger without name.""" with patch('loguru.logger.bind') as mock_bind: get_logger() mock_bind.assert_called_once() def test_get_logger_with_name(self): """Test getting logger with name.""" with patch('loguru.logger.bind') as mock_bind: get_logger("test_module") mock_bind.assert_called_once_with(name="test_module") class TestLoggerMixin: """Test cases for LoggerMixin class.""" def test_logger_property(self): """Test logger property in mixin.""" class TestClass(LoggerMixin): pass with patch('loguru.logger.bind') as mock_bind: test_obj = TestClass() _ = test_obj.logger # Verify logger was bound with class name and object id mock_bind.assert_called_once() args, kwargs = mock_bind.call_args assert kwargs["name"] == "TestClass" assert "id" in kwargs def test_logger_mixin_inheritance(self): """Test that logger mixin works with inheritance.""" class ParentClass(LoggerMixin): pass class ChildClass(ParentClass): pass with patch('loguru.logger.bind') as mock_bind: child_obj = ChildClass() _ = child_obj.logger # Verify logger was bound with child class name args, kwargs = mock_bind.call_args assert kwargs["name"] == "ChildClass"