mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Merge branch 'devel' into barchart
This commit is contained in:
commit
b281b0506f
@ -75,6 +75,13 @@ func (u *Unbound) wake() {
|
||||
}
|
||||
}
|
||||
|
||||
// Empty determines if the queue is empty.
|
||||
func (u *Unbound) Empty() bool {
|
||||
u.mu.Lock()
|
||||
defer u.mu.Unlock()
|
||||
return u.empty()
|
||||
}
|
||||
|
||||
// empty determines if the queue is empty.
|
||||
func (u *Unbound) empty() bool {
|
||||
return u.first == nil
|
||||
|
@ -25,12 +25,14 @@ import (
|
||||
|
||||
func TestQueue(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
pushes []terminalapi.Event
|
||||
wantPops []terminalapi.Event
|
||||
desc string
|
||||
pushes []terminalapi.Event
|
||||
wantEmpty bool // Checked after pushes and before pops.
|
||||
wantPops []terminalapi.Event
|
||||
}{
|
||||
{
|
||||
desc: "empty queue returns nil",
|
||||
desc: "empty queue returns nil",
|
||||
wantEmpty: true,
|
||||
wantPops: []terminalapi.Event{
|
||||
nil,
|
||||
},
|
||||
@ -42,6 +44,7 @@ func TestQueue(t *testing.T) {
|
||||
terminalapi.NewError("error2"),
|
||||
terminalapi.NewError("error3"),
|
||||
},
|
||||
wantEmpty: false,
|
||||
wantPops: []terminalapi.Event{
|
||||
terminalapi.NewError("error1"),
|
||||
terminalapi.NewError("error2"),
|
||||
@ -59,6 +62,11 @@ func TestQueue(t *testing.T) {
|
||||
q.Push(ev)
|
||||
}
|
||||
|
||||
gotEmpty := q.Empty()
|
||||
if gotEmpty != tc.wantEmpty {
|
||||
t.Errorf("Empty => got %v, want %v", gotEmpty, tc.wantEmpty)
|
||||
}
|
||||
|
||||
for i, want := range tc.wantPops {
|
||||
got := q.Pop()
|
||||
if diff := pretty.Compare(want, got); diff != "" {
|
||||
|
51
termdash.go
51
termdash.go
@ -25,6 +25,7 @@ package termdash
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
@ -51,7 +52,8 @@ func (o option) set(td *termdash) {
|
||||
}
|
||||
|
||||
// RedrawInterval sets how often termdash redraws the container and all the widgets.
|
||||
// Defaults to DefaultRedrawInterval.
|
||||
// Defaults to DefaultRedrawInterval. Use the controller to disable the
|
||||
// periodic redraw.
|
||||
func RedrawInterval(t time.Duration) Option {
|
||||
return option(func(td *termdash) {
|
||||
td.redrawInterval = t
|
||||
@ -88,6 +90,8 @@ func MouseSubscriber(f func(*terminalapi.Mouse)) Option {
|
||||
}
|
||||
|
||||
// Run runs the terminal dashboard with the provided container on the terminal.
|
||||
// Redraws the terminal periodically. If you prefer a manual redraw, use the
|
||||
// Controller instead.
|
||||
// Blocks until the context expires.
|
||||
func Run(ctx context.Context, t terminalapi.Terminal, c *container.Container, opts ...Option) error {
|
||||
td := newTermdash(t, c, opts...)
|
||||
@ -96,6 +100,51 @@ func Run(ctx context.Context, t terminalapi.Terminal, c *container.Container, op
|
||||
return td.start(ctx)
|
||||
}
|
||||
|
||||
// Controller controls a termdash instance.
|
||||
// The controller instance is only valid until Close() is called.
|
||||
// The controller is not thread-safe.
|
||||
type Controller struct {
|
||||
td *termdash
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// NewController initializes termdash and returns an instance of the controller.
|
||||
// Periodic redrawing is disabled when using the controller, the RedrawInterval
|
||||
// option is ignored.
|
||||
// Close the controller when it isn't needed anymore.
|
||||
func NewController(t terminalapi.Terminal, c *container.Container, opts ...Option) (*Controller, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctrl := &Controller{
|
||||
td: newTermdash(t, c, opts...),
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
// stops when Close() is called.
|
||||
go ctrl.td.processEvents(ctx)
|
||||
if err := ctrl.td.periodicRedraw(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctrl, nil
|
||||
}
|
||||
|
||||
// Redraw triggers redraw of the terminal.
|
||||
func (c *Controller) Redraw() error {
|
||||
if c.td == nil {
|
||||
return errors.New("the termdash instance is no longer running, this controller is now invalid")
|
||||
}
|
||||
|
||||
c.td.mu.Lock()
|
||||
defer c.td.mu.Unlock()
|
||||
return c.td.redraw()
|
||||
}
|
||||
|
||||
// Close closes the Controller and its termdash instance.
|
||||
func (c *Controller) Close() {
|
||||
c.cancel()
|
||||
c.td.stop()
|
||||
c.td = nil
|
||||
}
|
||||
|
||||
// termdash is a terminal based dashboard.
|
||||
// This object is thread-safe.
|
||||
type termdash struct {
|
||||
|
261
termdash_test.go
261
termdash_test.go
@ -34,7 +34,7 @@ import (
|
||||
"github.com/mum4k/termdash/widgets/fakewidget"
|
||||
)
|
||||
|
||||
// Example shows how to setup and run termdash.
|
||||
// Example shows how to setup and run termdash with periodic redraw.
|
||||
func Example() {
|
||||
// Create the terminal.
|
||||
t, err := termbox.New()
|
||||
@ -70,6 +70,41 @@ func Example() {
|
||||
}
|
||||
}
|
||||
|
||||
// Example shows how to setup and run termdash with manually triggered redraw.
|
||||
func Example_triggered() {
|
||||
// Create the terminal.
|
||||
t, err := termbox.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer t.Close()
|
||||
|
||||
wOpts := widgetapi.Options{
|
||||
MinimumSize: fakewidget.MinimumSize,
|
||||
WantKeyboard: true,
|
||||
WantMouse: true,
|
||||
}
|
||||
|
||||
// Create the container with a widget.
|
||||
c := container.New(
|
||||
t,
|
||||
container.PlaceWidget(fakewidget.New(wOpts)),
|
||||
)
|
||||
|
||||
// Create the controller and disable periodic redraw.
|
||||
ctrl, err := NewController(t, c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Close the controller and termdash once it isn't required anymore.
|
||||
defer ctrl.Close()
|
||||
|
||||
// Redraw the terminal manually.
|
||||
if err := ctrl.Redraw(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// errorHandler just stores the last error received.
|
||||
type errorHandler struct {
|
||||
err error
|
||||
@ -143,26 +178,6 @@ func TestRun(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "resizes the terminal",
|
||||
size: image.Point{60, 10},
|
||||
opts: []Option{
|
||||
RedrawInterval(1),
|
||||
},
|
||||
events: []terminalapi.Event{
|
||||
&terminalapi.Resize{Size: image.Point{70, 10}},
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(image.Point{70, 10})
|
||||
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(ft.Area()),
|
||||
widgetapi.Options{},
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "forwards mouse events to container",
|
||||
size: image.Point{60, 10},
|
||||
@ -340,9 +355,213 @@ func TestRun(t *testing.T) {
|
||||
t.Errorf("after => unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := untilEmpty(5*time.Second, eq); err != nil {
|
||||
t.Fatalf("untilEmpty => %v", err)
|
||||
}
|
||||
|
||||
if diff := faketerm.Diff(tc.want(got.Size()), got); diff != "" {
|
||||
t.Errorf("Run => %v", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestController(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
size image.Point
|
||||
opts []Option
|
||||
events []terminalapi.Event
|
||||
apiEvents func(*fakewidget.Mirror) // Calls to the API of the widget.
|
||||
controls func(*Controller) error
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "event triggers a redraw",
|
||||
size: image.Point{60, 10},
|
||||
events: []terminalapi.Event{
|
||||
&terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(ft.Area()),
|
||||
widgetapi.Options{
|
||||
WantKeyboard: true,
|
||||
WantMouse: true,
|
||||
},
|
||||
&terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
)
|
||||
return ft
|
||||
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "controller triggers redraw",
|
||||
size: image.Point{60, 10},
|
||||
apiEvents: func(mi *fakewidget.Mirror) {
|
||||
mi.Text("hello")
|
||||
},
|
||||
controls: func(ctrl *Controller) error {
|
||||
return ctrl.Redraw()
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
|
||||
mirror := fakewidget.New(widgetapi.Options{})
|
||||
mirror.Text("hello")
|
||||
fakewidget.MustDrawWithMirror(
|
||||
mirror,
|
||||
ft,
|
||||
testcanvas.MustNew(ft.Area()),
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "ignores periodic redraw via the controller",
|
||||
size: image.Point{60, 10},
|
||||
opts: []Option{
|
||||
RedrawInterval(1),
|
||||
},
|
||||
apiEvents: func(mi *fakewidget.Mirror) {
|
||||
mi.Text("hello")
|
||||
},
|
||||
controls: func(ctrl *Controller) error {
|
||||
return nil
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(ft.Area()),
|
||||
widgetapi.Options{},
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "does not redraw unless triggered when periodic disabled",
|
||||
size: image.Point{60, 10},
|
||||
apiEvents: func(mi *fakewidget.Mirror) {
|
||||
mi.Text("hello")
|
||||
},
|
||||
controls: func(ctrl *Controller) error {
|
||||
return nil
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(ft.Area()),
|
||||
widgetapi.Options{},
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "fails when redraw fails",
|
||||
size: image.Point{1, 1},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
return faketerm.MustNew(size)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "resizes the terminal",
|
||||
size: image.Point{60, 10},
|
||||
events: []terminalapi.Event{
|
||||
&terminalapi.Resize{Size: image.Point{70, 10}},
|
||||
},
|
||||
controls: func(ctrl *Controller) error {
|
||||
return ctrl.Redraw()
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(image.Point{70, 10})
|
||||
|
||||
fakewidget.MustDraw(
|
||||
ft,
|
||||
testcanvas.MustNew(ft.Area()),
|
||||
widgetapi.Options{},
|
||||
)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
eq := eventqueue.New()
|
||||
for _, ev := range tc.events {
|
||||
eq.Push(ev)
|
||||
}
|
||||
|
||||
got, err := faketerm.New(tc.size, faketerm.WithEventQueue(eq))
|
||||
if err != nil {
|
||||
t.Fatalf("faketerm.New => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
mi := fakewidget.New(widgetapi.Options{
|
||||
WantKeyboard: true,
|
||||
WantMouse: true,
|
||||
})
|
||||
cont := container.New(
|
||||
got,
|
||||
container.PlaceWidget(mi),
|
||||
)
|
||||
|
||||
ctrl, err := NewController(got, cont, tc.opts...)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("NewController => unexpected error: %v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer ctrl.Close()
|
||||
|
||||
if tc.apiEvents != nil {
|
||||
tc.apiEvents(mi)
|
||||
}
|
||||
|
||||
if err := untilEmpty(5*time.Second, eq); err != nil {
|
||||
t.Fatalf("untilEmpty => %v", err)
|
||||
}
|
||||
if tc.controls != nil {
|
||||
if err := tc.controls(ctrl); err != nil {
|
||||
t.Errorf("controls => unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if diff := faketerm.Diff(tc.want(got.Size()), got); diff != "" {
|
||||
t.Errorf("Run => %v", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// untilEmpty waits until the queue empties.
|
||||
// Waits at most the specified duration.
|
||||
func untilEmpty(timeout time.Duration, q *eventqueue.Unbound) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
tick := time.NewTimer(5 * time.Millisecond)
|
||||
defer tick.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
if q.Empty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return fmt.Errorf("while waiting for the event queue to empty: %v", ctx.Err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,9 @@ var MinimumSize = image.Point{24, 5}
|
||||
// Mirror is a fake widget. The fake widget draws a border around its assigned
|
||||
// canvas and writes the size of its assigned canvas on the first line of the
|
||||
// canvas. It writes the last received keyboard event onto the second line. It
|
||||
// writes the last received mouse event onto the third line.
|
||||
// writes the last received mouse event onto the third line. If a non-empty
|
||||
// string is provided via the Text() method, that text will be written right
|
||||
// after the canvas size on the first line.
|
||||
//
|
||||
// The widget requests the same options that are provided to the constructor.
|
||||
// If the options or canvas size don't allow for the three lines mentioned
|
||||
@ -57,6 +59,9 @@ type Mirror struct {
|
||||
// lines are the three lines that will be drawn on the canvas.
|
||||
lines []string
|
||||
|
||||
// text is the text provided by the last call to Text().
|
||||
text string
|
||||
|
||||
// mu protects lines.
|
||||
mu sync.RWMutex
|
||||
|
||||
@ -88,7 +93,7 @@ func (mi *Mirror) Draw(cvs *canvas.Canvas) error {
|
||||
return err
|
||||
}
|
||||
|
||||
mi.lines[sizeLine] = cvs.Size().String()
|
||||
mi.lines[sizeLine] = fmt.Sprintf("%s%s", cvs.Size().String(), mi.text)
|
||||
usable := area.ExcludeBorder(cvs.Area())
|
||||
start := cvs.Area().Intersect(usable).Min
|
||||
for i := 0; i < outputLines; i++ {
|
||||
@ -105,6 +110,12 @@ func (mi *Mirror) Draw(cvs *canvas.Canvas) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Text stores a text that should be displayed right after the canvas size on
|
||||
// the first line of the output.
|
||||
func (mi *Mirror) Text(txt string) {
|
||||
mi.text = txt
|
||||
}
|
||||
|
||||
// Keyboard draws the received key on the canvas.
|
||||
// Sending the keyboard.KeyEsc causes this widget to forget the last keyboard
|
||||
// event and return an error instead.
|
||||
@ -147,17 +158,29 @@ func (mi *Mirror) Options() widgetapi.Options {
|
||||
// widget onto the provided canvas and forwarding the given events.
|
||||
func Draw(t terminalapi.Terminal, cvs *canvas.Canvas, opts widgetapi.Options, events ...terminalapi.Event) error {
|
||||
mirror := New(opts)
|
||||
return DrawWithMirror(mirror, t, cvs, events...)
|
||||
}
|
||||
|
||||
// MustDraw is like Draw, but panics on all errors.
|
||||
func MustDraw(t terminalapi.Terminal, cvs *canvas.Canvas, opts widgetapi.Options, events ...terminalapi.Event) {
|
||||
if err := Draw(t, cvs, opts, events...); err != nil {
|
||||
panic(fmt.Sprintf("Draw => %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// DrawWithMirror is like Draw, but uses the provided Mirror instead of creating one.
|
||||
func DrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, events ...terminalapi.Event) error {
|
||||
for _, ev := range events {
|
||||
switch e := ev.(type) {
|
||||
case *terminalapi.Mouse:
|
||||
if !opts.WantMouse {
|
||||
if !mirror.opts.WantMouse {
|
||||
continue
|
||||
}
|
||||
if err := mirror.Mouse(e); err != nil {
|
||||
return err
|
||||
}
|
||||
case *terminalapi.Keyboard:
|
||||
if !opts.WantKeyboard {
|
||||
if !mirror.opts.WantKeyboard {
|
||||
continue
|
||||
}
|
||||
if err := mirror.Keyboard(e); err != nil {
|
||||
@ -174,9 +197,9 @@ func Draw(t terminalapi.Terminal, cvs *canvas.Canvas, opts widgetapi.Options, ev
|
||||
return cvs.Apply(t)
|
||||
}
|
||||
|
||||
// MustDraw is like Draw, but panics on all errors.
|
||||
func MustDraw(t terminalapi.Terminal, cvs *canvas.Canvas, opts widgetapi.Options, events ...terminalapi.Event) {
|
||||
if err := Draw(t, cvs, opts, events...); err != nil {
|
||||
panic(fmt.Sprintf("Draw => %v", err))
|
||||
// MustDrawWithMirror is like DrawWithMirror, but panics on all errors.
|
||||
func MustDrawWithMirror(mirror *Mirror, t terminalapi.Terminal, cvs *canvas.Canvas, events ...terminalapi.Event) {
|
||||
if err := DrawWithMirror(mirror, t, cvs, events...); err != nil {
|
||||
panic(fmt.Sprintf("DrawWithMirror => %v", err))
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ func TestMirror(t *testing.T) {
|
||||
desc string
|
||||
keyEvents []keyEvents // Keyboard events to send before calling Draw().
|
||||
mouseEvents []mouseEvents // Mouse events to send before calling Draw().
|
||||
apiEvents func(*Mirror) // External events via the widget's API.
|
||||
cvs *canvas.Canvas
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
@ -78,6 +79,21 @@ func TestMirror(t *testing.T) {
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "draws the box, canvas size and custom text",
|
||||
apiEvents: func(mi *Mirror) {
|
||||
mi.Text("hi")
|
||||
},
|
||||
cvs: testcanvas.MustNew(image.Rect(0, 0, 9, 3)),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
cvs := testcanvas.MustNew(ft.Area())
|
||||
testdraw.MustBorder(cvs, cvs.Area())
|
||||
testdraw.MustText(cvs, "(9,3)hi", image.Point{1, 1})
|
||||
testcanvas.MustApply(cvs, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "skips canvas size if there isn't a line for it",
|
||||
cvs: testcanvas.MustNew(image.Rect(0, 0, 3, 2)),
|
||||
@ -227,6 +243,10 @@ func TestMirror(t *testing.T) {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
w := New(widgetapi.Options{})
|
||||
|
||||
if tc.apiEvents != nil {
|
||||
tc.apiEvents(w)
|
||||
}
|
||||
|
||||
for _, keyEv := range tc.keyEvents {
|
||||
err := w.Keyboard(keyEv.k)
|
||||
if (err != nil) != keyEv.wantErr {
|
||||
@ -270,3 +290,71 @@ func TestOptions(t *testing.T) {
|
||||
t.Errorf("Options => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDraw(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
opts widgetapi.Options
|
||||
cvs *canvas.Canvas
|
||||
events []terminalapi.Event
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "canvas too small to draw a box",
|
||||
cvs: testcanvas.MustNew(image.Rect(0, 0, 1, 1)),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
return faketerm.MustNew(size)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "draws the box and canvas size",
|
||||
cvs: testcanvas.MustNew(image.Rect(0, 0, 9, 3)),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
cvs := testcanvas.MustNew(ft.Area())
|
||||
testdraw.MustBorder(cvs, cvs.Area())
|
||||
testdraw.MustText(cvs, "(9,3)", image.Point{1, 1})
|
||||
testcanvas.MustApply(cvs, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "draws both keyboard and mouse events",
|
||||
opts: widgetapi.Options{
|
||||
WantKeyboard: true,
|
||||
WantMouse: true,
|
||||
},
|
||||
cvs: testcanvas.MustNew(image.Rect(0, 0, 17, 5)),
|
||||
events: []terminalapi.Event{
|
||||
&terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
&terminalapi.Mouse{Button: mouse.ButtonLeft},
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
cvs := testcanvas.MustNew(ft.Area())
|
||||
testdraw.MustBorder(cvs, cvs.Area())
|
||||
testdraw.MustText(cvs, "(17,5)", image.Point{1, 1})
|
||||
testdraw.MustText(cvs, "KeyEnter", image.Point{1, 2})
|
||||
testdraw.MustText(cvs, "(0,0)ButtonLeft", image.Point{1, 3})
|
||||
testcanvas.MustApply(cvs, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := faketerm.MustNew(tc.cvs.Size())
|
||||
err := Draw(got, tc.cvs, tc.opts, tc.events...)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("Draw => got error:%v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
|
||||
if diff := faketerm.Diff(tc.want(tc.cvs.Size()), got); diff != "" {
|
||||
t.Errorf("Draw => %v", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user