mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
widget: add Editor tests
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user