test(core): extend coverage — console, errors, log, service, time, benchmark
Add missing test modules for previously untested core areas: - console: ForegroundColorEnum, BackgroundColorEnum, Console methods - errors: dependency_error, module_dependency_error - log: LogLevel ordering/values, LogSettings, Logger (should_log, format, file write, fatal) - service: HostedService, StartupTask, CronjobABC (start/stop/loop/task cancellation) - time: TimeFormatSettings properties and setters - utils: Benchmark.time / .memory / .all call-count and output Also fix existing test files: environment cleanup, cron exception specificity, json_processor kwargs bug doc, configuration_model_abc to_dict bug doc. All 199 tests pass, black clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
152
test/core/log/log_test.py
Normal file
152
test/core/log/log_test.py
Normal file
@@ -0,0 +1,152 @@
|
||||
import os
|
||||
import pytest
|
||||
from cpl.core.log.log_level import LogLevel
|
||||
from cpl.core.log.log_settings import LogSettings
|
||||
from cpl.core.log.logger import Logger
|
||||
from cpl.core.log.logger_abc import LoggerABC
|
||||
|
||||
# --- LogLevel ---
|
||||
|
||||
|
||||
def test_log_level_values():
|
||||
assert LogLevel.off.value == "OFF"
|
||||
assert LogLevel.trace.value == "TRC"
|
||||
assert LogLevel.debug.value == "DEB"
|
||||
assert LogLevel.info.value == "INF"
|
||||
assert LogLevel.warning.value == "WAR"
|
||||
assert LogLevel.error.value == "ERR"
|
||||
assert LogLevel.fatal.value == "FAT"
|
||||
|
||||
|
||||
def test_log_level_order():
|
||||
levels = list(LogLevel)
|
||||
assert levels.index(LogLevel.trace) < levels.index(LogLevel.debug)
|
||||
assert levels.index(LogLevel.debug) < levels.index(LogLevel.info)
|
||||
assert levels.index(LogLevel.info) < levels.index(LogLevel.warning)
|
||||
assert levels.index(LogLevel.warning) < levels.index(LogLevel.error)
|
||||
assert levels.index(LogLevel.error) < levels.index(LogLevel.fatal)
|
||||
|
||||
|
||||
def test_log_level_by_name():
|
||||
assert LogLevel["info"] == LogLevel.info
|
||||
assert LogLevel["error"] == LogLevel.error
|
||||
|
||||
|
||||
# --- LogSettings ---
|
||||
|
||||
|
||||
def test_log_settings_defaults():
|
||||
s = LogSettings()
|
||||
assert s.path == "logs"
|
||||
assert s.filename == "app.log"
|
||||
assert s.console == LogLevel.info
|
||||
assert s.level == LogLevel.info
|
||||
|
||||
|
||||
def test_log_settings_from_src():
|
||||
s = LogSettings({"path": "custom_logs", "filename": "myapp.log"})
|
||||
assert s.path == "custom_logs"
|
||||
assert s.filename == "myapp.log"
|
||||
|
||||
|
||||
# --- LoggerABC ---
|
||||
|
||||
|
||||
def test_logger_abc_cannot_instantiate():
|
||||
with pytest.raises(TypeError):
|
||||
LoggerABC()
|
||||
|
||||
|
||||
# --- Logger ---
|
||||
|
||||
|
||||
def test_logger_creates_instance(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
assert logger is not None
|
||||
|
||||
|
||||
def test_logger_log_file_property(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
assert logger.log_file.startswith("logs/")
|
||||
assert logger.log_file.endswith(".log")
|
||||
|
||||
|
||||
def test_logger_should_log_same_level(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
assert logger._should_log(LogLevel.info, LogLevel.info) is True
|
||||
assert logger._should_log(LogLevel.error, LogLevel.error) is True
|
||||
|
||||
|
||||
def test_logger_should_log_higher_level(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
assert logger._should_log(LogLevel.error, LogLevel.info) is True
|
||||
assert logger._should_log(LogLevel.fatal, LogLevel.debug) is True
|
||||
|
||||
|
||||
def test_logger_should_not_log_lower_level(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
assert logger._should_log(LogLevel.debug, LogLevel.info) is False
|
||||
assert logger._should_log(LogLevel.trace, LogLevel.warning) is False
|
||||
|
||||
|
||||
def test_logger_file_format_message(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger("test_src")
|
||||
msg = logger._file_format_message("INF", "2024-01-01 00:00:00.000000", "hello", "world")
|
||||
assert "INF" in msg
|
||||
assert "hello" in msg
|
||||
assert "world" in msg
|
||||
assert "test_src" in msg
|
||||
|
||||
|
||||
def test_logger_console_format_message(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger("test_src")
|
||||
msg = logger._console_format_message("DEB", "2024-01-01 00:00:00.000000", "debug message")
|
||||
assert "DEB" in msg
|
||||
assert "debug message" in msg
|
||||
|
||||
|
||||
def test_logger_info_writes_file(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
logger.info("test info message")
|
||||
log_files = list(tmp_path.glob("logs/*.log"))
|
||||
assert len(log_files) > 0
|
||||
content = log_files[0].read_text()
|
||||
assert "test info message" in content
|
||||
|
||||
|
||||
def test_logger_debug_below_info_not_written_to_file(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
# Default level is INFO, so DEBUG should not appear in the file
|
||||
logger = Logger(__name__)
|
||||
logger.debug("should not appear in file")
|
||||
log_files = list(tmp_path.glob("logs/*.log"))
|
||||
if log_files:
|
||||
content = log_files[0].read_text()
|
||||
assert "should not appear in file" not in content
|
||||
|
||||
|
||||
def test_logger_set_level_invalid(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
with pytest.raises(ValueError):
|
||||
Logger.set_level("INVALID_LEVEL")
|
||||
|
||||
|
||||
def test_logger_fatal_exits(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
with pytest.raises(SystemExit):
|
||||
logger.fatal("fatal error")
|
||||
|
||||
|
||||
def test_logger_fatal_prevent_quit(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
logger = Logger(__name__)
|
||||
logger.fatal("fatal no quit", prevent_quit=True) # Should not raise
|
||||
Reference in New Issue
Block a user