|
|
|
|
@ -194,6 +194,274 @@ func TestDeleteCharEdgeCases(t *testing.T) {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDeleteCharBackward(t *testing.T) {
|
|
|
|
|
t.Run("test 'X' deletes character before cursor", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "ello" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'ello'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' in middle of line", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "helo" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' at end of line", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "helo" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'XX' deletes two characters backward", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
|
|
|
|
|
sendKeys(tm, "X", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "llo" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'llo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDeleteCharBackwardWithCount(t *testing.T) {
|
|
|
|
|
t.Run("test '3X' deletes three characters backward", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0})
|
|
|
|
|
sendKeys(tm, "3", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "lo" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'lo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test '10X' with overflow", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0})
|
|
|
|
|
sendKeys(tm, "1", "0", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "o" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'o'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test '2X' from middle", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0})
|
|
|
|
|
sendKeys(tm, "2", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "hlo" {
|
|
|
|
|
t.Errorf("lines[0] = %q, want 'hlo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDeleteCharBackwardEdgeCases(t *testing.T) {
|
|
|
|
|
t.Run("test 'X' at start of line does nothing", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "hello" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
if m.ActiveWindow().Cursor.Col != 0 {
|
|
|
|
|
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' on empty line does nothing", func(t *testing.T) {
|
|
|
|
|
lines := []string{""}
|
|
|
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
if m.ActiveWindow().Cursor.Col != 0 {
|
|
|
|
|
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' on single character line from end", func(t *testing.T) {
|
|
|
|
|
lines := []string{"a"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "a" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' at second char deletes first", func(t *testing.T) {
|
|
|
|
|
lines := []string{"ab"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "b" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'b'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' with whitespace", func(t *testing.T) {
|
|
|
|
|
lines := []string{"a b c"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "ab c" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'ab c'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' preserves other lines", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello", "world"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().LineCount() != 2 {
|
|
|
|
|
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
|
|
|
|
|
}
|
|
|
|
|
if m.ActiveBuffer().Lines[1] != "world" {
|
|
|
|
|
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' multiple times deletes multiple chars backward", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0})
|
|
|
|
|
sendKeys(tm, "X", "X", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "lo" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'lo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' on line with tabs", func(t *testing.T) {
|
|
|
|
|
lines := []string{"a\tb"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "ab" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'ab'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test '5X' with only 3 chars available before cursor", func(t *testing.T) {
|
|
|
|
|
lines := []string{"abc"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
|
|
|
|
|
sendKeys(tm, "5", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "c" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'c'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' in middle preserves surrounding chars", func(t *testing.T) {
|
|
|
|
|
lines := []string{"abcde"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "abde" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'abde'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' cursor position after delete", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 3, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
// Cursor should move back one position after deleting char before it
|
|
|
|
|
if m.ActiveWindow().Cursor.Col != 2 {
|
|
|
|
|
t.Errorf("CursorX() = %d, want 2", m.ActiveWindow().Cursor.Col)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test '3X' cursor position after delete", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0})
|
|
|
|
|
sendKeys(tm, "3", "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "ho" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'ho'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
// Cursor should be at position 1 after deleting 3 chars backward from position 4
|
|
|
|
|
if m.ActiveWindow().Cursor.Col != 1 {
|
|
|
|
|
t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' at start of second line does nothing", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello", "world"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 1})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "hello" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
if m.ActiveBuffer().Lines[1] != "world" {
|
|
|
|
|
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' on whitespace-only line", func(t *testing.T) {
|
|
|
|
|
lines := []string{" "}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != " " {
|
|
|
|
|
t.Errorf("Line(0) = %q, want ' '", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("test 'X' from end of line deletes last char", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello"}
|
|
|
|
|
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0})
|
|
|
|
|
sendKeys(tm, "X")
|
|
|
|
|
|
|
|
|
|
m := getFinalModel(t, tm)
|
|
|
|
|
if m.ActiveBuffer().Lines[0] != "helo" {
|
|
|
|
|
t.Errorf("Line(0) = %q, want 'helo'", m.ActiveBuffer().Lines[0])
|
|
|
|
|
}
|
|
|
|
|
if m.ActiveWindow().Cursor.Col != 3 {
|
|
|
|
|
t.Errorf("CursorX() = %d, want 3", m.ActiveWindow().Cursor.Col)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDeleteToEndOfLine(t *testing.T) {
|
|
|
|
|
t.Run("test 'D' deletes to end of line", func(t *testing.T) {
|
|
|
|
|
lines := []string{"hello world"}
|
|
|
|
|
|