@@ -0,0 +1,160 @@
1+package cmd
2+
3+import (
4+ "strings"
5+ "testing"
6+
7+ "github.com/charmbracelet/crush/internal/stringext"
8+ uv "github.com/charmbracelet/ultraviolet"
9+ "github.com/stretchr/testify/require"
10+)
11+
12+type mockEnviron []string
13+
14+func (m mockEnviron) Getenv(key string) string {
15+ v, _ := m.LookupEnv(key)
16+ return v
17+}
18+
19+func (m mockEnviron) LookupEnv(key string) (string, bool) {
20+ for _, env := range m {
21+ kv := strings.SplitN(env, "=", 2)
22+ if len(kv) == 2 && kv[0] == key {
23+ return kv[1], true
24+ }
25+ }
26+ return "", false
27+}
28+
29+func (m mockEnviron) ExpandEnv(s string) string {
30+ return s // Not implemented for tests
31+}
32+
33+func (m mockEnviron) Slice() []string {
34+ return []string(m)
35+}
36+
37+func TestShouldQueryImageCapabilities(t *testing.T) {
38+ t.Parallel()
39+
40+ tests := []struct {
41+ name string
42+ env mockEnviron
43+ want bool
44+ }{
45+ {
46+ name: "kitty terminal",
47+ env: mockEnviron{"TERM=xterm-kitty"},
48+ want: true,
49+ },
50+ {
51+ name: "wezterm terminal",
52+ env: mockEnviron{"TERM=xterm-256color"},
53+ want: true,
54+ },
55+ {
56+ name: "wezterm with WEZTERM env",
57+ env: mockEnviron{"TERM=xterm-256color", "WEZTERM_EXECUTABLE=/Applications/WezTerm.app/Contents/MacOS/wezterm-gui"},
58+ want: true, // Not detected via TERM, only via stringext.ContainsAny which checks TERM
59+ },
60+ {
61+ name: "Apple Terminal",
62+ env: mockEnviron{"TERM_PROGRAM=Apple_Terminal", "TERM=xterm-256color"},
63+ want: false,
64+ },
65+ {
66+ name: "alacritty",
67+ env: mockEnviron{"TERM=alacritty"},
68+ want: true,
69+ },
70+ {
71+ name: "ghostty",
72+ env: mockEnviron{"TERM=xterm-ghostty"},
73+ want: true,
74+ },
75+ {
76+ name: "rio",
77+ env: mockEnviron{"TERM=rio"},
78+ want: true,
79+ },
80+ {
81+ name: "wezterm (detected via TERM)",
82+ env: mockEnviron{"TERM=wezterm"},
83+ want: true,
84+ },
85+ {
86+ name: "SSH session",
87+ env: mockEnviron{"SSH_TTY=/dev/pts/0", "TERM=xterm-256color"},
88+ want: false,
89+ },
90+ {
91+ name: "generic terminal",
92+ env: mockEnviron{"TERM=xterm-256color"},
93+ want: true,
94+ },
95+ {
96+ name: "kitty over SSH",
97+ env: mockEnviron{"SSH_TTY=/dev/pts/0", "TERM=xterm-kitty"},
98+ want: true,
99+ },
100+ {
101+ name: "Apple Terminal with kitty TERM (should still be false due to TERM_PROGRAM)",
102+ env: mockEnviron{"TERM_PROGRAM=Apple_Terminal", "TERM=xterm-kitty"},
103+ want: false,
104+ },
105+ }
106+
107+ for _, tt := range tests {
108+ t.Run(tt.name, func(t *testing.T) {
109+ t.Parallel()
110+ got := shouldQueryCapabilities(uv.Environ(tt.env))
111+ require.Equal(t, tt.want, got, "shouldQueryImageCapabilities() = %v, want %v", got, tt.want)
112+ })
113+ }
114+}
115+
116+// This is a helper to test the underlying logic of stringext.ContainsAny
117+// which is used by shouldQueryImageCapabilities
118+func TestStringextContainsAny(t *testing.T) {
119+ t.Parallel()
120+
121+ tests := []struct {
122+ name string
123+ s string
124+ substr []string
125+ want bool
126+ }{
127+ {
128+ name: "kitty in TERM",
129+ s: "xterm-kitty",
130+ substr: kittyTerminals,
131+ want: true,
132+ },
133+ {
134+ name: "wezterm in TERM",
135+ s: "wezterm",
136+ substr: kittyTerminals,
137+ want: true,
138+ },
139+ {
140+ name: "alacritty in TERM",
141+ s: "alacritty",
142+ substr: kittyTerminals,
143+ want: true,
144+ },
145+ {
146+ name: "generic terminal not in list",
147+ s: "xterm-256color",
148+ substr: kittyTerminals,
149+ want: false,
150+ },
151+ }
152+
153+ for _, tt := range tests {
154+ t.Run(tt.name, func(t *testing.T) {
155+ t.Parallel()
156+ got := stringext.ContainsAny(tt.s, tt.substr...)
157+ require.Equal(t, tt.want, got)
158+ })
159+ }
160+}