342 lines
9.6 KiB
Go
342 lines
9.6 KiB
Go
package editor
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.gophernest.net/azpect/TextEditor/internal/core"
|
|
)
|
|
|
|
// NOTE: AI Generated tests
|
|
|
|
// Default settings are: Number=true, RelativeNumber=true, TabSize=2, ScrollOff=8
|
|
|
|
func TestCommandSetBoolean(t *testing.T) {
|
|
t.Run("':set nonumber' disables line numbers", func(t *testing.T) {
|
|
// Default has Number=true
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "o", "n", "u", "m", "b", "e", "r", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveWindow().Options.Number {
|
|
t.Error("expected Number to be false after :set nonumber")
|
|
}
|
|
})
|
|
|
|
t.Run("':set number' enables after disable", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
// First disable, then enable
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "o", "n", "u", "enter")
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if !m.ActiveWindow().Options.Number {
|
|
t.Error("expected Number to be true after :set nu")
|
|
}
|
|
})
|
|
|
|
t.Run("':set number!' toggles number off", func(t *testing.T) {
|
|
// Default has Number=true
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "m", "b", "e", "r", "!", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveWindow().Options.Number {
|
|
t.Error("expected Number to be false after :set number!")
|
|
}
|
|
})
|
|
|
|
t.Run("':set number!' toggles back on", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
// Toggle off then on
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "!", "enter")
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "!", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if !m.ActiveWindow().Options.Number {
|
|
t.Error("expected Number to be true after double toggle")
|
|
}
|
|
})
|
|
|
|
t.Run("':set nornu' disables relative numbers", func(t *testing.T) {
|
|
// Default has RelativeNumber=true
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "o", "r", "n", "u", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveWindow().Options.RelativeNumber {
|
|
t.Error("expected RelativeNumber to be false after :set nornu")
|
|
}
|
|
})
|
|
|
|
t.Run("':set rnu' enables after disable", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
// Disable then enable
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "o", "r", "n", "u", "enter")
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "r", "n", "u", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if !m.ActiveWindow().Options.RelativeNumber {
|
|
t.Error("expected RelativeNumber to be true after :set rnu")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCommandSetInteger(t *testing.T) {
|
|
t.Run("':set tabstop=4' sets tab size", func(t *testing.T) {
|
|
// Default TabStop=2
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "t", "a", "b", "s", "t", "o", "p", "=", "4", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Settings().TabStop != 4 {
|
|
t.Errorf("TabStop = %d, want 4", m.Settings().TabStop)
|
|
}
|
|
})
|
|
|
|
t.Run("':set ts=8' uses short form", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "t", "s", "=", "8", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Settings().TabStop != 8 {
|
|
t.Errorf("TabStop = %d, want 8", m.Settings().TabStop)
|
|
}
|
|
})
|
|
|
|
t.Run("':set scrolloff=5' sets scroll offset", func(t *testing.T) {
|
|
// Default ScrollOff=8
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "s", "c", "r", "o", "l", "l", "o", "f", "f", "=", "5", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveWindow().Options.ScrollOff != 5 {
|
|
t.Errorf("ScrollOff = %d, want 5", m.ActiveWindow().Options.ScrollOff)
|
|
}
|
|
})
|
|
|
|
t.Run("':set so=10' uses short form", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "s", "o", "=", "1", "0", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.ActiveWindow().Options.ScrollOff != 10 {
|
|
t.Errorf("ScrollOff = %d, want 10", m.ActiveWindow().Options.ScrollOff)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCommandModeNavigation(t *testing.T) {
|
|
t.Run("':' enters command mode and esc exits", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "esc")
|
|
|
|
m := getFinalModel(t, tm)
|
|
// After esc we should be back in normal mode
|
|
if m.Mode() != core.NormalMode {
|
|
t.Errorf("Mode() = %v, want NormalMode after esc", m.Mode())
|
|
}
|
|
})
|
|
|
|
t.Run("'esc' exits command mode", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "esc")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Mode() != core.NormalMode {
|
|
t.Errorf("Mode() = %v, want NormalMode", m.Mode())
|
|
}
|
|
})
|
|
|
|
t.Run("'enter' executes and exits command mode", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Mode() != core.NormalMode {
|
|
t.Errorf("Mode() = %v, want NormalMode", m.Mode())
|
|
}
|
|
})
|
|
|
|
t.Run("command buffer is not cleared after execution", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "t", "e", "s", "t", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "test" {
|
|
t.Errorf("Command() = %q, want \"test\"", m.Command())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCommandModeEditing(t *testing.T) {
|
|
t.Run("backspace deletes character", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
// Type abc, backspace, then enter to execute and check result
|
|
sendKeys(tm, ":", "a", "b", "c", "backspace", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
// Command buffer preserves last command after execution
|
|
if m.Command() != "ab" {
|
|
t.Errorf("Command() = %q, want \"ab\"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("backspace at start does nothing", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "backspace", "a", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "a" {
|
|
t.Errorf("Command() = %q, want \"a\"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("multiple backspaces", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "a", "b", "c", "backspace", "backspace", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "a" {
|
|
t.Errorf("Command() = %q, want \"a\"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("delete key removes character at cursor", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
// Type abc, move left, delete 'c', then enter
|
|
sendKeys(tm, ":", "a", "b", "c", "left", "delete", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "ab" {
|
|
t.Errorf("Command() = %q, want \"ab\"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("delete at end acts as backspace", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "a", "b", "c", "delete", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "ab" {
|
|
t.Errorf("Command() = %q, want \"ab\"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("ctrl+w deletes previous word", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "m", "b", "e", "r", "ctrl+w", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "set " {
|
|
t.Errorf("Command() = %q, want \"set \"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("ctrl+w deletes word and trailing space", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "o", "n", "e", " ", "t", "w", "o", " ", "ctrl+w", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "one " {
|
|
t.Errorf("Command() = %q, want \"one \"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("ctrl+w at start does nothing", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "ctrl+w", "a", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "a" {
|
|
t.Errorf("Command() = %q, want \"a\"", m.Command())
|
|
}
|
|
})
|
|
|
|
t.Run("insert at cursor position", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
// Type 'ac', move left, insert 'b' -> 'abc'
|
|
sendKeys(tm, ":", "a", "c", "left", "b", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.Command() != "abc" {
|
|
t.Errorf("Command() = %q, want \"abc\"", m.Command())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCommandModeErrors(t *testing.T) {
|
|
t.Run("unknown command sets error", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
sendKeys(tm, ":", "u", "n", "k", "n", "o", "w", "n", "c", "m", "d", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.commandError == nil {
|
|
t.Error("expected commandError to be set for unknown command")
|
|
}
|
|
})
|
|
|
|
t.Run("valid command clears error", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
// First cause an error
|
|
sendKeys(tm, ":", "b", "a", "d", "enter")
|
|
// Then run a valid command
|
|
sendKeys(tm, ":", "s", "e", "t", " ", "n", "u", "enter")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.commandError != nil {
|
|
t.Errorf("expected commandError to be nil, got %v", m.commandError)
|
|
}
|
|
})
|
|
|
|
t.Run("esc clears error", func(t *testing.T) {
|
|
lines := []string{"hello"}
|
|
tm := newTestModelWithLines(t, lines)
|
|
|
|
// Cause an error
|
|
sendKeys(tm, ":", "b", "a", "d", "enter")
|
|
// Then escape
|
|
sendKeys(tm, ":", "esc")
|
|
|
|
m := getFinalModel(t, tm)
|
|
if m.commandError != nil {
|
|
t.Errorf("expected commandError to be nil after esc, got %v", m.commandError)
|
|
}
|
|
})
|
|
}
|