Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,28 @@
import shutil

# Content, saves, logs and user settings are all addressed relative to the
# repo, and some are opened at import time, so this runs before any game import.
# repo, and some are opened at import time, so this runs before anything else.
os.chdir(os.path.dirname(os.path.abspath(__file__)))

from src.game_engine import main # noqa: E402
from src.ui.textual_ui import TextualGameUI # noqa: E402 composition root: the frontend is chosen HERE

if __name__ == "__main__":
# Create necessary directories if they don't exist
os.makedirs("data/rooms", exist_ok=True)
os.makedirs("data/items", exist_ok=True)
os.makedirs("data/enemies", exist_ok=True)
os.makedirs("data/npcs", exist_ok=True)

# Copy debug.log to combat.log on each restart (overwrites old combat.log)
if os.path.exists("debug.log"):
shutil.copy2("debug.log", "combat.log")
# Clear debug.log for fresh logging this session
with open("debug.log", "w") as f:
f.write("")
def rotate_logs(log_file: str, previous: str = "combat.log") -> None:
"""Start the session with an empty log; keep the last session's as `previous`."""
if os.path.exists(log_file):
shutil.copy2(log_file, previous)
else:
# Create empty combat.log if debug.log doesn't exist
with open("combat.log", "w") as f:
with open(previous, "w") as f:
f.write("=== Combat Log (Fresh Session) ===\n")
open(log_file, "w").close()


if __name__ == "__main__":
from config.dev_config import DEBUG_LOG_FILE

# Before the game modules load: some of them log while importing.
rotate_logs(DEBUG_LOG_FILE)

from src.game_engine import main
from src.ui.textual_ui import TextualGameUI # composition root: the frontend is chosen HERE

# Run the game — build the concrete frontend and inject it into the backend.
main(TextualGameUI())
main(TextualGameUI())
54 changes: 54 additions & 0 deletions tests/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Debug logging goes to the log file only, and each launch starts a fresh one.

debug_log used to echo every line to the terminal as well. Lines printed while
the world loaded sat behind the game screen and reappeared in the terminal when
the player quit; the log panel (L) already shows them from the file.
"""
from __future__ import annotations

from pathlib import Path

import pytest

import main
import utils.debug_tools as debug_tools


def test_debug_log_writes_the_file_not_the_terminal(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str],
) -> None:
log = tmp_path / "debug.log"
monkeypatch.setattr(debug_tools, "DEBUG_MODE", True)
monkeypatch.setattr(debug_tools, "DEBUG_LOG_FILE", str(log))

debug_tools.debug_log("world loaded", "system")

captured = capsys.readouterr()
assert captured.out == "" and captured.err == ""
assert "world loaded" in log.read_text()


def test_each_launch_starts_an_empty_log_and_keeps_the_last_one(tmp_path: Path) -> None:
log, previous = tmp_path / "debug.log", tmp_path / "combat.log"
log.write_text("last session\n")

main.rotate_logs(str(log), str(previous))

assert log.read_text() == ""
assert previous.read_text() == "last session\n"


def test_first_launch_creates_both_files(tmp_path: Path) -> None:
log, previous = tmp_path / "debug.log", tmp_path / "combat.log"

main.rotate_logs(str(log), str(previous))

assert log.read_text() == ""
assert previous.exists()


def test_logs_rotate_before_the_game_modules_load() -> None:
"""Some modules log while importing (the combat system's attack table);
rotating after the imports erased those lines from the new session."""
source = Path(main.__file__).read_text()
assert source.index("rotate_logs(") < source.index("from src.")
10 changes: 5 additions & 5 deletions utils/debug_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@

def debug_log(message: object, category: str = "system") -> None:
"""
Log a debug message to the debug log file and console if DEBUG_MODE is True.
Log a debug message to the debug log file if DEBUG_MODE is True.

File only: the game screen owns the terminal, and anything printed there
is left behind in the player's scrollback when they quit. The log panel
(L) shows the file.

Args:
message (str): The message to log
Expand All @@ -52,10 +56,6 @@ def debug_log(message: object, category: str = "system") -> None:
# Format the log message
log_message = f"[{timestamp}] [{category.upper()}] [{filename}:{function_name}:{line_number}] {message}"

# Print to console
print(log_message, file=sys.stderr)

# Write to log file
try:
with open(DEBUG_LOG_FILE, "a") as f:
f.write(log_message + "\n")
Expand Down
Loading