// Package clitest provides utilities for testing cli.App.
package clitest import ( ) // Styles defines a common stylesheet for unit tests. var Styles = ui.RuneStylesheet{ '_': ui.Underlined, 'b': ui.Bold, '*': ui.Stylings(ui.Bold, ui.FgWhite, ui.BgMagenta), '+': ui.Inverse, '/': ui.FgBlue, '#': ui.Stylings(ui.Inverse, ui.FgBlue), '!': ui.FgRed, '?': ui.Stylings(ui.FgBrightWhite, ui.BgRed), '-': ui.FgMagenta, 'X': ui.Stylings(ui.Inverse, ui.FgMagenta), 'v': ui.FgGreen, 'V': ui.Stylings(ui.Underlined, ui.FgGreen), '$': ui.FgMagenta, 'c': ui.FgCyan, // mnemonic "Comment" } // Fixture is a test fixture. type Fixture struct { App cli.App TTY TTYCtrl width int codeCh <-chan string errCh <-chan error } // Setup sets up a test fixture. It contains an App whose ReadCode method has // been started asynchronously. func ( ...func(*cli.AppSpec, TTYCtrl)) *Fixture { , := NewFakeTTY() := cli.AppSpec{TTY: } for , := range { (&, ) } := cli.NewApp() , := StartReadCode(.ReadCode) , := .Size() return &Fixture{, , , , } } // WithSpec takes a function that operates on *cli.AppSpec, and wraps it into a // form suitable for passing to Setup. func ( func(*cli.AppSpec)) func(*cli.AppSpec, TTYCtrl) { return func( *cli.AppSpec, TTYCtrl) { () } } // WithTTY takes a function that operates on TTYCtrl, and wraps it to a form // suitable for passing to Setup. func ( func(TTYCtrl)) func(*cli.AppSpec, TTYCtrl) { return func( *cli.AppSpec, TTYCtrl) { () } } // Wait waits for ReaCode to finish, and returns its return values. func ( *Fixture) () (string, error) { return <-.codeCh, <-.errCh } // Stop stops ReadCode and waits for it to finish. If ReadCode has already been // stopped, it is a no-op. func ( *Fixture) () { .App.CommitEOF() .Wait() } // MakeBuffer is a helper for building a buffer. It is equivalent to // term.NewBufferBuilder(width of terminal).MarkLines(args...).Buffer(). func ( *Fixture) ( ...interface{}) *term.Buffer { return term.NewBufferBuilder(.width).MarkLines(...).Buffer() } // TestTTY is equivalent to f.TTY.TestBuffer(f.MakeBuffer(args...)). func ( *Fixture) ( *testing.T, ...interface{}) { .Helper() .TTY.TestBuffer(, .MakeBuffer(...)) } // TestTTYNotes is equivalent to f.TTY.TestNotesBuffer(f.MakeBuffer(args...)). func ( *Fixture) ( *testing.T, ...interface{}) { .Helper() .TTY.TestNotesBuffer(, .MakeBuffer(...)) } // StartReadCode starts the readCode function asynchronously, and returns two // channels that deliver its return values. The two channels are closed after // return values are delivered, so that subsequent reads will return zero values // and not block. func ( func() (string, error)) (<-chan string, <-chan error) { := make(chan string, 1) := make(chan error, 1) go func() { , := () <- <- close() close() }() return , }