turbo-editors/turbo-corepublic Fork 0
v0.9.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

controls_test.go · 310 lines · 7.8 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 20h ago1package ui
2
3import (
4 "strings"
5 "testing"
6
7 "github.com/gdamore/tcell/v2"
8)
9
10func TestALabelIsSkippedByTheFocusRing(t *testing.T) {
11 if NewLabel("Name:").CanFocus() {
12 t.Error("CanFocus() = true for a label")
13 }
14}
15
16func TestLabelDrawsItsText(t *testing.T) {
17 screen, root := newTestScreen(t, 20, 2)
18 l := NewLabel("File name:")
19 l.SetBounds(Rect{X: 1, Y: 0, W: 15, H: 1})
20
21 l.Draw(root, testTheme(t))
22 screen.Show()
23
24 if got := screenLines(t, screen)[0]; !strings.Contains(got, "File name:") {
25 t.Errorf("row 0 = %q", got)
26 }
27}
28
29func TestButtonPressRunsItsAction(t *testing.T) {
30 pressed := 0
31 b := NewButton("~O~K", func() { pressed++ })
32
33 b.Press()
34
35 if pressed != 1 {
36 t.Errorf("the action ran %d times, want 1", pressed)
37 }
38}
39
40func TestAButtonWithNoActionDoesNotPanic(t *testing.T) {
41 NewButton("~O~K", nil).Press()
42}
43
44func TestButtonRespondsToEnterAndSpaceWhenFocused(t *testing.T) {
45 pressed := 0
46 b := NewButton("~O~K", func() { pressed++ })
47
48 if b.HandleKey(keyEvent(tcell.KeyEnter, 0, tcell.ModNone)) {
49 t.Error("an unfocused button reacted to Enter")
50 }
51
52 b.SetFocused(true)
53 b.HandleKey(keyEvent(tcell.KeyEnter, 0, tcell.ModNone))
54 b.HandleKey(runeEvent(' '))
55
56 if pressed != 2 {
57 t.Errorf("the action ran %d times, want 2", pressed)
58 }
59 if b.HandleKey(runeEvent('z')) {
60 t.Error("the button claimed a key it does nothing with")
61 }
62}
63
64func TestClickingAButtonPressesIt(t *testing.T) {
65 pressed := 0
66 b := NewButton("~O~K", func() { pressed++ })
67 b.SetBounds(Rect{X: 5, Y: 3, W: 8, H: 1})
68
69 if !b.HandleMouse(clickEvent(6, 3)) {
70 t.Fatal("the click was not handled")
71 }
72 if pressed != 1 {
73 t.Errorf("the action ran %d times, want 1", pressed)
74 }
75 if b.HandleMouse(clickEvent(0, 0)) {
76 t.Error("the button claimed a click that missed it")
77 }
78}
79
80func TestButtonWidthAllowsForItsBrackets(t *testing.T) {
81 if got := ButtonWidth("~O~K"); got != 6 {
82 t.Errorf("ButtonWidth(\"~O~K\") = %d, want 6", got)
83 }
84}
85
86func TestButtonDrawsItsLabelAndAMarkerWhenFocused(t *testing.T) {
87 screen, root := newTestScreen(t, 20, 2)
88 b := NewButton("~O~K", nil)
89 b.SetBounds(Rect{X: 0, Y: 0, W: 8, H: 1})
90
91 b.Draw(root, testTheme(t))
92 screen.Show()
93 if got := screenLines(t, screen)[0]; strings.Contains(got, "►") {
94 t.Errorf("an unfocused, non-default button shows a marker: %q", got)
95 }
96
97 b.SetFocused(true)
98 b.Draw(root, testTheme(t))
99 screen.Show()
100 line := screenLines(t, screen)[0]
101 if !strings.Contains(line, "►") || !strings.Contains(line, "OK") {
102 t.Errorf("row 0 = %q, want a marker and the label", line)
103 }
104}
105
106func TestInputLineHoldsAndEditsText(t *testing.T) {
107 i := NewInputLine("main.go")
108 i.SetFocused(true)
109
110 if got := i.Text(); got != "main.go" {
111 t.Fatalf("Text() = %q", got)
112 }
113
114 i.HandleKey(keyEvent(tcell.KeyBackspace2, 0, tcell.ModNone))
115 if got := i.Text(); got != "main.g" {
116 t.Errorf("Text() = %q after a backspace, want %q", got, "main.g")
117 }
118
119 i.HandleKey(runeEvent('X'))
120 if got := i.Text(); got != "main.gX" {
121 t.Errorf("Text() = %q after typing, want %q", got, "main.gX")
122 }
123}
124
125func TestInputLineCursorMovementAndDelete(t *testing.T) {
126 i := NewInputLine("abc")
127 i.SetFocused(true)
128
129 i.HandleKey(keyEvent(tcell.KeyHome, 0, tcell.ModNone))
130 i.HandleKey(keyEvent(tcell.KeyDelete, 0, tcell.ModNone))
131 if got := i.Text(); got != "bc" {
132 t.Errorf("Text() = %q, want %q", got, "bc")
133 }
134
135 i.HandleKey(keyEvent(tcell.KeyEnd, 0, tcell.ModNone))
136 i.HandleKey(runeEvent('!'))
137 if got := i.Text(); got != "bc!" {
138 t.Errorf("Text() = %q, want %q", got, "bc!")
139 }
140
141 i.HandleKey(keyEvent(tcell.KeyLeft, 0, tcell.ModNone))
142 i.HandleKey(runeEvent('-'))
143 if got := i.Text(); got != "bc-!" {
144 t.Errorf("Text() = %q, want the character inserted at the cursor", got)
145 }
146}
147
148func TestInputLineIgnoresDeletesAtItsEdges(t *testing.T) {
149 i := NewInputLine("ab")
150 i.SetFocused(true)
151
152 i.HandleKey(keyEvent(tcell.KeyHome, 0, tcell.ModNone))
153 i.HandleKey(keyEvent(tcell.KeyBackspace2, 0, tcell.ModNone))
154 i.HandleKey(keyEvent(tcell.KeyEnd, 0, tcell.ModNone))
155 i.HandleKey(keyEvent(tcell.KeyDelete, 0, tcell.ModNone))
156
157 if got := i.Text(); got != "ab" {
158 t.Errorf("Text() = %q, want it unchanged", got)
159 }
160}
161
162func TestInputLineCtrlUClearsIt(t *testing.T) {
163 i := NewInputLine("something")
164 i.SetFocused(true)
165
166 i.HandleKey(keyEvent(tcell.KeyCtrlU, 0, tcell.ModNone))
167
168 if got := i.Text(); got != "" {
169 t.Errorf("Text() = %q, want it empty", got)
170 }
171}
172
173func TestInputLineReportsEveryChange(t *testing.T) {
174 var seen []string
175 i := NewInputLine("")
176 i.SetFocused(true)
177 i.OnChange = func(text string) { seen = append(seen, text) }
178
179 i.HandleKey(runeEvent('a'))
180 i.HandleKey(runeEvent('b'))
181 i.HandleKey(keyEvent(tcell.KeyBackspace2, 0, tcell.ModNone))
182
183 want := []string{"a", "ab", "a"}
184 if len(seen) != len(want) {
185 t.Fatalf("OnChange saw %v, want %v", seen, want)
186 }
187 for i, w := range want {
188 if seen[i] != w {
189 t.Errorf("OnChange call %d saw %q, want %q", i, seen[i], w)
190 }
191 }
192}
193
194func TestAnUnfocusedInputLineIgnoresKeys(t *testing.T) {
195 i := NewInputLine("abc")
196
197 if i.HandleKey(runeEvent('z')) {
198 t.Error("an unfocused field claimed a key")
199 }
200 if got := i.Text(); got != "abc" {
201 t.Errorf("Text() = %q, want it unchanged", got)
202 }
203}
204
205func TestInputLineScrollsToKeepTheCursorVisible(t *testing.T) {
206 screen, root := newTestScreen(t, 20, 2)
207 i := NewInputLine("abcdefghijklmnop")
208 i.SetBounds(Rect{X: 0, Y: 0, W: 6, H: 1})
209 i.SetFocused(true)
210
211 i.Draw(root, testTheme(t))
212 screen.Show()
213
214 // The cursor sits at the end of the text, so the tail must be showing.
215 if got := screenLines(t, screen)[0][:6]; !strings.Contains(got, "op") {
216 t.Errorf("row 0 = %q, want the end of the text visible", got)
217 }
218 if _, _, visible := screen.GetCursor(); !visible {
219 t.Error("a focused field did not place the terminal cursor")
220 }
221}
222
223func TestClickingAnInputLinePutsTheCursorThere(t *testing.T) {
224 i := NewInputLine("abcdef")
225 i.SetBounds(Rect{X: 4, Y: 2, W: 10, H: 1})
226
227 if !i.HandleMouse(clickEvent(7, 2)) {
228 t.Fatal("the click was not handled")
229 }
230 if i.cursor != 3 {
231 t.Errorf("cursor = %d, want 3", i.cursor)
232 }
233
234 i.HandleMouse(clickEvent(13, 2)) // past the end of the text
235 if i.cursor != 6 {
236 t.Errorf("cursor = %d, want it clamped to the end of the text", i.cursor)
237 }
238}
239
240func TestCheckBoxToggles(t *testing.T) {
241 var states []bool
242 c := NewCheckBox("~R~ecursive", false)
243 c.OnToggle = func(on bool) { states = append(states, on) }
244 c.SetFocused(true)
245
246 c.HandleKey(runeEvent(' '))
247 if !c.Checked() {
248 t.Error("Space did not tick the box")
249 }
250
251 c.HandleKey(keyEvent(tcell.KeyEnter, 0, tcell.ModNone))
252 if c.Checked() {
253 t.Error("Enter did not untick the box")
254 }
255
256 if len(states) != 2 || !states[0] || states[1] {
257 t.Errorf("OnToggle saw %v, want [true false]", states)
258 }
259}
260
261func TestClickingACheckBoxTogglesIt(t *testing.T) {
262 c := NewCheckBox("~R~ecursive", false)
263 c.SetBounds(Rect{X: 2, Y: 2, W: 15, H: 1})
264
265 c.HandleMouse(clickEvent(3, 2))
266
267 if !c.Checked() {
268 t.Error("the click did not tick the box")
269 }
270 if c.HandleMouse(clickEvent(30, 30)) {
271 t.Error("the box claimed a click that missed it")
272 }
273}
274
275func TestCheckBoxDrawsItsMark(t *testing.T) {
276 screen, root := newTestScreen(t, 20, 2)
277 c := NewCheckBox("~R~ecursive", true)
278 c.SetBounds(Rect{X: 0, Y: 0, W: 16, H: 1})
279
280 c.Draw(root, testTheme(t))
281 screen.Show()
282
283 got := screenLines(t, screen)[0]
284 if !strings.HasPrefix(got, "[×] Recursive") {
285 t.Errorf("row 0 = %q, want a ticked box and the label", got)
286 }
287}
288
289func TestAnUnfocusedCheckBoxIgnoresKeys(t *testing.T) {
290 c := NewCheckBox("x", false)
291
292 if c.HandleKey(runeEvent(' ')) {
293 t.Error("an unfocused box claimed a key")
294 }
295 if c.Checked() {
296 t.Error("an unfocused box was toggled by a key")
297 }
298}
299
300func TestInputLineLeavesAltAndCtrlLettersAlone(t *testing.T) {
301 i := NewInputLine("")
302 i.SetFocused(true)
303
304 if i.HandleKey(keyEvent(tcell.KeyRune, 'c', tcell.ModAlt)) {
305 t.Error("the field swallowed Alt-C, which belongs to a dialog's buttons")
306 }
307 if got := i.Text(); got != "" {
308 t.Errorf("Text() = %q, want the modified key not to have been typed", got)
309 }
310}