turbo-editors/turbo-corepublic Fork 0
main
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.

uitest_test.go · 125 lines · 4.3 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 12h ago1package ui
2
3import (
4 "strings"
5 "testing"
6
7 "github.com/gdamore/tcell/v2"
8
📦 Turbo Core f3ade8d k33g 4h ago9 "rickub.com/turbo-editors/turbo-core/theme"
🛟 Updated. 28d5985 k33g 12h ago10)
11
12// newTestScreen returns a simulated terminal of the given size, already
13// initialised, together with a painter covering it.
14//
15// tcell's SimulationScreen is a real Screen that draws into memory, so every
16// widget below is exercised through exactly the code path a terminal takes —
17// no rendering is stubbed out.
18func newTestScreen(t *testing.T, width, height int) (tcell.SimulationScreen, *Painter) {
19 t.Helper()
20
21 screen := tcell.NewSimulationScreen("UTF-8")
22 if err := screen.Init(); err != nil {
23 t.Fatalf("initialising the simulation screen: %v", err)
24 }
25 t.Cleanup(screen.Fini)
26 screen.SetSize(width, height)
27
28 return screen, NewPainter(screen)
29}
30
31// screenLines returns what the simulated screen currently shows, one string
32// per row, so a test can assert on the picture rather than on cells.
33func screenLines(t *testing.T, screen tcell.SimulationScreen) []string {
34 t.Helper()
35
36 cells, width, height := screen.GetContents()
37 lines := make([]string, height)
38 for y := range height {
39 var row strings.Builder
40 for x := range width {
41 runes := cells[y*width+x].Runes
42 if len(runes) == 0 {
43 row.WriteRune(' ')
44 continue
45 }
46 row.WriteRune(runes[0])
47 }
48 lines[y] = row.String()
49 }
50 return lines
51}
52
53// styleAt returns the style of one cell of the simulated screen.
54func styleAt(t *testing.T, screen tcell.SimulationScreen, x, y int) tcell.Style {
55 t.Helper()
56
57 cells, width, _ := screen.GetContents()
58 return cells[y*width+x].Style
59}
60
61// testTheme is a theme whose every key has a distinct, easily recognised
62// colour, so a test can prove which style was used.
63func testTheme(t *testing.T) *theme.Theme {
64 t.Helper()
65
66 th, err := theme.Parse([]byte(`
67 [colors]
68 default = { fg = "white", bg = "black" }
69 desktop = { fg = "blue", bg = "navy" }
70 shadow = { fg = "gray", bg = "black" }
71 "menu.bar" = { fg = "black", bg = "silver" }
72 "menu.item" = { fg = "black", bg = "silver" }
73 "menu.selected" = { fg = "black", bg = "green" }
74 "menu.shortcut" = { fg = "maroon", bg = "silver" }
75 "menu.disabled" = { fg = "gray", bg = "silver" }
76 "window.frame.active" = { fg = "white", bg = "navy" }
77 "window.frame.inactive" = { fg = "silver", bg = "navy" }
78 "window.title.active" = { fg = "yellow", bg = "navy" }
79 "window.title.inactive" = { fg = "silver", bg = "navy" }
80 "window.body" = { fg = "silver", bg = "navy" }
81 statusbar = { fg = "black", bg = "silver" }
82 "statusbar.key" = { fg = "maroon", bg = "silver" }
83 "statusbar.hint" = { fg = "navy", bg = "silver" }
84 scrollbar = { fg = "navy", bg = "teal" }
85 "scrollbar.thumb" = { fg = "aqua", bg = "teal" }
86 "dialog.frame" = { fg = "white", bg = "silver" }
87 "dialog.body" = { fg = "black", bg = "silver" }
88 "dialog.title" = { fg = "black", bg = "silver" }
89 "dialog.label" = { fg = "black", bg = "silver" }
90 button = { fg = "black", bg = "green" }
91 "button.focused" = { fg = "white", bg = "green" }
92 "button.shortcut" = { fg = "yellow", bg = "green" }
93 input = { fg = "black", bg = "teal" }
94 "input.focused" = { fg = "white", bg = "teal" }
95 list = { fg = "black", bg = "silver" }
96 "list.selected" = { fg = "white", bg = "navy" }
97 "list.unfocused" = { fg = "black", bg = "gray" }
98 checkbox = { fg = "black", bg = "silver" }
99 "checkbox.focused" = { fg = "white", bg = "navy" }
100 `), "")
101 if err != nil {
102 t.Fatalf("parsing the test theme: %v", err)
103 }
104 return th
105}
106
107// keyEvent builds a key press.
108func keyEvent(key tcell.Key, r rune, mods tcell.ModMask) *tcell.EventKey {
109 return tcell.NewEventKey(key, r, mods)
110}
111
112// runeEvent builds the press of a printable character.
113func runeEvent(r rune) *tcell.EventKey {
114 return tcell.NewEventKey(tcell.KeyRune, r, tcell.ModNone)
115}
116
117// clickEvent builds a left-button press at a screen position.
118func clickEvent(x, y int) *tcell.EventMouse {
119 return tcell.NewEventMouse(x, y, tcell.Button1, tcell.ModNone)
120}
121
122// releaseEvent builds the release of every mouse button at a position.
123func releaseEvent(x, y int) *tcell.EventMouse {
124 return tcell.NewEventMouse(x, y, tcell.ButtonNone, tcell.ModNone)
125}