326 lines
8.0 KiB
Go
326 lines
8.0 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/x/exp/teatest"
|
|
)
|
|
|
|
// sendKeys sends a sequence of keys to the test model
|
|
func sendKeys(tm *teatest.TestModel, keys ...string) {
|
|
for _, key := range keys {
|
|
switch key {
|
|
case "esc":
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyEscape})
|
|
case "enter":
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyEnter})
|
|
case "backspace":
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyBackspace})
|
|
case "ctrl+c":
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlC})
|
|
case "ctrl+d":
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlD})
|
|
default:
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(key)})
|
|
}
|
|
}
|
|
}
|
|
|
|
// newTestModel creates a test model with default content
|
|
func newTestModel(t *testing.T) *teatest.TestModel {
|
|
lines := []string{"line 1", "line 2", "line 3", "line 4", "line 5", "line 6"}
|
|
return teatest.NewTestModel(t, newModel(lines), teatest.WithInitialTermSize(80, 24))
|
|
}
|
|
|
|
func newTestModelWithLines(t *testing.T, lines []string) *teatest.TestModel {
|
|
return teatest.NewTestModel(t, newModel(lines), teatest.WithInitialTermSize(80, 24))
|
|
}
|
|
|
|
func newTestModelWithCursorPos(t *testing.T, pos Position) *teatest.TestModel {
|
|
lines := []string{"line 1", "line 2", "line 3", "line 4", "line 5", "line 6"}
|
|
return teatest.NewTestModel(t, newModelWithPos(lines, pos), teatest.WithInitialTermSize(80, 24))
|
|
}
|
|
|
|
func newTestModelWithCursorPosAndLines(t *testing.T, lines []string, pos Position) *teatest.TestModel {
|
|
return teatest.NewTestModel(t, newModelWithPos(lines, pos), teatest.WithInitialTermSize(80, 24))
|
|
}
|
|
|
|
// getFinalModel extracts the final model state (sends ctrl+c to quit first)
|
|
func getFinalModel(t *testing.T, tm *teatest.TestModel) model {
|
|
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlC})
|
|
fm := tm.FinalModel(t, teatest.WithFinalTimeout(time.Second))
|
|
return fm.(model)
|
|
}
|
|
|
|
func TestMoveDown(t *testing.T) {
|
|
t.Run("test 'j'", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 1 {
|
|
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'jjjj'", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "j", "j", "j", "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 4 {
|
|
t.Errorf("cursor.y = %d, want 4", m.cursor.y)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'jjjjjjjjj's with overflow", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "j", "j", "j", "j", "j", "j", "j", "j", "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 5 {
|
|
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveDownWithCount(t *testing.T) {
|
|
t.Run("test '3j'", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "3", "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 3 {
|
|
t.Errorf("cursor.y = %d, want 3", m.cursor.y)
|
|
}
|
|
})
|
|
|
|
t.Run("test '10j' with overflow", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "1", "0", "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 5 {
|
|
t.Errorf("cursor.y = %d, want 5", m.cursor.y)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveDownWithOverflow(t *testing.T) {
|
|
lines := []string{"long line", "small"}
|
|
|
|
t.Run("test 'j' with overflow", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 8, Line: 0})
|
|
sendKeys(tm, "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
want := len(lines[1])
|
|
if m.cursor.x != want {
|
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'j' without overflow", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 3, Line: 0})
|
|
sendKeys(tm, "j")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 3 {
|
|
t.Errorf("cursor.x = %d, want 3", m.cursor.x)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveUp(t *testing.T) {
|
|
t.Run("test 'k'", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 2})
|
|
sendKeys(tm, "k")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 1 {
|
|
t.Errorf("cursor.y = %d, want 1", m.cursor.y)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'kkkk'", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 4})
|
|
sendKeys(tm, "k", "k", "k", "k")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 0 {
|
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'k' at top (no movement)", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "k", "k", "k")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 0 {
|
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveUpWithCount(t *testing.T) {
|
|
t.Run("test '3k'", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 5})
|
|
sendKeys(tm, "3", "k")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 2 {
|
|
t.Errorf("cursor.y = %d, want 2", m.cursor.y)
|
|
}
|
|
})
|
|
|
|
t.Run("test '10k' with overflow", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 0, Line: 3})
|
|
sendKeys(tm, "1", "0", "k")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.y != 0 {
|
|
t.Errorf("cursor.y = %d, want 0", m.cursor.y)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveUpWithOverflow(t *testing.T) {
|
|
lines := []string{"small", "long line"}
|
|
|
|
t.Run("test 'k' with overflow", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 10, Line: 1})
|
|
sendKeys(tm, "k")
|
|
|
|
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 'k' without overflow", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPosAndLines(t, lines, Position{Col: 3, Line: 1})
|
|
sendKeys(tm, "k")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 3 {
|
|
t.Errorf("cursor.x = %d, want 3", m.cursor.x)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveRight(t *testing.T) {
|
|
t.Run("test 'l'", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "l")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 1 {
|
|
t.Errorf("cursor.x = %d, want 1", m.cursor.x)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'llll'", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "l", "l", "l", "l")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 4 {
|
|
t.Errorf("cursor.x = %d, want 4", m.cursor.x)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'l' at end of line (no movement past end)", func(t *testing.T) {
|
|
lines := []string{"abc"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, "l", "l", "l", "l", "l", "l")
|
|
|
|
m := getFinalModel(t, tm)
|
|
want := len(lines[0])
|
|
if m.cursor.x != want {
|
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveRightWithCount(t *testing.T) {
|
|
t.Run("test '3l'", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "3", "l")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 3 {
|
|
t.Errorf("cursor.x = %d, want 3", m.cursor.x)
|
|
}
|
|
})
|
|
|
|
t.Run("test '10l' with overflow", func(t *testing.T) {
|
|
lines := []string{"short"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, "1", "0", "l")
|
|
|
|
m := getFinalModel(t, tm)
|
|
want := len(lines[0])
|
|
if m.cursor.x != want {
|
|
t.Errorf("cursor.x = %d, want %d", m.cursor.x, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveLeft(t *testing.T) {
|
|
t.Run("test 'h'", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 3, Line: 0})
|
|
sendKeys(tm, "h")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 2 {
|
|
t.Errorf("cursor.x = %d, want 2", m.cursor.x)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'hhhh'", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 4, Line: 0})
|
|
sendKeys(tm, "h", "h", "h", "h")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 0 {
|
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
|
}
|
|
})
|
|
|
|
t.Run("test 'h' at start (no movement)", func(t *testing.T) {
|
|
tm := newTestModel(t)
|
|
sendKeys(tm, "h", "h", "h")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 0 {
|
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMoveLeftWithCount(t *testing.T) {
|
|
t.Run("test '3h'", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 5, Line: 0})
|
|
sendKeys(tm, "3", "h")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 2 {
|
|
t.Errorf("cursor.x = %d, want 2", m.cursor.x)
|
|
}
|
|
})
|
|
|
|
t.Run("test '10h' with overflow", func(t *testing.T) {
|
|
tm := newTestModelWithCursorPos(t, Position{Col: 3, Line: 0})
|
|
sendKeys(tm, "1", "0", "h")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.cursor.x != 0 {
|
|
t.Errorf("cursor.x = %d, want 0", m.cursor.x)
|
|
}
|
|
})
|
|
}
|