1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-27 13:48:49 +08:00

Wait for subscribers to process events.

This commit is contained in:
Jakub Sobon 2019-03-02 18:24:10 -05:00
parent 80843ae031
commit 4465dced2d
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
3 changed files with 50 additions and 15 deletions

View File

@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Refactoring packages that contained a mix of public and internal identifiers. - Refactoring packages that contained a mix of public and internal identifiers.
### Fixed
- The termdash_test now correctly waits until all subscribers processed events,
not just received them.
#### Breaking API changes #### Breaking API changes
The following packages were refactored, no impact is expected as the removed The following packages were refactored, no impact is expected as the removed

View File

@ -88,6 +88,15 @@ func MouseSubscriber(f func(*terminalapi.Mouse)) Option {
}) })
} }
// withEDS indicates that termdash should run with the provided event
// distribution system instead of creating one.
// Useful for tests.
func withEDS(eds *event.DistributionSystem) Option {
return option(func(td *termdash) {
td.eds = eds
})
}
// Run runs the terminal dashboard with the provided container on the terminal. // Run runs the terminal dashboard with the provided container on the terminal.
// Redraws the terminal periodically. If you prefer a manual redraw, use the // Redraws the terminal periodically. If you prefer a manual redraw, use the
// Controller instead. // Controller instead.

View File

@ -16,7 +16,6 @@ package termdash
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"image" "image"
"sync" "sync"
@ -26,6 +25,7 @@ import (
"github.com/kylelemons/godebug/pretty" "github.com/kylelemons/godebug/pretty"
"github.com/mum4k/termdash/container" "github.com/mum4k/termdash/container"
"github.com/mum4k/termdash/internal/canvas/testcanvas" "github.com/mum4k/termdash/internal/canvas/testcanvas"
"github.com/mum4k/termdash/internal/event"
"github.com/mum4k/termdash/internal/event/eventqueue" "github.com/mum4k/termdash/internal/event/eventqueue"
"github.com/mum4k/termdash/internal/event/testevent" "github.com/mum4k/termdash/internal/event/testevent"
"github.com/mum4k/termdash/internal/faketerm" "github.com/mum4k/termdash/internal/faketerm"
@ -189,6 +189,9 @@ func TestRun(t *testing.T) {
size image.Point size image.Point
opts func(*eventHandlers) []Option opts func(*eventHandlers) []Option
events []terminalapi.Event events []terminalapi.Event
// The number of expected processed events, used for synchronization.
// Equals len(events) * number of subscribers for the event type.
wantProcessed int
// function to execute after the test case, can do additional comparison. // function to execute after the test case, can do additional comparison.
after func(*eventHandlers) error after func(*eventHandlers) error
want func(size image.Point) *faketerm.Terminal want func(size image.Point) *faketerm.Terminal
@ -238,6 +241,7 @@ func TestRun(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
&terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft}, &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonLeft},
}, },
wantProcessed: 3,
want: func(size image.Point) *faketerm.Terminal { want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size) ft := faketerm.MustNew(size)
@ -263,6 +267,7 @@ func TestRun(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
&terminalapi.Keyboard{Key: keyboard.KeyEnter}, &terminalapi.Keyboard{Key: keyboard.KeyEnter},
}, },
wantProcessed: 2,
want: func(size image.Point) *faketerm.Terminal { want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size) ft := faketerm.MustNew(size)
@ -290,6 +295,7 @@ func TestRun(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
terminalapi.NewError("input error"), terminalapi.NewError("input error"),
}, },
wantProcessed: 1,
after: func(eh *eventHandlers) error { after: func(eh *eventHandlers) error {
if want := "input error"; eh.handler.get().Error() != want { if want := "input error"; eh.handler.get().Error() != want {
return fmt.Errorf("errorHandler got %v, want %v", eh.handler.get(), want) return fmt.Errorf("errorHandler got %v, want %v", eh.handler.get(), want)
@ -319,6 +325,7 @@ func TestRun(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
&terminalapi.Keyboard{Key: keyboard.KeyF1}, &terminalapi.Keyboard{Key: keyboard.KeyF1},
}, },
wantProcessed: 3,
after: func(eh *eventHandlers) error { after: func(eh *eventHandlers) error {
want := terminalapi.Keyboard{Key: keyboard.KeyF1} want := terminalapi.Keyboard{Key: keyboard.KeyF1}
if diff := pretty.Compare(want, eh.keySub.get()); diff != "" { if diff := pretty.Compare(want, eh.keySub.get()); diff != "" {
@ -352,6 +359,7 @@ func TestRun(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
&terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonWheelUp}, &terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonWheelUp},
}, },
wantProcessed: 4,
after: func(eh *eventHandlers) error { after: func(eh *eventHandlers) error {
want := terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonWheelUp} want := terminalapi.Mouse{Position: image.Point{0, 0}, Button: mouse.ButtonWheelUp}
if diff := pretty.Compare(want, eh.mouseSub.get()); diff != "" { if diff := pretty.Compare(want, eh.mouseSub.get()); diff != "" {
@ -408,7 +416,11 @@ func TestRun(t *testing.T) {
} }
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
err = Run(ctx, got, cont, tc.opts(handlers)...)
eds := event.NewDistributionSystem()
opts := tc.opts(handlers)
opts = append(opts, withEDS(eds))
err = Run(ctx, got, cont, opts...)
cancel() cancel()
if (err != nil) != tc.wantErr { if (err != nil) != tc.wantErr {
t.Errorf("Run => unexpected error: %v, wantErr: %v", err, tc.wantErr) t.Errorf("Run => unexpected error: %v, wantErr: %v", err, tc.wantErr)
@ -418,8 +430,8 @@ func TestRun(t *testing.T) {
} }
if err := testevent.WaitFor(5*time.Second, func() error { if err := testevent.WaitFor(5*time.Second, func() error {
if !eq.Empty() { if got, want := eds.Processed(), tc.wantProcessed; got != want {
return errors.New("event queue not empty") return fmt.Errorf("the event distribution system processed %d events, want %d", got, want)
} }
return nil return nil
}); err != nil { }); err != nil {
@ -447,6 +459,9 @@ func TestController(t *testing.T) {
size image.Point size image.Point
opts []Option opts []Option
events []terminalapi.Event events []terminalapi.Event
// The number of expected processed events, used for synchronization.
// Equals len(events) * number of subscribers for the event type.
wantProcessed int
apiEvents func(*fakewidget.Mirror) // Calls to the API of the widget. apiEvents func(*fakewidget.Mirror) // Calls to the API of the widget.
controls func(*Controller) error controls func(*Controller) error
want func(size image.Point) *faketerm.Terminal want func(size image.Point) *faketerm.Terminal
@ -458,6 +473,7 @@ func TestController(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
&terminalapi.Keyboard{Key: keyboard.KeyEnter}, &terminalapi.Keyboard{Key: keyboard.KeyEnter},
}, },
wantProcessed: 2,
want: func(size image.Point) *faketerm.Terminal { want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size) ft := faketerm.MustNew(size)
@ -553,6 +569,7 @@ func TestController(t *testing.T) {
events: []terminalapi.Event{ events: []terminalapi.Event{
&terminalapi.Resize{Size: image.Point{70, 10}}, &terminalapi.Resize{Size: image.Point{70, 10}},
}, },
wantProcessed: 1,
controls: func(ctrl *Controller) error { controls: func(ctrl *Controller) error {
return ctrl.Redraw() return ctrl.Redraw()
}, },
@ -596,7 +613,10 @@ func TestController(t *testing.T) {
t.Fatalf("container.New => unexpected error: %v", err) t.Fatalf("container.New => unexpected error: %v", err)
} }
ctrl, err := NewController(got, cont, tc.opts...) eds := event.NewDistributionSystem()
opts := tc.opts
opts = append(opts, withEDS(eds))
ctrl, err := NewController(got, cont, opts...)
if (err != nil) != tc.wantErr { if (err != nil) != tc.wantErr {
t.Errorf("NewController => unexpected error: %v, wantErr: %v", err, tc.wantErr) t.Errorf("NewController => unexpected error: %v, wantErr: %v", err, tc.wantErr)
} }
@ -609,13 +629,14 @@ func TestController(t *testing.T) {
} }
if err := testevent.WaitFor(5*time.Second, func() error { if err := testevent.WaitFor(5*time.Second, func() error {
if !eq.Empty() { if got, want := eds.Processed(), tc.wantProcessed; got != want {
return errors.New("event queue not empty") return fmt.Errorf("the event distribution system processed %d events, want %d", got, want)
} }
return nil return nil
}); err != nil { }); err != nil {
t.Fatalf("testevent.WaitFor => %v", err) t.Fatalf("testevent.WaitFor => %v", err)
} }
if tc.controls != nil { if tc.controls != nil {
if err := tc.controls(ctrl); err != nil { if err := tc.controls(ctrl); err != nil {
t.Errorf("controls => unexpected error: %v", err) t.Errorf("controls => unexpected error: %v", err)