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

📦 Turbo Core f3ade8d · on v1.0.2 · k33g · 11h ago
uitest_test.go · 125 lines · 4.3 KBGo Blame HistoryRaw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package ui

import (
	"strings"
	"testing"

	"github.com/gdamore/tcell/v2"

	"rickub.com/turbo-editors/turbo-core/theme"
)

// newTestScreen returns a simulated terminal of the given size, already
// initialised, together with a painter covering it.
//
// tcell's SimulationScreen is a real Screen that draws into memory, so every
// widget below is exercised through exactly the code path a terminal takes —
// no rendering is stubbed out.
func newTestScreen(t *testing.T, width, height int) (tcell.SimulationScreen, *Painter) {
	t.Helper()

	screen := tcell.NewSimulationScreen("UTF-8")
	if err := screen.Init(); err != nil {
		t.Fatalf("initialising the simulation screen: %v", err)
	}
	t.Cleanup(screen.Fini)
	screen.SetSize(width, height)

	return screen, NewPainter(screen)
}

// screenLines returns what the simulated screen currently shows, one string
// per row, so a test can assert on the picture rather than on cells.
func screenLines(t *testing.T, screen tcell.SimulationScreen) []string {
	t.Helper()

	cells, width, height := screen.GetContents()
	lines := make([]string, height)
	for y := range height {
		var row strings.Builder
		for x := range width {
			runes := cells[y*width+x].Runes
			if len(runes) == 0 {
				row.WriteRune(' ')
				continue
			}
			row.WriteRune(runes[0])
		}
		lines[y] = row.String()
	}
	return lines
}

// styleAt returns the style of one cell of the simulated screen.
func styleAt(t *testing.T, screen tcell.SimulationScreen, x, y int) tcell.Style {
	t.Helper()

	cells, width, _ := screen.GetContents()
	return cells[y*width+x].Style
}

// testTheme is a theme whose every key has a distinct, easily recognised
// colour, so a test can prove which style was used.
func testTheme(t *testing.T) *theme.Theme {
	t.Helper()

	th, err := theme.Parse([]byte(`
		[colors]
		default              = { fg = "white",   bg = "black" }
		desktop              = { fg = "blue",    bg = "navy" }
		shadow               = { fg = "gray",    bg = "black" }
		"menu.bar"           = { fg = "black",   bg = "silver" }
		"menu.item"          = { fg = "black",   bg = "silver" }
		"menu.selected"      = { fg = "black",   bg = "green" }
		"menu.shortcut"      = { fg = "maroon",  bg = "silver" }
		"menu.disabled"      = { fg = "gray",    bg = "silver" }
		"window.frame.active"   = { fg = "white",  bg = "navy" }
		"window.frame.inactive" = { fg = "silver", bg = "navy" }
		"window.title.active"   = { fg = "yellow", bg = "navy" }
		"window.title.inactive" = { fg = "silver", bg = "navy" }
		"window.body"        = { fg = "silver",  bg = "navy" }
		statusbar            = { fg = "black",   bg = "silver" }
		"statusbar.key"      = { fg = "maroon",  bg = "silver" }
		"statusbar.hint"     = { fg = "navy",    bg = "silver" }
		scrollbar            = { fg = "navy",    bg = "teal" }
		"scrollbar.thumb"    = { fg = "aqua",    bg = "teal" }
		"dialog.frame"       = { fg = "white",   bg = "silver" }
		"dialog.body"        = { fg = "black",   bg = "silver" }
		"dialog.title"       = { fg = "black",   bg = "silver" }
		"dialog.label"       = { fg = "black",   bg = "silver" }
		button               = { fg = "black",   bg = "green" }
		"button.focused"     = { fg = "white",   bg = "green" }
		"button.shortcut"    = { fg = "yellow",  bg = "green" }
		input                = { fg = "black",   bg = "teal" }
		"input.focused"      = { fg = "white",   bg = "teal" }
		list                 = { fg = "black",   bg = "silver" }
		"list.selected"      = { fg = "white",   bg = "navy" }
		"list.unfocused"     = { fg = "black",   bg = "gray" }
		checkbox             = { fg = "black",   bg = "silver" }
		"checkbox.focused"   = { fg = "white",   bg = "navy" }
	`), "")
	if err != nil {
		t.Fatalf("parsing the test theme: %v", err)
	}
	return th
}

// keyEvent builds a key press.
func keyEvent(key tcell.Key, r rune, mods tcell.ModMask) *tcell.EventKey {
	return tcell.NewEventKey(key, r, mods)
}

// runeEvent builds the press of a printable character.
func runeEvent(r rune) *tcell.EventKey {
	return tcell.NewEventKey(tcell.KeyRune, r, tcell.ModNone)
}

// clickEvent builds a left-button press at a screen position.
func clickEvent(x, y int) *tcell.EventMouse {
	return tcell.NewEventMouse(x, y, tcell.Button1, tcell.ModNone)
}

// releaseEvent builds the release of every mouse button at a position.
func releaseEvent(x, y int) *tcell.EventMouse {
	return tcell.NewEventMouse(x, y, tcell.ButtonNone, tcell.ModNone)
}