1package cmd
2
3import (
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
12type mockEnviron []string
13
14func (m mockEnviron) Getenv(key string) string {
15 v, _ := m.LookupEnv(key)
16 return v
17}
18
19func (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
29func (m mockEnviron) ExpandEnv(s string) string {
30 return s // Not implemented for tests
31}
32
33func (m mockEnviron) Slice() []string {
34 return []string(m)
35}
36
37func 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
118func 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}