termdash/private/segdisp/sixteen/sixteen_test.go

1712 lines
49 KiB
Go

// Copyright 2019 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 sixteen
import (
"image"
"sort"
"testing"
"github.com/kylelemons/godebug/pretty"
"github.com/mum4k/termdash/cell"
"github.com/mum4k/termdash/private/area"
"github.com/mum4k/termdash/private/canvas"
"github.com/mum4k/termdash/private/canvas/braille/testbraille"
"github.com/mum4k/termdash/private/canvas/testcanvas"
"github.com/mum4k/termdash/private/faketerm"
"github.com/mum4k/termdash/private/segdisp"
"github.com/mum4k/termdash/private/segdisp/segment"
"github.com/mum4k/termdash/private/segdisp/segment/testsegment"
)
func TestDraw(t *testing.T) {
tests := []struct {
desc string
opts []Option
drawOpts []Option
cellCanvas image.Rectangle
// If not nil, it is called before Draw is called and can set, clear or
// toggle segments or characters.
update func(*Display) error
want func(size image.Point) *faketerm.Terminal
wantErr bool
wantUpdateErr bool
}{
{
desc: "fails for area not wide enough",
cellCanvas: image.Rect(0, 0, segdisp.MinCols-1, segdisp.MinRows),
wantErr: true,
},
{
desc: "fails for area not tall enough",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows-1),
wantErr: true,
},
{
desc: "fails to set invalid segment (too small)",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(Segment(-1))
},
wantUpdateErr: true,
},
{
desc: "fails to set invalid segment (too large)",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(Segment(segmentMax))
},
wantUpdateErr: true,
},
{
desc: "fails to clear invalid segment (too small)",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.ClearSegment(Segment(-1))
},
wantUpdateErr: true,
},
{
desc: "fails to clear invalid segment (too large)",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.ClearSegment(Segment(segmentMax))
},
wantUpdateErr: true,
},
{
desc: "fails to toggle invalid segment (too small)",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.ToggleSegment(Segment(-1))
},
wantUpdateErr: true,
},
{
desc: "fails to toggle invalid segment (too large)",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.ToggleSegment(Segment(segmentMax))
},
wantUpdateErr: true,
},
{
desc: "empty when no segments set",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
},
{
desc: "smallest valid display 6x5, A1",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(A1)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal) // A1
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, A2",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(A2)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(5, 0, 8, 1), segment.Horizontal) // A2
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, F",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(F)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(0, 1, 1, 8), segment.Vertical) // F
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, J",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(J)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(4, 1, 5, 8), segment.Vertical) // J
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, B",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(B)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(8, 1, 9, 8), segment.Vertical) // B
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, G1",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(G1)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 8, 4, 9), segment.Horizontal) // G1
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, G2",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(G2)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(5, 8, 8, 9), segment.Horizontal) // G2
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, E",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(E)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(0, 9, 1, 16), segment.Vertical) // E
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, M",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(M)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(4, 9, 5, 16), segment.Vertical) // M
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, C",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(C)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(8, 9, 9, 16), segment.Vertical) // C
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, D1",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(D1)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 16, 4, 17), segment.Horizontal) // D1
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, D2",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(D2)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(5, 16, 8, 17), segment.Horizontal) // D2
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, H",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(H)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustDiagonal(bc, image.Rect(1, 1, 4, 8), 1, segment.LeftToRight) // H
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, K",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(K)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustDiagonal(bc, image.Rect(5, 1, 8, 8), 1, segment.RightToLeft) // K
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, N",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(N)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustDiagonal(bc, image.Rect(1, 9, 4, 16), 1, segment.RightToLeft) // N
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, L",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
return d.SetSegment(L)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustDiagonal(bc, image.Rect(5, 9, 8, 16), 1, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, all segments",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal) // A1
testsegment.MustHV(bc, image.Rect(5, 0, 8, 1), segment.Horizontal) // A2
testsegment.MustHV(bc, image.Rect(0, 1, 1, 8), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(4, 1, 5, 8), segment.Vertical) // J
testsegment.MustHV(bc, image.Rect(8, 1, 9, 8), segment.Vertical) // B
testsegment.MustHV(bc, image.Rect(1, 8, 4, 9), segment.Horizontal) // G1
testsegment.MustHV(bc, image.Rect(5, 8, 8, 9), segment.Horizontal) // G2
testsegment.MustHV(bc, image.Rect(0, 9, 1, 16), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(4, 9, 5, 16), segment.Vertical) // M
testsegment.MustHV(bc, image.Rect(8, 9, 9, 16), segment.Vertical) // C
testsegment.MustHV(bc, image.Rect(1, 16, 4, 17), segment.Horizontal) // D1
testsegment.MustHV(bc, image.Rect(5, 16, 8, 17), segment.Horizontal) // D2
testsegment.MustDiagonal(bc, image.Rect(1, 1, 4, 8), 1, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(5, 1, 8, 8), 1, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(1, 9, 4, 16), 1, segment.RightToLeft) // N
testsegment.MustDiagonal(bc, image.Rect(5, 9, 8, 16), 1, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, all segments, sets cell options provided to new",
opts: []Option{
CellOpts(
cell.FgColor(cell.ColorRed),
cell.BgColor(cell.ColorGreen),
),
},
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
cOpts := []cell.Option{
cell.FgColor(cell.ColorRed),
cell.BgColor(cell.ColorGreen),
}
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal, segment.CellOpts(cOpts...)) // A1
testsegment.MustHV(bc, image.Rect(5, 0, 8, 1), segment.Horizontal, segment.CellOpts(cOpts...)) // A2
testsegment.MustHV(bc, image.Rect(0, 1, 1, 8), segment.Vertical, segment.CellOpts(cOpts...)) // F
testsegment.MustHV(bc, image.Rect(4, 1, 5, 8), segment.Vertical, segment.CellOpts(cOpts...)) // J
testsegment.MustHV(bc, image.Rect(8, 1, 9, 8), segment.Vertical, segment.CellOpts(cOpts...)) // B
testsegment.MustHV(bc, image.Rect(1, 8, 4, 9), segment.Horizontal, segment.CellOpts(cOpts...)) // G1
testsegment.MustHV(bc, image.Rect(5, 8, 8, 9), segment.Horizontal, segment.CellOpts(cOpts...)) // G2
testsegment.MustHV(bc, image.Rect(0, 9, 1, 16), segment.Vertical, segment.CellOpts(cOpts...)) // E
testsegment.MustHV(bc, image.Rect(4, 9, 5, 16), segment.Vertical, segment.CellOpts(cOpts...)) // M
testsegment.MustHV(bc, image.Rect(8, 9, 9, 16), segment.Vertical, segment.CellOpts(cOpts...)) // C
testsegment.MustHV(bc, image.Rect(1, 16, 4, 17), segment.Horizontal, segment.CellOpts(cOpts...)) // D1
testsegment.MustHV(bc, image.Rect(5, 16, 8, 17), segment.Horizontal, segment.CellOpts(cOpts...)) // D2
testsegment.MustDiagonal(bc, image.Rect(1, 1, 4, 8), 1, segment.LeftToRight, segment.DiagonalCellOpts(cOpts...)) // H
testsegment.MustDiagonal(bc, image.Rect(5, 1, 8, 8), 1, segment.RightToLeft, segment.DiagonalCellOpts(cOpts...)) // K
testsegment.MustDiagonal(bc, image.Rect(1, 9, 4, 16), 1, segment.RightToLeft, segment.DiagonalCellOpts(cOpts...)) // N
testsegment.MustDiagonal(bc, image.Rect(5, 9, 8, 16), 1, segment.LeftToRight, segment.DiagonalCellOpts(cOpts...)) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "smallest valid display 6x5, all segments, sets cell options provided to draw",
drawOpts: []Option{
CellOpts(
cell.FgColor(cell.ColorRed),
cell.BgColor(cell.ColorGreen),
),
},
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
cOpts := []cell.Option{
cell.FgColor(cell.ColorRed),
cell.BgColor(cell.ColorGreen),
}
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal, segment.CellOpts(cOpts...)) // A1
testsegment.MustHV(bc, image.Rect(5, 0, 8, 1), segment.Horizontal, segment.CellOpts(cOpts...)) // A2
testsegment.MustHV(bc, image.Rect(0, 1, 1, 8), segment.Vertical, segment.CellOpts(cOpts...)) // F
testsegment.MustHV(bc, image.Rect(4, 1, 5, 8), segment.Vertical, segment.CellOpts(cOpts...)) // J
testsegment.MustHV(bc, image.Rect(8, 1, 9, 8), segment.Vertical, segment.CellOpts(cOpts...)) // B
testsegment.MustHV(bc, image.Rect(1, 8, 4, 9), segment.Horizontal, segment.CellOpts(cOpts...)) // G1
testsegment.MustHV(bc, image.Rect(5, 8, 8, 9), segment.Horizontal, segment.CellOpts(cOpts...)) // G2
testsegment.MustHV(bc, image.Rect(0, 9, 1, 16), segment.Vertical, segment.CellOpts(cOpts...)) // E
testsegment.MustHV(bc, image.Rect(4, 9, 5, 16), segment.Vertical, segment.CellOpts(cOpts...)) // M
testsegment.MustHV(bc, image.Rect(8, 9, 9, 16), segment.Vertical, segment.CellOpts(cOpts...)) // C
testsegment.MustHV(bc, image.Rect(1, 16, 4, 17), segment.Horizontal, segment.CellOpts(cOpts...)) // D1
testsegment.MustHV(bc, image.Rect(5, 16, 8, 17), segment.Horizontal, segment.CellOpts(cOpts...)) // D2
testsegment.MustDiagonal(bc, image.Rect(1, 1, 4, 8), 1, segment.LeftToRight, segment.DiagonalCellOpts(cOpts...)) // H
testsegment.MustDiagonal(bc, image.Rect(5, 1, 8, 8), 1, segment.RightToLeft, segment.DiagonalCellOpts(cOpts...)) // K
testsegment.MustDiagonal(bc, image.Rect(1, 9, 4, 16), 1, segment.RightToLeft, segment.DiagonalCellOpts(cOpts...)) // N
testsegment.MustDiagonal(bc, image.Rect(5, 9, 8, 16), 1, segment.LeftToRight, segment.DiagonalCellOpts(cOpts...)) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "clears the display",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
d.Clear()
return nil
},
},
{
desc: "clears the display and sets cell options",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
d.Clear(CellOpts(cell.FgColor(cell.ColorBlue)))
return d.SetSegment(A1)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal, segment.CellOpts(cell.FgColor(cell.ColorBlue))) // A1
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "clears some segments",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
for _, s := range []Segment{A1, A2, G1, G2, D1, D2, L} {
if err := d.ClearSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(0, 1, 1, 8), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(4, 1, 5, 8), segment.Vertical) // J
testsegment.MustHV(bc, image.Rect(8, 1, 9, 8), segment.Vertical) // B
testsegment.MustHV(bc, image.Rect(0, 9, 1, 16), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(4, 9, 5, 16), segment.Vertical) // M
testsegment.MustHV(bc, image.Rect(8, 9, 9, 16), segment.Vertical) // C
testsegment.MustDiagonal(bc, image.Rect(1, 1, 4, 8), 1, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(5, 1, 8, 8), 1, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(1, 9, 4, 16), 1, segment.RightToLeft) // N
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "toggles some segments off",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
for _, s := range []Segment{A1, A2, G1, G2, D1, D2, L} {
if err := d.ToggleSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(0, 1, 1, 8), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(4, 1, 5, 8), segment.Vertical) // J
testsegment.MustHV(bc, image.Rect(8, 1, 9, 8), segment.Vertical) // B
testsegment.MustHV(bc, image.Rect(0, 9, 1, 16), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(4, 9, 5, 16), segment.Vertical) // M
testsegment.MustHV(bc, image.Rect(8, 9, 9, 16), segment.Vertical) // C
testsegment.MustDiagonal(bc, image.Rect(1, 1, 4, 8), 1, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(5, 1, 8, 8), 1, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(1, 9, 4, 16), 1, segment.RightToLeft) // N
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "toggles some segments on",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
for _, s := range []Segment{A1, A2, G1, G2, D1, D2, L} {
if err := d.ToggleSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal) // A1
testsegment.MustHV(bc, image.Rect(5, 0, 8, 1), segment.Horizontal) // A2
testsegment.MustHV(bc, image.Rect(1, 8, 4, 9), segment.Horizontal) // G1
testsegment.MustHV(bc, image.Rect(5, 8, 8, 9), segment.Horizontal) // G2
testsegment.MustHV(bc, image.Rect(1, 16, 4, 17), segment.Horizontal) // D1
testsegment.MustHV(bc, image.Rect(5, 16, 8, 17), segment.Horizontal) // D2
testsegment.MustDiagonal(bc, image.Rect(5, 9, 8, 16), 1, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "set is idempotent",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
if err := d.SetSegment(A1); err != nil {
return err
}
return d.SetSegment(A1)
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(1, 0, 4, 1), segment.Horizontal) // A1
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "clear is idempotent",
cellCanvas: image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows),
update: func(d *Display) error {
if err := d.SetSegment(A1); err != nil {
return err
}
if err := d.ClearSegment(A1); err != nil {
return err
}
return d.ClearSegment(A1)
},
},
{
desc: "segment width of two",
cellCanvas: image.Rect(0, 0, segdisp.MinCols*2, segdisp.MinRows*2),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(2, 0, 10, 2), segment.Horizontal) // A1
testsegment.MustHV(bc, image.Rect(12, 0, 20, 2), segment.Horizontal) // A2
testsegment.MustHV(bc, image.Rect(0, 2, 2, 18), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(10, 2, 12, 18), segment.Vertical, segment.SkipSlopesLTE(2)) // J
testsegment.MustHV(bc, image.Rect(20, 2, 22, 18), segment.Vertical, segment.ReverseSlopes()) // B
testsegment.MustHV(bc, image.Rect(2, 18, 10, 20), segment.Horizontal, segment.SkipSlopesLTE(2)) // G1
testsegment.MustHV(bc, image.Rect(12, 18, 20, 20), segment.Horizontal, segment.SkipSlopesLTE(2)) // G2
testsegment.MustHV(bc, image.Rect(0, 20, 2, 36), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(10, 20, 12, 36), segment.Vertical, segment.SkipSlopesLTE(2)) // M
testsegment.MustHV(bc, image.Rect(20, 20, 22, 36), segment.Vertical, segment.ReverseSlopes()) // C
testsegment.MustHV(bc, image.Rect(2, 36, 10, 38), segment.Horizontal, segment.ReverseSlopes()) // D1
testsegment.MustHV(bc, image.Rect(12, 36, 20, 38), segment.Horizontal, segment.ReverseSlopes()) // D2
testsegment.MustDiagonal(bc, image.Rect(3, 3, 9, 17), 2, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(13, 3, 19, 17), 2, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(3, 21, 9, 35), 2, segment.RightToLeft) // N
testsegment.MustDiagonal(bc, image.Rect(13, 21, 19, 35), 2, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "segment width of three",
cellCanvas: image.Rect(0, 0, segdisp.MinCols*3, segdisp.MinRows*3),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(2, 0, 16, 3), segment.Horizontal) // A1
testsegment.MustHV(bc, image.Rect(17, 0, 31, 3), segment.Horizontal) // A2
testsegment.MustHV(bc, image.Rect(0, 2, 3, 28), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(15, 2, 18, 28), segment.Vertical) // J
testsegment.MustHV(bc, image.Rect(30, 2, 33, 28), segment.Vertical) // B
testsegment.MustHV(bc, image.Rect(2, 27, 16, 30), segment.Horizontal) // G1
testsegment.MustHV(bc, image.Rect(17, 27, 31, 30), segment.Horizontal) // G2
testsegment.MustHV(bc, image.Rect(0, 29, 3, 55), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(15, 29, 18, 55), segment.Vertical) // M
testsegment.MustHV(bc, image.Rect(30, 29, 33, 55), segment.Vertical) // C
testsegment.MustHV(bc, image.Rect(2, 54, 16, 57), segment.Horizontal) // D1
testsegment.MustHV(bc, image.Rect(17, 54, 31, 57), segment.Horizontal) // D2
testsegment.MustDiagonal(bc, image.Rect(3, 3, 15, 27), 3, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(18, 3, 30, 27), 3, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(3, 30, 15, 54), 3, segment.RightToLeft) // N
testsegment.MustDiagonal(bc, image.Rect(18, 30, 30, 54), 3, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "segment with even width is changed to odd",
cellCanvas: image.Rect(0, 0, segdisp.MinCols*4, segdisp.MinRows*4),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(4, 0, 21, 5), segment.Horizontal) // A1
testsegment.MustHV(bc, image.Rect(24, 0, 41, 5), segment.Horizontal) // A2
testsegment.MustHV(bc, image.Rect(0, 4, 5, 37), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(20, 4, 25, 37), segment.Vertical) // J
testsegment.MustHV(bc, image.Rect(40, 4, 45, 37), segment.Vertical) // B
testsegment.MustHV(bc, image.Rect(4, 36, 21, 41), segment.Horizontal) // G1
testsegment.MustHV(bc, image.Rect(24, 36, 41, 41), segment.Horizontal) // G2
testsegment.MustHV(bc, image.Rect(0, 40, 5, 73), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(20, 40, 25, 73), segment.Vertical) // M
testsegment.MustHV(bc, image.Rect(40, 40, 45, 73), segment.Vertical) // C
testsegment.MustHV(bc, image.Rect(4, 72, 21, 77), segment.Horizontal) // D1
testsegment.MustHV(bc, image.Rect(24, 72, 41, 77), segment.Horizontal) // D2
testsegment.MustDiagonal(bc, image.Rect(6, 6, 19, 35), 5, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(26, 6, 39, 35), 5, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(6, 42, 19, 71), 5, segment.RightToLeft) // N
testsegment.MustDiagonal(bc, image.Rect(26, 42, 39, 71), 5, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "segment with odd width and e√en peak to peak distance is changed to odd",
cellCanvas: image.Rect(0, 0, segdisp.MinCols*7, segdisp.MinRows*7),
update: func(d *Display) error {
for _, s := range AllSegments() {
if err := d.SetSegment(s); err != nil {
return err
}
}
return nil
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testsegment.MustHV(bc, image.Rect(7, 0, 39, 9), segment.Horizontal) // A1
testsegment.MustHV(bc, image.Rect(44, 0, 76, 9), segment.Horizontal) // A2
testsegment.MustHV(bc, image.Rect(0, 7, 9, 67), segment.Vertical) // F
testsegment.MustHV(bc, image.Rect(37, 7, 46, 67), segment.Vertical) // J
testsegment.MustHV(bc, image.Rect(74, 7, 83, 67), segment.Vertical) // B
testsegment.MustHV(bc, image.Rect(7, 65, 39, 74), segment.Horizontal) // G1
testsegment.MustHV(bc, image.Rect(44, 65, 76, 74), segment.Horizontal) // G2
testsegment.MustHV(bc, image.Rect(0, 72, 9, 132), segment.Vertical) // E
testsegment.MustHV(bc, image.Rect(37, 72, 46, 132), segment.Vertical) // M
testsegment.MustHV(bc, image.Rect(74, 72, 83, 132), segment.Vertical) // C
testsegment.MustHV(bc, image.Rect(7, 130, 39, 139), segment.Horizontal) // D1
testsegment.MustHV(bc, image.Rect(44, 130, 76, 139), segment.Horizontal) // D2
testsegment.MustDiagonal(bc, image.Rect(10, 10, 36, 64), 9, segment.LeftToRight) // H
testsegment.MustDiagonal(bc, image.Rect(47, 10, 73, 64), 9, segment.RightToLeft) // K
testsegment.MustDiagonal(bc, image.Rect(10, 75, 36, 129), 9, segment.RightToLeft) // N
testsegment.MustDiagonal(bc, image.Rect(47, 75, 73, 129), 9, segment.LeftToRight) // L
testbraille.MustApply(bc, ft)
return ft
},
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
d := New(tc.opts...)
if tc.update != nil {
err := tc.update(d)
if (err != nil) != tc.wantUpdateErr {
t.Errorf("tc.update => unexpected error: %v, wantUpdateErr: %v", err, tc.wantUpdateErr)
}
if err != nil {
return
}
}
cvs, err := canvas.New(tc.cellCanvas)
if err != nil {
t.Fatalf("canvas.New => unexpected error: %v", err)
}
{
err := d.Draw(cvs, tc.drawOpts...)
if (err != nil) != tc.wantErr {
t.Errorf("Draw => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
}
size := area.Size(tc.cellCanvas)
want := faketerm.MustNew(size)
if tc.want != nil {
want = tc.want(size)
}
got, err := faketerm.New(size)
if err != nil {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
if err := cvs.Apply(got); err != nil {
t.Fatalf("bc.Apply => unexpected error: %v", err)
}
if diff := faketerm.Diff(want, got); diff != "" {
t.Fatalf("Draw => %v", diff)
}
})
}
}
// mustDrawSegments returns a fake terminal of the specified size with the
// segments drawn on it or panics.
func mustDrawSegments(size image.Point, seg ...Segment) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
d := New()
for _, s := range seg {
if err := d.SetSegment(s); err != nil {
panic(err)
}
}
if err := d.Draw(cvs); err != nil {
panic(err)
}
testcanvas.MustApply(cvs, ft)
return ft
}
func TestSetCharacter(t *testing.T) {
tests := []struct {
desc string
char rune
// If not nil, it is called before Draw is called and can set, clear or
// toggle segments or characters.
update func(*Display) error
want func(size image.Point) *faketerm.Terminal
wantErr bool
}{
{
desc: "fails on unsupported character",
char: '←',
wantErr: true,
},
{
desc: "displays ' '",
char: ' ',
},
{
desc: "doesn't clear the display",
update: func(d *Display) error {
return d.SetSegment(A2)
},
char: 'W',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, E, N, L, C, B, A2)
},
},
{
desc: "displays '!'",
char: '!',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, B, C)
},
},
{
desc: "displays '\"'",
char: '"',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, B)
},
},
{
desc: "displays '#'",
char: '#',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, B, G1, G2, M, C, D1, D2)
},
},
{
desc: "displays '$'",
char: '$',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, J, G1, G2, M, C, D1, D2)
},
},
{
desc: "displays '%'",
char: '%',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, F, J, K, G1, G2, N, M, C, D2)
},
},
{
desc: "displays '&'",
char: '&',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, H, J, G1, E, L, D1, D2)
},
},
{
desc: "displays '",
char: '\'',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J)
},
},
{
desc: "displays '('",
char: '(',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, K, L)
},
},
{
desc: "displays ')'",
char: ')',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H, N)
},
},
{
desc: "displays '*'",
char: '*',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H, J, K, G1, G2, N, M, L)
},
},
{
desc: "displays '+'",
char: '+',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, G1, G2, M)
},
},
{
desc: "displays ','",
char: ',',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, N)
},
},
{
desc: "displays '-'",
char: '-',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, G2)
},
},
{
desc: "displays '/'",
char: '/',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, N, K)
},
},
{
desc: "displays '0'",
char: '0',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, K, B, E, N, C, D1, D2)
},
},
{
desc: "displays '1'",
char: '1',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, K, B, C)
},
},
{
desc: "displays '2'",
char: '2',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, B, G1, G2, E, D1, D2)
},
},
{
desc: "displays '3'",
char: '3',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, B, G2, C, D1, D2)
},
},
{
desc: "displays '4'",
char: '4',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, B, G1, G2, C)
},
},
{
desc: "displays '5'",
char: '5',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, G1, L, D1, D2)
},
},
{
desc: "displays '6'",
char: '6',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, G1, G2, E, C, D1, D2)
},
},
{
desc: "displays '7'",
char: '7',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, B, C)
},
},
{
desc: "displays '8'",
char: '8',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, G1, G2, E, C, D1, D2)
},
},
{
desc: "displays '9'",
char: '9',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, G1, G2, C, D1, D2)
},
},
{
desc: "displays ':'",
char: ':',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, M)
},
},
{
desc: "displays ';'",
char: ';',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, N)
},
},
{
desc: "displays '<'",
char: '<',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, K, G1, L)
},
},
{
desc: "displays '='",
char: '=',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, G2, D1, D2)
},
},
{
desc: "displays '>'",
char: '>',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H, G2, N)
},
},
{
desc: "displays '?'",
char: '?',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, B, G2, M)
},
},
{
desc: "displays '@'",
char: '@',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, J, B, G2, E, D1, D2)
},
},
{
desc: "displays 'A'",
char: 'A',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, G1, G2, E, C)
},
},
{
desc: "displays 'B'",
char: 'B',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, J, B, G2, M, C, D1, D2)
},
},
{
desc: "displays 'C'",
char: 'C',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, E, D1, D2)
},
},
{
desc: "displays 'D'",
char: 'D',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, J, B, M, C, D1, D2)
},
},
{
desc: "displays 'E'",
char: 'E',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, G1, E, D1, D2)
},
},
{
desc: "displays 'F'",
char: 'F',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, G1, E)
},
},
{
desc: "displays 'G'",
char: 'G',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, G2, E, C, D1, D2)
},
},
{
desc: "displays 'H'",
char: 'H',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, B, G1, G2, E, C)
},
},
{
desc: "displays 'I'",
char: 'I',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, J, M, D1, D2)
},
},
{
desc: "displays 'J'",
char: 'J',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, B, E, C, D1, D2)
},
},
{
desc: "displays 'K'",
char: 'K',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, K, G1, E, L)
},
},
{
desc: "displays 'L'",
char: 'L',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, E, D1, D2)
},
},
{
desc: "displays 'M'",
char: 'M',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, H, K, B, E, C)
},
},
{
desc: "displays 'N'",
char: 'N',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, H, B, E, L, C)
},
},
{
desc: "displays 'O'",
char: 'O',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, E, C, D1, D2)
},
},
{
desc: "displays 'P'",
char: 'P',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, G1, G2, E)
},
},
{
desc: "displays 'Q'",
char: 'Q',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, E, L, C, D1, D2)
},
},
{
desc: "displays 'R'",
char: 'R',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, B, G1, G2, E, L)
},
},
{
desc: "displays 'S'",
char: 'S',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, F, G1, G2, C, D1, D2)
},
},
{
desc: "displays 'T'",
char: 'T',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, J, M)
},
},
{
desc: "displays 'U'",
char: 'U',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, B, E, C, D1, D2)
},
},
{
desc: "displays 'V'",
char: 'V',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, K, E, N)
},
},
{
desc: "displays 'W'",
char: 'W',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, E, N, L, C, B)
},
},
{
desc: "displays 'X'",
char: 'X',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H, K, N, L)
},
},
{
desc: "displays 'Y'",
char: 'Y',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, B, G1, G2, C, D1, D2)
},
},
{
desc: "displays 'Z'",
char: 'Z',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, A2, K, N, D1, D2)
},
},
{
desc: "displays '['",
char: '[',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A2, J, M, D2)
},
},
{
desc: "displays '\\'",
char: '\\',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H, L)
},
},
{
desc: "displays ']'",
char: ']',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, J, M, D1)
},
},
{
desc: "displays '^'",
char: '^',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, N, L)
},
},
{
desc: "displays '_'",
char: '_',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, D1, D2)
},
},
{
desc: "displays '`'",
char: '`',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H)
},
},
{
desc: "displays 'a'",
char: 'a',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, E, M, D1, D2)
},
},
{
desc: "displays 'b'",
char: 'b',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, G1, E, M, D1)
},
},
{
desc: "displays 'c'",
char: 'c',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, E, D1)
},
},
{
desc: "displays 'd'",
char: 'd',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, B, G2, M, C, D2)
},
},
{
desc: "displays 'e'",
char: 'e',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, E, N, D1)
},
},
{
desc: "displays 'f'",
char: 'f',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A2, J, G1, G2, M)
},
},
{
desc: "displays 'g'",
char: 'g',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, F, J, G1, M, D1)
},
},
{
desc: "displays 'h'",
char: 'h',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, G1, E, M)
},
},
{
desc: "displays 'i'",
char: 'i',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, M)
},
},
{
desc: "displays 'j'",
char: 'j',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, E, M, D1)
},
},
{
desc: "displays 'k'",
char: 'k',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, K, M, L)
},
},
{
desc: "displays 'l'",
char: 'l',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, E)
},
},
{
desc: "displays 'm'",
char: 'm',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, G2, E, M, C)
},
},
{
desc: "displays 'n'",
char: 'n',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, E, M)
},
},
{
desc: "displays 'o'",
char: 'o',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, E, M, D1)
},
},
{
desc: "displays 'p'",
char: 'p',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, F, J, G1, E)
},
},
{
desc: "displays 'q'",
char: 'q',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, F, J, G1, M)
},
},
{
desc: "displays 'r'",
char: 'r',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, E)
},
},
{
desc: "displays 's'",
char: 's',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, F, G1, M, D1)
},
},
{
desc: "displays 't'",
char: 't',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, F, G1, E, D1)
},
},
{
desc: "displays 'u'",
char: 'u',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, E, M, D1)
},
},
{
desc: "displays 'v'",
char: 'v',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, E, N)
},
},
{
desc: "displays 'w'",
char: 'w',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, E, N, L, C)
},
},
{
desc: "displays 'x'",
char: 'x',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, H, K, N, L)
},
},
{
desc: "displays 'y'",
char: 'y',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, B, G2, C, D2)
},
},
{
desc: "displays 'z'",
char: 'z',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, G1, N, D1)
},
},
{
desc: "displays '{'",
char: '{',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A2, J, G1, M, D2)
},
},
{
desc: "displays '|'",
char: '|',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, J, M)
},
},
{
desc: "displays '}'",
char: '}',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, A1, J, G2, M, D1)
},
},
{
desc: "displays '~'",
char: '~',
want: func(size image.Point) *faketerm.Terminal {
return mustDrawSegments(size, K, G1, G2, N)
},
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
d := New()
if tc.update != nil {
err := tc.update(d)
if err != nil {
t.Fatalf("tc.update => unexpected error: %v", err)
}
}
{
err := d.SetCharacter(tc.char)
if (err != nil) != tc.wantErr {
t.Errorf("SetCharacter => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
}
ar := image.Rect(0, 0, segdisp.MinCols, segdisp.MinRows)
cvs, err := canvas.New(ar)
if err != nil {
t.Fatalf("canvas.New => unexpected error: %v", err)
}
if err := d.Draw(cvs); err != nil {
t.Fatalf("Draw => unexpected error: %v", err)
}
size := area.Size(ar)
want := faketerm.MustNew(size)
if tc.want != nil {
want = tc.want(size)
}
got, err := faketerm.New(size)
if err != nil {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
if err := cvs.Apply(got); err != nil {
t.Fatalf("bc.Apply => unexpected error: %v", err)
}
if diff := faketerm.Diff(want, got); diff != "" {
t.Fatalf("SetCharacter => %v", diff)
}
})
}
}
func TestAllSegments(t *testing.T) {
want := []Segment{A1, A2, B, C, D1, D2, E, F, G1, G2, H, J, K, L, M, N}
got := AllSegments()
sort.Slice(got, func(i, j int) bool {
return int(got[i]) < int(got[j])
})
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("AllSegments => unexpected diff (-want, +got):\n%s", diff)
}
}
func TestSupportsChars(t *testing.T) {
tests := []struct {
desc string
str string
wantRes bool
wantUnsupp []rune
}{
{
desc: "supports all chars in an empty string",
wantRes: true,
},
{
desc: "supports all chars in the string",
str: " wW ",
wantRes: true,
},
{
desc: "supports some chars in the string",
str: " w←W :",
wantRes: false,
wantUnsupp: []rune{'←'},
},
{
desc: "supports no chars in the string",
str: "←",
wantRes: false,
wantUnsupp: []rune{'←'},
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
gotRes, gotUnsupp := SupportsChars(tc.str)
if gotRes != tc.wantRes {
t.Errorf("SupportsChars(%q) => %v, %v, want %v, %v", tc.str, gotRes, gotUnsupp, tc.wantRes, tc.wantUnsupp)
}
sort.Slice(gotUnsupp, func(i, j int) bool {
return gotUnsupp[i] < gotUnsupp[j]
})
sort.Slice(tc.wantUnsupp, func(i, j int) bool {
return tc.wantUnsupp[i] < tc.wantUnsupp[j]
})
if diff := pretty.Compare(tc.wantUnsupp, gotUnsupp); diff != "" {
t.Errorf("SupportsChars => unexpected unsupported characters returned, diff (-want, +got):\n%s", diff)
}
})
}
}
func TestSanitize(t *testing.T) {
tests := []struct {
desc string
str string
want string
}{
{
desc: "no alternation to empty string",
},
{
desc: "all characters are supported",
str: " wW",
want: " wW",
},
{
desc: "some characters are supported",
str: " w←W:",
want: " w W:",
},
{
desc: "no characters are supported",
str: "←",
want: " ",
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
got := Sanitize(tc.str)
if got != tc.want {
t.Errorf("Sanitize => %q, want %q", got, tc.want)
}
})
}
}