Gim/internal/editor/integration_motion_screen_test.go
Hayden Hargreaves 7a7472fd12
All checks were successful
Run Test Suite / test (push) Successful in 17s
feat: implemtned H, M, L screen actions, tested
2026-04-06 21:04:51 -07:00

163 lines
4.6 KiB
Go

package editor
import (
"fmt"
"testing"
"git.gophernest.net/azpect/TextEditor/internal/core"
)
func TestScreenTopMotion(t *testing.T) {
t.Run("H moves to the top visible line first non-blank", func(t *testing.T) {
lines := screenMotionLines(100)
lines[82] = " top"
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "H")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 82, 4)
})
t.Run("3H moves to third visible line from top", func(t *testing.T) {
lines := screenMotionLines(100)
lines[84] = " third"
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "3", "H")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 84, 2)
})
t.Run("H count clamps to bottom visible line", func(t *testing.T) {
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "9", "9", "9", "H")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 99, 0)
})
}
func TestScreenMiddleMotion(t *testing.T) {
t.Run("M moves to middle visible line first non-blank", func(t *testing.T) {
lines := screenMotionLines(100)
lines[90] = "\tmiddle"
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "M")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 90, 1)
})
t.Run("count before M is ignored", func(t *testing.T) {
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "9", "M")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 90, 0)
})
}
func TestScreenBottomMotion(t *testing.T) {
t.Run("L moves to bottom visible line first non-blank", func(t *testing.T) {
lines := screenMotionLines(100)
lines[99] = " bottom"
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "L")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 99, 2)
})
t.Run("3L moves to third visible line from bottom", func(t *testing.T) {
lines := screenMotionLines(100)
lines[97] = " above"
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "3", "L")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 97, 4)
})
t.Run("L count clamps to top visible line", func(t *testing.T) {
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "9", "9", "9", "L")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 82, 0)
})
}
func TestScreenMotionsEdgeCases(t *testing.T) {
t.Run("small file: H and L clamp to file bounds", func(t *testing.T) {
lines := []string{" one", "two", "three", "four", "five"}
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "L")
sendKeys(tm, "H")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 0, 4)
})
t.Run("M on blank middle line lands at column 0", func(t *testing.T) {
lines := screenMotionLines(100)
lines[90] = ""
tm := newTestModelWithTermSize(t, lines, core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "M")
m := getFinalModel(t, tm)
assertCursorPos(t, m, 90, 0)
})
}
func TestScreenMotionsIntegration(t *testing.T) {
t.Run("dH treats H as a linewise motion", func(t *testing.T) {
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "d", "H")
m := getFinalModel(t, tm)
if m.ActiveBuffer().LineCount() != 82 {
t.Errorf("LineCount() = %d, want 82", m.ActiveBuffer().LineCount())
}
if m.ActiveBuffer().Line(81) != "line 81" {
t.Errorf("Line(81) = %q, want %q", m.ActiveBuffer().Line(81), "line 81")
}
})
t.Run("H works as a visual line motion", func(t *testing.T) {
tm := newTestModelWithTermSize(t, screenMotionLines(100), core.Position{Col: 0, Line: 0}, 80, 20)
sendKeys(tm, "G", "V", "H", "d")
m := getFinalModel(t, tm)
if m.ActiveBuffer().LineCount() != 82 {
t.Errorf("LineCount() = %d, want 82", m.ActiveBuffer().LineCount())
}
if m.Mode() != core.NormalMode {
t.Errorf("Mode() = %v, want %v", m.Mode(), core.NormalMode)
}
})
}
func screenMotionLines(n int) []string {
lines := make([]string, n)
for i := range n {
lines[i] = fmt.Sprintf("line %d", i)
}
return lines
}
func assertCursorPos(t *testing.T, m *Model, wantLine, wantCol int) {
t.Helper()
if m.ActiveWindow().Cursor.Line != wantLine {
t.Errorf("Cursor.Line = %d, want %d", m.ActiveWindow().Cursor.Line, wantLine)
}
if m.ActiveWindow().Cursor.Col != wantCol {
t.Errorf("Cursor.Col = %d, want %d", m.ActiveWindow().Cursor.Col, wantCol)
}
}