|
1 | 1 | """Unit tests for functions defined in src/log.py.""" |
2 | 2 |
|
3 | 3 | import logging |
| 4 | + |
4 | 5 | import pytest |
| 6 | +from pytest_mock import MockerFixture |
| 7 | +from rich.logging import RichHandler |
5 | 8 |
|
6 | | -from log import get_logger |
7 | | -from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR |
| 9 | +from log import get_logger, resolve_log_level, create_log_handler |
| 10 | +from constants import LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, DEFAULT_LOG_FORMAT |
8 | 11 |
|
9 | 12 |
|
10 | 13 | def test_get_logger() -> None: |
@@ -57,3 +60,59 @@ def test_get_logger_default_log_level(monkeypatch: pytest.MonkeyPatch) -> None: |
57 | 60 |
|
58 | 61 | logger = get_logger("test_default") |
59 | 62 | assert logger.level == logging.INFO |
| 63 | + |
| 64 | + |
| 65 | +@pytest.mark.parametrize( |
| 66 | + ("level_name", "expected_level"), |
| 67 | + [ |
| 68 | + ("DEBUG", logging.DEBUG), |
| 69 | + ("debug", logging.DEBUG), |
| 70 | + ("INFO", logging.INFO), |
| 71 | + ("WARNING", logging.WARNING), |
| 72 | + ("ERROR", logging.ERROR), |
| 73 | + ("CRITICAL", logging.CRITICAL), |
| 74 | + ("critical", logging.CRITICAL), |
| 75 | + ], |
| 76 | +) |
| 77 | +def test_resolve_log_level( |
| 78 | + monkeypatch: pytest.MonkeyPatch, level_name: str, expected_level: int |
| 79 | +) -> None: |
| 80 | + """Test that resolve_log_level correctly resolves valid level names.""" |
| 81 | + monkeypatch.setenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, level_name) |
| 82 | + assert resolve_log_level() == expected_level |
| 83 | + |
| 84 | + |
| 85 | +def test_resolve_log_level_invalid_fallback(monkeypatch: pytest.MonkeyPatch) -> None: |
| 86 | + """Test that resolve_log_level falls back to INFO for invalid values.""" |
| 87 | + monkeypatch.setenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, "BOGUS") |
| 88 | + assert resolve_log_level() == logging.INFO |
| 89 | + |
| 90 | + |
| 91 | +def test_resolve_log_level_default(monkeypatch: pytest.MonkeyPatch) -> None: |
| 92 | + """Test that resolve_log_level defaults to INFO when env var is unset.""" |
| 93 | + monkeypatch.delenv(LIGHTSPEED_STACK_LOG_LEVEL_ENV_VAR, raising=False) |
| 94 | + assert resolve_log_level() == logging.INFO |
| 95 | + |
| 96 | + |
| 97 | +def test_create_log_handler_tty(mocker: MockerFixture) -> None: |
| 98 | + """Test that create_log_handler returns RichHandler when TTY is available.""" |
| 99 | + mocker.patch("sys.stderr.isatty", return_value=True) |
| 100 | + handler = create_log_handler() |
| 101 | + assert isinstance(handler, RichHandler) |
| 102 | + |
| 103 | + |
| 104 | +def test_create_log_handler_non_tty(mocker: MockerFixture) -> None: |
| 105 | + """Test that create_log_handler returns StreamHandler when no TTY.""" |
| 106 | + mocker.patch("sys.stderr.isatty", return_value=False) |
| 107 | + handler = create_log_handler() |
| 108 | + assert isinstance(handler, logging.StreamHandler) |
| 109 | + assert not isinstance(handler, RichHandler) |
| 110 | + |
| 111 | + |
| 112 | +def test_create_log_handler_non_tty_format(mocker: MockerFixture) -> None: |
| 113 | + """Test that non-TTY handler uses DEFAULT_LOG_FORMAT.""" |
| 114 | + mocker.patch("sys.stderr.isatty", return_value=False) |
| 115 | + handler = create_log_handler() |
| 116 | + assert handler.formatter is not None |
| 117 | + # pylint: disable=protected-access |
| 118 | + assert handler.formatter._fmt == DEFAULT_LOG_FORMAT |
0 commit comments