"""Extensive tests for the custom SVG exporter."""
from __future__ import annotations
import pytest
from textual_webterm.svg_exporter import (
ANSI_COLORS,
DEFAULT_BG,
DEFAULT_FG,
CharData,
_color_to_hex,
_escape_xml,
render_terminal_svg,
)
class TestColorToHex:
"""Tests for _color_to_hex function."""
@pytest.mark.parametrize(
("color", "is_foreground", "expected"),
[
("default", True, DEFAULT_FG),
("default", False, DEFAULT_BG),
("#ff0000", True, "#ff0000"),
("#123456", True, "#123456"),
("#AABBCC", True, "#AABBCC"),
("ff0000", True, "#ff0000"),
("123456", True, "#123456"),
("AABBCC", True, "#AABBCC"),
("ff8700", True, "#ff8700"),
("red", True, ANSI_COLORS["red"]),
("green", True, ANSI_COLORS["green"]),
("blue", True, ANSI_COLORS["blue"]),
("white", True, ANSI_COLORS["white"]),
("black", True, ANSI_COLORS["black"]),
("brightred", True, ANSI_COLORS["brightred"]),
("brightgreen", True, ANSI_COLORS["brightgreen"]),
("brightblue", True, ANSI_COLORS["brightblue"]),
("RED", True, ANSI_COLORS["red"]),
("Green", True, ANSI_COLORS["green"]),
("BRIGHTBLUE", True, ANSI_COLORS["brightblue"]),
("unknowncolor", True, DEFAULT_FG),
("unknowncolor", False, DEFAULT_BG),
("rgb(255,0,0)", True, DEFAULT_FG),
("rgb(0,255,0)", False, DEFAULT_BG),
("gray", True, ANSI_COLORS["gray"]),
("grey", True, ANSI_COLORS["grey"]),
("lightgray", True, ANSI_COLORS["lightgray"]),
("lightgrey", True, ANSI_COLORS["lightgrey"]),
],
)
def test_color_to_hex(self, color: str, is_foreground: bool, expected: str) -> None:
"""Color conversion covers named/hex/default cases."""
assert _color_to_hex(color, is_foreground=is_foreground) == expected
class TestEscapeXml:
"""Tests for XML escaping."""
@pytest.mark.parametrize(
("input_str", "expected"),
[
("hello world", "hello world"),
("<", "<"),
("a < b", "a < b"),
(">", ">"),
("a > b", "a > b"),
("&", "&"),
("a & b", "a & b"),
('"', """),
("'", "'"),
('', "<script>"alert"</script>"),
("你好世界", "你好世界"),
("🎉🚀", "🎉🚀"),
],
)
def test_escape_xml(self, input_str: str, expected: str) -> None:
"""Escape XML special chars and preserve unicode."""
assert _escape_xml(input_str) == expected
class TestRenderTerminalSvg:
"""Tests for render_terminal_svg function."""
def _char(
self,
data: str,
fg: str = "default",
bg: str = "default",
bold: bool = False,
italics: bool = False,
underscore: bool = False,
reverse: bool = False,
) -> CharData:
"""Helper to create CharData."""
return {
"data": data,
"fg": fg,
"bg": bg,
"bold": bold,
"italics": italics,
"underscore": underscore,
"reverse": reverse,
}
def _make_buffer(self, rows: list[str]) -> list[list[CharData]]:
"""Create simple buffer from strings."""
return [[self._char(c) for c in row] for row in rows]
def test_empty_buffer(self) -> None:
"""Empty buffer produces valid SVG."""
svg = render_terminal_svg([], width=80, height=24)
assert svg.startswith("