mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-30 13:48:54 +08:00
Test coverage for string, segment and area functions.
This commit is contained in:
parent
0ee98483ac
commit
ed725da9a0
@ -40,6 +40,7 @@ The following outlines segments in the display and their names.
|
||||
package sixteen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
@ -115,10 +116,37 @@ var characterSegments = map[rune][]Segment{
|
||||
'W': {F, E, N, L, C, B},
|
||||
}
|
||||
|
||||
// Option is used to provide options.
|
||||
type Option interface {
|
||||
// set sets the provided option.
|
||||
set(*Display)
|
||||
// SupportsChars asserts whether the display supports all runes in the
|
||||
// provided string.
|
||||
// The display only supports a subset of ASCII runes.
|
||||
// Returns any unsupported runes found in the string in an unspecified order.
|
||||
func SupportsChars(s string) (bool, []rune) {
|
||||
unsupp := map[rune]bool{}
|
||||
for _, r := range s {
|
||||
if _, ok := characterSegments[r]; !ok {
|
||||
unsupp[r] = true
|
||||
}
|
||||
}
|
||||
|
||||
var res []rune
|
||||
for r := range unsupp {
|
||||
res = append(res, r)
|
||||
}
|
||||
return len(res) == 0, res
|
||||
}
|
||||
|
||||
// Sanitize returns a copy of the string, replacing all unsupported characters
|
||||
// with a space character.
|
||||
func Sanitize(s string) string {
|
||||
var b bytes.Buffer
|
||||
for _, r := range s {
|
||||
if _, ok := characterSegments[r]; !ok {
|
||||
b.WriteRune(' ')
|
||||
continue
|
||||
}
|
||||
b.WriteRune(r)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// AllSegments returns all 16 segments in an undefined order.
|
||||
@ -130,6 +158,12 @@ func AllSegments() []Segment {
|
||||
return res
|
||||
}
|
||||
|
||||
// Option is used to provide options.
|
||||
type Option interface {
|
||||
// set sets the provided option.
|
||||
set(*Display)
|
||||
}
|
||||
|
||||
// option implements Option.
|
||||
type option func(*Display)
|
||||
|
||||
@ -180,7 +214,7 @@ func (d *Display) Clear(opts ...Option) {
|
||||
// This method is idempotent.
|
||||
func (d *Display) SetSegment(s Segment) error {
|
||||
if s <= segmentUnknown || s >= segmentMax {
|
||||
return fmt.Errorf("unknown segment %v", s)
|
||||
return fmt.Errorf("unknown segment %v(%d)", s, s)
|
||||
}
|
||||
d.segments[s] = true
|
||||
return nil
|
||||
@ -190,7 +224,7 @@ func (d *Display) SetSegment(s Segment) error {
|
||||
// This method is idempotent.
|
||||
func (d *Display) ClearSegment(s Segment) error {
|
||||
if s <= segmentUnknown || s >= segmentMax {
|
||||
return fmt.Errorf("unknown segment %v", s)
|
||||
return fmt.Errorf("unknown segment %v(%d)", s, s)
|
||||
}
|
||||
d.segments[s] = false
|
||||
return nil
|
||||
@ -200,7 +234,7 @@ func (d *Display) ClearSegment(s Segment) error {
|
||||
// or clears it depending on its current state.
|
||||
func (d *Display) ToggleSegment(s Segment) error {
|
||||
if s <= segmentUnknown || s >= segmentMax {
|
||||
return fmt.Errorf("unknown segment %v", s)
|
||||
return fmt.Errorf("unknown segment %v(%d)", s, s)
|
||||
}
|
||||
if d.segments[s] {
|
||||
d.segments[s] = false
|
||||
@ -233,16 +267,23 @@ func (d *Display) SetCharacter(c rune) error {
|
||||
// Minimum valid size of a cell canvas in order to draw the segment display.
|
||||
const (
|
||||
// MinCols is the smallest valid amount of columns in a cell area.
|
||||
MinCols = 4
|
||||
MinCols = 6
|
||||
// MinRowPixels is the smallest valid amount of rows in a cell area.
|
||||
MinRows = 3
|
||||
MinRows = 5
|
||||
)
|
||||
|
||||
// aspectRatio is the desired aspect ratio of a single segment display.
|
||||
var aspectRatio = image.Point{3, 5}
|
||||
|
||||
// Draw draws the current state of the segment display onto the canvas.
|
||||
// The canvas must be at least MinCols x MinRows cells, or an error will be
|
||||
// returned.
|
||||
// Any options provided to draw overwrite the values provided to New.
|
||||
func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o.set(d)
|
||||
}
|
||||
|
||||
ar, err := Required(cvs.Area())
|
||||
if err != nil {
|
||||
return err
|
||||
@ -253,7 +294,7 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
return fmt.Errorf("braille.New => %v", err)
|
||||
}
|
||||
|
||||
bcAr := area.WithRatio(bc.Area(), image.Point{3, 5})
|
||||
bcAr := area.WithRatio(bc.Area(), aspectRatio)
|
||||
segW := segWidth(bcAr)
|
||||
if segW == 4 {
|
||||
segW = 5
|
||||
@ -307,6 +348,10 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
d1Ar := image.Rect(eg, botStart, eg+shortL, botStart+segW)
|
||||
d2Ar := image.Rect(d1Ar.Max.X+ptp, botStart, d1Ar.Max.X+ptp+shortL, botStart+segW)
|
||||
|
||||
var sOpts []segment.Option
|
||||
if len(d.cellOpts) > 0 {
|
||||
sOpts = append(sOpts, segment.CellOpts(d.cellOpts...))
|
||||
}
|
||||
for _, segArg := range []struct {
|
||||
s Segment
|
||||
st segment.Type
|
||||
@ -334,7 +379,8 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
continue
|
||||
}
|
||||
log.Printf("segment.HV for %v, ar:%v", segArg.s, segArg.ar)
|
||||
if err := segment.HV(bc, segArg.ar, segArg.st, segArg.opts...); err != nil {
|
||||
sOpts := append(sOpts, segArg.opts...)
|
||||
if err := segment.HV(bc, segArg.ar, segArg.st, sOpts...); err != nil {
|
||||
return fmt.Errorf("failed to draw segment %v, segment.HV => %v", segArg.s, err)
|
||||
}
|
||||
}
|
||||
@ -363,6 +409,10 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
botREndY := int(numbers.Round(float64(cAr.Max.Y) - segPeakDist + diaLeg - float64(diaGap)*0.3))
|
||||
lAr := image.Rect(botRStartX, botRStartY, botREndX, botREndY)
|
||||
|
||||
var dsOpts []segment.DiagonalOption
|
||||
if len(d.cellOpts) > 0 {
|
||||
dsOpts = append(dsOpts, segment.DiagonalCellOpts(d.cellOpts...))
|
||||
}
|
||||
for _, segArg := range []struct {
|
||||
s Segment
|
||||
dt segment.DiagonalType
|
||||
@ -377,7 +427,7 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
continue
|
||||
}
|
||||
log.Printf("segment.Diagonal for %v, ar:%v", segArg.s, segArg.ar)
|
||||
if err := segment.Diagonal(bc, segArg.ar, segW, segArg.dt); err != nil {
|
||||
if err := segment.Diagonal(bc, segArg.ar, segW, segArg.dt, dsOpts...); err != nil {
|
||||
return fmt.Errorf("failed to draw segment %v, segment.Diagonal => %v", segArg.s, err)
|
||||
}
|
||||
}
|
||||
@ -389,20 +439,20 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
|
||||
// size or a smaller area that is required to draw one display.
|
||||
// Returns a smaller area when the provided area didn't have the required
|
||||
// aspect ratio.
|
||||
// Returns an error if the area is too small to draw a segment display.
|
||||
// Returns an error if the area is too small to draw a segment display, i.e.
|
||||
// smaller than MinCols x MinRows.
|
||||
func Required(cellArea image.Rectangle) (image.Rectangle, error) {
|
||||
bcAr := image.Rect(cellArea.Min.X, cellArea.Min.Y, cellArea.Max.X*braille.ColMult, cellArea.Max.Y*braille.RowMult)
|
||||
bcArAdj := area.WithRatio(bcAr, image.Point{3, 5})
|
||||
if bcArAdj.Empty() {
|
||||
return image.ZR, fmt.Errorf("cell area %v is to small to draw the segment display, need at least %d x %d cells", cellArea, MinCols, MinRows)
|
||||
if cols, rows := cellArea.Dx(), cellArea.Dy(); cols < MinCols || rows < MinRows {
|
||||
return image.ZR, fmt.Errorf("cell area %v is too small to draw the segment display, has %dx%d cells, need at least %dx%d cells",
|
||||
cellArea, cols, rows, MinCols, MinRows)
|
||||
}
|
||||
|
||||
bcAr := image.Rect(cellArea.Min.X, cellArea.Min.Y, cellArea.Max.X*braille.ColMult, cellArea.Max.Y*braille.RowMult)
|
||||
bcArAdj := area.WithRatio(bcAr, aspectRatio)
|
||||
|
||||
needCols := int(math.Ceil(float64(bcArAdj.Dx()) / braille.ColMult))
|
||||
needRows := int(math.Ceil(float64(bcArAdj.Dy()) / braille.RowMult))
|
||||
needAr := image.Rect(cellArea.Min.X, cellArea.Min.Y, cellArea.Min.X+needCols, cellArea.Min.Y+needRows)
|
||||
if !needAr.In(cellArea) {
|
||||
return image.ZR, fmt.Errorf("what just happened?")
|
||||
}
|
||||
return needAr, nil
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,14 @@ package sixteen
|
||||
|
||||
import (
|
||||
"image"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"github.com/mum4k/termdash/area"
|
||||
"github.com/mum4k/termdash/canvas"
|
||||
"github.com/mum4k/termdash/canvas/braille/testbraille"
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/draw/segdisp/segment"
|
||||
"github.com/mum4k/termdash/draw/segdisp/segment/testsegment"
|
||||
"github.com/mum4k/termdash/terminal/faketerm"
|
||||
@ -32,18 +35,78 @@ func TestDraw(t *testing.T) {
|
||||
opts []Option
|
||||
drawOpts []Option
|
||||
cellCanvas image.Rectangle
|
||||
// If not nil, called before Draw is called - can set, clear or toggle segments.
|
||||
update func(*Display) error
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
// 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, MinCols-1, MinRows),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "fails for area not tall enough",
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows-1),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "fails to set invalid segment (too small)",
|
||||
cellCanvas: image.Rect(0, 0, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.ToggleSegment(Segment(segmentMax))
|
||||
},
|
||||
wantUpdateErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty when no segments set",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, A1",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(A1)
|
||||
},
|
||||
@ -58,7 +121,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, A2",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(A2)
|
||||
},
|
||||
@ -73,7 +136,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, F",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(F)
|
||||
},
|
||||
@ -88,7 +151,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, J",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(J)
|
||||
},
|
||||
@ -103,7 +166,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, B",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(B)
|
||||
},
|
||||
@ -118,7 +181,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, G1",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(G1)
|
||||
},
|
||||
@ -133,7 +196,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, G2",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(G2)
|
||||
},
|
||||
@ -148,7 +211,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, E",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(E)
|
||||
},
|
||||
@ -163,7 +226,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, M",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(M)
|
||||
},
|
||||
@ -178,7 +241,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, C",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(C)
|
||||
},
|
||||
@ -193,7 +256,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, D1",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(D1)
|
||||
},
|
||||
@ -208,7 +271,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, D2",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(D2)
|
||||
},
|
||||
@ -223,7 +286,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, H",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(H)
|
||||
},
|
||||
@ -238,7 +301,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, K",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(K)
|
||||
},
|
||||
@ -254,7 +317,7 @@ func TestDraw(t *testing.T) {
|
||||
|
||||
{
|
||||
desc: "smallest valid display 6x5, N",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(N)
|
||||
},
|
||||
@ -269,7 +332,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, L",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
return d.SetSegment(L)
|
||||
},
|
||||
@ -284,7 +347,7 @@ func TestDraw(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "smallest valid display 6x5, all segments",
|
||||
cellCanvas: image.Rect(0, 0, 6, 5),
|
||||
cellCanvas: image.Rect(0, 0, MinCols, MinRows),
|
||||
update: func(d *Display) error {
|
||||
for _, s := range AllSegments() {
|
||||
if err := d.SetSegment(s); err != nil {
|
||||
@ -322,14 +385,280 @@ func TestDraw(t *testing.T) {
|
||||
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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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, MinCols, 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)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
d := New(tc.opts...)
|
||||
if tc.update != nil {
|
||||
if err := tc.update(d); err != nil {
|
||||
t.Fatalf("tc.update => unexpected error: %v", err)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,7 +668,7 @@ func TestDraw(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
err := d.Draw(cvs)
|
||||
err := d.Draw(cvs, tc.drawOpts...)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("Draw => unexpected error: %v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
@ -368,3 +697,156 @@ func TestDraw(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequired(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
cellArea image.Rectangle
|
||||
want image.Rectangle
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "fails when area isn't wide enough",
|
||||
cellArea: image.Rect(0, 0, MinCols-1, MinRows),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "fails when area isn't tall enough",
|
||||
cellArea: image.Rect(0, 0, MinCols, MinRows-1),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "returns same area when no adjustment needed",
|
||||
cellArea: image.Rect(0, 0, MinCols, MinRows),
|
||||
want: image.Rect(0, 0, MinCols, MinRows),
|
||||
},
|
||||
{
|
||||
desc: "adjusts width to aspect ratio",
|
||||
cellArea: image.Rect(0, 0, MinCols+100, MinRows),
|
||||
want: image.Rect(0, 0, MinCols, MinRows),
|
||||
},
|
||||
{
|
||||
desc: "adjusts height to aspect ratio",
|
||||
cellArea: image.Rect(0, 0, MinCols, MinRows+100),
|
||||
want: image.Rect(0, 0, MinCols, MinRows),
|
||||
},
|
||||
{
|
||||
desc: "adjusts larger area to aspect ratio",
|
||||
cellArea: image.Rect(0, 0, MinCols*2, MinRows*4),
|
||||
want: image.Rect(0, 0, 12, 10),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got, err := Required(tc.cellArea)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("Required => unexpected error: %v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("Required => unexpected diff (-want, +got):\n%s", 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user