1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-27 13:48:49 +08:00

2029 lines
45 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 zoom
import (
"image"
"testing"
"github.com/kylelemons/godebug/pretty"
"github.com/mum4k/termdash/internal/mouse"
"github.com/mum4k/termdash/internal/terminalapi"
"github.com/mum4k/termdash/widgets/linechart/internal/axes"
)
// mustNewXDetails creates the XDetails or panics.
func mustNewXDetails(cvsAr image.Rectangle, xp *axes.XProperties) *axes.XDetails {
xd, err := axes.NewXDetails(cvsAr, xp)
if err != nil {
panic(err)
}
return xd
}
func TestTracker(t *testing.T) {
tests := []struct {
desc string
opts []Option
xp *axes.XProperties
cvsAr image.Rectangle
graphAr image.Rectangle
// mutate if not nil, can mutate the state of the tracker.
// I.e. send mouse events or update the X scale or canvas areas.
mutate func(*Tracker) error
wantHighlight bool
wantHighlightRange *Range
wantZoom *axes.XDetails
wantErr bool
wantMutateErr bool
}{
{
desc: "New fails when graph area doesn't fall inside the canvas",
xp: &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 10, 10),
graphAr: image.Rect(20, 20, 30, 30),
wantErr: true,
},
{
desc: "New fails on ScrollStep too low",
opts: []Option{
ScrollStep(0),
},
xp: &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 10, 10),
graphAr: image.Rect(2, 0, 10, 10),
wantErr: true,
},
{
desc: "New fails on ScrollStep too high",
opts: []Option{
ScrollStep(101),
},
xp: &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 10, 10),
graphAr: image.Rect(2, 0, 10, 10),
wantErr: true,
},
{
desc: "Update fails when graph area doesn't fall inside the canvas",
xp: &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 10, 10),
graphAr: image.Rect(1, 1, 9, 9),
mutate: func(tr *Tracker) error {
cvsAr := image.Rect(0, 0, 10, 10)
graphAr := image.Rect(20, 20, 30, 30)
return tr.Update(tr.baseX, cvsAr, graphAr)
},
wantMutateErr: true,
},
{
desc: "no highlight or zoom without mouse events",
xp: &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 10, 10),
graphAr: image.Rect(3, 0, 10, 10),
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 10, 10),
&axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
),
},
{
desc: "highlights single column",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 0, End: 1, last: 0},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights single column in a new canvas portion after size increase, regression for #148",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 4, 4),
graphAr: image.Rect(2, 0, 4, 4),
mutate: func(tr *Tracker) error {
newX, err := axes.NewXDetails(image.Rect(0, 0, 6, 6), &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
})
if err != nil {
return err
}
if err := tr.Update(
newX,
image.Rect(0, 0, 6, 6),
image.Rect(2, 0, 6, 6),
); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 5},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 0, End: 1, last: 0},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns to the right of start",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 0, End: 3, last: 2},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns to the right of start then middle",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 0, End: 2, last: 1},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns to the right of start then left of start",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 0, End: 2, last: 0},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns to the left of start",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 0, End: 3, last: 0},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns to the left of start then middle",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 1, End: 3, last: 1},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns to the left of start then right",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 2, End: 4, last: 3},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights multiple columns in the middle",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: true,
wantHighlightRange: &Range{Start: 1, End: 4, last: 3},
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "does not highlight for clicks outside of graph area",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 6, 6),
graphAr: image.Rect(2, 0, 6, 6),
mutate: func(tr *Tracker) error {
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{1, 0},
Button: mouse.ButtonLeft,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 6, 6),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "doesn't zoom when only one column highlighted",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
),
},
{
desc: "highlights and zooms into the X axis once",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 1,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "highlights and zooms into the X axis twice",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
// Zoom into values 1-3.
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonRelease,
}); err != nil {
return err
}
// Zoom into values 2-3.
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 2,
Max: 3,
ReqYWidth: 2,
},
),
},
{
desc: "doesn't zoom below two values",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
// Zoom into values 1-3.
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonRelease,
}); err != nil {
return err
}
// Zoom into values 2-3.
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{5, 0},
Button: mouse.ButtonRelease,
}); err != nil {
return err
}
// Doesn't zoom further.
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 2,
Max: 3,
ReqYWidth: 2,
},
),
},
{
desc: "fails to zoom when X coordinate of click too high",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{7, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonRelease,
})
},
wantMutateErr: true,
},
{
desc: "cancels highlight and zooms on unrelated mouse button",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonMiddle,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
),
},
{
desc: "cancels highlight and zooms on button release outside of the graph area",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{0, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
),
},
{
desc: "highlights of single columns doesn't zoom",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
),
},
{
desc: "highlights of multiple columns maximizes zoom",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonRelease,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
),
},
{
desc: "ignores scroll events outside of graph area",
opts: []Option{
ScrollStep(30),
},
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{1, 0},
Button: mouse.ButtonWheelUp,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
),
},
{
desc: "multiple scroll ups maximize zoom",
opts: []Option{
ScrollStep(30),
},
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
),
},
{
desc: "multiple scroll downs minimize zoom",
opts: []Option{
ScrollStep(30),
},
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
}); err != nil {
return err
}
return tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
})
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
{
desc: "zoom normalized when axis changed (new values)",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonRelease,
}); err != nil {
return err
}
newX, err := axes.NewXDetails(image.Rect(0, 0, 8, 8), &axes.XProperties{
Min: 0,
Max: 0,
ReqYWidth: 2,
})
if err != nil {
return err
}
return tr.Update(
newX,
image.Rect(0, 0, 8, 8),
image.Rect(2, 0, 8, 8),
)
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 0,
ReqYWidth: 2,
},
),
},
{
desc: "fully unzooms when axis changes",
xp: &axes.XProperties{
Min: 0,
Max: 5,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonRelease,
}); err != nil {
return err
}
newX, err := axes.NewXDetails(image.Rect(0, 0, 8, 8), &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
})
if err != nil {
return err
}
return tr.Update(
newX,
image.Rect(0, 0, 8, 8),
image.Rect(2, 0, 8, 8),
)
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 8, 8),
&axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
),
},
{
desc: "zoom normalized when terminal size changed",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{3, 0},
Button: mouse.ButtonRelease,
}); err != nil {
return err
}
newX, err := axes.NewXDetails(image.Rect(0, 0, 4, 4), &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
})
if err != nil {
return err
}
return tr.Update(
newX,
image.Rect(0, 0, 4, 4),
image.Rect(2, 0, 4, 4),
)
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 4, 4),
&axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
),
},
{
desc: "cancels highlight when terminal size changed",
xp: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
mutate: func(tr *Tracker) error {
if err := tr.Mouse(&terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonLeft,
}); err != nil {
return err
}
newX, err := axes.NewXDetails(image.Rect(0, 0, 4, 4), &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
})
if err != nil {
return err
}
return tr.Update(
newX,
image.Rect(0, 0, 4, 4),
image.Rect(2, 0, 4, 4),
)
},
wantHighlight: false,
wantZoom: mustNewXDetails(
image.Rect(0, 0, 4, 4),
&axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
),
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
xd, err := axes.NewXDetails(tc.cvsAr, tc.xp)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
tracker, err := New(xd, tc.cvsAr, tc.graphAr, tc.opts...)
if (err != nil) != tc.wantErr {
t.Errorf("New => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
if tc.mutate != nil {
err := tc.mutate(tracker)
if (err != nil) != tc.wantMutateErr {
t.Errorf("tc.mutate => unexpected error: %v, wantMutateErr: %v", err, tc.wantMutateErr)
}
if err != nil {
return
}
}
gotHighlight, gotHightlightRange := tracker.Highlight()
if gotHighlight != tc.wantHighlight {
t.Errorf("Hightlight => %v, _, want %v, _", gotHighlight, tc.wantHighlight)
}
if diff := pretty.Compare(tc.wantHighlightRange, gotHightlightRange); diff != "" {
t.Errorf("Hightlight => unexpected range, diff (-want, +got):\n%s", diff)
}
gotZoom := tracker.Zoom()
if diff := pretty.Compare(tc.wantZoom, gotZoom); diff != "" {
t.Errorf("Zoom => unexpected XDetails, diff (-want, +got):\n%s", diff)
}
})
}
}
func TestNormalize(t *testing.T) {
tests := []struct {
desc string
baseMin *axes.Value
baseMax *axes.Value
min int
max int
opts *normalizeOptions
wantMin int
wantMax int
}{
{
desc: "min and max within the base axis",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: 1,
max: 2,
wantMin: 1,
wantMax: 2,
},
{
desc: "min and max on the edges of base",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: 0,
max: 3,
wantMin: 0,
wantMax: 3,
},
{
desc: "min and max normalized",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: -1,
max: 4,
wantMin: 0,
wantMax: 3,
},
{
desc: "min is below base, max is the first value",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: -1,
max: 0,
wantMin: 0,
wantMax: 1,
},
{
desc: "min is below base, max is the first value, no space on the axis",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(0, 0),
min: -1,
max: 0,
wantMin: 0,
wantMax: 0,
},
{
desc: "max is above base, min is the last value",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: 3,
max: 4,
wantMin: 2,
wantMax: 3,
},
{
desc: "min is below base, max is the first value, no space on the axis",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(0, 0),
min: 0,
max: 1,
wantMin: 0,
wantMax: 0,
},
{
desc: "both min and max are below base, min < max",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: -2,
max: -1,
wantMin: 0,
wantMax: 1,
},
{
desc: "both min and max are below base, min > max",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: -1,
max: -2,
wantMin: 0,
wantMax: 1,
},
{
desc: "both min and max are above base, min < max",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: 4,
max: 5,
wantMin: 2,
wantMax: 3,
},
{
desc: "both min and max are above base, min > max",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(3, 0),
min: 5,
max: 4,
wantMin: 2,
wantMax: 3,
},
{
desc: "both min and max are below base, base only has one value",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(0, 0),
min: -2,
max: -1,
wantMin: 0,
wantMax: 0,
},
{
desc: "max in the middle, min above base",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(4, 0),
min: 5,
max: 3,
wantMin: 3,
wantMax: 4,
},
{
desc: "min in the middle, max below base",
baseMin: axes.NewValue(0, 0),
baseMax: axes.NewValue(4, 0),
min: 3,
max: -1,
wantMin: 0,
wantMax: 3,
},
{
desc: "zoom rolls when base axis rolls to the left",
opts: &normalizeOptions{
oldBaseMin: axes.NewValue(10, 0),
oldBaseMax: axes.NewValue(20, 0),
},
baseMin: axes.NewValue(17, 0),
baseMax: axes.NewValue(27, 0),
min: 15,
max: 16,
wantMin: 22,
wantMax: 23,
},
{
desc: "zoom rolls when base axis rolls to the right",
opts: &normalizeOptions{
oldBaseMin: axes.NewValue(10, 0),
oldBaseMax: axes.NewValue(20, 0),
},
baseMin: axes.NewValue(1, 0),
baseMax: axes.NewValue(11, 0),
min: 15,
max: 16,
wantMin: 6,
wantMax: 7,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
gotMin, gotMax := normalize(tc.baseMin, tc.baseMax, tc.min, tc.max, tc.opts)
if gotMin != tc.wantMin || gotMax != tc.wantMax {
t.Errorf("normalize => %v, %v, want %v, %v", gotMin, gotMax, tc.wantMin, tc.wantMax)
}
})
}
}
func TestNewZoomedFromBase(t *testing.T) {
tests := []struct {
desc string
min int
max int
baseP *axes.XProperties
cvsAr image.Rectangle
wantP *axes.XProperties
wantErr bool
}{
{
desc: "returns zoomed axis",
min: 1,
max: 2,
baseP: &axes.XProperties{
Min: 0,
Max: 3,
ReqYWidth: 2,
CustomLabels: map[int]string{
1: "1",
},
LO: axes.LabelOrientationVertical,
},
cvsAr: image.Rect(0, 0, 10, 10),
wantP: &axes.XProperties{
Min: 1,
Max: 2,
ReqYWidth: 2,
CustomLabels: map[int]string{
1: "1",
},
LO: axes.LabelOrientationVertical,
},
},
{
desc: "fails on negative max",
min: 1,
max: -2,
baseP: &axes.XProperties{
Min: 0,
Max: 3,
ReqYWidth: 2,
CustomLabels: map[int]string{
1: "1",
},
LO: axes.LabelOrientationVertical,
},
cvsAr: image.Rect(0, 0, 10, 10),
wantErr: true,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
base, err := axes.NewXDetails(tc.cvsAr, tc.baseP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
got, err := newZoomedFromBase(tc.min, tc.max, base, tc.cvsAr)
if (err != nil) != tc.wantErr {
t.Errorf("newZoomedFromBase => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
var want *axes.XDetails
if tc.wantP != nil {
w, err := axes.NewXDetails(tc.cvsAr, tc.wantP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
want = w
}
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("newZoomedFromBase => unexpected diff (-want, +got):\n%s", diff)
}
})
}
}
func TestFindCellPair(t *testing.T) {
tests := []struct {
desc string
cvsAr image.Rectangle
baseP *axes.XProperties
minCell int
maxCell int
wantMin *axes.Value
wantMax *axes.Value
wantErr bool
}{
{
desc: "fails when minCell isn't on the graph",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 3,
},
minCell: -1,
maxCell: 3,
wantErr: true,
},
{
desc: "fails when maxCell isn't on the graph",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 3,
},
minCell: 0,
maxCell: 4,
wantErr: true,
},
{
desc: "nothing to do, cells point at distinct values",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 2,
},
minCell: 0,
maxCell: 2,
wantMin: axes.NewValue(0, 2),
wantMax: axes.NewValue(2, 2),
},
{
desc: "cells point at the same value, distinct found above max",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 2,
},
minCell: 1,
maxCell: 2,
wantMin: axes.NewValue(1, 2),
wantMax: axes.NewValue(2, 2),
},
{
desc: "cells point at the same value, distinct found below min",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 2,
},
minCell: 2,
maxCell: 2,
wantMin: axes.NewValue(1, 2),
wantMax: axes.NewValue(2, 2),
},
{
desc: "cells point at the same value, only distinct are first and last",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 0,
},
minCell: 1,
maxCell: 2,
wantMin: axes.NewValue(0, 2),
wantMax: axes.NewValue(0, 2),
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
base, err := axes.NewXDetails(tc.cvsAr, tc.baseP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
gotMin, gotMax, err := findCellPair(base, tc.minCell, tc.maxCell)
if (err != nil) != tc.wantErr {
t.Errorf("findCellPair => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
if diff := pretty.Compare(tc.wantMin, gotMin); diff != "" {
t.Errorf("findCellPair => unexpected min, diff (-want, +got):\n%s", diff)
}
if diff := pretty.Compare(tc.wantMax, gotMax); diff != "" {
t.Errorf("findCellPair => unexpected max, diff (-want, +got):\n%s", diff)
}
})
}
}
func TestZoomToHighlight(t *testing.T) {
tests := []struct {
desc string
baseP *axes.XProperties
hRange *Range
cvsAr image.Rectangle
wantP *axes.XProperties
wantErr bool
}{
{
desc: "fails on impossible range",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 3,
},
hRange: &Range{Start: -1, End: 2},
wantErr: true,
},
{
desc: "zooms to highlighted area",
cvsAr: image.Rect(0, 0, 4, 4),
baseP: &axes.XProperties{
Min: 0,
Max: 3,
},
hRange: &Range{Start: 1, End: 3},
wantP: &axes.XProperties{
Min: 1,
Max: 2,
},
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
base, err := axes.NewXDetails(tc.cvsAr, tc.baseP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
got, err := zoomToHighlight(base, tc.hRange, tc.cvsAr)
if (err != nil) != tc.wantErr {
t.Errorf("zoomToHighlight => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
var want *axes.XDetails
if tc.wantP != nil {
w, err := axes.NewXDetails(tc.cvsAr, tc.wantP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
want = w
}
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("zoomToHighlight => unexpected diff (-want, +got):\n%s", diff)
}
})
}
}
func TestZoomToScroll(t *testing.T) {
tests := []struct {
desc string
mouse *terminalapi.Mouse
cvsAr image.Rectangle
graphAr image.Rectangle
currP *axes.XProperties
baseP *axes.XProperties
opts []Option
wantP *axes.XProperties
wantErr bool
}{
{
desc: "scroll up in the middle zooms in evenly",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonWheelUp,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
},
{
desc: "scroll up at the left edge",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 0,
Max: 3,
ReqYWidth: 2,
},
},
{
desc: "scroll up at the right edge",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonWheelUp,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 1,
Max: 4,
ReqYWidth: 2,
},
},
{
desc: "zoom in when current is already zoomed",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonWheelUp,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 2,
Max: 3,
ReqYWidth: 2,
},
},
{
desc: "zoom in moves min over the current max",
opts: []Option{
ScrollStep(150),
},
mouse: &terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonWheelUp,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 3,
Max: 4,
ReqYWidth: 2,
},
},
{
desc: "zoom in moves max under the current min",
opts: []Option{
ScrollStep(150),
},
mouse: &terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelUp,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 0,
Max: 1,
ReqYWidth: 2,
},
},
{
desc: "scroll down in the middle zooms out evenly",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonWheelDown,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 2,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 1,
Max: 4,
ReqYWidth: 2,
},
},
{
desc: "scroll down in the middle zooms out completely",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{4, 0},
Button: mouse.ButtonWheelDown,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
},
{
desc: "scroll down at the left edge",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 1,
Max: 4,
ReqYWidth: 2,
},
},
{
desc: "scroll down at the right edge",
opts: []Option{
ScrollStep(30),
},
mouse: &terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonWheelDown,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
wantP: &axes.XProperties{
Min: 0,
Max: 3,
ReqYWidth: 2,
},
},
{
desc: "zoom out moves min below base, zooms out completely",
opts: []Option{
ScrollStep(150),
},
mouse: &terminalapi.Mouse{
Position: image.Point{6, 0},
Button: mouse.ButtonWheelDown,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
},
{
desc: "zoom out moves max above base, zooms out completely",
opts: []Option{
ScrollStep(150),
},
mouse: &terminalapi.Mouse{
Position: image.Point{2, 0},
Button: mouse.ButtonWheelDown,
},
cvsAr: image.Rect(0, 0, 8, 8),
graphAr: image.Rect(2, 0, 8, 8),
currP: &axes.XProperties{
Min: 1,
Max: 3,
ReqYWidth: 2,
},
baseP: &axes.XProperties{
Min: 0,
Max: 4,
ReqYWidth: 2,
},
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
var curr *axes.XDetails
if tc.currP != nil {
c, err := axes.NewXDetails(tc.cvsAr, tc.currP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
curr = c
}
var base *axes.XDetails
if tc.baseP != nil {
b, err := axes.NewXDetails(tc.cvsAr, tc.baseP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
base = b
}
got, err := zoomToScroll(tc.mouse, tc.cvsAr, tc.graphAr, curr, base, newOptions(tc.opts...))
if (err != nil) != tc.wantErr {
t.Errorf("zoomToScroll => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
if err != nil {
return
}
var want *axes.XDetails
if tc.wantP != nil {
w, err := axes.NewXDetails(tc.cvsAr, tc.wantP)
if err != nil {
t.Fatalf("NewXDetails => unexpected error: %v", err)
}
want = w
}
if diff := pretty.Compare(want, got); diff != "" {
t.Errorf("zoomToHighlight => unexpected diff (-want, +got):\n%s", diff)
}
})
}
}