mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
widget: define incrementing combinedPos and test
This commit restructures seekPosition from a complex state-manipulating loop into a simple loop of iteratively applying an increment operation to the combinedPos. The increment operation itself is now tested, and much easier to understand. Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
+105
-3
@@ -6,12 +6,13 @@ import (
|
||||
|
||||
nsareg "eliasnaur.com/font/noto/sans/arabic/regular"
|
||||
"gioui.org/font/opentype"
|
||||
"gioui.org/io/system"
|
||||
"gioui.org/text"
|
||||
"golang.org/x/image/font/gofont/goregular"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
func TestFirstPos(t *testing.T) {
|
||||
func makeTestText(fontSize, lineWidth int) ([]text.Line, []text.Line) {
|
||||
ltrFace, _ := opentype.Parse(goregular.TTF)
|
||||
rtlFace, _ := opentype.Parse(nsareg.TTF)
|
||||
|
||||
@@ -25,11 +26,15 @@ func TestFirstPos(t *testing.T) {
|
||||
Face: rtlFace,
|
||||
},
|
||||
})
|
||||
fontSize := 16
|
||||
lineWidth := int(fontSize) * 10
|
||||
ltrText := shaper.LayoutString(text.Font{Typeface: "LTR"}, fixed.I(fontSize), lineWidth, english, "The quick brown fox\njumps over the lazy dog.")
|
||||
rtlText := shaper.LayoutString(text.Font{Typeface: "RTL"}, fixed.I(fontSize), lineWidth, arabic, "الحب سماء لا\nتمط غير الأحلام")
|
||||
return ltrText, rtlText
|
||||
}
|
||||
|
||||
func TestFirstPos(t *testing.T) {
|
||||
fontSize := 16
|
||||
lineWidth := fontSize * 10
|
||||
ltrText, rtlText := makeTestText(fontSize, lineWidth)
|
||||
type testcase struct {
|
||||
name string
|
||||
line text.Line
|
||||
@@ -142,3 +147,100 @@ func TestFirstPos(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncrementPosition(t *testing.T) {
|
||||
fontSize := 16
|
||||
lineWidth := fontSize * 3
|
||||
ltrText, rtlText := makeTestText(fontSize, lineWidth)
|
||||
type trial struct {
|
||||
input, output combinedPos
|
||||
}
|
||||
type testcase struct {
|
||||
name string
|
||||
align text.Alignment
|
||||
width int
|
||||
lines []text.Line
|
||||
firstInput combinedPos
|
||||
check func(t *testing.T, iteration int, input, output combinedPos, end bool)
|
||||
}
|
||||
for _, tc := range []testcase{
|
||||
{
|
||||
name: "ltr",
|
||||
align: text.Start,
|
||||
width: lineWidth,
|
||||
lines: ltrText,
|
||||
firstInput: firstPos(ltrText[0], text.Start, lineWidth),
|
||||
},
|
||||
{
|
||||
name: "rtl",
|
||||
align: text.Start,
|
||||
width: lineWidth,
|
||||
lines: rtlText,
|
||||
firstInput: firstPos(rtlText[0], text.Start, lineWidth),
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
input := tc.firstInput
|
||||
for i := 0; true; i++ {
|
||||
output, end := incrementPosition(tc.lines, tc.align, tc.width, input)
|
||||
finalRunes := tc.lines[len(tc.lines)-1].Layout.Runes
|
||||
finalRune := finalRunes.Count + finalRunes.Offset
|
||||
if end && output.runes != finalRune {
|
||||
t.Errorf("iteration %d ended prematurely. Has runes %d, expected %d", i, output.runes, finalRune)
|
||||
}
|
||||
if end {
|
||||
break
|
||||
}
|
||||
if input == output {
|
||||
t.Errorf("iteration %d: identical output:\ninput: %#+v\noutput: %#+v", i, input, output)
|
||||
}
|
||||
// We should always advance on either the X or Y axis.
|
||||
if input.y == output.y {
|
||||
expectedAdvance := tc.lines[input.lineCol.Y].Layout.Clusters[input.clusterIndex].Advance != 0
|
||||
rtl := tc.lines[input.lineCol.Y].Layout.Direction.Progression() == system.TowardOrigin
|
||||
if expectedAdvance {
|
||||
if (rtl && input.x <= output.x) || (!rtl && input.x >= output.x) {
|
||||
t.Errorf("iteration %d advanced the wrong way on x axis: input %v(%d) output %v(%d)", i, input.x, input.x, output.x, output.x)
|
||||
}
|
||||
} else if input.x != output.x {
|
||||
t.Errorf("iteration %d advanced x axis when it should not have: input %v(%d) output %v(%d)", i, input.x, input.x, output.x, output.x)
|
||||
}
|
||||
// If we stayed on the same line, the line-local rune count should
|
||||
// be incremented.
|
||||
if input.lineCol.X >= output.lineCol.X {
|
||||
t.Errorf("iteration %d advanced lineCol.X incorrectly: input %d output %d", i, input.lineCol.X, output.lineCol.X)
|
||||
}
|
||||
// We don't necessarily increment clusters every time, but it should never
|
||||
// go down.
|
||||
if input.clusterIndex > output.clusterIndex {
|
||||
t.Errorf("iteration %d advanced clusterIndex incorrectly: input %d output %d", i, input.clusterIndex, output.clusterIndex)
|
||||
}
|
||||
} else {
|
||||
if input.y >= output.y {
|
||||
t.Errorf("iteration %d advanced the wrong way on y axis: input %v(%d) output %v(%d)", i, input.y, input.y, output.y, output.y)
|
||||
} else {
|
||||
// We correctly advanced on Y axis, so X should be reset to "start of line"
|
||||
// for the text direction.
|
||||
rtl := tc.lines[input.lineCol.Y].Layout.Direction.Progression() == system.TowardOrigin
|
||||
if (rtl && input.x >= output.x) || (!rtl && input.x <= output.x) {
|
||||
t.Errorf("iteration %d reset x axis incorrectly: input %v(%d) output %v(%d)", i, input.x, input.x, output.x, output.x)
|
||||
}
|
||||
}
|
||||
if input.lineCol.Y >= output.lineCol.Y {
|
||||
t.Errorf("iteration %d advanced lineCol.Y incorrectly: input %d output %d", i, input.lineCol.Y, output.lineCol.Y)
|
||||
}
|
||||
if output.clusterIndex != 0 {
|
||||
t.Errorf("iteration %d should have zeroed clusterIndex, got: %d", i, output.clusterIndex)
|
||||
}
|
||||
if output.lineCol.X != 0 {
|
||||
t.Errorf("iteration %d should have zeroed lineCol.X, got: %d", i, output.lineCol.X)
|
||||
}
|
||||
}
|
||||
if output.runes != input.runes+1 {
|
||||
t.Errorf("iteration %d advanced runes incorrectly: input %d output %d", i, input.runes, output.runes)
|
||||
}
|
||||
input = output
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user