forked from genewildish/Mainline
feat: modernize project with uv, add pytest test suite
- Add pyproject.toml with modern Python packaging (PEP 517/518) - Add uv-based dependency management replacing inline venv bootstrap - Add requirements.txt and requirements-dev.txt for compatibility - Add mise.toml with dev tasks (test, lint, run, sync, ci) - Add .python-version pinned to Python 3.12 - Add comprehensive pytest test suite (73 tests) for: - engine/config, filter, terminal, sources, mic, ntfy modules - Configure pytest with coverage reporting (16% total, 100% on tested modules) - Configure ruff for linting with Python 3.10+ target - Remove redundant venv bootstrap code from mainline.py - Update .gitignore for uv/venv artifacts Run 'uv sync' to install dependencies, 'uv run pytest' to test.
This commit is contained in:
124
tests/test_terminal.py
Normal file
124
tests/test_terminal.py
Normal file
@@ -0,0 +1,124 @@
|
||||
"""
|
||||
Tests for engine.terminal module.
|
||||
"""
|
||||
|
||||
import io
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
from engine import terminal
|
||||
|
||||
|
||||
class TestTerminalDimensions:
|
||||
"""Tests for terminal width/height functions."""
|
||||
|
||||
def test_tw_returns_columns(self):
|
||||
"""tw() returns terminal width."""
|
||||
with patch.object(sys.stdout, "isatty", return_value=True):
|
||||
with patch("os.get_terminal_size") as mock_size:
|
||||
mock_size.return_value = io.StringIO("columns=120")
|
||||
mock_size.columns = 120
|
||||
result = terminal.tw()
|
||||
assert isinstance(result, int)
|
||||
|
||||
def test_th_returns_lines(self):
|
||||
"""th() returns terminal height."""
|
||||
with patch.object(sys.stdout, "isatty", return_value=True):
|
||||
with patch("os.get_terminal_size") as mock_size:
|
||||
mock_size.return_value = io.StringIO("lines=30")
|
||||
mock_size.lines = 30
|
||||
result = terminal.th()
|
||||
assert isinstance(result, int)
|
||||
|
||||
def test_tw_fallback_on_error(self):
|
||||
"""tw() falls back to 80 on error."""
|
||||
with patch("os.get_terminal_size", side_effect=OSError):
|
||||
result = terminal.tw()
|
||||
assert result == 80
|
||||
|
||||
def test_th_fallback_on_error(self):
|
||||
"""th() falls back to 24 on error."""
|
||||
with patch("os.get_terminal_size", side_effect=OSError):
|
||||
result = terminal.th()
|
||||
assert result == 24
|
||||
|
||||
|
||||
class TestANSICodes:
|
||||
"""Tests for ANSI escape code constants."""
|
||||
|
||||
def test_ansi_constants_exist(self):
|
||||
"""All ANSI constants are defined."""
|
||||
assert terminal.RST == "\033[0m"
|
||||
assert terminal.BOLD == "\033[1m"
|
||||
assert terminal.DIM == "\033[2m"
|
||||
|
||||
def test_green_shades_defined(self):
|
||||
"""Green gradient colors are defined."""
|
||||
assert terminal.G_HI == "\033[38;5;46m"
|
||||
assert terminal.G_MID == "\033[38;5;34m"
|
||||
assert terminal.G_LO == "\033[38;5;22m"
|
||||
|
||||
def test_white_shades_defined(self):
|
||||
"""White/gray tones are defined."""
|
||||
assert terminal.W_COOL == "\033[38;5;250m"
|
||||
assert terminal.W_DIM == "\033[2;38;5;245m"
|
||||
|
||||
def test_cursor_controls_defined(self):
|
||||
"""Cursor control codes are defined."""
|
||||
assert "?" in terminal.CURSOR_OFF
|
||||
assert "?" in terminal.CURSOR_ON
|
||||
|
||||
|
||||
class TestTypeOut:
|
||||
"""Tests for type_out function."""
|
||||
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
@patch("time.sleep")
|
||||
def test_type_out_writes_text(self, mock_sleep, mock_stdout):
|
||||
"""type_out writes text to stdout."""
|
||||
with patch("random.random", return_value=0.5):
|
||||
terminal.type_out("Hi", color=terminal.G_HI)
|
||||
output = mock_stdout.getvalue()
|
||||
assert len(output) > 0
|
||||
|
||||
@patch("time.sleep")
|
||||
def test_type_out_uses_color(self, mock_sleep):
|
||||
"""type_out applies color codes."""
|
||||
with patch("sys.stdout", new_callable=io.StringIO):
|
||||
with patch("random.random", return_value=0.5):
|
||||
terminal.type_out("Test", color=terminal.G_HI)
|
||||
|
||||
|
||||
class TestSlowPrint:
|
||||
"""Tests for slow_print function."""
|
||||
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
@patch("time.sleep")
|
||||
def test_slow_print_writes_text(self, mock_sleep, mock_stdout):
|
||||
"""slow_print writes text to stdout."""
|
||||
terminal.slow_print("Hi", color=terminal.G_DIM, delay=0)
|
||||
output = mock_stdout.getvalue()
|
||||
assert len(output) > 0
|
||||
|
||||
|
||||
class TestBootLn:
|
||||
"""Tests for boot_ln function."""
|
||||
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
@patch("time.sleep")
|
||||
def test_boot_ln_writes_label_and_status(self, mock_sleep, mock_stdout):
|
||||
"""boot_ln shows label and status."""
|
||||
with patch("random.uniform", return_value=0):
|
||||
terminal.boot_ln("Loading", "OK", ok=True)
|
||||
output = mock_stdout.getvalue()
|
||||
assert "Loading" in output
|
||||
assert "OK" in output
|
||||
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
@patch("time.sleep")
|
||||
def test_boot_ln_error_status(self, mock_sleep, mock_stdout):
|
||||
"""boot_ln shows red for error status."""
|
||||
with patch("random.uniform", return_value=0):
|
||||
terminal.boot_ln("Loading", "FAIL", ok=False)
|
||||
output = mock_stdout.getvalue()
|
||||
assert "FAIL" in output
|
||||
Reference in New Issue
Block a user