textgrid-rust/tests/test_color_packing.py
2026-07-20 12:53:51 +10:00

163 lines
5.5 KiB
Python

"""Tests for textgrid color packing (no GPU required)."""
from textgrid._pack_style import pack_style_colors, _pack_one, _xterm
def test_pack_red():
"""(255, 0, 0) → 0xFF000000 (R in bits 31-24)"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=(255, 0, 0)),))
assert result[0] == 0xFF000000
def test_pack_green():
"""(0, 255, 0) → 0x00FF0000 (G in bits 23-16)"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=(0, 255, 0)),))
assert result[0] == 0x00FF0000
def test_pack_blue():
"""(0, 0, 255) → 0x0000FF00 (B in bits 15-8)"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=(0, 0, 255)),))
assert result[0] == 0x0000FF00
def test_pack_black():
"""(0, 0, 0) → 0x00000000"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=(0, 0, 0)),))
assert result[0] == 0x00000000
def test_pack_white():
"""(255, 255, 255) → 0xFFFFFF00"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=(255, 255, 255)),))
assert result[0] == 0xFFFFFF00
def test_pack_fg_and_bg():
"""fg and bg are interleaved in the output array"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=(255, 0, 0), bg_color=(0, 0, 255)),))
assert result[0] == 0xFF000000, "fg should be first"
assert result[1] == 0x0000FF00, "bg should be second"
assert result[2] == 0, "attr should be 0 for default style"
def test_pack_xterm_index_9():
"""xterm index 9 is bright red = (255, 0, 0)"""
from termstr import CharStyle
result = pack_style_colors((CharStyle(fg_color=9),))
expected = pack_style_colors((CharStyle(fg_color=(255, 0, 0)),))
assert result[0] == expected[0], "index 9 should match (255, 0, 0)"
def test_xterm_table_index_0():
"""xterm index 0 is (0, 0, 0)"""
assert _xterm[0] == (0, 0, 0)
def test_xterm_table_index_1():
"""xterm index 1 is (205, 0, 0)"""
assert _xterm[1] == (205, 0, 0)
def test_xterm_table_index_15():
"""xterm index 15 is (255, 255, 255)"""
assert _xterm[15] == (255, 255, 255)
def test_xterm_table_index_16():
"""xterm index 16 is (0, 0, 0) — start of color cube"""
assert _xterm[16] == (0, 0, 0)
def test_xterm_table_index_231():
"""xterm index 231 is (255, 255, 255) — end of color cube"""
assert _xterm[231] == (255, 255, 255)
def test_xterm_table_index_232():
"""xterm index 232 is (8, 8, 8) — start of gray ramp"""
assert _xterm[232] == (8, 8, 8)
def test_xterm_table_index_255():
"""xterm index 255 is (238, 238, 238) — end of gray ramp"""
assert _xterm[255] == (238, 238, 238)
def test_identity_fast_path_matches_slow_path():
"""all(s is first) fast path produces same output as per-element iteration"""
from termstr import CharStyle
style = CharStyle(fg_color=(255, 80, 80), bg_color=(20, 40, 60))
styles = tuple([style] * 100)
# The identity check will trigger for n > 1
result = pack_style_colors(styles)
# Length: 100 chars * 3 values (fg, bg, attr) = 300
assert len(result) == 300
# Every triplet should be identical
for i in range(0, 300, 3):
assert result[i] == result[0], f"fg differs at char {i//3}"
assert result[i + 1] == result[1], f"bg differs at char {i//3}"
assert result[i + 2] == result[2], f"attr differs at char {i//3}"
def test_mixed_styles_are_all_different():
"""Each char has different colors — no identity optimization triggered"""
from termstr import CharStyle
styles = tuple([
CharStyle(fg_color=(255, 0, 0)),
CharStyle(fg_color=(0, 255, 0)),
CharStyle(fg_color=(0, 0, 255)),
])
result = pack_style_colors(styles)
assert len(result) == 9
assert result[0] != result[3], "red != green"
assert result[0] != result[6], "red != blue"
assert result[3] != result[6], "green != blue"
def test_output_length():
"""N chars produces 3N output values"""
from termstr import CharStyle
for n in [1, 5, 100]:
styles = tuple([CharStyle(fg_color=(255, 0, 0))] * n)
result = pack_style_colors(styles)
assert len(result) == 3 * n, f"expected {3*n}, got {len(result)}"
def test_xterm_pack_matches_rgb():
"""Packing xterm index should produce same u32 as direct RGB"""
from termstr import CharStyle
for idx in [1, 9, 16, 100, 200, 255]:
r, g, b = _xterm[idx]
xterm_result = pack_style_colors((CharStyle(fg_color=idx),))
rgb_result = pack_style_colors((CharStyle(fg_color=(r, g, b)),))
assert xterm_result[0] == rgb_result[0], \
f"index {idx} = ({r},{g},{b}) didn't match direct RGB"
def test_attr_encoding():
"""bold/italic flags encoded in attr byte"""
from termstr import CharStyle
r = pack_style_colors((CharStyle(fg_color=(255, 0, 0)),))
assert r[2] == 0, "default: no bold, no italic"
r = pack_style_colors((CharStyle(fg_color=(255, 0, 0)).bold(),))
assert r[2] & 1, "bold bit set"
r = pack_style_colors((CharStyle(fg_color=(255, 0, 0)).italic(),))
assert r[2] & 2, "italic bit set"
r = pack_style_colors((CharStyle(fg_color=(255, 0, 0)).bold().italic(),))
assert (r[2] & 3) == 3, "both bold and italic bits set"
r = pack_style_colors((CharStyle(fg_color=(255, 0, 0)).underline(),))
assert r[2] & 4, "underline bit set"
r = pack_style_colors((CharStyle(fg_color=(255, 0, 0)).bold().italic().underline(),))
assert (r[2] & 7) == 7, "bold, italic, and underline bits set"