More tests. AI generated a bunch
This commit is contained in:
parent
69ad105aa5
commit
51e20aa87d
692
motion_test.go
692
motion_test.go
@ -323,3 +323,695 @@ func TestMoveLeftWithCount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- G and gg Tests ---
|
||||||
|
|
||||||
|
func TestMoveToBottom(t *testing.T) {
|
||||||
|
t.Run("test 'G' from top", func(t *testing.T) {
|
||||||
|
tm := newTestModel(t)
|
||||||
|
sendKeys(tm, "G")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 5 {
|
||||||
|
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'G' from middle", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 2})
|
||||||
|
sendKeys(tm, "G")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 5 {
|
||||||
|
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'G' already at bottom", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 5})
|
||||||
|
sendKeys(tm, "G")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 5 {
|
||||||
|
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'G' clamps cursor.x", func(t *testing.T) {
|
||||||
|
lines := []string{"long line here", "short"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 10, Line: 0})
|
||||||
|
sendKeys(tm, "G")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 1 {
|
||||||
|
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
||||||
|
}
|
||||||
|
want := len(lines[1])
|
||||||
|
if m.cursor.x != want {
|
||||||
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'G' on single line file", func(t *testing.T) {
|
||||||
|
lines := []string{"only line"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "G")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 0 {
|
||||||
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMoveToTop(t *testing.T) {
|
||||||
|
t.Run("test 'gg' from bottom", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 5})
|
||||||
|
sendKeys(tm, "g", "g")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 0 {
|
||||||
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'gg' from middle", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 3})
|
||||||
|
sendKeys(tm, "g", "g")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 0 {
|
||||||
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'gg' already at top", func(t *testing.T) {
|
||||||
|
tm := newTestModel(t)
|
||||||
|
sendKeys(tm, "g", "g")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 0 {
|
||||||
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'gg' clamps cursor.x", func(t *testing.T) {
|
||||||
|
lines := []string{"short", "long line here"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 10, Line: 1})
|
||||||
|
sendKeys(tm, "g", "g")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 0 {
|
||||||
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
||||||
|
}
|
||||||
|
want := len(lines[0])
|
||||||
|
if m.cursor.x != want {
|
||||||
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 0 and $ Tests ---
|
||||||
|
|
||||||
|
func TestMoveToLineStart(t *testing.T) {
|
||||||
|
t.Run("test '0' from middle of line", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 3, Line: 0})
|
||||||
|
sendKeys(tm, "0")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '0' from end of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello world"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: len(lines[0]), Line: 0})
|
||||||
|
sendKeys(tm, "0")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '0' already at start", func(t *testing.T) {
|
||||||
|
tm := newTestModel(t)
|
||||||
|
sendKeys(tm, "0")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '0' on empty line", func(t *testing.T) {
|
||||||
|
lines := []string{""}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "0")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '0' preserves line", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 3, Line: 2})
|
||||||
|
sendKeys(tm, "0")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 2 {
|
||||||
|
t.Errorf("cursor.y = %d, want 2", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMoveToLineEnd(t *testing.T) {
|
||||||
|
t.Run("test '$' from start of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "$")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
want := len(lines[0])
|
||||||
|
if m.cursor.x != want {
|
||||||
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '$' from middle of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello world"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 3, Line: 0})
|
||||||
|
sendKeys(tm, "$")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
want := len(lines[0])
|
||||||
|
if m.cursor.x != want {
|
||||||
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '$' already at end", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: len(lines[0]), Line: 0})
|
||||||
|
sendKeys(tm, "$")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
want := len(lines[0])
|
||||||
|
if m.cursor.x != want {
|
||||||
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '$' on empty line", func(t *testing.T) {
|
||||||
|
lines := []string{""}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "$")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '$' preserves line", func(t *testing.T) {
|
||||||
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 2})
|
||||||
|
sendKeys(tm, "$")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 2 {
|
||||||
|
t.Errorf("cursor.y = %d, want 2", m.cursor.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Delete Char (x) Tests ---
|
||||||
|
|
||||||
|
func TestDeleteChar(t *testing.T) {
|
||||||
|
t.Run("test 'x' deletes character under cursor", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "ello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'ello'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'x' in middle of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 2, Line: 0})
|
||||||
|
sendKeys(tm, "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "helo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'helo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'x' at end of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 4, Line: 0})
|
||||||
|
sendKeys(tm, "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "hell" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'hell'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'xx' deletes two characters", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "x", "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "llo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'llo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteCharWithCount(t *testing.T) {
|
||||||
|
t.Run("test '3x' deletes three characters", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "3", "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "lo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'lo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '10x' with overflow", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "1", "0", "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "" {
|
||||||
|
t.Errorf("lines[0] = %q, want ''", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '2x' from middle", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 1, Line: 0})
|
||||||
|
sendKeys(tm, "2", "x")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "hlo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'hlo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Insert Mode Tests ---
|
||||||
|
|
||||||
|
func TestEnterInsert(t *testing.T) {
|
||||||
|
t.Run("test 'i' enters insert mode", func(t *testing.T) {
|
||||||
|
tm := newTestModel(t)
|
||||||
|
sendKeys(tm, "i")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.mode != InsertMode {
|
||||||
|
t.Errorf("mode = %d, want InsertMode (%d)", m.mode, InsertMode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'i' insert at beginning", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "i", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "Xhello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'i' insert in middle", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 2, Line: 0})
|
||||||
|
sendKeys(tm, "i", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "heXllo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'heXllo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'i' cursor moves back on esc", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 2, Line: 0})
|
||||||
|
sendKeys(tm, "i", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 2 {
|
||||||
|
t.Errorf("cursor.x = %d, want 2", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnterInsertAfter(t *testing.T) {
|
||||||
|
t.Run("test 'a' enters insert mode", func(t *testing.T) {
|
||||||
|
tm := newTestModel(t)
|
||||||
|
sendKeys(tm, "a")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.mode != InsertMode {
|
||||||
|
t.Errorf("mode = %d, want InsertMode (%d)", m.mode, InsertMode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'a' inserts after cursor", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "a", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "hXello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'hXello'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'a' from middle of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 2, Line: 0})
|
||||||
|
sendKeys(tm, "a", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "helXlo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'helXlo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnterInsertLineStart(t *testing.T) {
|
||||||
|
t.Run("test 'I' enters insert mode at line start", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 3, Line: 0})
|
||||||
|
sendKeys(tm, "I", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "Xhello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'I' from end of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 5, Line: 0})
|
||||||
|
sendKeys(tm, "I", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "Xhello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'Xhello'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnterInsertLineEnd(t *testing.T) {
|
||||||
|
t.Run("test 'A' enters insert mode at line end", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "A", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "helloX" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'helloX'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'A' from middle of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 2, Line: 0})
|
||||||
|
sendKeys(tm, "A", "X", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "helloX" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'helloX'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Open Line Tests ---
|
||||||
|
|
||||||
|
func TestOpenLineBelow(t *testing.T) {
|
||||||
|
t.Run("test 'o' creates line below", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "o", "n", "e", "w", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 3 {
|
||||||
|
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[1] != "new" {
|
||||||
|
t.Errorf("lines[1] = %q, want 'new'", m.lines[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'o' from middle of file", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2", "line 3"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 0, Line: 1})
|
||||||
|
sendKeys(tm, "o", "n", "e", "w", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 4 {
|
||||||
|
t.Errorf("len(lines) = %d, want 4", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[2] != "new" {
|
||||||
|
t.Errorf("lines[2] = %q, want 'new'", m.lines[2])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'o' at end of file", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 0, Line: 1})
|
||||||
|
sendKeys(tm, "o", "n", "e", "w", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 3 {
|
||||||
|
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[2] != "new" {
|
||||||
|
t.Errorf("lines[2] = %q, want 'new'", m.lines[2])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'o' cursor moves to new line", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "o", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.y != 1 {
|
||||||
|
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
||||||
|
}
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenLineBelowWithCount(t *testing.T) {
|
||||||
|
t.Run("test '3o' creates 3 lines", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "3", "o", "x", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 4 {
|
||||||
|
t.Errorf("len(lines) = %d, want 4", len(m.lines))
|
||||||
|
}
|
||||||
|
for i := 1; i <= 3; i++ {
|
||||||
|
if m.lines[i] != "x" {
|
||||||
|
t.Errorf("lines[%d] = %q, want 'x'", i, m.lines[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test '2o' with multiple chars", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "2", "o", "a", "b", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 3 {
|
||||||
|
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[1] != "ab" {
|
||||||
|
t.Errorf("lines[1] = %q, want 'ab'", m.lines[1])
|
||||||
|
}
|
||||||
|
if m.lines[2] != "ab" {
|
||||||
|
t.Errorf("lines[2] = %q, want 'ab'", m.lines[2])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenLineAbove(t *testing.T) {
|
||||||
|
t.Run("test 'O' creates line above", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 0, Line: 1})
|
||||||
|
sendKeys(tm, "O", "n", "e", "w", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 3 {
|
||||||
|
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[1] != "new" {
|
||||||
|
t.Errorf("lines[1] = %q, want 'new'", m.lines[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'O' at top of file", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "O", "n", "e", "w", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 3 {
|
||||||
|
t.Errorf("len(lines) = %d, want 3", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[0] != "new" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'new'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test 'O' cursor at start of new line", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1", "line 2"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 3, Line: 1})
|
||||||
|
sendKeys(tm, "O", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.cursor.x != 0 {
|
||||||
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenLineAboveWithCount(t *testing.T) {
|
||||||
|
t.Run("test '3O' creates 3 lines above", func(t *testing.T) {
|
||||||
|
lines := []string{"line 1"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 0, Line: 0})
|
||||||
|
sendKeys(tm, "3", "O", "x", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 4 {
|
||||||
|
t.Errorf("len(lines) = %d, want 4", len(m.lines))
|
||||||
|
}
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
if m.lines[i] != "x" {
|
||||||
|
t.Errorf("lines[%d] = %q, want 'x'", i, m.lines[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Insert Mode Special Keys ---
|
||||||
|
|
||||||
|
func TestInsertModeEnter(t *testing.T) {
|
||||||
|
t.Run("test enter splits line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello world"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 5, Line: 0})
|
||||||
|
sendKeys(tm, "i", "enter", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 2 {
|
||||||
|
t.Errorf("len(lines) = %d, want 2", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[0] != "hello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||||
|
}
|
||||||
|
if m.lines[1] != " world" {
|
||||||
|
t.Errorf("lines[1] = %q, want ' world'", m.lines[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test enter at end of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 5, Line: 0})
|
||||||
|
sendKeys(tm, "i", "enter", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 2 {
|
||||||
|
t.Errorf("len(lines) = %d, want 2", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[0] != "hello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||||
|
}
|
||||||
|
if m.lines[1] != "" {
|
||||||
|
t.Errorf("lines[1] = %q, want ''", m.lines[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test enter at start of line", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "i", "enter", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 2 {
|
||||||
|
t.Errorf("len(lines) = %d, want 2", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[0] != "" {
|
||||||
|
t.Errorf("lines[0] = %q, want ''", m.lines[0])
|
||||||
|
}
|
||||||
|
if m.lines[1] != "hello" {
|
||||||
|
t.Errorf("lines[1] = %q, want 'hello'", m.lines[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertModeBackspace(t *testing.T) {
|
||||||
|
t.Run("test backspace deletes character", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 3, Line: 0})
|
||||||
|
sendKeys(tm, "i", "backspace", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "helo" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'helo'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test backspace at start of line joins lines", func(t *testing.T) {
|
||||||
|
lines := []string{"hello", "world"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 0, Line: 1})
|
||||||
|
sendKeys(tm, "i", "backspace", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if len(m.lines) != 1 {
|
||||||
|
t.Errorf("len(lines) = %d, want 1", len(m.lines))
|
||||||
|
}
|
||||||
|
if m.lines[0] != "helloworld" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'helloworld'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test backspace at start of first line does nothing", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithLines(t, lines)
|
||||||
|
sendKeys(tm, "i", "backspace", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "hello" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'hello'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test multiple backspaces", func(t *testing.T) {
|
||||||
|
lines := []string{"hello"}
|
||||||
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 5, Line: 0})
|
||||||
|
sendKeys(tm, "i", "backspace", "backspace", "backspace", "esc")
|
||||||
|
|
||||||
|
m := getFinalModel(t, tm)
|
||||||
|
if m.lines[0] != "he" {
|
||||||
|
t.Errorf("lines[0] = %q, want 'he'", m.lines[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user