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