From ffec83a001be70c169726b56cc293a839366c51f Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 20 Jun 2020 16:03:46 +0200 Subject: [PATCH] widget: add Editor tests Signed-off-by: Elias Naur --- widget/editor_test.go | 139 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 widget/editor_test.go diff --git a/widget/editor_test.go b/widget/editor_test.go new file mode 100644 index 00000000..538e1ad9 --- /dev/null +++ b/widget/editor_test.go @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package widget + +import ( + "fmt" + "image" + "math/rand" + "reflect" + "testing" + "testing/quick" + + "gioui.org/f32" + "gioui.org/font/gofont" + "gioui.org/layout" + "gioui.org/op" + "gioui.org/text" + "gioui.org/unit" +) + +func TestEditor(t *testing.T) { + e := new(Editor) + gtx := layout.Context{ + Ops: new(op.Ops), + Constraints: layout.Exact(image.Pt(100, 100)), + } + cache := text.NewCache(gofont.Collection()) + fontSize := unit.Px(10) + font := text.Font{} + + e.SetText("æbc\naøå•") + e.Layout(gtx, cache, font, fontSize) + assertCaret(t, e, 0, 0, 0) + e.moveEnd() + assertCaret(t, e, 0, 3, len("æbc")) + e.Move(+1) + assertCaret(t, e, 1, 0, len("æbc\n")) + e.Move(-1) + assertCaret(t, e, 0, 3, len("æbc")) + e.moveLines(+1) + assertCaret(t, e, 1, 3, len("æbc\naøå")) + e.moveEnd() + assertCaret(t, e, 1, 4, len("æbc\naøå•")) + e.Move(+1) + assertCaret(t, e, 1, 4, len("æbc\naøå•")) +} + +// assertCaret asserts that the editor caret is at a particular line +// and column, and that the byte position matches as well. +func assertCaret(t *testing.T, e *Editor, line, col, bytes int) { + t.Helper() + gotLine, gotCol := e.CaretPos() + if gotLine != line || gotCol != col { + t.Errorf("caret at (%d, %d), expected (%d, %d)", gotLine, gotCol, line, col) + } + if bytes != e.rr.caret { + t.Errorf("caret at buffer position %d, expected %d", e.rr.caret, bytes) + } +} + +type editMutation int + +const ( + setText editMutation = iota + moveRune + moveLine + movePage + moveStart + moveEnd + moveCoord + moveLast // Mark end; never generated. +) + +func TestEditorCaretConsistency(t *testing.T) { + gtx := layout.Context{ + Ops: new(op.Ops), + Constraints: layout.Exact(image.Pt(100, 100)), + } + cache := text.NewCache(gofont.Collection()) + fontSize := unit.Px(10) + font := text.Font{} + for _, a := range []text.Alignment{text.Start, text.Middle, text.End} { + e := &Editor{ + Alignment: a, + } + e.Layout(gtx, cache, font, fontSize) + + consistent := func() error { + t.Helper() + gotLine, gotCol := e.CaretPos() + gotCoords := e.CaretCoords() + wantLine, wantCol, wantX, wantY := e.layoutCaret() + wantCoords := f32.Pt(float32(wantX)/64, float32(wantY)) + if wantLine == gotLine && wantCol == gotCol && gotCoords == wantCoords { + return nil + } + return fmt.Errorf("caret (%d,%d) pos %s, want (%d,%d) pos %s", gotLine, gotCol, gotCoords, wantLine, wantCol, wantCoords) + } + if err := consistent(); err != nil { + t.Errorf("initial editor inconsistency (alignment %s): %v", a, err) + } + + move := func(mutation editMutation, str string, distance int8, x, y uint16) bool { + switch mutation { + case setText: + e.SetText(str) + e.Layout(gtx, cache, font, fontSize) + case moveRune: + e.Move(int(distance)) + case moveLine: + e.moveLines(int(distance)) + case movePage: + e.movePages(int(distance)) + case moveStart: + e.moveStart() + case moveEnd: + e.moveEnd() + case moveCoord: + e.moveCoord(image.Pt(int(x), int(y))) + default: + return false + } + if err := consistent(); err != nil { + t.Error(err) + return false + } + return true + } + if err := quick.Check(move, nil); err != nil { + t.Errorf("editor inconsistency (alignment %s): %v", a, err) + } + } +} + +// Generate generates a value of itself, for testing/quick. +func (editMutation) Generate(rand *rand.Rand, size int) reflect.Value { + t := editMutation(rand.Intn(int(moveLast))) + return reflect.ValueOf(t) +}