""" 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