Gim/internal/editor/integration_delete_test.go
Hayden Hargreaves e362c9f118
All checks were successful
Run Test Suite / test (push) Successful in 56s
feat: gap buffer is implemented, tested
Not sure if this is perfect, but it seems to be working
2026-04-02 12:39:30 -07:00

689 lines
22 KiB
Go

package editor
import (
"testing"
"git.gophernest.net/azpect/TextEditor/internal/core"
)
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.ActiveBuffer().Lines[0].String() != "ello" {
t.Errorf("lines[0] = %q, want 'ello'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'x' in middle of line", func(t *testing.T) {
lines := []string{"hello"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "hell" {
t.Errorf("lines[0] = %q, want 'hell'", m.ActiveBuffer().Lines[0].String())
}
})
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.ActiveBuffer().Lines[0].String() != "llo" {
t.Errorf("lines[0] = %q, want 'llo'", m.ActiveBuffer().Lines[0].String())
}
})
}
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.ActiveBuffer().Lines[0].String() != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.ActiveBuffer().Lines[0].String())
}
})
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.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("lines[0] = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test '2x' from middle", func(t *testing.T) {
lines := []string{"hello"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
sendKeys(tm, "2", "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "hlo" {
t.Errorf("lines[0] = %q, want 'hlo'", m.ActiveBuffer().Lines[0].String())
}
})
}
func TestDeleteCharEdgeCases(t *testing.T) {
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].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
if m.ActiveWindow().Cursor.Col != 0 {
t.Errorf("CursorX() = %d, want 0", m.ActiveWindow().Cursor.Col)
}
})
t.Run("test 'x' on single character line", func(t *testing.T) {
lines := []string{"a"}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'x' at last char deletes it", 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].String() != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'x' with whitespace", func(t *testing.T) {
lines := []string{"a b c"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "ab c" {
t.Errorf("Line(0) = %q, want 'ab c'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'x' preserves other lines", func(t *testing.T) {
lines := []string{"hello", "world"}
tm := newTestModelWithLines(t, lines)
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].String() != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1].String())
}
})
t.Run("test 'x' multiple times deletes multiple chars", func(t *testing.T) {
lines := []string{"hello"}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "x", "x", "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "lo" {
t.Errorf("Line(0) = %q, want 'lo'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'x' on line with tabs", func(t *testing.T) {
lines := []string{"a\tb"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "ab" {
t.Errorf("Line(0) = %q, want 'ab'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test '5x' with only 3 chars available", func(t *testing.T) {
lines := []string{"abc"}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "5", "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'x' in middle preserves surrounding chars", func(t *testing.T) {
lines := []string{"abcde"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "x")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "abde" {
t.Errorf("Line(0) = %q, want 'abde'", m.ActiveBuffer().Lines[0].String())
}
})
}
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].String() != "ello" {
t.Errorf("lines[0] = %q, want 'ello'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "helo" {
t.Errorf("lines[0] = %q, want 'helo'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "llo" {
t.Errorf("lines[0] = %q, want 'llo'", m.ActiveBuffer().Lines[0].String())
}
})
}
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].String() != "lo" {
t.Errorf("lines[0] = %q, want 'lo'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "o" {
t.Errorf("lines[0] = %q, want 'o'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "hlo" {
t.Errorf("lines[0] = %q, want 'hlo'", m.ActiveBuffer().Lines[0].String())
}
})
}
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].String() != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0].String())
}
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].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
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].String() != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "b" {
t.Errorf("Line(0) = %q, want 'b'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "ab c" {
t.Errorf("Line(0) = %q, want 'ab c'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1].String())
}
})
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].String() != "lo" {
t.Errorf("Line(0) = %q, want 'lo'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "ab" {
t.Errorf("Line(0) = %q, want 'ab'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "c" {
t.Errorf("Line(0) = %q, want 'c'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "abde" {
t.Errorf("Line(0) = %q, want 'abde'", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "ho" {
t.Errorf("Line(0) = %q, want 'ho'", m.ActiveBuffer().Lines[0].String())
}
// 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].String() != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0].String())
}
if m.ActiveBuffer().Lines[1].String() != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1].String())
}
})
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].String() != " " {
t.Errorf("Line(0) = %q, want ' '", m.ActiveBuffer().Lines[0].String())
}
})
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].String() != "helo" {
t.Errorf("Line(0) = %q, want 'helo'", m.ActiveBuffer().Lines[0].String())
}
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"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' from start of line deletes entire content", func(t *testing.T) {
lines := []string{"hello world"}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' at last character", func(t *testing.T) {
lines := []string{"hello"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 4, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "hell" {
t.Errorf("Line(0) = %q, want 'hell'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' cursor position after delete", func(t *testing.T) {
lines := []string{"hello world"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
// Cursor should move to last character of remaining text
if m.ActiveWindow().Cursor.Col != 4 {
t.Errorf("CursorX() = %d, want 4", m.ActiveWindow().Cursor.Col)
}
})
t.Run("test 'D' deletes nothing on blank line", func(t *testing.T) {
lines := []string{""}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' with count deletes following lines", func(t *testing.T) {
lines := []string{"hello", "world", "hi", "mom"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "2", "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %q, want '3'", m.ActiveBuffer().LineCount())
}
if m.ActiveBuffer().Lines[0].String() != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0].String())
}
if m.ActiveBuffer().Lines[1].String() != "hi" {
t.Errorf("Line(1) = %q, want 'hi'", m.ActiveBuffer().Lines[1].String())
}
})
t.Run("test 'D' with count deletes following lines with overflow", func(t *testing.T) {
lines := []string{"hello", "world", "hi", "mom"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "8", "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().LineCount() != 1 {
t.Errorf("LineCount() = %q, want '1'", m.ActiveBuffer().LineCount())
}
if m.ActiveBuffer().Lines[0].String() != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0].String())
}
})
}
func TestDeleteToEndOfLineEdgeCases(t *testing.T) {
t.Run("test 'D' on single character line", func(t *testing.T) {
lines := []string{"a"}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' at end of file", func(t *testing.T) {
lines := []string{"line 1", "line 2"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 1})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().LineCount() != 2 {
t.Errorf("LineCount() = %d, want 2", m.ActiveBuffer().LineCount())
}
if m.ActiveBuffer().Lines[1].String() != "" {
t.Errorf("Line(1) = %q, want ''", m.ActiveBuffer().Lines[1].String())
}
})
t.Run("test 'D' preserves lines above", func(t *testing.T) {
lines := []string{"line 1", "line 2", "line 3"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 0, Line: 1})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "line 1" {
t.Errorf("Line(0) = %q, want 'line 1'", m.ActiveBuffer().Lines[0].String())
}
if m.ActiveBuffer().Lines[2].String() != "line 3" {
t.Errorf("Line(2) = %q, want 'line 3'", m.ActiveBuffer().Lines[2].String())
}
})
t.Run("test 'D' cursor clamps to valid position", func(t *testing.T) {
lines := []string{"hello world"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "he" {
t.Errorf("Line(0) = %q, want 'he'", m.ActiveBuffer().Lines[0].String())
}
// Cursor should clamp to last char
if m.ActiveWindow().Cursor.Col != 1 {
t.Errorf("CursorX() = %d, want 1", m.ActiveWindow().Cursor.Col)
}
})
t.Run("test 'D' on whitespace-only line", func(t *testing.T) {
lines := []string{" "}
tm := newTestModelWithLines(t, lines)
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "" {
t.Errorf("Line(0) = %q, want ''", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' from middle of whitespace-only line", func(t *testing.T) {
lines := []string{" "}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != " " {
t.Errorf("Line(0) = %q, want ' '", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' with tabs", func(t *testing.T) {
lines := []string{"hello\tworld"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "hello" {
t.Errorf("Line(0) = %q, want 'hello'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' on line with only one char remaining after cursor", func(t *testing.T) {
lines := []string{"ab"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 1, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "a" {
t.Errorf("Line(0) = %q, want 'a'", m.ActiveBuffer().Lines[0].String())
}
})
t.Run("test 'D' does not affect line below", func(t *testing.T) {
lines := []string{"hello", "world"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[1].String() != "world" {
t.Errorf("Line(1) = %q, want 'world'", m.ActiveBuffer().Lines[1].String())
}
})
t.Run("test 'D' with multiple lines", func(t *testing.T) {
lines := []string{"first line", "second line", "third line"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 5, Line: 0})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveBuffer().Lines[0].String() != "first" {
t.Errorf("Line(0) = %q, want 'first'", m.ActiveBuffer().Lines[0].String())
}
if m.ActiveBuffer().LineCount() != 3 {
t.Errorf("LineCount() = %d, want 3", m.ActiveBuffer().LineCount())
}
})
t.Run("test 'D' preserves cursor Y position", func(t *testing.T) {
lines := []string{"line 1", "line 2", "line 3"}
tm := newTestModelWithLinesAndCursorPos(t, lines, core.Position{Col: 2, Line: 1})
sendKeys(tm, "D")
m := getFinalModel(t, tm)
if m.ActiveWindow().Cursor.Line != 1 {
t.Errorf("CursorY() = %d, want 1", m.ActiveWindow().Cursor.Line)
}
})
}