2019-07-03 23:22:30 +00:00
|
|
|
package drawtool
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2019-12-23 02:21:58 +00:00
|
|
|
"git.kirsle.net/go/render"
|
2019-07-03 23:22:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestHistory(t *testing.T) {
|
|
|
|
// Test assertion helpers.
|
|
|
|
shouldBool := func(note string, expect, actual bool) {
|
|
|
|
if actual != expect {
|
|
|
|
t.Errorf(
|
|
|
|
"Unexpected boolean result (%s)\n"+
|
|
|
|
"Expected: %+v\n"+
|
|
|
|
" Got: %+v",
|
|
|
|
note,
|
|
|
|
expect,
|
|
|
|
actual,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shouldInt := func(note string, expect, actual int) {
|
|
|
|
if actual != expect {
|
|
|
|
t.Errorf(
|
|
|
|
"Unexpected integer result (%s)\n"+
|
|
|
|
"Expected: %+v\n"+
|
|
|
|
" Got: %+v",
|
|
|
|
note,
|
|
|
|
expect,
|
|
|
|
actual,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
shouldPoint := func(note string, expect render.Point, actual *Stroke) {
|
|
|
|
if actual == nil {
|
|
|
|
t.Errorf("Missing history stroke for shouldPoint(%s)", note)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if actual.PointA != expect {
|
|
|
|
t.Errorf(
|
|
|
|
"Unexpected point result (%s)\n"+
|
|
|
|
"Expected: %+v\n"+
|
|
|
|
" Got: %+v",
|
|
|
|
note,
|
|
|
|
expect,
|
|
|
|
actual.PointA,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var H = NewHistory(10)
|
|
|
|
|
|
|
|
// Add and remove and re-add the first element.
|
|
|
|
H.AddStroke(&Stroke{
|
|
|
|
PointA: render.NewPoint(999, 999),
|
|
|
|
})
|
|
|
|
shouldInt("first element", 1, H.Size())
|
|
|
|
shouldBool("can undo first element", true, H.Undo())
|
|
|
|
shouldBool("latest should be null", true, H.Latest() == nil)
|
|
|
|
|
|
|
|
H = NewHistory(10)
|
|
|
|
|
|
|
|
shouldBool("can't Undo with fresh history", false, H.Undo())
|
|
|
|
shouldInt("size should be zero", 0, H.Size())
|
|
|
|
|
|
|
|
H.AddStroke(&Stroke{
|
|
|
|
PointA: render.NewPoint(1, 1),
|
|
|
|
})
|
|
|
|
|
|
|
|
shouldInt("after first stroke", 1, H.Size())
|
|
|
|
shouldPoint("head is the newest point", render.NewPoint(1, 1), H.Latest())
|
|
|
|
|
|
|
|
H.AddStroke(&Stroke{
|
|
|
|
PointA: render.NewPoint(2, 2),
|
|
|
|
})
|
|
|
|
|
|
|
|
shouldInt("after second stroke", 2, H.Size())
|
|
|
|
shouldPoint("head is the newest point", render.NewPoint(2, 2), H.Latest())
|
|
|
|
|
|
|
|
// Undo.
|
|
|
|
shouldBool("undo second stroke", true, H.Undo())
|
|
|
|
shouldInt("after undo the future stroke is still part of the size", 2, H.Size())
|
|
|
|
shouldPoint("after undo, the newest point", render.NewPoint(1, 1), H.Latest())
|
|
|
|
|
|
|
|
// Redo.
|
|
|
|
shouldBool("redo second stroke", true, H.Redo())
|
|
|
|
shouldInt("after redo second stroke, size is still the same", 2, H.Size())
|
|
|
|
shouldPoint("after redo, the newest point", render.NewPoint(2, 2), H.Latest())
|
|
|
|
|
|
|
|
// Another redo must fail.
|
|
|
|
shouldBool("redo when there is nothing to redo", false, H.Redo())
|
|
|
|
|
|
|
|
// Add a few more points.
|
|
|
|
for i := 3; i <= 6; i++ {
|
|
|
|
H.AddStroke(&Stroke{
|
2023-12-02 20:33:14 +00:00
|
|
|
PointA: render.NewPoint(i, i),
|
2019-07-03 23:22:30 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
shouldInt("after adding more strokes", 6, H.Size())
|
|
|
|
shouldPoint("last point added", render.NewPoint(6, 6), H.Latest())
|
|
|
|
|
|
|
|
// Undo a few times.
|
|
|
|
shouldBool("undo^1", true, H.Undo())
|
|
|
|
shouldBool("undo^2", true, H.Undo())
|
|
|
|
shouldBool("undo^3", true, H.Undo())
|
|
|
|
shouldInt("after a few undos, the size still contains future history", 6, H.Size())
|
|
|
|
|
|
|
|
// A new stroke invalidates the future history.
|
|
|
|
H.AddStroke(&Stroke{
|
|
|
|
PointA: render.NewPoint(7, 7),
|
|
|
|
})
|
|
|
|
shouldInt("after new history, size is recapped to tail", 4, H.Size())
|
|
|
|
shouldBool("can't Redo after new point added", false, H.Redo())
|
|
|
|
|
|
|
|
// Overflow past our history size to test rollover.
|
|
|
|
for i := 8; i <= 16; i++ {
|
|
|
|
H.AddStroke(&Stroke{
|
2023-12-02 20:33:14 +00:00
|
|
|
PointA: render.NewPoint(i, i),
|
2019-07-03 23:22:30 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
shouldInt("after tons of new history, size is capped out", 10, H.Size())
|
|
|
|
shouldPoint("after overflow, latest point", render.NewPoint(16, 16), H.Latest())
|
|
|
|
shouldPoint("after overflow, first point", render.NewPoint(7, 7), H.Oldest())
|
|
|
|
|
|
|
|
// Undo back to beginning.
|
|
|
|
for i := 0; i < H.Size(); i++ {
|
|
|
|
shouldBool("bulk undo to beginning", true, H.Undo())
|
|
|
|
}
|
|
|
|
shouldBool("after bulk undo, tail", true, H.Latest() == nil)
|
|
|
|
shouldBool("can't undo further", false, H.Undo())
|
|
|
|
}
|