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  }