mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-13 09:57:51 +08:00
cli/clicore: Export FakeTTY and FakeSignalSource.
This commit is contained in:
parent
6c4b737e9f
commit
156a1cc504
|
@ -163,7 +163,7 @@ func TestReadCode_RendersHighlightedCode(t *testing.T) {
|
|||
wantBuf := ui.NewBufferBuilder(80).
|
||||
WriteString("abc", "31" /* SGR for red foreground */).
|
||||
SetDotToCursor().Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("Did not see buffer containing highlighted code")
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ func TestReadCode_RendersPrompt(t *testing.T) {
|
|||
wantBuf := ui.NewBufferBuilder(80).
|
||||
WriteUnstyled("> a").
|
||||
SetDotToCursor().Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("Did not see buffer containing prompt")
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ func TestReadCode_RendersRPrompt(t *testing.T) {
|
|||
|
||||
wantBuf := ui.NewBufferBuilder(4).
|
||||
WriteUnstyled("a").SetDotToCursor().WriteUnstyled(" R").Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("Did not see buffer containing rprompt")
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ func TestReadCode_RedrawsOnPromptLateUpdate(t *testing.T) {
|
|||
bufOldPrompt := ui.NewBufferBuilder(80).
|
||||
WriteUnstyled("old").SetDotToCursor().Buffer()
|
||||
// Wait until old prompt is rendered
|
||||
if !checkBuffer(bufOldPrompt, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(bufOldPrompt) {
|
||||
t.Errorf("Did not see buffer containing old prompt")
|
||||
}
|
||||
|
||||
|
@ -250,7 +250,7 @@ func TestReadCode_RedrawsOnPromptLateUpdate(t *testing.T) {
|
|||
prompt.lateUpdates <- nil
|
||||
bufNewPrompt := ui.NewBufferBuilder(80).
|
||||
WriteUnstyled("new").SetDotToCursor().Buffer()
|
||||
if !checkBuffer(bufNewPrompt, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(bufNewPrompt) {
|
||||
t.Errorf("Did not see buffer containing new prompt")
|
||||
}
|
||||
|
||||
|
@ -268,14 +268,14 @@ func TestReadCode_DrawsAndFlushesNotes(t *testing.T) {
|
|||
|
||||
// Sanity-check initial state.
|
||||
initBuf := ui.NewBufferBuilder(80).Buffer()
|
||||
if !checkBuffer(initBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(initBuf) {
|
||||
t.Errorf("did not get initial state")
|
||||
}
|
||||
|
||||
ed.Notify("note")
|
||||
|
||||
wantNotesBuf := ui.NewBufferBuilder(80).WriteUnstyled("note").Buffer()
|
||||
if !checkBuffer(wantNotesBuf, terminal.NotesBufCh) {
|
||||
if !terminal.VerifyNotesBuffer(wantNotesBuf) {
|
||||
t.Errorf("did not render notes")
|
||||
}
|
||||
|
||||
|
@ -299,7 +299,7 @@ func TestReadCode_UsesFinalStateInFinalRedraw(t *testing.T) {
|
|||
// Wait until a non-final state is drawn.
|
||||
wantBuf := ui.NewBufferBuilder(80).WriteUnstyled("s").SetDotToCursor().
|
||||
WriteUnstyled("ome code").Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("did not get expected buffer before sending Enter")
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ func TestReadCode_QuitsOnSIGHUP(t *testing.T) {
|
|||
|
||||
wantBuf := ui.NewBufferBuilder(80).WriteUnstyled("a").
|
||||
SetDotToCursor().Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("did not get expected buffer before sending SIGHUP")
|
||||
}
|
||||
|
||||
|
@ -348,14 +348,14 @@ func TestReadCode_ResetsOnSIGINT(t *testing.T) {
|
|||
codeCh, _ := ed.readCodeAsync()
|
||||
wantBuf := ui.NewBufferBuilder(80).WriteUnstyled("a").
|
||||
SetDotToCursor().Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("did not get expected buffer before sending SIGINT")
|
||||
}
|
||||
|
||||
sigs.Ch <- syscall.SIGINT
|
||||
|
||||
wantBuf = ui.NewBufferBuilder(80).Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("Terminal state is not reset after SIGINT")
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ func TestReadCode_RedrawsOnSIGWINCH(t *testing.T) {
|
|||
|
||||
wantBuf := ui.NewBufferBuilder(80).WriteUnstyled("1234567890").
|
||||
SetDotToCursor().Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("did not get expected buffer before sending SIGWINCH")
|
||||
}
|
||||
|
||||
|
@ -381,21 +381,21 @@ func TestReadCode_RedrawsOnSIGWINCH(t *testing.T) {
|
|||
|
||||
wantBuf = ui.NewBufferBuilder(4).WriteUnstyled("1234567890").
|
||||
SetDotToCursor().Buffer()
|
||||
if !checkBuffer(wantBuf, terminal.BufCh) {
|
||||
if !terminal.VerifyBuffer(wantBuf) {
|
||||
t.Errorf("Terminal is not redrawn after SIGWINCH")
|
||||
}
|
||||
|
||||
cleanup(terminal, codeCh)
|
||||
}
|
||||
|
||||
func setup() (*App, *fakeTTY, *fakeSignalSource) {
|
||||
terminal := newFakeTTY()
|
||||
sigsrc := newFakeSignalSource()
|
||||
func setup() (*App, *FakeTTY, *FakeSignalSource) {
|
||||
terminal := NewFakeTTY()
|
||||
sigsrc := NewFakeSignalSource()
|
||||
ed := NewApp(terminal, sigsrc)
|
||||
return ed, terminal, sigsrc
|
||||
}
|
||||
|
||||
func cleanup(t *fakeTTY, codeCh <-chan string) {
|
||||
func cleanup(t *FakeTTY, codeCh <-chan string) {
|
||||
// Causes BasicMode to quit
|
||||
t.EventCh <- tty.KeyEvent{Rune: '\n'}
|
||||
// Wait until ReadCode has finished execution
|
||||
|
|
|
@ -4,24 +4,25 @@ import "os"
|
|||
|
||||
const maxFakeSignals = 1024
|
||||
|
||||
// An implementation of SignalSource that is useful in tests.
|
||||
type fakeSignalSource struct {
|
||||
// FakeSignalSource is an implementation of SignalSource that is useful in
|
||||
// tests.
|
||||
type FakeSignalSource struct {
|
||||
// A channel on which fake signals can be injected.
|
||||
Ch chan os.Signal
|
||||
}
|
||||
|
||||
// Creates a new FakeSignalSource.
|
||||
func newFakeSignalSource() *fakeSignalSource {
|
||||
return &fakeSignalSource{make(chan os.Signal, maxFakeSignals)}
|
||||
// NewFakeSignalSource creates a new FakeSignalSource.
|
||||
func NewFakeSignalSource() *FakeSignalSource {
|
||||
return &FakeSignalSource{make(chan os.Signal, maxFakeSignals)}
|
||||
}
|
||||
|
||||
// NotifySignals returns sigs.Ch.
|
||||
func (sigs *fakeSignalSource) NotifySignals() <-chan os.Signal {
|
||||
func (sigs *FakeSignalSource) NotifySignals() <-chan os.Signal {
|
||||
return sigs.Ch
|
||||
}
|
||||
|
||||
// StopSignals closes sig.Ch and set it to nil.
|
||||
func (sigs *fakeSignalSource) StopSignals() {
|
||||
func (sigs *FakeSignalSource) StopSignals() {
|
||||
close(sigs.Ch)
|
||||
sigs.Ch = nil
|
||||
}
|
||||
|
|
|
@ -10,14 +10,14 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// Maximum number of buffer updates fakeTTY expect to see.
|
||||
// Maximum number of buffer updates FakeTTY expect to see.
|
||||
maxBufferUpdates = 1024
|
||||
// Maximum number of events fakeTTY produces.
|
||||
// Maximum number of events FakeTTY produces.
|
||||
maxEvents = 1024
|
||||
)
|
||||
|
||||
// An implementation of the TTY interface that is useful in tests.
|
||||
type fakeTTY struct {
|
||||
// FakeTTY is an implementation of the TTY interface that is useful in tests.
|
||||
type FakeTTY struct {
|
||||
// Callback to be returned from Setup.
|
||||
RestoreFunc func()
|
||||
// Error to be returned from Setup.
|
||||
|
@ -36,9 +36,9 @@ type fakeTTY struct {
|
|||
height, width int
|
||||
}
|
||||
|
||||
// Creates a new FakeTTY.
|
||||
func newFakeTTY() *fakeTTY {
|
||||
return &fakeTTY{
|
||||
// NewFakeTTY creates a new FakeTTY.
|
||||
func NewFakeTTY() *FakeTTY {
|
||||
return &FakeTTY{
|
||||
RestoreFunc: func() {},
|
||||
EventCh: make(chan tty.Event, maxEvents),
|
||||
BufCh: make(chan *ui.Buffer, maxBufferUpdates),
|
||||
|
@ -48,74 +48,84 @@ func newFakeTTY() *fakeTTY {
|
|||
}
|
||||
|
||||
// Setup returns t.RestoreFunc and t.SetupErr.
|
||||
func (t *fakeTTY) Setup() (func(), error) {
|
||||
func (t *FakeTTY) Setup() (func(), error) {
|
||||
return t.RestoreFunc, t.SetupErr
|
||||
}
|
||||
|
||||
// Size returns the size previously set by SetSize.
|
||||
func (t *fakeTTY) Size() (h, w int) {
|
||||
func (t *FakeTTY) Size() (h, w int) {
|
||||
t.sizeMutex.RLock()
|
||||
defer t.sizeMutex.RUnlock()
|
||||
return t.height, t.width
|
||||
}
|
||||
|
||||
// SetSize sets the size that will be returned by Size.
|
||||
func (t *fakeTTY) SetSize(h, w int) {
|
||||
func (t *FakeTTY) SetSize(h, w int) {
|
||||
t.sizeMutex.Lock()
|
||||
defer t.sizeMutex.Unlock()
|
||||
t.height, t.width = h, w
|
||||
}
|
||||
|
||||
// StartInput returns t.EventCh.
|
||||
func (t *fakeTTY) StartInput() <-chan tty.Event {
|
||||
func (t *FakeTTY) StartInput() <-chan tty.Event {
|
||||
return t.EventCh
|
||||
}
|
||||
|
||||
// SetRawInput does nothing.
|
||||
func (t *fakeTTY) SetRawInput(b bool) {}
|
||||
func (t *FakeTTY) SetRawInput(b bool) {}
|
||||
|
||||
// StopInput closes t.EventCh
|
||||
func (t *fakeTTY) StopInput() { close(t.EventCh) }
|
||||
func (t *FakeTTY) StopInput() { close(t.EventCh) }
|
||||
|
||||
// Newline does nothing.
|
||||
func (t *fakeTTY) Newline() {}
|
||||
func (t *FakeTTY) Newline() {}
|
||||
|
||||
// Buffer returns the last recorded buffer.
|
||||
func (t *fakeTTY) Buffer() *ui.Buffer { return t.Bufs[len(t.Bufs)-1] }
|
||||
func (t *FakeTTY) Buffer() *ui.Buffer { return t.Bufs[len(t.Bufs)-1] }
|
||||
|
||||
// ResetBuffer records a nil buffer.
|
||||
func (t *fakeTTY) ResetBuffer() { t.recordBuf(nil) }
|
||||
func (t *FakeTTY) ResetBuffer() { t.recordBuf(nil) }
|
||||
|
||||
// UpdateBuffer records a new pair of buffers, i.e. sending them to their
|
||||
// respective channels and appending them to their respective slices.
|
||||
func (t *fakeTTY) UpdateBuffer(bufNotes, buf *ui.Buffer, _ bool) error {
|
||||
func (t *FakeTTY) UpdateBuffer(bufNotes, buf *ui.Buffer, _ bool) error {
|
||||
t.recordNotesBuf(bufNotes)
|
||||
t.recordBuf(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *fakeTTY) recordBuf(buf *ui.Buffer) {
|
||||
func (t *FakeTTY) recordBuf(buf *ui.Buffer) {
|
||||
t.Bufs = append(t.Bufs, buf)
|
||||
t.BufCh <- buf
|
||||
}
|
||||
|
||||
func (t *fakeTTY) recordNotesBuf(buf *ui.Buffer) {
|
||||
func (t *FakeTTY) recordNotesBuf(buf *ui.Buffer) {
|
||||
t.NotesBufs = append(t.NotesBufs, buf)
|
||||
t.NotesBufCh <- buf
|
||||
}
|
||||
|
||||
var checkBufferTimeout = time.Second
|
||||
// VerifyBuffer verifies that a buffer will appear within one second.
|
||||
func (t *FakeTTY) VerifyBuffer(b *ui.Buffer) bool {
|
||||
return verifyBuffer(b, t.BufCh)
|
||||
}
|
||||
|
||||
// VerifyNotesBuffer verifies that a notes buffer will appear within one second.
|
||||
func (t *FakeTTY) VerifyNotesBuffer(b *ui.Buffer) bool {
|
||||
return verifyBuffer(b, t.NotesBufCh)
|
||||
}
|
||||
|
||||
var verifyBufferTimeout = time.Second
|
||||
|
||||
// Check that an expected buffer will eventually appear. Also useful for waiting
|
||||
// until the editor reaches a certain state.
|
||||
func checkBuffer(want *ui.Buffer, ch <-chan *ui.Buffer) bool {
|
||||
func verifyBuffer(want *ui.Buffer, ch <-chan *ui.Buffer) bool {
|
||||
for {
|
||||
select {
|
||||
case buf := <-ch:
|
||||
if reflect.DeepEqual(buf, want) {
|
||||
return true
|
||||
}
|
||||
case <-time.After(checkBufferTimeout):
|
||||
case <-time.After(verifyBufferTimeout):
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user