github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/io/router/key_test.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package router 4 5 import ( 6 "reflect" 7 "testing" 8 9 "github.com/cybriq/giocore/io/event" 10 "github.com/cybriq/giocore/io/key" 11 "github.com/cybriq/giocore/op" 12 ) 13 14 func TestKeyWakeup(t *testing.T) { 15 handler := new(int) 16 var ops op.Ops 17 key.InputOp{Tag: handler}.Add(&ops) 18 19 var r Router 20 // Test that merely adding a handler doesn't trigger redraw. 21 r.Frame(&ops) 22 if _, wake := r.WakeupTime(); wake { 23 t.Errorf("adding key.InputOp triggered a redraw") 24 } 25 // However, adding a handler queues a Focus(false) event. 26 if evts := r.Events(handler); len(evts) != 1 { 27 t.Errorf("no Focus event for newly registered key.InputOp") 28 } 29 // Verify that r.Events does trigger a redraw. 30 r.Frame(&ops) 31 if _, wake := r.WakeupTime(); !wake { 32 t.Errorf("key.FocusEvent event didn't trigger a redraw") 33 } 34 } 35 36 func TestKeyMultiples(t *testing.T) { 37 handlers := make([]int, 3) 38 ops := new(op.Ops) 39 r := new(Router) 40 41 key.SoftKeyboardOp{Show: true}.Add(ops) 42 key.InputOp{Tag: &handlers[0]}.Add(ops) 43 key.FocusOp{Tag: &handlers[2]}.Add(ops) 44 key.InputOp{Tag: &handlers[1]}.Add(ops) 45 46 // The last one must be focused: 47 key.InputOp{Tag: &handlers[2]}.Add(ops) 48 49 r.Frame(ops) 50 51 assertKeyEvent(t, r.Events(&handlers[0]), false) 52 assertKeyEvent(t, r.Events(&handlers[1]), false) 53 assertKeyEvent(t, r.Events(&handlers[2]), true) 54 assertFocus(t, r, &handlers[2]) 55 assertKeyboard(t, r, TextInputOpen) 56 } 57 58 func TestKeyStacked(t *testing.T) { 59 handlers := make([]int, 4) 60 ops := new(op.Ops) 61 r := new(Router) 62 63 s := op.Save(ops) 64 key.InputOp{Tag: &handlers[0]}.Add(ops) 65 key.FocusOp{Tag: nil}.Add(ops) 66 s.Load() 67 s = op.Save(ops) 68 key.SoftKeyboardOp{Show: false}.Add(ops) 69 key.InputOp{Tag: &handlers[1]}.Add(ops) 70 key.FocusOp{Tag: &handlers[1]}.Add(ops) 71 s.Load() 72 s = op.Save(ops) 73 key.InputOp{Tag: &handlers[2]}.Add(ops) 74 key.SoftKeyboardOp{Show: true}.Add(ops) 75 s.Load() 76 s = op.Save(ops) 77 key.InputOp{Tag: &handlers[3]}.Add(ops) 78 s.Load() 79 80 r.Frame(ops) 81 82 assertKeyEvent(t, r.Events(&handlers[0]), false) 83 assertKeyEvent(t, r.Events(&handlers[1]), true) 84 assertKeyEvent(t, r.Events(&handlers[2]), false) 85 assertKeyEvent(t, r.Events(&handlers[3]), false) 86 assertFocus(t, r, &handlers[1]) 87 assertKeyboard(t, r, TextInputOpen) 88 } 89 90 func TestKeySoftKeyboardNoFocus(t *testing.T) { 91 ops := new(op.Ops) 92 r := new(Router) 93 94 // It's possible to open the keyboard 95 // without any active focus: 96 key.SoftKeyboardOp{Show: true}.Add(ops) 97 98 r.Frame(ops) 99 100 assertFocus(t, r, nil) 101 assertKeyboard(t, r, TextInputOpen) 102 } 103 104 func TestKeyRemoveFocus(t *testing.T) { 105 handlers := make([]int, 2) 106 ops := new(op.Ops) 107 r := new(Router) 108 109 // New InputOp with Focus and Keyboard: 110 s := op.Save(ops) 111 key.InputOp{Tag: &handlers[0]}.Add(ops) 112 key.FocusOp{Tag: &handlers[0]}.Add(ops) 113 key.SoftKeyboardOp{Show: true}.Add(ops) 114 s.Load() 115 116 // New InputOp without any focus: 117 s = op.Save(ops) 118 key.InputOp{Tag: &handlers[1]}.Add(ops) 119 s.Load() 120 121 r.Frame(ops) 122 123 // Add some key events: 124 event := event.Event(key.Event{Name: key.NameTab, Modifiers: key.ModShortcut, State: key.Press}) 125 r.Queue(event) 126 127 assertKeyEvent(t, r.Events(&handlers[0]), true, event) 128 assertKeyEvent(t, r.Events(&handlers[1]), false) 129 assertFocus(t, r, &handlers[0]) 130 assertKeyboard(t, r, TextInputOpen) 131 132 ops.Reset() 133 134 // Will get the focus removed: 135 s = op.Save(ops) 136 key.InputOp{Tag: &handlers[0]}.Add(ops) 137 s.Load() 138 139 // Unchanged: 140 s = op.Save(ops) 141 key.InputOp{Tag: &handlers[1]}.Add(ops) 142 s.Load() 143 144 // Remove focus by focusing on a tag that don't exist. 145 s = op.Save(ops) 146 key.FocusOp{Tag: new(int)}.Add(ops) 147 s.Load() 148 149 r.Frame(ops) 150 151 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 152 assertFocus(t, r, nil) 153 assertKeyboard(t, r, TextInputClose) 154 155 ops.Reset() 156 157 s = op.Save(ops) 158 key.InputOp{Tag: &handlers[0]}.Add(ops) 159 s.Load() 160 161 s = op.Save(ops) 162 key.InputOp{Tag: &handlers[1]}.Add(ops) 163 s.Load() 164 165 r.Frame(ops) 166 167 assertKeyEventUnexpected(t, r.Events(&handlers[0])) 168 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 169 assertFocus(t, r, nil) 170 assertKeyboard(t, r, TextInputKeep) 171 172 ops.Reset() 173 174 // Set focus to InputOp which already 175 // exists in the previous frame: 176 s = op.Save(ops) 177 key.FocusOp{Tag: &handlers[0]}.Add(ops) 178 key.InputOp{Tag: &handlers[0]}.Add(ops) 179 key.SoftKeyboardOp{Show: true}.Add(ops) 180 s.Load() 181 182 // Remove focus. 183 s = op.Save(ops) 184 key.InputOp{Tag: &handlers[1]}.Add(ops) 185 key.FocusOp{Tag: nil}.Add(ops) 186 s.Load() 187 188 r.Frame(ops) 189 190 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 191 assertFocus(t, r, nil) 192 assertKeyboard(t, r, TextInputOpen) 193 } 194 195 func TestKeyFocusedInvisible(t *testing.T) { 196 handlers := make([]int, 2) 197 ops := new(op.Ops) 198 r := new(Router) 199 200 // Set new InputOp with focus: 201 s := op.Save(ops) 202 key.FocusOp{Tag: &handlers[0]}.Add(ops) 203 key.InputOp{Tag: &handlers[0]}.Add(ops) 204 key.SoftKeyboardOp{Show: true}.Add(ops) 205 s.Load() 206 207 // Set new InputOp without focus: 208 s = op.Save(ops) 209 key.InputOp{Tag: &handlers[1]}.Add(ops) 210 s.Load() 211 212 r.Frame(ops) 213 214 assertKeyEvent(t, r.Events(&handlers[0]), true) 215 assertKeyEvent(t, r.Events(&handlers[1]), false) 216 assertFocus(t, r, &handlers[0]) 217 assertKeyboard(t, r, TextInputOpen) 218 219 ops.Reset() 220 221 // 222 // Removed first (focused) element! 223 // 224 225 // Unchanged: 226 s = op.Save(ops) 227 key.InputOp{Tag: &handlers[1]}.Add(ops) 228 s.Load() 229 230 r.Frame(ops) 231 232 assertKeyEventUnexpected(t, r.Events(&handlers[0])) 233 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 234 assertFocus(t, r, nil) 235 assertKeyboard(t, r, TextInputClose) 236 237 ops.Reset() 238 239 // Respawn the first element: 240 // It must receive one `Event{Focus: false}`. 241 s = op.Save(ops) 242 key.InputOp{Tag: &handlers[0]}.Add(ops) 243 s.Load() 244 245 // Unchanged 246 s = op.Save(ops) 247 key.InputOp{Tag: &handlers[1]}.Add(ops) 248 s.Load() 249 250 r.Frame(ops) 251 252 assertKeyEvent(t, r.Events(&handlers[0]), false) 253 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 254 assertFocus(t, r, nil) 255 assertKeyboard(t, r, TextInputKeep) 256 257 } 258 259 func assertKeyEvent(t *testing.T, events []event.Event, expected bool, expectedInputs ...event.Event) { 260 t.Helper() 261 var evtFocus int 262 var evtKeyPress int 263 for _, e := range events { 264 switch ev := e.(type) { 265 case key.FocusEvent: 266 if ev.Focus != expected { 267 t.Errorf("focus is expected to be %v, got %v", expected, ev.Focus) 268 } 269 evtFocus++ 270 case key.Event, key.EditEvent: 271 if len(expectedInputs) <= evtKeyPress { 272 t.Errorf("unexpected key events") 273 } 274 if !reflect.DeepEqual(ev, expectedInputs[evtKeyPress]) { 275 t.Errorf("expected %v events, got %v", expectedInputs[evtKeyPress], ev) 276 } 277 evtKeyPress++ 278 } 279 } 280 if evtFocus <= 0 { 281 t.Errorf("expected focus event") 282 } 283 if evtFocus > 1 { 284 t.Errorf("expected single focus event") 285 } 286 if evtKeyPress != len(expectedInputs) { 287 t.Errorf("expected key events") 288 } 289 } 290 291 func assertKeyEventUnexpected(t *testing.T, events []event.Event) { 292 t.Helper() 293 var evtFocus int 294 for _, e := range events { 295 switch e.(type) { 296 case key.FocusEvent: 297 evtFocus++ 298 } 299 } 300 if evtFocus > 1 { 301 t.Errorf("unexpected focus event") 302 } 303 } 304 305 func assertFocus(t *testing.T, router *Router, expected event.Tag) { 306 t.Helper() 307 if router.kqueue.focus != expected { 308 t.Errorf("expected %v to be focused, got %v", expected, router.kqueue.focus) 309 } 310 } 311 312 func assertKeyboard(t *testing.T, router *Router, expected TextInputState) { 313 t.Helper() 314 if router.kqueue.state != expected { 315 t.Errorf("expected %v keyboard, got %v", expected, router.kqueue.state) 316 } 317 }