- Add renderer.py with parse_ansi(), get_default_font_path(), render_to_pil() - Update KittyDisplay and SixelDisplay to use shared renderer - Enhance parse_ansi to handle full ANSI color codes (4-bit, 256-color) - Update tests to use shared renderer functions
129 lines
3.9 KiB
Python
129 lines
3.9 KiB
Python
"""
|
|
Tests for engine.display.backends.sixel module.
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
class TestSixelDisplay:
|
|
"""Tests for SixelDisplay class."""
|
|
|
|
def test_init_stores_dimensions(self):
|
|
"""init stores dimensions."""
|
|
from engine.display.backends.sixel import SixelDisplay
|
|
|
|
display = SixelDisplay()
|
|
display.init(80, 24)
|
|
assert display.width == 80
|
|
assert display.height == 24
|
|
|
|
def test_init_custom_cell_size(self):
|
|
"""init accepts custom cell size."""
|
|
from engine.display.backends.sixel import SixelDisplay
|
|
|
|
display = SixelDisplay(cell_width=12, cell_height=18)
|
|
assert display.cell_width == 12
|
|
assert display.cell_height == 18
|
|
|
|
def test_show_handles_empty_buffer(self):
|
|
"""show handles empty buffer gracefully."""
|
|
from engine.display.backends.sixel import SixelDisplay
|
|
|
|
display = SixelDisplay()
|
|
display.init(80, 24)
|
|
|
|
with patch("engine.display.backends.sixel._encode_sixel") as mock_encode:
|
|
mock_encode.return_value = ""
|
|
display.show([])
|
|
|
|
def test_show_handles_pil_import_error(self):
|
|
"""show gracefully handles missing PIL."""
|
|
from engine.display.backends.sixel import SixelDisplay
|
|
|
|
display = SixelDisplay()
|
|
display.init(80, 24)
|
|
|
|
with patch.dict("sys.modules", {"PIL": None}):
|
|
display.show(["test line"])
|
|
|
|
def test_clear_sends_escape_sequence(self):
|
|
"""clear sends clear screen escape sequence."""
|
|
from engine.display.backends.sixel import SixelDisplay
|
|
|
|
display = SixelDisplay()
|
|
|
|
with patch("sys.stdout") as mock_stdout:
|
|
display.clear()
|
|
mock_stdout.buffer.write.assert_called()
|
|
|
|
def test_cleanup_does_nothing(self):
|
|
"""cleanup does nothing."""
|
|
from engine.display.backends.sixel import SixelDisplay
|
|
|
|
display = SixelDisplay()
|
|
display.cleanup()
|
|
|
|
|
|
class TestSixelAnsiParsing:
|
|
"""Tests for ANSI parsing in SixelDisplay."""
|
|
|
|
def test_parse_empty_string(self):
|
|
"""handles empty string."""
|
|
from engine.display.renderer import parse_ansi
|
|
|
|
result = parse_ansi("")
|
|
assert len(result) > 0
|
|
|
|
def test_parse_plain_text(self):
|
|
"""parses plain text without ANSI codes."""
|
|
from engine.display.renderer import parse_ansi
|
|
|
|
result = parse_ansi("hello world")
|
|
assert len(result) == 1
|
|
text, fg, bg, bold = result[0]
|
|
assert text == "hello world"
|
|
|
|
def test_parse_with_color_codes(self):
|
|
"""parses ANSI color codes."""
|
|
from engine.display.renderer import parse_ansi
|
|
|
|
result = parse_ansi("\033[31mred\033[0m")
|
|
assert len(result) == 1
|
|
assert result[0][0] == "red"
|
|
assert result[0][1] == (205, 49, 49)
|
|
|
|
def test_parse_with_bold(self):
|
|
"""parses bold codes."""
|
|
from engine.display.renderer import parse_ansi
|
|
|
|
result = parse_ansi("\033[1mbold\033[0m")
|
|
assert len(result) == 1
|
|
assert result[0][0] == "bold"
|
|
assert result[0][3] is True
|
|
|
|
def test_parse_256_color(self):
|
|
"""parses 256 color codes."""
|
|
from engine.display.renderer import parse_ansi
|
|
|
|
result = parse_ansi("\033[38;5;196mred\033[0m")
|
|
assert len(result) == 1
|
|
assert result[0][0] == "red"
|
|
|
|
|
|
class TestSixelEncoding:
|
|
"""Tests for Sixel encoding."""
|
|
|
|
def test_encode_empty_image(self):
|
|
"""handles empty image."""
|
|
from engine.display.backends.sixel import _encode_sixel
|
|
|
|
with patch("PIL.Image.Image") as mock_image:
|
|
mock_img_instance = MagicMock()
|
|
mock_img_instance.convert.return_value = mock_img_instance
|
|
mock_img_instance.size = (0, 0)
|
|
mock_img_instance.load.return_value = {}
|
|
mock_image.return_value = mock_img_instance
|
|
|
|
result = _encode_sixel(mock_img_instance)
|
|
assert result == ""
|