package termcolor
import (
"maps"
"testing"
)
func TestParseReplies(t *testing.T) {
for _, tc := range []struct {
name string
in string
want map[int]Color
}{
{"four digit channels with st", "\x1b]10;rgb:cccc/cccc/cccc\x1b\\\x1b]11;rgb:1c1c/2a2a/3c3c\x1b\\", map[int]Color{
Foreground: {0xcccc, 0xcccc, 0xcccc}, Background: {0x1c1c, 0x2a2a, 0x3c3c}}},
{"two digit channels with bel", "\x1b]4;5;rgb:ff/00/80\a\x1b]12;rgb:11/22/33\a", map[int]Color{
5: {0xffff, 0, 0x8080}, Cursor: {0x1111, 0x2222, 0x3333}}},
{"one digit channels", "\x1b]4;0;rgb:f/0/a\x1b\\", map[int]Color{0: {0xffff, 0, 0xaaaa}}},
{"three digit channels", "\x1b]4;1;rgb:fff/000/fff\x1b\\", map[int]Color{1: {0xffff, 0, 0xffff}}},
{"sentinel and junk around replies", "\x1b[?62;1c\x1b]4;1;rgb:8888/8888/8888\x1b\\junk", map[int]Color{
1: {0x8888, 0x8888, 0x8888}}},
{"incomplete reply ignored", "\x1b]10;rgb:cccc/c", nil},
{"unrelated osc ignored", "\x1b]7;file:///tmp\x1b\\\x1b[?1;2c", nil},
} {
got := ParseReplies([]byte(tc.in))
if len(got) != len(tc.want) {
t.Fatalf("%s: ParseReplies(%q) = %v, want %v", tc.name, tc.in, got, tc.want)
}
for k, v := range tc.want {
if got[k] != v {
t.Fatalf("%s: ParseReplies(%q)[%d] = %v, want %v", tc.name, tc.in, k, got[k], v)
}
}
}
}
func TestDA1End(t *testing.T) {
in := "\x1b]10;?x\x1b[?62;22c rest"
if got, want := DA1End([]byte(in)), len("\x1b]10;?x\x1b[?62;22c"); got != want {
t.Fatalf("DA1End = %d, want %d", got, want)
}
if DA1End([]byte("\x1b]10;rgb:0000/0000/0000\x1b\\")) != -1 {
t.Fatal("a color reply is not the sentinel")
}
if DA1End([]byte("\x1b[?62;")) != -1 {
t.Fatal("an incomplete sentinel must not match")
}
}
func TestEncodeColorsRoundTrip(t *testing.T) {
in := map[int]Color{Foreground: {0xffff, 0xffff, 0xffff}, 5: {0x8000, 0, 0x8000}, Background: {0, 0, 0}}
out, ok := DecodeColors(EncodeColors(in))
if !ok || !maps.Equal(out, in) {
t.Fatalf("round trip = %v %v, want %v", out, ok, in)
}
if EncodeColors(nil) != nil {
t.Fatal("no colors must encode to nothing so the payload stays legacy")
}
if _, ok := DecodeColors(nil); ok {
t.Fatal("a legacy payload must decode as unknown")
}
if _, ok := DecodeColors([]byte{colorsVersion + 1, 1}); ok {
t.Fatal("an unknown version must decode as unknown")
}
if _, ok := DecodeColors([]byte{colorsVersion, 2, 0, 0, 0, 0, 0, 0, 0}); ok {
t.Fatal("a truncated section must decode as unknown")
}
}
func TestAgreed(t *testing.T) {
a := map[int]Color{Foreground: {1, 2, 3}, Background: {4, 5, 6}}
b := map[int]Color{Foreground: {1, 2, 3}, Background: {7, 8, 9}}
if c, ok := Agreed(Foreground, []map[int]Color{a, b}); !ok || c != (Color{1, 2, 3}) {
t.Fatalf("agreed foreground = %v %v", c, ok)
}
if _, ok := Agreed(Background, []map[int]Color{a, b}); ok {
t.Fatal("a disagreement must stay silent")
}
if _, ok := Agreed(Cursor, []map[int]Color{a, b}); ok {
t.Fatal("a color nobody reported must stay silent")
}
if _, ok := Agreed(Foreground, []map[int]Color{a, nil}); ok {
t.Fatal("a viewer without colors must stay silent")
}
if _, ok := Agreed(Foreground, nil); ok {
t.Fatal("zero viewers must stay silent")
}
}
func TestReply(t *testing.T) {
c := Color{0x1234, 0x5678, 0x9abc}
if got, want := Reply(5, c), "\x1b]4;5;rgb:1234/5678/9abc\x1b\\"; got != want {
t.Fatalf("Reply(5) = %q, want %q", got, want)
}
if got, want := Reply(Background, c), "\x1b]11;rgb:1234/5678/9abc\x1b\\"; got != want {
t.Fatalf("Reply(Background) = %q, want %q", got, want)
}
}