package clitest
import (
)
const (
fakeTTYBufferUpdates = 4096
fakeTTYEvents = 4096
fakeTTYSignals = 4096
)
type fakeTTY struct {
setup func() (func(), error)
eventCh chan term.Event
eventChClosed bool
eventChMutex sync.Mutex
bufCh, notesBufCh chan *term.Buffer
bufs, notesBufs []*term.Buffer
bufMutex sync.RWMutex
sigCh chan os.Signal
raw int
cleared int
sizeMutex sync.RWMutex
height, width int
}
const (
FakeTTYHeight = 20
FakeTTYWidth = 50
)
func () (cli.TTY, TTYCtrl) {
:= &fakeTTY{
eventCh: make(chan term.Event, fakeTTYEvents),
sigCh: make(chan os.Signal, fakeTTYSignals),
bufCh: make(chan *term.Buffer, fakeTTYBufferUpdates),
notesBufCh: make(chan *term.Buffer, fakeTTYBufferUpdates),
height: FakeTTYHeight, width: FakeTTYWidth,
}
return , TTYCtrl{}
}
func ( *fakeTTY) () (func(), error) {
if .setup == nil {
return func() {}, nil
}
return .setup()
}
func ( *fakeTTY) () (, int) {
.sizeMutex.RLock()
defer .sizeMutex.RUnlock()
return .height, .width
}
func ( *fakeTTY) () (term.Event, error) {
return <-.eventCh, nil
}
func ( *fakeTTY) ( int) {
.raw =
}
func ( *fakeTTY) () {
.eventChMutex.Lock()
defer .eventChMutex.Unlock()
close(.eventCh)
.eventChClosed = true
}
func ( *fakeTTY) () *term.Buffer {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
return .bufs[len(.bufs)-1]
}
func ( *fakeTTY) () {
.bufMutex.Lock()
defer .bufMutex.Unlock()
.recordBuf(nil)
}
func ( *fakeTTY) (, *term.Buffer, bool) error {
.bufMutex.Lock()
defer .bufMutex.Unlock()
.recordNotesBuf()
.recordBuf()
return nil
}
func ( *fakeTTY) () {
}
func ( *fakeTTY) () {
}
func ( *fakeTTY) () {
.cleared++
}
func ( *fakeTTY) () <-chan os.Signal { return .sigCh }
func ( *fakeTTY) () { close(.sigCh) }
func ( *fakeTTY) ( *term.Buffer) {
.bufs = append(.bufs, )
.bufCh <-
}
func ( *fakeTTY) ( *term.Buffer) {
.notesBufs = append(.notesBufs, )
.notesBufCh <-
}
type TTYCtrl struct{ *fakeTTY }
func ( cli.TTY) (TTYCtrl, bool) {
, := .(*fakeTTY)
return TTYCtrl{},
}
func ( TTYCtrl) ( func(), error) {
.setup = func() (func(), error) {
return ,
}
}
func ( TTYCtrl) (, int) {
.sizeMutex.Lock()
defer .sizeMutex.Unlock()
.height, .width = ,
}
func ( TTYCtrl) ( ...term.Event) {
for , := range {
.inject()
}
}
func ( TTYCtrl) ( term.Event) {
.eventChMutex.Lock()
defer .eventChMutex.Unlock()
if !.eventChClosed {
.eventCh <-
}
}
func ( TTYCtrl) () chan term.Event {
return .eventCh
}
func ( TTYCtrl) ( ...os.Signal) {
for , := range {
.sigCh <-
}
}
func ( TTYCtrl) () int {
return .raw
}
func ( TTYCtrl) () int {
return .cleared
}
func ( TTYCtrl) ( *testing.T, *term.Buffer) {
.Helper()
:= testBuffer(, , .bufCh)
if ! {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
:= .LastBuffer()
.Logf("Last buffer: %s", .TTYString())
if == nil {
:= .BufferHistory()
for := len() - 1; >= 0; -- {
if [] != nil {
.Logf("Last non-nil buffer: %s", [].TTYString())
return
}
}
}
}
}
func ( TTYCtrl) ( *testing.T, *term.Buffer) {
.Helper()
:= testBuffer(, , .notesBufCh)
if ! {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
:= .NotesBufferHistory()
.Logf("There has been %d notes buffers. None-nil ones are:", len())
for , := range {
if != nil {
.Logf("#%d:\n%s", , .TTYString())
}
}
}
}
func ( TTYCtrl) () []*term.Buffer {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
return .bufs
}
func ( TTYCtrl) () *term.Buffer {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
if len(.bufs) == 0 {
return nil
}
return .bufs[len(.bufs)-1]
}
func ( TTYCtrl) () []*term.Buffer {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
return .notesBufs
}
func ( TTYCtrl) () *term.Buffer {
.bufMutex.RLock()
defer .bufMutex.RUnlock()
if len(.notesBufs) == 0 {
return nil
}
return .notesBufs[len(.notesBufs)-1]
}
func ( *testing.T, *term.Buffer, <-chan *term.Buffer) bool {
.Helper()
:= time.After(testutil.ScaledMs(100))
for {
select {
case := <-:
if reflect.DeepEqual(, ) {
return true
}
case <-:
.Errorf("Wanted buffer not shown")
.Logf("Want: %s", .TTYString())
return false
}
}
}