peco.peco/action_test.go
2020-12-22 20:30:20 +09:00

374 lines
7.6 KiB
Go

package peco
import (
"testing"
"time"
"unicode/utf8"
"context"
"github.com/peco/peco/filter"
"github.com/stretchr/testify/assert"
)
func TestActionFunc(t *testing.T) {
called := 0
af := ActionFunc(func(_ context.Context, _ *Peco, _ Event) {
called++
})
af.Execute(context.TODO(), nil, nil)
if !assert.Equal(t, called, 1, "Expected ActionFunc to be called once, but it got called %d times", called) {
return
}
}
func TestActionNames(t *testing.T) {
// These names MUST exist
names := []string{
"ForwardChar",
"BackwardChar",
"ForwardWord",
"BackwardWord",
"BeginningOfLine",
"EndOfLine",
"EndOfFile",
"DeleteForwardChar",
"DeleteBackwardChar",
"DeleteForwardWord",
"DeleteBackwardWord",
"KillEndOfLine",
"DeleteAll",
"SelectPreviousPage",
"SelectNextPage",
"SelectPrevious",
"SelectNext",
"ToggleSelection",
"ToggleSelectionAndSelectNext",
"RotateMatcher",
"Finish",
"Cancel",
}
for _, name := range names {
name := "peco." + name
if _, ok := NameToAction(name); !ok {
t.Errorf("Action %s should exist, but it does not", name)
}
}
}
func writeQueryToPrompt(t *testing.T, screen Screen, message string) {
for str := message; true; {
r, size := utf8.DecodeRuneInString(str)
if r == utf8.RuneError {
assert.Equal(t, 0, size, "when in error, we should have size == 0")
return
}
if r == ' ' {
screen.SendEvent(KeyEvent(KeySpace))
} else {
screen.SendEvent(RuneEvent(r))
}
str = str[size:]
}
}
func expectCaretPos(t *testing.T, c *Caret, expect int) bool {
return assert.Equal(t, expect, c.Pos(), "Expected caret position %d, got %d", expect, c.Pos())
}
func expectQueryString(t *testing.T, q *Query, expect string) bool {
return assert.Equal(t, expect, q.String(), "Expected '%s', got '%s'", expect, q.String())
}
func TestDoDeleteForwardChar(t *testing.T) {
state := newPeco()
q := state.Query()
c := state.Caret()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
q.Set("Hello, World!")
c.SetPos(5)
doDeleteForwardChar(ctx, state, nil)
if !expectQueryString(t, q, "Hello World!") {
return
}
if !expectCaretPos(t, c, 5) {
return
}
c.SetPos(q.Len())
doDeleteForwardChar(ctx, state, nil)
expectQueryString(t, q, "Hello World!")
expectCaretPos(t, c, q.Len())
c.SetPos(0)
doDeleteForwardChar(ctx, state, nil)
expectQueryString(t, q, "ello World!")
expectCaretPos(t, c, 0)
}
func TestDoDeleteForwardWord(t *testing.T) {
state := newPeco()
q := state.Query()
c := state.Caret()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
q.Set("Hello, World!")
c.SetPos(5)
// delete the comma
doDeleteForwardWord(ctx, state, nil)
if !expectQueryString(t, q, "Hello World!") {
return
}
if !expectCaretPos(t, c, 5) {
return
}
// at the end of the query, should not delete anything
c.SetPos(q.Len())
doDeleteForwardWord(ctx, state, nil)
if !expectQueryString(t, q, "Hello World!") {
return
}
if !expectCaretPos(t, c, q.Len()) {
return
}
// back to the first column, should delete 'Hello'
c.SetPos(0)
doDeleteForwardWord(ctx, state, nil)
if !expectQueryString(t, q, " World!") {
return
}
if !expectCaretPos(t, c, 0) {
return
}
// should delete "World"
c.SetPos(1)
doDeleteForwardWord(ctx, state, nil)
if !expectQueryString(t, q, " ") {
return
}
}
func TestDoDeleteBackwardChar(t *testing.T) {
state := newPeco()
q := state.Query()
c := state.Caret()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
q.Set("Hello, World!")
c.SetPos(5)
doDeleteBackwardChar(ctx, state, nil)
expectQueryString(t, q, "Hell, World!")
expectCaretPos(t, c, 4)
c.SetPos(q.Len())
doDeleteBackwardChar(ctx, state, nil)
expectQueryString(t, q, "Hell, World")
expectCaretPos(t, c, q.Len())
c.SetPos(0)
doDeleteBackwardChar(ctx, state, nil)
expectQueryString(t, q, "Hell, World")
expectCaretPos(t, c, 0)
}
func TestDoDeleteBackwardWord(t *testing.T) {
state := newPeco()
q := state.Query()
c := state.Caret()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
// In case of an overflow (bug)
q.Set("foo")
c.SetPos(5)
doDeleteBackwardWord(ctx, state, nil)
// https://github.com/peco/peco/pull/184#issuecomment-54026739
// Case 1. " foo<caret>" -> " "
q.Set(" foo")
c.SetPos(4)
doDeleteBackwardWord(ctx, state, nil)
if !expectQueryString(t, q, " ") {
return
}
if !expectCaretPos(t, c, 1) {
return
}
// Case 2. "foo bar<caret>" -> "foo "
q.Set("foo bar")
c.SetPos(7)
doDeleteBackwardWord(ctx, state, nil)
if !expectQueryString(t, q, "foo ") {
return
}
if !expectCaretPos(t, c, 4) {
return
}
}
func TestDoAcceptChar(t *testing.T) {
state := newPeco()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
message := "Hello, World!"
writeQueryToPrompt(t, state.screen, message)
time.Sleep(500 * time.Millisecond)
if qs := state.Query().String(); qs != message {
t.Errorf("Expected query to be populated as '%s', but got '%s'", message, qs)
}
state.Caret().Move(-1 * len("World!"))
writeQueryToPrompt(t, state.screen, "Cruel ")
time.Sleep(500 * time.Millisecond)
expected := "Hello, Cruel World!"
if qs := state.Query().String(); qs != expected {
t.Errorf("Expected query to be populated as '%s', but got '%s'", expected, qs)
}
}
func TestRotateFilter(t *testing.T) {
state := newPeco()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
size := state.filters.Size()
if size <= 1 {
t.Skip("Can't proceed testing, only have 1 filter registered")
return
}
var prev filter.Filter
first := state.Filters().Current()
prev = first
for i := 0; i < size; i++ {
state.screen.SendEvent(KeyEvent(KeyCtrlR))
time.Sleep(500 * time.Millisecond)
f := state.Filters().Current()
if f == prev {
t.Errorf("failed to rotate")
}
prev = f
}
if first != prev {
t.Errorf("should have rotated back to first one, but didn't")
}
// TODO toggle ExecQuery()
}
func TestBeginningOfLineAndEndOfLine(t *testing.T) {
state := newPeco()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
message := "Hello, World!"
writeQueryToPrompt(t, state.screen, message)
state.screen.SendEvent(KeyEvent(KeyCtrlA))
time.Sleep(time.Second)
if !assert.Equal(t, state.Caret().Pos(), 0, "Expected caret position to be 0, got %d", state.Caret().Pos()) {
return
}
state.screen.SendEvent(KeyEvent(KeyCtrlE))
time.Sleep(time.Second)
if !assert.Equal(t, state.Caret().Pos(), len(message), "Expected caret position to be %d, got %d", len(message), state.Caret().Pos()) {
return
}
}
func TestBackToInitialFilter(t *testing.T) {
state := newPeco()
ctx, cancel := context.WithCancel(context.Background())
go state.Run(ctx)
defer cancel()
<-state.Ready()
state.config.Keymap["C-q"] = "peco.BackToInitialFilter"
if !assert.NoError(t, state.populateKeymap(), "populateKeymap expected to succeed") {
return
}
if !assert.Equal(t, state.Filters().Index(), 0, "Expected filter to be at position 0, got %d", state.Filters().Index()) {
return
}
state.screen.SendEvent(KeyEvent(KeyCtrlR))
time.Sleep(time.Second)
if !assert.Equal(t, state.Filters().Index(), 1, "Expected filter to be at position 1, got %d", state.Filters().Index()) {
return
}
state.screen.SendEvent(KeyEvent(KeyCtrlQ))
time.Sleep(time.Second)
if !assert.Equal(t, state.Filters().Index(), 0, "Expected filter to be at position 0, got %d", state.Filters().Index()) {
return
}
}