884 lines
29 KiB
Go
884 lines
29 KiB
Go
package editor
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
"b612.me/apps/b612/bed/cmdline"
|
|
"b612.me/apps/b612/bed/event"
|
|
"b612.me/apps/b612/bed/key"
|
|
"b612.me/apps/b612/bed/mode"
|
|
"b612.me/apps/b612/bed/state"
|
|
"b612.me/apps/b612/bed/window"
|
|
)
|
|
|
|
type testUI struct {
|
|
eventCh chan<- event.Event
|
|
initCh chan struct{}
|
|
redrawCh chan struct{}
|
|
}
|
|
|
|
func newTestUI() *testUI {
|
|
return &testUI{
|
|
initCh: make(chan struct{}),
|
|
redrawCh: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
func (ui *testUI) Init(eventCh chan<- event.Event) error {
|
|
ui.eventCh = eventCh
|
|
go func() { defer close(ui.initCh); <-ui.redrawCh }()
|
|
return nil
|
|
}
|
|
|
|
func (*testUI) Run(map[mode.Mode]*key.Manager) {}
|
|
|
|
func (*testUI) Size() (int, int) { return 90, 20 }
|
|
|
|
func (ui *testUI) Redraw(state.State) error {
|
|
ui.redrawCh <- struct{}{}
|
|
return nil
|
|
}
|
|
|
|
func (*testUI) Close() error { return nil }
|
|
|
|
func (ui *testUI) Emit(e event.Event) {
|
|
<-ui.initCh
|
|
ui.eventCh <- e
|
|
switch e.Type {
|
|
case event.ExecuteCmdline, event.NextSearch, event.PreviousSearch:
|
|
<-ui.redrawCh
|
|
}
|
|
<-ui.redrawCh
|
|
}
|
|
|
|
func createTemp(dir, str string) (*os.File, error) {
|
|
f, err := os.CreateTemp(dir, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if str != "" {
|
|
if _, err = f.WriteString(str); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if err = f.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
if str == "" {
|
|
if err = os.Remove(f.Name()); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func TestEditorOpenEmptyWriteQuit(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.OpenEmpty(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.Increment, Count: 13})
|
|
ui.Emit(event.Event{Type: event.Decrement, Count: 6})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name()})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "1 (0x1) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name())
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "\x07"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorOpenWriteQuit(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("skip on Windows")
|
|
}
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartInsert})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '4'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '8'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '0'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '0'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'f'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'a'})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.CursorLeft})
|
|
ui.Emit(event.Event{Type: event.Decrement})
|
|
ui.Emit(event.Event{Type: event.StartInsertHead})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '1'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '2'})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.CursorEnd})
|
|
ui.Emit(event.Event{Type: event.Delete})
|
|
ui.Emit(event.Event{Type: event.WriteQuit})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.err; err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name())
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "\x12\x48\xff"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorOpenQuitBang(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.OpenEmpty(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartInsert})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '4'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '8'})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.Quit})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err, expected := editor.err, "you have unsaved changes in [No Name], "+
|
|
"add ! to force :quit"; err == nil || !strings.HasSuffix(err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, err)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEditorOpenWriteQuitBang(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "ab")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.SwitchFocus})
|
|
ui.Emit(event.Event{Type: event.StartAppendEnd})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'c'})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.WriteQuit, Arg: f.Name() + ".out", Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name())
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "ab"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
bs, err = os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "abc"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorReadWriteQuit(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
r := strings.NewReader("Hello, world!")
|
|
if err := editor.Read(r); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.WriteQuit, Arg: f.Name()})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name())
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "Hello, world!"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorWritePartial(t *testing.T) {
|
|
str := "Hello, world! こんにちは、世界!"
|
|
f, err := createTemp(t.TempDir(), str)
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
for _, testCase := range []struct {
|
|
cmdRange string
|
|
count int
|
|
expected string
|
|
}{
|
|
{"", 41, str},
|
|
{"-10,$+10", 41, str},
|
|
{"10,25", 16, str[10:26]},
|
|
{".+3+3+3+5+5 , .+0xa-0x6", 16, str[4:20]},
|
|
{"$-20,.+28", 9, str[20:29]},
|
|
} {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
fout, err := createTemp(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func(name string) {
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
for _, c := range testCase.cmdRange + "w " + name {
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: c})
|
|
}
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}(fout.Name())
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := fmt.Sprintf("%[1]d (0x%[1]x) bytes written", testCase.count); editor.err == nil ||
|
|
!strings.Contains(editor.err.Error(), expected) {
|
|
t.Errorf("err should be contain %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(fout.Name())
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if string(bs) != testCase.expected {
|
|
t.Errorf("file contents should be %q but got %q", testCase.expected, string(bs))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEditorWriteVisualSelection(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 4})
|
|
ui.Emit(event.Event{Type: event.StartVisual})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 5})
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'w'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: ' '})
|
|
for _, ch := range f.Name() + ".out" {
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: ch})
|
|
}
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
ui.Emit(event.Event{Type: event.Quit})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "6 (0x6) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "o, wor"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorWriteUndo(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "abc")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out"})
|
|
ui.Emit(event.Event{Type: event.Undo})
|
|
ui.Emit(event.Event{Type: event.Quit})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "2 (0x2) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name())
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "abc"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
bs, err = os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "bc"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorSearch(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "abcdefabcdefabcdef")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartCmdlineSearchForward})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'e'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'f'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
ui.Emit(event.Event{Type: event.Nop}) // wait for redraw
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.PreviousSearch})
|
|
ui.Emit(event.Event{Type: event.NextSearch})
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.StartCmdlineSearchBackward})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'b'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'c'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
ui.Emit(event.Event{Type: event.Nop}) // wait for redraw
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.PreviousSearch})
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out"})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "14 (0xe) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "abcdfacdfacdef"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorCmdlineCursorGoto(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '6'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out1"})
|
|
ui.Emit(event.Event{Type: event.Undo})
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '0'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '%'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
ui.Emit(event.Event{Type: event.DeletePrevByte})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out2"})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name() + ".out1")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "Hello,world!"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
bs, err = os.ReadFile(f.Name() + ".out2")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "Hello, wrld!"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorCmdlineQuit(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.OpenEmpty(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'q'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'u'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'i'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 't'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.err; err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEditorCmdlineQuitAll(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.OpenEmpty(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'q'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'a'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'l'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'l'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.err; err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEditorCmdlineQuitErr(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.OpenEmpty(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.StartCmdlineCommand})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'c'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'q'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: ' '})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '4'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '2'})
|
|
ui.Emit(event.Event{Type: event.ExecuteCmdline})
|
|
}()
|
|
if err, expected := editor.Run(), (&quitErr{42}); !reflect.DeepEqual(expected, err) {
|
|
t.Errorf("err should be %v but got: %v", expected, err)
|
|
}
|
|
if err := editor.err; err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEditorReplace(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 2})
|
|
ui.Emit(event.Event{Type: event.StartReplace})
|
|
ui.Emit(event.Event{Type: event.SwitchFocus})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'a'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'b'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'c'})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 2})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'd'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: 'e'})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.CursorLeft, Count: 5})
|
|
ui.Emit(event.Event{Type: event.StartReplaceByte})
|
|
ui.Emit(event.Event{Type: event.SwitchFocus})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '2'})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 2})
|
|
ui.Emit(event.Event{Type: event.StartReplace})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '2'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '3'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '4'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '5'})
|
|
ui.Emit(event.Event{Type: event.Backspace})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.CursorEnd})
|
|
ui.Emit(event.Event{Type: event.StartReplace})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '6'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '7'})
|
|
ui.Emit(event.Event{Type: event.Rune, Rune: '8'})
|
|
ui.Emit(event.Event{Type: event.Backspace})
|
|
ui.Emit(event.Event{Type: event.ExitInsert})
|
|
ui.Emit(event.Event{Type: event.CursorHead})
|
|
ui.Emit(event.Event{Type: event.DeleteByte})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out"})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "13 (0xd) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "earcrsterldvw"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorCopyCutPaste(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 2})
|
|
ui.Emit(event.Event{Type: event.StartVisual})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 5})
|
|
ui.Emit(event.Event{Type: event.Copy})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 3})
|
|
ui.Emit(event.Event{Type: event.Paste})
|
|
ui.Emit(event.Event{Type: event.CursorPrev, Count: 2})
|
|
ui.Emit(event.Event{Type: event.StartVisual})
|
|
ui.Emit(event.Event{Type: event.CursorPrev, Count: 5})
|
|
ui.Emit(event.Event{Type: event.Cut})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 5})
|
|
ui.Emit(event.Event{Type: event.PastePrev})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out"})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "19 (0x13) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "Hell w woo,llo,rld!"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorShowBinary(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.ShowBinary})
|
|
ui.Emit(event.Event{Type: event.Quit})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "01001000"; editor.err == nil || editor.err.Error() != expected {
|
|
t.Errorf("err should be %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEditorShowDecimal(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.ShowDecimal})
|
|
ui.Emit(event.Event{Type: event.Quit})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "72"; editor.err == nil || editor.err.Error() != expected {
|
|
t.Errorf("err should be %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEditorShift(t *testing.T) {
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
f, err := createTemp(t.TempDir(), "Hello, world!")
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.Open(f.Name()); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.ShiftLeft, Count: 1})
|
|
ui.Emit(event.Event{Type: event.CursorNext, Count: 7})
|
|
ui.Emit(event.Event{Type: event.ShiftRight, Count: 3})
|
|
ui.Emit(event.Event{Type: event.Write, Arg: f.Name() + ".out"})
|
|
ui.Emit(event.Event{Type: event.Quit, Bang: true})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "13 (0xd) bytes written"; editor.err == nil ||
|
|
!strings.HasSuffix(editor.err.Error(), expected) {
|
|
t.Errorf("err should end with %q but got: %v", expected, editor.err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
bs, err := os.ReadFile(f.Name() + ".out")
|
|
if err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if expected := "\x90ello, \x0eorld!"; string(bs) != expected {
|
|
t.Errorf("file contents should be %q but got %q", expected, string(bs))
|
|
}
|
|
}
|
|
|
|
func TestEditorChdir(t *testing.T) {
|
|
dir, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
ui := newTestUI()
|
|
editor := NewEditor(ui, window.NewManager(), cmdline.NewCmdline())
|
|
if err := editor.Init(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.OpenEmpty(); err != nil {
|
|
t.Fatalf("err should be nil but got: %v", err)
|
|
}
|
|
go func() {
|
|
ui.Emit(event.Event{Type: event.Pwd})
|
|
ui.Emit(event.Event{Type: event.Chdir, Arg: "../"})
|
|
ui.Emit(event.Event{Type: event.Chdir, Arg: "-"})
|
|
ui.Emit(event.Event{Type: event.Quit})
|
|
}()
|
|
if err := editor.Run(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
if err := editor.err; err == nil || err.Error() != dir {
|
|
t.Errorf("err should be %q but got: %v", dir, err)
|
|
}
|
|
if editor.errtyp != state.MessageInfo {
|
|
t.Errorf("errtyp should be MessageInfo but got: %v", editor.errtyp)
|
|
}
|
|
if err := editor.Close(); err != nil {
|
|
t.Errorf("err should be nil but got: %v", err)
|
|
}
|
|
}
|