Gim/internal/editor/helpers_test.go
2026-02-26 12:14:59 -07:00

131 lines
3.5 KiB
Go

package editor
import (
"testing"
"time"
"git.gophernest.net/azpect/TextEditor/internal/action"
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})
case "ctrl+u":
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlU})
case "ctrl+v":
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlV})
case "ctrl+w":
tm.Send(tea.KeyMsg{Type: tea.KeyCtrlW})
default:
tm.Send(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(key)})
}
}
}
// TestModelOption is a functional option for configuring test models
type TestModelOption func(*testModelConfig)
type testModelConfig struct {
lines []string
pos action.Position
width int
height int
regName rune
regType action.RegisterType
regContent []string
}
// WithLines sets the initial buffer lines
func WithLines(lines []string) TestModelOption {
return func(c *testModelConfig) {
c.lines = lines
}
}
// WithCursorPos sets the initial cursor position
func WithCursorPos(pos action.Position) TestModelOption {
return func(c *testModelConfig) {
c.pos = pos
}
}
// WithTermSize sets the terminal dimensions
func WithTermSize(width, height int) TestModelOption {
return func(c *testModelConfig) {
c.width = width
c.height = height
}
}
// WithRegister sets a register's content
func WithRegister(name rune, regType action.RegisterType, content []string) TestModelOption {
return func(c *testModelConfig) {
c.regName = name
c.regType = regType
c.regContent = content
}
}
// newTestModel creates a test model with optional configuration
func newTestModel(t *testing.T, opts ...TestModelOption) *teatest.TestModel {
// Default configuration
cfg := testModelConfig{
lines: []string{"line 1", "line 2", "line 3", "line 4", "line 5", "line 6"},
pos: action.Position{Col: 0, Line: 0},
width: 80,
height: 24,
}
// Apply options
for _, opt := range opts {
opt(&cfg)
}
// Create model
m := NewModel(cfg.lines, cfg.pos)
// Set register if provided
if cfg.regContent != nil {
m.SetRegister(cfg.regName, cfg.regType, cfg.regContent)
}
return teatest.NewTestModel(t, m, teatest.WithInitialTermSize(cfg.width, cfg.height))
}
// Convenience functions for backward compatibility
func newTestModelWithLines(t *testing.T, lines []string) *teatest.TestModel {
return newTestModel(t, WithLines(lines))
}
func newTestModelWithCursorPos(t *testing.T, pos action.Position) *teatest.TestModel {
return newTestModel(t, WithCursorPos(pos))
}
func newTestModelWithLinesAndCursorPos(t *testing.T, lines []string, pos action.Position) *teatest.TestModel {
return newTestModel(t, WithLines(lines), WithCursorPos(pos))
}
func newTestModelWithTermSize(t *testing.T, lines []string, pos action.Position, width, height int) *teatest.TestModel {
return newTestModel(t, WithLines(lines), WithCursorPos(pos), WithTermSize(width, height))
}
// 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)
}