package editor import ( "testing" "git.gophernest.net/azpect/TextEditor/internal/action" ) // --- w, e, and b Tests --- func TestMoveForwardWord(t *testing.T) { t.Run("test 'w' moves forward one word", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 6 { t.Errorf("m.CursorX() = %d, want 6", m.CursorX()) } }) t.Run("test 'www' moves forward three words", func(t *testing.T) { lines := []string{"hello world hello world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "w", "w", "w") m := getFinalModel(t, tm) if m.CursorX() != 18 { t.Errorf("m.CursorX() = %d, want 18", m.CursorX()) } }) t.Run("test 'w' moves to next line", func(t *testing.T) { lines := []string{"hello", "world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } if m.CursorY() != 1 { t.Errorf("m.CursorY() = %d, want 1", m.CursorY()) } }) t.Run("test 'w' at end of file preserves position", func(t *testing.T) { lines := []string{"hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 5, Line: 0}) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 5 { t.Errorf("m.CursorX() = %d, want 5", m.CursorX()) } if m.CursorY() != 0 { t.Errorf("m.CursorY() = %d, want 0", m.CursorY()) } }) t.Run("test 'w' stops at punctuation", func(t *testing.T) { lines := []string{"hello.word"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 5 { t.Errorf("m.CursorX() = %d, want 5", m.CursorX()) } }) t.Run("test 'w' skips underscore", func(t *testing.T) { lines := []string{"hello_world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 11 { t.Errorf("m.CursorX() = %d, want 11", m.CursorX()) } }) t.Run("test 'w' moves once past punctuation", func(t *testing.T) { lines := []string{".hello"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 1 { t.Errorf("m.CursorX() = %d, want 1", m.CursorX()) } }) t.Run("test 'w' from middle of word skips only remaining chars", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 2, Line: 0}) sendKeys(tm, "w") m := getFinalModel(t, tm) if m.CursorX() != 6 { t.Errorf("m.CursorX() = %d, want 6", m.CursorX()) } }) } func TestMoveToWordEnd(t *testing.T) { t.Run("test 'e' moves to end of current word", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 4 { t.Errorf("m.CursorX() = %d, want 4", m.CursorX()) } }) t.Run("test 'eee' moves to end of three words", func(t *testing.T) { lines := []string{"hello world hello world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e", "e", "e") m := getFinalModel(t, tm) if m.CursorX() != 16 { t.Errorf("m.CursorX() = %d, want 16", m.CursorX()) } }) t.Run("test 'e' moves to next line when at end of word", func(t *testing.T) { lines := []string{"hello", "world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 4, Line: 0}) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 4 { t.Errorf("m.CursorX() = %d, want 4", m.CursorX()) } if m.CursorY() != 1 { t.Errorf("m.CursorY() = %d, want 1", m.CursorY()) } }) t.Run("test 'e' at end of file preserves position", func(t *testing.T) { lines := []string{"hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 4, Line: 0}) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 4 { t.Errorf("m.CursorX() = %d, want 4", m.CursorX()) } if m.CursorY() != 0 { t.Errorf("m.CursorY() = %d, want 0", m.CursorY()) } }) t.Run("test 'e' stops at end of word before punctuation", func(t *testing.T) { lines := []string{"hello.world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 4 { t.Errorf("m.CursorX() = %d, want 4", m.CursorX()) } }) t.Run("test 'e' stops at end of punctuation sequence", func(t *testing.T) { lines := []string{"..hello"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 1 { t.Errorf("m.CursorX() = %d, want 1", m.CursorX()) } }) t.Run("test 'e' skips underscore", func(t *testing.T) { lines := []string{"hello_world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 10 { t.Errorf("m.CursorX() = %d, want 10", m.CursorX()) } }) t.Run("test 'e' moves past leading punctuation to end of word", func(t *testing.T) { lines := []string{".hello"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 5 { t.Errorf("m.CursorX() = %d, want 5", m.CursorX()) } }) t.Run("test 'e' from middle of word moves to end of current word", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 2, Line: 0}) sendKeys(tm, "e") m := getFinalModel(t, tm) if m.CursorX() != 4 { t.Errorf("m.CursorX() = %d, want 4", m.CursorX()) } }) t.Run("test 'ee' lands at end of each class in multi-char punctuation", func(t *testing.T) { lines := []string{"hello..world"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "e", "e") m := getFinalModel(t, tm) if m.CursorX() != 6 { t.Errorf("m.CursorX() = %d, want 6", m.CursorX()) } }) } func TestMoveBackwardWord(t *testing.T) { t.Run("test 'b' moves to start of current word", func(t *testing.T) { lines := []string{"hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 3, Line: 0}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } }) t.Run("test 'b' at word start moves to end previous", func(t *testing.T) { lines := []string{"hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 6, Line: 0}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } }) t.Run("test 'bbb' moves to back three word", func(t *testing.T) { lines := []string{"hello world hello world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 23, Line: 0}) sendKeys(tm, "b", "b", "b") m := getFinalModel(t, tm) if m.CursorX() != 6 { t.Errorf("m.CursorX() = %d, want 6", m.CursorX()) } }) t.Run("test 'b' moves to prev line when at start of line", func(t *testing.T) { lines := []string{"hello", "world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 0, Line: 1}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } if m.CursorY() != 0 { t.Errorf("m.CursorY() = %d, want 0", m.CursorY()) } }) t.Run("test 'b' at start of file preserves position", func(t *testing.T) { lines := []string{"hello"} tm := newTestModelWithLines(t, lines) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } }) t.Run("test 'b' stops at punctuation", func(t *testing.T) { lines := []string{"hello.world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 6, Line: 0}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 5 { t.Errorf("m.CursorX() = %d, want 5", m.CursorX()) } }) t.Run("test 'b' stops at end of punctuation sequence", func(t *testing.T) { lines := []string{"..hello"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 2, Line: 0}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } }) t.Run("test 'b' stops at end of punctuation sequence before word", func(t *testing.T) { lines := []string{"hello..world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 7, Line: 0}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 5 { t.Errorf("m.CursorX() = %d, want 5", m.CursorX()) } }) t.Run("test 'b' stops at end of punctuation sequence on newline", func(t *testing.T) { lines := []string{"hello.", "world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 0, Line: 1}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 5 { t.Errorf("m.CursorX() = %d, want 5", m.CursorX()) } if m.CursorY() != 0 { t.Errorf("m.CursorY() = %d, want 0", m.CursorY()) } }) t.Run("test 'b' skips underscore", func(t *testing.T) { lines := []string{"hello_world"} tm := newTestModelWithLinesAndCursorPos(t, lines, action.Position{Col: 10, Line: 0}) sendKeys(tm, "b") m := getFinalModel(t, tm) if m.CursorX() != 0 { t.Errorf("m.CursorX() = %d, want 0", m.CursorX()) } }) }