Files
hqt/tests/test_logging.py
felixm 90944948f5 Initial commit: hqt — HQ Terminal TUI
TUI for orchestrating AI coding harness sessions (Claude Code, Codex,
Kiro, etc.) via tmux. Click CLI bootstraps a Textual TUI over
ProjectService/SessionService backed by SQLite, spawning harness
sessions as tmux windows through TmuxManager.

Includes recent fixes:
- Visible Tab focus highlight on dialog OK/Cancel buttons
- Auto-select first project on launch
- Auto-select first session + per-project session-selection memory
- tmux new-window targets an explicit free index, fixing
  "index N in use" failures (broken spawn/attach in attached sessions)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:06:57 -04:00

43 lines
1.5 KiB
Python

import logging
import sys
import hqt.logging as hqt_logging
from hqt.config import Settings
def test_setup_logging_does_not_write_to_terminal(tmp_path, monkeypatch):
"""setup_logging must NOT attach a StreamHandler that writes to the real
terminal stderr/stdout.
The TUI is a Textual app that paints to sys.__stderr__. A root-logger
StreamHandler bound to that same fd writes raw log lines straight onto the
pane Textual owns, corrupting tmux's grid — visible as rendering artifacts
when switching back to the hqt window. Logs must go to file only.
"""
settings = Settings(db_path=tmp_path / "hqt.db")
monkeypatch.setattr(hqt_logging, "get_settings", lambda: settings)
root = logging.getLogger()
saved_handlers = root.handlers[:]
saved_level = root.level
try:
root.handlers.clear()
hqt_logging.setup_logging()
terminal_streams = {sys.stderr, sys.__stderr__, sys.stdout, sys.__stdout__}
offending = [
h
for h in root.handlers
# FileHandler subclasses StreamHandler but writes to a file, not the terminal.
if type(h) is logging.StreamHandler
and getattr(h, "stream", None) in terminal_streams
]
assert not offending, (
f"setup_logging attached a terminal StreamHandler: {offending}"
)
# Logs are still captured to a file.
assert any(isinstance(h, logging.FileHandler) for h in root.handlers)
finally:
root.handlers[:] = saved_handlers
root.setLevel(saved_level)