termdash/internal/canvas/braille/braille_test.go

993 lines
27 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 braille
import (
"image"
"testing"
"github.com/kylelemons/godebug/pretty"
"github.com/mum4k/termdash/cell"
"github.com/mum4k/termdash/internal/area"
"github.com/mum4k/termdash/internal/canvas"
"github.com/mum4k/termdash/internal/canvas/testcanvas"
"github.com/mum4k/termdash/internal/faketerm"
)
func Example_copiedToCanvas() {
// Given a parent canvas the widget receives from the infrastructure:
parent, err := canvas.New(image.Rect(0, 0, 3, 3))
if err != nil {
panic(err)
}
// The widget can create a braille canvas with the same or smaller area:
braille, err := New(parent.Area())
if err != nil {
panic(err)
}
// After setting / clearing / toggling of pixels on the braille canvas, it
// can be copied back to the parent canvas.
if err := braille.SetPixel(image.Point{0, 0}); err != nil {
panic(err)
}
if err := braille.CopyTo(parent); err != nil {
panic(err)
}
}
func Example_appliedToTerminal() {
// When working with a terminal directly:
ft, err := faketerm.New(image.Point{3, 3})
if err != nil {
panic(err)
}
// The widget can create a braille canvas with the same or smaller area:
braille, err := New(ft.Area())
if err != nil {
panic(err)
}
// After setting / clearing / toggling of pixels on the braille canvas, it
// can be applied to the terminal.
if err := braille.SetPixel(image.Point{0, 0}); err != nil {
panic(err)
}
if err := braille.Apply(ft); err != nil {
panic(err)
}
}
func TestNew(t *testing.T) {
tests := []struct {
desc string
ar image.Rectangle
wantSize image.Point
wantArea image.Rectangle
wantCellArea image.Rectangle
wantErr bool
}{
{
desc: "fails on a negative area",
ar: image.Rect(-1, -1, -2, -2),
wantErr: true,
},
{
desc: "braille from zero-based single-cell area",
ar: image.Rect(0, 0, 1, 1),
wantSize: image.Point{2, 4},
wantArea: image.Rect(0, 0, 2, 4),
wantCellArea: image.Rect(0, 0, 1, 1),
},
{
desc: "braille from non-zero-based single-cell area",
ar: image.Rect(3, 3, 4, 4),
wantSize: image.Point{2, 4},
wantArea: image.Rect(0, 0, 2, 4),
wantCellArea: image.Rect(0, 0, 1, 1),
},
{
desc: "braille from zero-based multi-cell area",
ar: image.Rect(0, 0, 3, 3),
wantSize: image.Point{6, 12},
wantArea: image.Rect(0, 0, 6, 12),
wantCellArea: image.Rect(0, 0, 3, 3),
},
{
desc: "braille from non-zero-based multi-cell area",
ar: image.Rect(6, 6, 9, 9),
wantSize: image.Point{6, 12},
wantArea: image.Rect(0, 0, 6, 12),
wantCellArea: image.Rect(0, 0, 3, 3),
},
{
desc: "braille from non-zero-based multi-cell rectangular area",
ar: image.Rect(6, 6, 9, 10),
wantSize: image.Point{6, 16},
wantArea: image.Rect(0, 0, 6, 16),
wantCellArea: image.Rect(0, 0, 3, 4),
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
got, err := New(tc.ar)
if (err != nil) != tc.wantErr {
t.Errorf("New => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
gotSize := got.Size()
if diff := pretty.Compare(tc.wantSize, gotSize); diff != "" {
t.Errorf("Size => unexpected diff (-want, +got):\n%s", diff)
}
gotArea := got.Area()
if diff := pretty.Compare(tc.wantArea, gotArea); diff != "" {
t.Errorf("Area => unexpected diff (-want, +got):\n%s", diff)
}
gotCellArea := got.CellArea()
if diff := pretty.Compare(tc.wantCellArea, gotCellArea); diff != "" {
t.Errorf("CellArea => unexpected diff (-want, +got):\n%s", diff)
}
})
}
}
func TestBraille(t *testing.T) {
tests := []struct {
desc string
ar image.Rectangle
pixelOps func(*Canvas) error
want func(size image.Point) *faketerm.Terminal
wantErr bool
}{
{
desc: "fails on pixel with negative X",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{-1, 0})
},
wantErr: true,
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
},
{
desc: "fails on pixel with negative Y",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{0, -1})
},
wantErr: true,
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
},
{
desc: "SetCellOptions fails on a cell outside of the braille canvas",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetCellOpts(image.Point{0, -1})
},
wantErr: true,
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
},
{
desc: "SetCellOptions sets options on cell with no options",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetCellOpts(image.Point{0, 0}, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
c := testcanvas.MustCell(cvs, image.Point{0, 0})
testcanvas.MustSetCell(cvs, image.Point{0, 0}, c.Rune, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "SetCellOptions preserves the cell rune",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
return c.SetCellOpts(image.Point{0, 0}, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(cvs, image.Point{0, 0}, '⠁', cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "SetCellOptions overwrites options set previously",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue)); err != nil {
return err
}
return c.SetCellOpts(image.Point{0, 0}, cell.FgColor(cell.ColorGreen), cell.BgColor(cell.ColorYellow))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(cvs, image.Point{0, 0}, '⠁', cell.FgColor(cell.ColorGreen), cell.BgColor(cell.ColorYellow))
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "SetCellOptions sets default options when no options provided",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue)); err != nil {
return err
}
return c.SetCellOpts(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(cvs, image.Point{0, 0}, '⠁')
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "SetCellOptions is idempotent",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetCellOpts(image.Point{0, 0}, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue)); err != nil {
return err
}
return c.SetCellOpts(image.Point{0, 0}, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
c := testcanvas.MustCell(cvs, image.Point{0, 0})
testcanvas.MustSetCell(cvs, image.Point{0, 0}, c.Rune, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "SetAreaCellOptions fails on area too large",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetAreaCellOpts(image.Rect(0, 0, 2, 2), cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
},
wantErr: true,
},
{
desc: "SetAreaCellOptions sets the cell options in full area",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetAreaCellOpts(image.Rect(0, 0, 1, 1), cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
for _, p := range []image.Point{
{0, 0},
} {
c := testcanvas.MustCell(cvs, p)
testcanvas.MustSetCell(cvs, p, c.Rune, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
}
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "SetAreaCellOptions sets the cell options in a sub-area",
ar: image.Rect(0, 0, 3, 3),
pixelOps: func(c *Canvas) error {
return c.SetAreaCellOpts(image.Rect(0, 0, 2, 2), cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
cvs := testcanvas.MustNew(ft.Area())
for _, p := range []image.Point{
{0, 0},
{0, 1},
{1, 0},
{1, 1},
} {
c := testcanvas.MustCell(cvs, p)
testcanvas.MustSetCell(cvs, p, c.Rune, cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
}
testcanvas.MustApply(cvs, ft)
return ft
},
},
{
desc: "set pixel 0,0",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠁')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set is idempotent",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
return c.SetPixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠁')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 1,0",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{1, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠈')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 0,1",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{0, 1})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠂')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 1,1",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{1, 1})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠐')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 0,2",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{0, 2})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠄')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 1,2",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{1, 2})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠠')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 0,3",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{0, 3})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⡀')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixel 1,3",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{1, 3})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⢀')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "fails on point outside of the canvas",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{2, 0})
},
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
wantErr: true,
},
{
desc: "clears the canvas",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
return c.Clear()
},
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
},
{
desc: "sets multiple pixels",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
return c.SetPixel(image.Point{0, 1})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠋')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "sets all the pixels in a cell",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 1}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 1}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 2}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 2}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 3}); err != nil {
return err
}
return c.SetPixel(image.Point{1, 3})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⣿')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set cell options",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.SetPixel(image.Point{0, 0}, cell.FgColor(cell.ColorRed))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠁', cell.FgColor(cell.ColorRed))
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "set pixels in multiple cells",
ar: image.Rect(0, 0, 2, 2),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{2, 2}); err != nil {
return err
}
return c.SetPixel(image.Point{1, 7})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠁') // pixel 0,0
testcanvas.MustSetCell(c, image.Point{1, 0}, '⠄') // pixel 0,2
testcanvas.MustSetCell(c, image.Point{0, 1}, '⢀') // pixel 1,3
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "clear pixels in multiple cells",
ar: image.Rect(0, 0, 2, 2),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{2, 2}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 7}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{2, 2}); err != nil {
return err
}
return c.ClearPixel(image.Point{1, 7})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '')
testcanvas.MustSetCell(c, image.Point{1, 0}, '')
testcanvas.MustSetCell(c, image.Point{0, 1}, '')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggle pixels in multiple cells",
ar: image.Rect(0, 0, 2, 2),
pixelOps: func(c *Canvas) error {
if err := c.TogglePixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.TogglePixel(image.Point{2, 2}); err != nil {
return err
}
if err := c.TogglePixel(image.Point{1, 7}); err != nil {
return err
}
if err := c.TogglePixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.TogglePixel(image.Point{2, 2}); err != nil {
return err
}
return c.TogglePixel(image.Point{1, 7})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '')
testcanvas.MustSetCell(c, image.Point{1, 0}, '')
testcanvas.MustSetCell(c, image.Point{0, 1}, '')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "sets and clears one pixel",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 1}); err != nil {
return err
}
return c.ClearPixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠊')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "sets and clears all pixels",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 1}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 1}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 2}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 2}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 3}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 3}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{1, 0}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{0, 1}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{1, 1}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{0, 2}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{1, 2}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{0, 3}); err != nil {
return err
}
return c.ClearPixel(image.Point{1, 3})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "clear is idempotent when cell doesn't contain braille pattern character",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.ClearPixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
},
{
desc: "clear fails on point outside of the canvas",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.ClearPixel(image.Point{3, 1})
},
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
wantErr: true,
},
{
desc: "clear is idempotent when the pixel is already cleared",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.ClearPixel(image.Point{0, 0}); err != nil {
return err
}
return c.ClearPixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "clearing a pixel sets options on the cell",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{0, 1}); err != nil {
return err
}
return c.ClearPixel(image.Point{0, 0}, cell.FgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠊', cell.FgColor(cell.ColorBlue))
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggles a pixel which adds the first braille pattern character",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.TogglePixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠁')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggles a pixel on",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
return c.TogglePixel(image.Point{1, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠉')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggles a pixel on and sets options",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
return c.TogglePixel(image.Point{1, 0}, cell.FgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠉', cell.FgColor(cell.ColorBlue))
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggles a pixel off",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
return c.TogglePixel(image.Point{0, 0})
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠈')
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggles a pixel off and sets options",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
if err := c.SetPixel(image.Point{0, 0}); err != nil {
return err
}
if err := c.SetPixel(image.Point{1, 0}); err != nil {
return err
}
return c.TogglePixel(image.Point{0, 0}, cell.FgColor(cell.ColorBlue))
},
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
c := testcanvas.MustNew(ft.Area())
testcanvas.MustSetCell(c, image.Point{0, 0}, '⠈', cell.FgColor(cell.ColorBlue))
testcanvas.MustApply(c, ft)
return ft
},
},
{
desc: "toggle fails on point outside of the canvas",
ar: image.Rect(0, 0, 1, 1),
pixelOps: func(c *Canvas) error {
return c.TogglePixel(image.Point{3, 3})
},
want: func(size image.Point) *faketerm.Terminal {
return faketerm.MustNew(size)
},
wantErr: true,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
bc, err := New(tc.ar)
if err != nil {
t.Fatalf("New => unexpected error: %v", err)
}
err = tc.pixelOps(bc)
if (err != nil) != tc.wantErr {
t.Errorf("pixelOps => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
size := area.Size(tc.ar)
gotApplied, err := faketerm.New(size)
if err != nil {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
if err := bc.Apply(gotApplied); err != nil {
t.Fatalf("bc.Apply => unexpected error: %v", err)
}
if diff := faketerm.Diff(tc.want(size), gotApplied); diff != "" {
t.Fatalf("Direct Apply => %v", diff)
}
// When copied to another another canvas, the result on the
// terminal must be the same.
rc, err := canvas.New(tc.ar)
if err != nil {
t.Fatalf("canvas.New => unexpected error: %v", err)
}
if err := bc.CopyTo(rc); err != nil {
t.Fatalf("CopyTo => unexpected error: %v", err)
}
gotCopied, err := faketerm.New(size)
if err != nil {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
if err := rc.Apply(gotCopied); err != nil {
t.Fatalf("rc.Apply => unexpected error: %v", err)
}
if diff := faketerm.Diff(tc.want(size), gotCopied); diff != "" {
t.Fatalf("Copy then Apply => %v", diff)
}
})
}
}