elvish/pkg/cli/tk/utils_test.go
Qi Xiao 5327ba3521 Make tests compatible with "go test -count n" (n > 1).
The "-count" flag causes the test functions to be invoked multiple times. Since
some tests mutate their test data or some global state, they will fail when
invoked with a count larger than 1.

This commit changes *some* of such tests to either avoid mutating the test data,
or resetting the global state. Some such tests still remain and will be fixed later.
2021-02-17 22:46:32 +00:00

160 lines
3.3 KiB
Go

package tk
import (
"reflect"
"testing"
"src.elv.sh/pkg/cli/term"
"src.elv.sh/pkg/ui"
)
// renderTest is a test case to be used in TestRenderer.
type renderTest struct {
Name string
Given Renderer
Width int
Height int
Want interface{ Buffer() *term.Buffer }
}
// testRender runs the given Renderer tests.
func testRender(t *testing.T, tests []renderTest) {
t.Helper()
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
t.Helper()
buf := test.Given.Render(test.Width, test.Height)
wantBuf := test.Want.Buffer()
if !reflect.DeepEqual(buf, wantBuf) {
t.Errorf("Buffer mismatch")
t.Logf("Got: %s", buf.TTYString())
t.Logf("Want: %s", wantBuf.TTYString())
}
})
}
}
// handleTest is a test case to be used in testHandle.
type handleTest struct {
Name string
Given Handler
Event term.Event
Events []term.Event
WantNewState interface{}
WantUnhandled bool
}
// testHandle runs the given Handler tests.
func testHandle(t *testing.T, tests []handleTest) {
t.Helper()
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
t.Helper()
handler := test.Given
oldState := getState(handler)
defer setState(handler, oldState)
var handled bool
switch {
case test.Event != nil && test.Events != nil:
t.Fatal("Malformed test case: both Event and Events non-nil:",
test.Event, test.Events)
case test.Event == nil && test.Events == nil:
t.Fatal("Malformed test case: both Event and Events nil")
case test.Event != nil:
handled = handler.Handle(test.Event)
default: // test.Events != nil
for _, event := range test.Events {
handled = handler.Handle(event)
}
}
if handled != !test.WantUnhandled {
t.Errorf("Got handled %v, want %v", handled, !test.WantUnhandled)
}
if test.WantNewState != nil {
state := getState(test.Given)
if !reflect.DeepEqual(state, test.WantNewState) {
t.Errorf("Got state %v, want %v", state, test.WantNewState)
}
}
})
}
}
func getState(v interface{}) interface{} {
return reflectState(v).Interface()
}
func setState(v, state interface{}) {
reflectState(v).Set(reflect.ValueOf(state))
}
func reflectState(v interface{}) reflect.Value {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = reflect.Indirect(rv)
}
return rv.FieldByName("State")
}
// Test for the test utilities.
func TestTestRender(t *testing.T) {
testRender(t, []renderTest{
{
Name: "test",
Given: &testWidget{text: ui.T("test")},
Width: 10, Height: 10,
Want: term.NewBufferBuilder(10).Write("test"),
},
})
}
type testHandlerWithState struct {
State testHandlerState
}
type testHandlerState struct {
last term.Event
total int
}
func (h *testHandlerWithState) Handle(e term.Event) bool {
if e == term.K('x') {
return false
}
h.State.last = e
h.State.total++
return true
}
func TestTestHandle(t *testing.T) {
testHandle(t, []handleTest{
{
Name: "WantNewState",
Given: &testHandlerWithState{},
Event: term.K('a'),
WantNewState: testHandlerState{last: term.K('a'), total: 1},
},
{
Name: "Multiple events",
Given: &testHandlerWithState{},
Events: []term.Event{term.K('a'), term.K('b')},
WantNewState: testHandlerState{last: term.K('b'), total: 2},
},
{
Name: "WantUnhaneld",
Given: &testHandlerWithState{},
Event: term.K('x'),
WantUnhandled: true,
},
})
}