mirror of https://github.com/mum4k/termdash.git
1148 lines
29 KiB
Go
1148 lines
29 KiB
Go
// Copyright 2018 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package container
|
|
|
|
import (
|
|
"image"
|
|
"testing"
|
|
|
|
"github.com/mum4k/termdash/align"
|
|
"github.com/mum4k/termdash/cell"
|
|
"github.com/mum4k/termdash/linestyle"
|
|
"github.com/mum4k/termdash/private/canvas/testcanvas"
|
|
"github.com/mum4k/termdash/private/draw"
|
|
"github.com/mum4k/termdash/private/draw/testdraw"
|
|
"github.com/mum4k/termdash/private/faketerm"
|
|
"github.com/mum4k/termdash/private/fakewidget"
|
|
"github.com/mum4k/termdash/widgetapi"
|
|
)
|
|
|
|
func TestDrawWidget(t *testing.T) {
|
|
tests := []struct {
|
|
desc string
|
|
termSize image.Point
|
|
container func(ft *faketerm.Terminal) (*Container, error)
|
|
want func(size image.Point) *faketerm.Terminal
|
|
wantErr bool
|
|
}{
|
|
{
|
|
desc: "draws widget with container border",
|
|
termSize: image.Point{9, 5},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
testdraw.MustBorder(cvs, image.Rect(1, 1, 8, 4))
|
|
testdraw.MustText(cvs, "(7,3)", image.Point{2, 2})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "absolute margin on root container",
|
|
termSize: image.Point{20, 10},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
MarginTop(1),
|
|
MarginRight(2),
|
|
MarginBottom(3),
|
|
MarginLeft(4),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(image.Rect(4, 1, 18, 7))
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "relative margin on root container",
|
|
termSize: image.Point{20, 20},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
MarginTopPercent(10),
|
|
MarginRightPercent(20),
|
|
MarginBottomPercent(50),
|
|
MarginLeftPercent(40),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(image.Rect(8, 2, 16, 10))
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws vertical sub-containers with margin",
|
|
termSize: image.Point{20, 10},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
SplitVertical(
|
|
Left(
|
|
Border(linestyle.Double),
|
|
MarginTop(1),
|
|
MarginRight(2),
|
|
MarginBottom(3),
|
|
MarginLeft(4),
|
|
),
|
|
Right(
|
|
Border(linestyle.Double),
|
|
MarginTop(3),
|
|
MarginRight(4),
|
|
MarginBottom(1),
|
|
MarginLeft(2),
|
|
),
|
|
),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Outer container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Borders around the sub-containers.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(5, 2, 8, 6),
|
|
draw.BorderLineStyle(linestyle.Double),
|
|
)
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(12, 4, 15, 8),
|
|
draw.BorderLineStyle(linestyle.Double),
|
|
)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws horizontal sub-containers with margin",
|
|
termSize: image.Point{20, 20},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
SplitHorizontal(
|
|
Top(
|
|
Border(linestyle.Double),
|
|
MarginTop(1),
|
|
MarginRight(2),
|
|
MarginBottom(3),
|
|
MarginLeft(4),
|
|
),
|
|
Bottom(
|
|
Border(linestyle.Double),
|
|
MarginTop(3),
|
|
MarginRight(4),
|
|
MarginBottom(1),
|
|
MarginLeft(2),
|
|
),
|
|
),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Outer container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Borders around the sub-containers.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(5, 2, 17, 7),
|
|
draw.BorderLineStyle(linestyle.Double),
|
|
)
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(3, 13, 15, 18),
|
|
draw.BorderLineStyle(linestyle.Double),
|
|
)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws padded widget, absolute padding",
|
|
termSize: image.Point{20, 10},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
PaddingTop(1),
|
|
PaddingRight(2),
|
|
PaddingBottom(3),
|
|
PaddingLeft(4),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
wAr := image.Rect(5, 2, 17, 6)
|
|
wCvs := testcanvas.MustNew(wAr)
|
|
// Fake widget border.
|
|
fakewidget.MustDraw(ft, wCvs, &widgetapi.Meta{}, widgetapi.Options{})
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws padded widget, relative padding",
|
|
termSize: image.Point{20, 20},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
PaddingTopPercent(10),
|
|
PaddingRightPercent(30),
|
|
PaddingBottomPercent(20),
|
|
PaddingLeftPercent(20),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
wAr := image.Rect(4, 2, 14, 16)
|
|
wCvs := testcanvas.MustNew(wAr)
|
|
// Fake widget border.
|
|
fakewidget.MustDraw(ft, wCvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{})
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws padded sub-containers",
|
|
termSize: image.Point{20, 10},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
PaddingTop(1),
|
|
PaddingRight(2),
|
|
PaddingBottom(3),
|
|
PaddingLeft(4),
|
|
Border(linestyle.Light),
|
|
SplitVertical(
|
|
Left(Border(linestyle.Double)),
|
|
Right(Border(linestyle.Double)),
|
|
),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Outer container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Borders around the sub-containers.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(5, 2, 11, 6),
|
|
draw.BorderLineStyle(linestyle.Double),
|
|
)
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(11, 2, 17, 6),
|
|
draw.BorderLineStyle(linestyle.Double),
|
|
)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws with both padding and margin enabled",
|
|
termSize: image.Point{30, 20},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
PaddingTop(1),
|
|
PaddingRight(2),
|
|
PaddingBottom(3),
|
|
PaddingLeft(4),
|
|
MarginTop(1),
|
|
MarginRight(2),
|
|
MarginBottom(3),
|
|
MarginLeft(4),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
image.Rect(4, 1, 28, 17),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
wAr := image.Rect(9, 3, 25, 13)
|
|
wCvs := testcanvas.MustNew(wAr)
|
|
// Fake widget border.
|
|
fakewidget.MustDraw(ft, wCvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{})
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws widget with container border and title aligned on the left",
|
|
termSize: image.Point{9, 5},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
BorderTitle("ab"),
|
|
BorderTitleAlignLeft(),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
draw.BorderTitle(
|
|
"ab",
|
|
draw.OverrunModeThreeDot,
|
|
cell.FgColor(cell.ColorYellow),
|
|
),
|
|
)
|
|
|
|
// Fake widget border.
|
|
testdraw.MustBorder(cvs, image.Rect(1, 1, 8, 4))
|
|
testdraw.MustText(cvs, "(7,3)", image.Point{2, 2})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws widget with container border and title aligned in the center",
|
|
termSize: image.Point{9, 5},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
BorderTitle("ab"),
|
|
BorderTitleAlignCenter(),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
draw.BorderTitle(
|
|
"ab",
|
|
draw.OverrunModeThreeDot,
|
|
cell.FgColor(cell.ColorYellow),
|
|
),
|
|
draw.BorderTitleAlign(align.HorizontalCenter),
|
|
)
|
|
|
|
// Fake widget border.
|
|
testdraw.MustBorder(cvs, image.Rect(1, 1, 8, 4))
|
|
testdraw.MustText(cvs, "(7,3)", image.Point{2, 2})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws widget with container border and title aligned on the right",
|
|
termSize: image.Point{9, 5},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
BorderTitle("ab"),
|
|
BorderTitleAlignRight(),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
draw.BorderTitle(
|
|
"ab",
|
|
draw.OverrunModeThreeDot,
|
|
cell.FgColor(cell.ColorYellow),
|
|
),
|
|
draw.BorderTitleAlign(align.HorizontalRight),
|
|
)
|
|
|
|
// Fake widget border.
|
|
testdraw.MustBorder(cvs, image.Rect(1, 1, 8, 4))
|
|
testdraw.MustText(cvs, "(7,3)", image.Point{2, 2})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws widget with container border and title that is trimmed",
|
|
termSize: image.Point{9, 5},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
BorderTitle("abcdefgh"),
|
|
BorderTitleAlignRight(),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
draw.BorderTitle(
|
|
"abcdefgh",
|
|
draw.OverrunModeThreeDot,
|
|
cell.FgColor(cell.ColorYellow),
|
|
),
|
|
draw.BorderTitleAlign(align.HorizontalRight),
|
|
)
|
|
|
|
// Fake widget border.
|
|
testdraw.MustBorder(cvs, image.Rect(1, 1, 8, 4))
|
|
testdraw.MustText(cvs, "(7,3)", image.Point{2, 2})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "draws widget without container border",
|
|
termSize: image.Point{9, 5},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
|
|
// Fake widget border.
|
|
testdraw.MustBorder(cvs, image.Rect(0, 0, 9, 5))
|
|
testdraw.MustText(cvs, "(9,5)", image.Point{1, 1})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "widget.Draw returns an error",
|
|
termSize: image.Point{5, 5}, // Too small for the widget's box.
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
return faketerm.MustNew(size)
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
desc: "container with border and no space isn't drawn",
|
|
termSize: image.Point{1, 1},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
testdraw.MustText(cvs, "⇄", image.Point{0, 0})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "container without the requested space for its widget isn't drawn",
|
|
termSize: image.Point{1, 1},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
MinimumSize: image.Point{2, 2}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
testdraw.MustText(cvs, "⇄", image.Point{0, 0})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "widget's canvas is limited to the requested maximum size",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
MaximumSize: image.Point{10, 10},
|
|
})),
|
|
AlignHorizontal(align.HorizontalLeft),
|
|
AlignVertical(align.VerticalTop),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
contCvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
contCvs,
|
|
contCvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
testcanvas.MustApply(contCvs, ft)
|
|
|
|
// Fake widget.
|
|
cvs := testcanvas.MustNew(image.Rect(1, 1, 11, 11))
|
|
fakewidget.MustDraw(ft, cvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "widget's canvas is limited to the requested maximum width",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
MaximumSize: image.Point{10, 0},
|
|
})),
|
|
AlignHorizontal(align.HorizontalLeft),
|
|
AlignVertical(align.VerticalTop),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
contCvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
contCvs,
|
|
contCvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
testcanvas.MustApply(contCvs, ft)
|
|
|
|
// Fake widget.
|
|
cvs := testcanvas.MustNew(image.Rect(1, 1, 11, 21))
|
|
fakewidget.MustDraw(ft, cvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "widget's canvas is limited to the requested maximum height",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
MaximumSize: image.Point{0, 10},
|
|
})),
|
|
AlignHorizontal(align.HorizontalLeft),
|
|
AlignVertical(align.VerticalTop),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
contCvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
contCvs,
|
|
contCvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
testcanvas.MustApply(contCvs, ft)
|
|
|
|
// Fake widget.
|
|
cvs := testcanvas.MustNew(image.Rect(1, 1, 21, 11))
|
|
fakewidget.MustDraw(ft, cvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "widget gets the requested aspect ratio",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{1, 2}},
|
|
)),
|
|
AlignHorizontal(align.HorizontalLeft),
|
|
AlignVertical(align.VerticalTop),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(1, 1, 11, 21))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "widget's canvas is limited to the requested maximum size and ratio",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
MaximumSize: image.Point{20, 19},
|
|
Ratio: image.Point{1, 1},
|
|
})),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
contCvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
contCvs,
|
|
contCvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
testcanvas.MustApply(contCvs, ft)
|
|
|
|
// Fake widget.
|
|
cvs := testcanvas.MustNew(image.Rect(1, 1, 20, 20))
|
|
fakewidget.MustDraw(ft, cvs, &widgetapi.Meta{Focused: true}, widgetapi.Options{})
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
|
|
{
|
|
desc: "horizontal left align for the widget",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
AlignHorizontal(align.HorizontalLeft),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{1, 2}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(1, 1, 11, 21))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "horizontal center align for the widget",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
AlignHorizontal(align.HorizontalCenter),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{1, 2}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(6, 1, 16, 21))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "horizontal right align for the widget",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
AlignHorizontal(align.HorizontalRight),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{1, 2}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(11, 1, 21, 21))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "vertical top align for the widget",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
AlignVertical(align.VerticalTop),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{2, 1}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(1, 1, 21, 11))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "vertical middle align for the widget",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
AlignVertical(align.VerticalMiddle),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{2, 1}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(1, 6, 21, 16))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "vertical bottom align for the widget",
|
|
termSize: image.Point{22, 22},
|
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
|
return New(
|
|
ft,
|
|
Border(linestyle.Light),
|
|
AlignVertical(align.VerticalBottom),
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{
|
|
Ratio: image.Point{2, 1}},
|
|
)),
|
|
)
|
|
},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
// Container border.
|
|
testdraw.MustBorder(
|
|
cvs,
|
|
cvs.Area(),
|
|
draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)),
|
|
)
|
|
|
|
// Fake widget border.
|
|
wCvs := testcanvas.MustNew(image.Rect(1, 11, 21, 21))
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
wCvs,
|
|
&widgetapi.Meta{Focused: true},
|
|
widgetapi.Options{},
|
|
)
|
|
|
|
testcanvas.MustCopyTo(wCvs, cvs)
|
|
testcanvas.MustApply(cvs, ft)
|
|
return ft
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
got := faketerm.MustNew(tc.termSize)
|
|
c, err := tc.container(got)
|
|
if err != nil {
|
|
t.Fatalf("tc.container => unexpected error: %v", err)
|
|
}
|
|
err = c.Draw()
|
|
if (err != nil) != tc.wantErr {
|
|
t.Errorf("Draw => unexpected error: %v, wantErr: %v", err, tc.wantErr)
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if diff := faketerm.Diff(tc.want(got.Size()), got); diff != "" {
|
|
t.Errorf("Draw => %v", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDrawHandlesTerminalResize(t *testing.T) {
|
|
termSize := image.Point{60, 10}
|
|
got, err := faketerm.New(termSize)
|
|
if err != nil {
|
|
t.Errorf("faketerm.New => unexpected error: %v", err)
|
|
}
|
|
|
|
cont, err := New(
|
|
got,
|
|
SplitVertical(
|
|
Left(
|
|
SplitHorizontal(
|
|
Top(
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
),
|
|
Bottom(
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
),
|
|
),
|
|
),
|
|
Right(
|
|
SplitVertical(
|
|
Left(
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
),
|
|
Right(
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("New => unexpected error: %v", err)
|
|
}
|
|
|
|
// The following tests aren't hermetic, they all access the same container
|
|
// and fake terminal in order to retain state between resizes.
|
|
tests := []struct {
|
|
desc string
|
|
resize *image.Point // if not nil, the fake terminal will be resized.
|
|
want func(size image.Point) *faketerm.Terminal
|
|
}{
|
|
{
|
|
desc: "handles the initial draw request",
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(0, 0, 30, 5)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(0, 5, 30, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(30, 0, 45, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(45, 0, 60, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "increase in size",
|
|
resize: &image.Point{80, 10},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(0, 0, 40, 5)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(0, 5, 40, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(40, 0, 60, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(60, 0, 80, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
return ft
|
|
},
|
|
},
|
|
{
|
|
desc: "decrease in size",
|
|
resize: &image.Point{50, 10},
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
ft := faketerm.MustNew(size)
|
|
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(0, 0, 25, 5)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(0, 5, 25, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(25, 0, 37, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
fakewidget.MustDraw(
|
|
ft,
|
|
testcanvas.MustNew(image.Rect(37, 0, 50, 10)),
|
|
&widgetapi.Meta{},
|
|
widgetapi.Options{},
|
|
)
|
|
return ft
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
if tc.resize != nil {
|
|
if err := got.Resize(*tc.resize); err != nil {
|
|
t.Fatalf("Resize => unexpected error: %v", err)
|
|
}
|
|
}
|
|
if err := cont.Draw(); err != nil {
|
|
t.Fatalf("Draw => unexpected error: %v", err)
|
|
}
|
|
|
|
if diff := faketerm.Diff(tc.want(got.Size()), got); diff != "" {
|
|
t.Errorf("Draw => %v", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|