gitstack

grindlemire/go-tui code browser

4.6 KB Go 136 lines 2026-06-03 · d15bb9f raw
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
126
127
128
129
130
131
132
133
134
135
136
package tui

import "testing"

func TestKeyEvent_IsRune(t *testing.T) {
	type tc struct {
		event    KeyEvent
		expected bool
	}

	tests := map[string]tc{
		"rune event":         {event: KeyEvent{Key: KeyRune, Rune: 'a'}, expected: true},
		"enter event":        {event: KeyEvent{Key: KeyEnter}, expected: false},
		"escape event":       {event: KeyEvent{Key: KeyEscape}, expected: false},
		"arrow event":        {event: KeyEvent{Key: KeyUp}, expected: false},
		"function event":     {event: KeyEvent{Key: KeyF1}, expected: false},
		"function key event": {event: KeyEvent{Key: KeyF1}, expected: false},
		"rune with mod":      {event: KeyEvent{Key: KeyRune, Rune: 'x', Mod: ModCtrl}, expected: true},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			got := tt.event.IsRune()
			if got != tt.expected {
				t.Errorf("KeyEvent{Key: %v}.IsRune() = %v, want %v", tt.event.Key, got, tt.expected)
			}
		})
	}
}

func TestKeyEvent_Is(t *testing.T) {
	type tc struct {
		event    KeyEvent
		key      Key
		mods     []Modifier
		expected bool
	}

	tests := map[string]tc{
		"enter matches enter":          {event: KeyEvent{Key: KeyEnter}, key: KeyEnter, expected: true},
		"enter does not match escape":  {event: KeyEvent{Key: KeyEnter}, key: KeyEscape, expected: false},
		"rune matches rune":            {event: KeyEvent{Key: KeyRune, Rune: 'a'}, key: KeyRune, expected: true},
		"ctrl+a with ctrl matches":     {event: KeyEvent{Key: KeyRune, Rune: 'a', Mod: ModCtrl}, key: KeyRune, mods: []Modifier{ModCtrl}, expected: true},
		"ctrl+a without ctrl no match": {event: KeyEvent{Key: KeyRune, Rune: 'a', Mod: ModCtrl}, key: KeyRune, expected: true},
		"no mod with ctrl no match":    {event: KeyEvent{Key: KeyRune, Rune: 'a'}, key: KeyRune, mods: []Modifier{ModCtrl}, expected: false},
		"ctrl+alt matches both":        {event: KeyEvent{Key: KeyRune, Rune: 'a', Mod: ModCtrl | ModAlt}, key: KeyRune, mods: []Modifier{ModCtrl, ModAlt}, expected: true},
		"ctrl+alt only ctrl no match":  {event: KeyEvent{Key: KeyRune, Rune: 'a', Mod: ModCtrl | ModAlt}, key: KeyRune, mods: []Modifier{ModCtrl}, expected: false},
		"shift matches shift":          {event: KeyEvent{Key: KeyUp, Mod: ModShift}, key: KeyUp, mods: []Modifier{ModShift}, expected: true},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			got := tt.event.Is(tt.key, tt.mods...)
			if got != tt.expected {
				t.Errorf("KeyEvent.Is(%v, %v) = %v, want %v", tt.key, tt.mods, got, tt.expected)
			}
		})
	}
}

func TestKeyEvent_Char(t *testing.T) {
	type tc struct {
		event    KeyEvent
		expected rune
	}

	tests := map[string]tc{
		"rune a":       {event: KeyEvent{Key: KeyRune, Rune: 'a'}, expected: 'a'},
		"rune space":   {event: KeyEvent{Key: KeyRune, Rune: ' '}, expected: ' '},
		"rune unicode": {event: KeyEvent{Key: KeyRune, Rune: '日'}, expected: '日'},
		"enter":        {event: KeyEvent{Key: KeyEnter}, expected: 0},
		"escape":       {event: KeyEvent{Key: KeyEscape}, expected: 0},
		"arrow":        {event: KeyEvent{Key: KeyUp}, expected: 0},
		"function key": {event: KeyEvent{Key: KeyF1}, expected: 0},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			got := tt.event.Char()
			if got != tt.expected {
				t.Errorf("KeyEvent{Key: %v, Rune: %q}.Char() = %q, want %q", tt.event.Key, tt.event.Rune, got, tt.expected)
			}
		})
	}
}

func TestEvent_TypeAssertion(t *testing.T) {
	type tc struct {
		event    Event
		isKey    bool
		isResize bool
	}

	tests := map[string]tc{
		"key event":    {event: KeyEvent{Key: KeyEnter}, isKey: true, isResize: false},
		"resize event": {event: ResizeEvent{Width: 80, Height: 24}, isKey: false, isResize: true},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			_, isKey := tt.event.(KeyEvent)
			_, isResize := tt.event.(ResizeEvent)
			if isKey != tt.isKey {
				t.Errorf("type assertion to KeyEvent = %v, want %v", isKey, tt.isKey)
			}
			if isResize != tt.isResize {
				t.Errorf("type assertion to ResizeEvent = %v, want %v", isResize, tt.isResize)
			}
		})
	}
}

func TestResizeEvent(t *testing.T) {
	type tc struct {
		width  int
		height int
	}

	tests := map[string]tc{
		"standard terminal": {width: 80, height: 24},
		"large terminal":    {width: 200, height: 50},
		"small terminal":    {width: 40, height: 10},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			e := ResizeEvent{Width: tt.width, Height: tt.height}
			if e.Width != tt.width {
				t.Errorf("ResizeEvent.Width = %d, want %d", e.Width, tt.width)
			}
			if e.Height != tt.height {
				t.Errorf("ResizeEvent.Height = %d, want %d", e.Height, tt.height)
			}
		})
	}
}