nightshift/tests/test_terminal.py
K. Hodges 93a50ddb42 added hotdog animations
I am a professional software engineer
2026-05-20 03:55:43 -07:00

90 lines
3.0 KiB
Python

from io import StringIO
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from nightshift.artifacts import ArtifactStore
from nightshift.runlog import RunLogger
from nightshift.terminal import (
HOTDOG_ANIMATIONS,
TerminalAnimation,
animation_frames,
format_banner,
format_console_event_line,
)
class FakeTTY(StringIO):
def isatty(self) -> bool:
return True
class TerminalStylingTests(unittest.TestCase):
def test_banner_is_plain_without_tty(self) -> None:
banner = format_banner(stream=StringIO())
self.assertIn("NightShift", banner)
self.assertNotIn("\x1b[", banner)
def test_banner_uses_ansi_when_tty(self) -> None:
banner = format_banner(stream=FakeTTY())
self.assertIn("NightShift", banner)
self.assertIn("\x1b[", banner)
def test_animation_frames_fall_back_to_agent_thinking(self) -> None:
self.assertEqual(animation_frames("missing"), tuple(HOTDOG_ANIMATIONS["agent_thinking"]))
self.assertEqual(animation_frames("classic_dance"), tuple(HOTDOG_ANIMATIONS["classic_dance"]))
def test_terminal_animation_is_disabled_for_non_tty(self) -> None:
stream = StringIO()
animation = TerminalAnimation(stream=stream)
with animation:
pass
self.assertEqual(stream.getvalue(), "")
def test_console_event_line_colors_success_and_failure(self) -> None:
success = format_console_event_line(
"2026-05-17T00:00:00Z",
"task.finish",
"Finished task",
{"status": "complete"},
stream=FakeTTY(),
)
failure = format_console_event_line(
"2026-05-17T00:00:00Z",
"task.finish",
"Finished task",
{"status": "failed"},
stream=FakeTTY(),
)
self.assertIn("\x1b[32m", success)
self.assertIn("\x1b[31m", failure)
self.assertTrue(success.endswith("\x1b[0m"))
self.assertTrue(failure.endswith("\x1b[0m"))
def test_run_logger_console_output_is_separate_from_run_log(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
artifacts = ArtifactStore(root, ".nightshift", run_id="test-run")
console_lines: list[str] = []
logger = RunLogger(console=console_lines.append)
logger.bind(artifacts)
with patch(
"nightshift.runlog.format_console_event_line",
return_value="\x1b[32mstyled line\x1b[0m",
):
logger.event("task.finish", "Finished task", status="complete", token="abc")
self.assertEqual(console_lines[-1], "\x1b[32mstyled line\x1b[0m")
run_log = artifacts.run_log_path.read_text(encoding="utf-8")
self.assertIn("task.finish", run_log)
self.assertIn("status=complete", run_log)
self.assertNotIn("\x1b[", run_log)
self.assertNotIn("abc", run_log)
if __name__ == "__main__":
unittest.main()