test_execution_engine, test_mcp_server_code_execution test_mcp_server_files_search test_mcp_server_web_search müssen noch gemacht werden
148 lines
5.8 KiB
Python
148 lines
5.8 KiB
Python
"""Tests for DebugLogger (backend/managers/debug_logger.py)."""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
import pytest
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from backend.managers.debug_logger import DebugLogger
|
|
|
|
|
|
# ── Fixtures ──────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.fixture
|
|
def logger():
|
|
return DebugLogger()
|
|
|
|
|
|
# ── Initialization ────────────────────────────────────────────────────────────
|
|
|
|
class TestInit:
|
|
def test_logs_start_empty(self, logger):
|
|
assert logger.logs == []
|
|
|
|
|
|
# ── log() ─────────────────────────────────────────────────────────────────────
|
|
|
|
class TestLog:
|
|
def test_log_appends_entry(self, logger):
|
|
logger.log("started")
|
|
assert len(logger.logs) == 1
|
|
|
|
def test_log_sets_level_info(self, logger):
|
|
logger.log("started")
|
|
assert logger.logs[0]["level"] == "INFO"
|
|
|
|
def test_log_stores_message(self, logger):
|
|
logger.log("executing file.py")
|
|
assert logger.logs[0]["message"] == "executing file.py"
|
|
|
|
def test_log_adds_timestamp(self, logger):
|
|
logger.log("started")
|
|
ts = logger.logs[0]["timestamp"]
|
|
# HH:MM:SS format — exactly 8 chars with two colons
|
|
assert len(ts) == 8
|
|
assert ts[2] == ":" and ts[5] == ":"
|
|
|
|
|
|
# ── log_error() ───────────────────────────────────────────────────────────────
|
|
|
|
class TestLogError:
|
|
def test_log_error_appends_entry(self, logger):
|
|
logger.log_error("something broke")
|
|
assert len(logger.logs) == 1
|
|
|
|
def test_log_error_sets_level_error(self, logger):
|
|
logger.log_error("something broke")
|
|
assert logger.logs[0]["level"] == "ERROR"
|
|
|
|
def test_log_error_stores_message(self, logger):
|
|
logger.log_error("exit code 1")
|
|
assert logger.logs[0]["message"] == "exit code 1"
|
|
|
|
def test_log_and_log_error_are_distinct_levels(self, logger):
|
|
logger.log("info message")
|
|
logger.log_error("error message")
|
|
assert logger.logs[0]["level"] == "INFO"
|
|
assert logger.logs[1]["level"] == "ERROR"
|
|
|
|
|
|
# ── get_logs() ────────────────────────────────────────────────────────────────
|
|
|
|
class TestGetLogs:
|
|
def test_get_logs_returns_all_entries(self, logger):
|
|
logger.log("first")
|
|
logger.log_error("second")
|
|
assert len(logger.get_logs()) == 2
|
|
|
|
def test_get_logs_returns_internal_list(self, logger):
|
|
assert logger.get_logs() is logger.logs
|
|
|
|
|
|
# ── clear() ───────────────────────────────────────────────────────────────────
|
|
|
|
class TestClear:
|
|
def test_clear_removes_all_entries(self, logger):
|
|
logger.log("first")
|
|
logger.log_error("second")
|
|
logger.clear()
|
|
assert logger.logs == []
|
|
|
|
def test_clear_on_empty_is_safe(self, logger):
|
|
logger.clear()
|
|
assert logger.logs == []
|
|
|
|
def test_log_after_clear_works(self, logger):
|
|
logger.log("before")
|
|
logger.clear()
|
|
logger.log("after")
|
|
assert len(logger.logs) == 1
|
|
assert logger.logs[0]["message"] == "after"
|
|
|
|
|
|
# ── format_debug_output() ─────────────────────────────────────────────────────
|
|
|
|
class TestFormatDebugOutput:
|
|
def test_success_exit_code_shows_success(self, logger):
|
|
result = logger.format_debug_output({"rc": 0, "stdout": "", "stderr": ""})
|
|
assert "[SUCCESS]" in result
|
|
|
|
def test_nonzero_exit_code_shows_failed(self, logger):
|
|
result = logger.format_debug_output({"rc": 1, "stdout": "", "stderr": ""})
|
|
assert "[FAILED]" in result
|
|
|
|
def test_exit_code_included_in_output(self, logger):
|
|
result = logger.format_debug_output({"rc": 42, "stdout": "", "stderr": ""})
|
|
assert "42" in result
|
|
|
|
def test_stdout_included_when_present(self, logger):
|
|
result = logger.format_debug_output({"rc": 0, "stdout": "Hello", "stderr": ""})
|
|
assert "Hello" in result
|
|
assert "stdout" in result
|
|
|
|
def test_stderr_included_when_present(self, logger):
|
|
result = logger.format_debug_output({"rc": 1, "stdout": "", "stderr": "NameError"})
|
|
assert "NameError" in result
|
|
assert "stderr" in result
|
|
|
|
def test_no_output_message_when_both_empty(self, logger):
|
|
result = logger.format_debug_output({"rc": 0, "stdout": "", "stderr": ""})
|
|
assert "No output produced." in result
|
|
|
|
def test_log_entries_appended_to_output(self, logger):
|
|
logger.log("Executing file.py...")
|
|
logger.log_error("exit code 1")
|
|
result = logger.format_debug_output({"rc": 1, "stdout": "", "stderr": ""})
|
|
assert "Executing file.py..." in result
|
|
assert "exit code 1" in result
|
|
|
|
def test_returns_string(self, logger):
|
|
result = logger.format_debug_output({"rc": 0, "stdout": "", "stderr": ""})
|
|
assert isinstance(result, str)
|
|
|
|
def test_missing_keys_do_not_raise(self, logger):
|
|
# Defensive: format_debug_output uses .get() so missing keys are safe
|
|
result = logger.format_debug_output({})
|
|
assert isinstance(result, str)
|