e842547421
But update signature to take a writer. This is a backwards incompatible change for those overriding the HelpPrinter, but the hope is that this feature is largely unused and the usage is easily updated.
624 lines
13 KiB
Go
624 lines
13 KiB
Go
package cli_test
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/codegangsta/cli"
|
|
)
|
|
|
|
func ExampleApp() {
|
|
// set args for examples sake
|
|
os.Args = []string{"greet", "--name", "Jeremy"}
|
|
|
|
app := cli.NewApp()
|
|
app.Name = "greet"
|
|
app.Flags = []cli.Flag{
|
|
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
|
}
|
|
app.Action = func(c *cli.Context) {
|
|
fmt.Printf("Hello %v\n", c.String("name"))
|
|
}
|
|
app.Author = "Harrison"
|
|
app.Email = "harrison@lolwut.com"
|
|
app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
|
|
app.Run(os.Args)
|
|
// Output:
|
|
// Hello Jeremy
|
|
}
|
|
|
|
func ExampleAppSubcommand() {
|
|
// set args for examples sake
|
|
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
|
|
app := cli.NewApp()
|
|
app.Name = "say"
|
|
app.Commands = []cli.Command{
|
|
{
|
|
Name: "hello",
|
|
Aliases: []string{"hi"},
|
|
Usage: "use it to see a description",
|
|
Description: "This is how we describe hello the function",
|
|
Subcommands: []cli.Command{
|
|
{
|
|
Name: "english",
|
|
Aliases: []string{"en"},
|
|
Usage: "sends a greeting in english",
|
|
Description: "greets someone in english",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "name",
|
|
Value: "Bob",
|
|
Usage: "Name of the person to greet",
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) {
|
|
fmt.Println("Hello,", c.String("name"))
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
app.Run(os.Args)
|
|
// Output:
|
|
// Hello, Jeremy
|
|
}
|
|
|
|
func ExampleAppHelp() {
|
|
// set args for examples sake
|
|
os.Args = []string{"greet", "h", "describeit"}
|
|
|
|
app := cli.NewApp()
|
|
app.Name = "greet"
|
|
app.Flags = []cli.Flag{
|
|
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
|
}
|
|
app.Commands = []cli.Command{
|
|
{
|
|
Name: "describeit",
|
|
Aliases: []string{"d"},
|
|
Usage: "use it to see a description",
|
|
Description: "This is how we describe describeit the function",
|
|
Action: func(c *cli.Context) {
|
|
fmt.Printf("i like to describe things")
|
|
},
|
|
},
|
|
}
|
|
app.Run(os.Args)
|
|
// Output:
|
|
// NAME:
|
|
// describeit - use it to see a description
|
|
//
|
|
// USAGE:
|
|
// command describeit [arguments...]
|
|
//
|
|
// DESCRIPTION:
|
|
// This is how we describe describeit the function
|
|
}
|
|
|
|
func ExampleAppBashComplete() {
|
|
// set args for examples sake
|
|
os.Args = []string{"greet", "--generate-bash-completion"}
|
|
|
|
app := cli.NewApp()
|
|
app.Name = "greet"
|
|
app.EnableBashCompletion = true
|
|
app.Commands = []cli.Command{
|
|
{
|
|
Name: "describeit",
|
|
Aliases: []string{"d"},
|
|
Usage: "use it to see a description",
|
|
Description: "This is how we describe describeit the function",
|
|
Action: func(c *cli.Context) {
|
|
fmt.Printf("i like to describe things")
|
|
},
|
|
}, {
|
|
Name: "next",
|
|
Usage: "next example",
|
|
Description: "more stuff to see when generating bash completion",
|
|
Action: func(c *cli.Context) {
|
|
fmt.Printf("the next example")
|
|
},
|
|
},
|
|
}
|
|
|
|
app.Run(os.Args)
|
|
// Output:
|
|
// describeit
|
|
// d
|
|
// next
|
|
// help
|
|
// h
|
|
}
|
|
|
|
func TestApp_Run(t *testing.T) {
|
|
s := ""
|
|
|
|
app := cli.NewApp()
|
|
app.Action = func(c *cli.Context) {
|
|
s = s + c.Args().First()
|
|
}
|
|
|
|
err := app.Run([]string{"command", "foo"})
|
|
expect(t, err, nil)
|
|
err = app.Run([]string{"command", "bar"})
|
|
expect(t, err, nil)
|
|
expect(t, s, "foobar")
|
|
}
|
|
|
|
var commandAppTests = []struct {
|
|
name string
|
|
expected bool
|
|
}{
|
|
{"foobar", true},
|
|
{"batbaz", true},
|
|
{"b", true},
|
|
{"f", true},
|
|
{"bat", false},
|
|
{"nothing", false},
|
|
}
|
|
|
|
func TestApp_Command(t *testing.T) {
|
|
app := cli.NewApp()
|
|
fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
|
|
batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
|
|
app.Commands = []cli.Command{
|
|
fooCommand,
|
|
batCommand,
|
|
}
|
|
|
|
for _, test := range commandAppTests {
|
|
expect(t, app.Command(test.name) != nil, test.expected)
|
|
}
|
|
}
|
|
|
|
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
|
|
var parsedOption, firstArg string
|
|
|
|
app := cli.NewApp()
|
|
command := cli.Command{
|
|
Name: "cmd",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
|
|
},
|
|
Action: func(c *cli.Context) {
|
|
parsedOption = c.String("option")
|
|
firstArg = c.Args().First()
|
|
},
|
|
}
|
|
app.Commands = []cli.Command{command}
|
|
|
|
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
|
|
|
|
expect(t, parsedOption, "my-option")
|
|
expect(t, firstArg, "my-arg")
|
|
}
|
|
|
|
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
|
var context *cli.Context
|
|
|
|
a := cli.NewApp()
|
|
a.Commands = []cli.Command{
|
|
{
|
|
Name: "foo",
|
|
Action: func(c *cli.Context) {
|
|
context = c
|
|
},
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "lang",
|
|
Value: "english",
|
|
Usage: "language for the greeting",
|
|
},
|
|
},
|
|
Before: func(_ *cli.Context) error { return nil },
|
|
},
|
|
}
|
|
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
|
|
|
|
expect(t, context.Args().Get(0), "abcd")
|
|
expect(t, context.String("lang"), "spanish")
|
|
}
|
|
|
|
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
|
var parsedOption string
|
|
var args []string
|
|
|
|
app := cli.NewApp()
|
|
command := cli.Command{
|
|
Name: "cmd",
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
|
|
},
|
|
Action: func(c *cli.Context) {
|
|
parsedOption = c.String("option")
|
|
args = c.Args()
|
|
},
|
|
}
|
|
app.Commands = []cli.Command{command}
|
|
|
|
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
|
|
|
|
expect(t, parsedOption, "my-option")
|
|
expect(t, args[0], "my-arg")
|
|
expect(t, args[1], "--")
|
|
expect(t, args[2], "--notARealFlag")
|
|
}
|
|
|
|
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
|
|
var args []string
|
|
|
|
app := cli.NewApp()
|
|
command := cli.Command{
|
|
Name: "cmd",
|
|
Action: func(c *cli.Context) {
|
|
args = c.Args()
|
|
},
|
|
}
|
|
app.Commands = []cli.Command{command}
|
|
|
|
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
|
|
|
|
expect(t, args[0], "my-arg")
|
|
expect(t, args[1], "--")
|
|
expect(t, args[2], "notAFlagAtAll")
|
|
}
|
|
|
|
func TestApp_Float64Flag(t *testing.T) {
|
|
var meters float64
|
|
|
|
app := cli.NewApp()
|
|
app.Flags = []cli.Flag{
|
|
cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
|
|
}
|
|
app.Action = func(c *cli.Context) {
|
|
meters = c.Float64("height")
|
|
}
|
|
|
|
app.Run([]string{"", "--height", "1.93"})
|
|
expect(t, meters, 1.93)
|
|
}
|
|
|
|
func TestApp_ParseSliceFlags(t *testing.T) {
|
|
var parsedOption, firstArg string
|
|
var parsedIntSlice []int
|
|
var parsedStringSlice []string
|
|
|
|
app := cli.NewApp()
|
|
command := cli.Command{
|
|
Name: "cmd",
|
|
Flags: []cli.Flag{
|
|
cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
|
|
cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
|
|
},
|
|
Action: func(c *cli.Context) {
|
|
parsedIntSlice = c.IntSlice("p")
|
|
parsedStringSlice = c.StringSlice("ip")
|
|
parsedOption = c.String("option")
|
|
firstArg = c.Args().First()
|
|
},
|
|
}
|
|
app.Commands = []cli.Command{command}
|
|
|
|
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
|
|
|
|
IntsEquals := func(a, b []int) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i, v := range a {
|
|
if v != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
StrsEquals := func(a, b []string) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i, v := range a {
|
|
if v != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
var expectedIntSlice = []int{22, 80}
|
|
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
|
|
|
|
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
|
|
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
|
|
}
|
|
|
|
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
|
|
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
|
|
}
|
|
}
|
|
|
|
func TestApp_DefaultStdout(t *testing.T) {
|
|
app := cli.NewApp()
|
|
|
|
if app.Writer != os.Stdout {
|
|
t.Error("Default output writer not set.")
|
|
}
|
|
}
|
|
|
|
type mockWriter struct {
|
|
written []byte
|
|
}
|
|
|
|
func (fw *mockWriter) Write(p []byte) (n int, err error) {
|
|
if fw.written == nil {
|
|
fw.written = p
|
|
} else {
|
|
fw.written = append(fw.written, p...)
|
|
}
|
|
|
|
return len(p), nil
|
|
}
|
|
|
|
func (fw *mockWriter) GetWritten() (b []byte) {
|
|
return fw.written
|
|
}
|
|
|
|
func TestApp_SetStdout(t *testing.T) {
|
|
w := &mockWriter{}
|
|
|
|
app := cli.NewApp()
|
|
app.Name = "test"
|
|
app.Writer = w
|
|
|
|
err := app.Run([]string{"help"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Run error: %s", err)
|
|
}
|
|
|
|
if len(w.written) == 0 {
|
|
t.Error("App did not write output to desired writer.")
|
|
}
|
|
}
|
|
|
|
func TestApp_BeforeFunc(t *testing.T) {
|
|
beforeRun, subcommandRun := false, false
|
|
beforeError := fmt.Errorf("fail")
|
|
var err error
|
|
|
|
app := cli.NewApp()
|
|
|
|
app.Before = func(c *cli.Context) error {
|
|
beforeRun = true
|
|
s := c.String("opt")
|
|
if s == "fail" {
|
|
return beforeError
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
app.Commands = []cli.Command{
|
|
cli.Command{
|
|
Name: "sub",
|
|
Action: func(c *cli.Context) {
|
|
subcommandRun = true
|
|
},
|
|
},
|
|
}
|
|
|
|
app.Flags = []cli.Flag{
|
|
cli.StringFlag{Name: "opt"},
|
|
}
|
|
|
|
// run with the Before() func succeeding
|
|
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Run error: %s", err)
|
|
}
|
|
|
|
if beforeRun == false {
|
|
t.Errorf("Before() not executed when expected")
|
|
}
|
|
|
|
if subcommandRun == false {
|
|
t.Errorf("Subcommand not executed when expected")
|
|
}
|
|
|
|
// reset
|
|
beforeRun, subcommandRun = false, false
|
|
|
|
// run with the Before() func failing
|
|
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
|
|
|
// should be the same error produced by the Before func
|
|
if err != beforeError {
|
|
t.Errorf("Run error expected, but not received")
|
|
}
|
|
|
|
if beforeRun == false {
|
|
t.Errorf("Before() not executed when expected")
|
|
}
|
|
|
|
if subcommandRun == true {
|
|
t.Errorf("Subcommand executed when NOT expected")
|
|
}
|
|
|
|
}
|
|
|
|
func TestApp_AfterFunc(t *testing.T) {
|
|
afterRun, subcommandRun := false, false
|
|
afterError := fmt.Errorf("fail")
|
|
var err error
|
|
|
|
app := cli.NewApp()
|
|
|
|
app.After = func(c *cli.Context) error {
|
|
afterRun = true
|
|
s := c.String("opt")
|
|
if s == "fail" {
|
|
return afterError
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
app.Commands = []cli.Command{
|
|
cli.Command{
|
|
Name: "sub",
|
|
Action: func(c *cli.Context) {
|
|
subcommandRun = true
|
|
},
|
|
},
|
|
}
|
|
|
|
app.Flags = []cli.Flag{
|
|
cli.StringFlag{Name: "opt"},
|
|
}
|
|
|
|
// run with the After() func succeeding
|
|
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("Run error: %s", err)
|
|
}
|
|
|
|
if afterRun == false {
|
|
t.Errorf("After() not executed when expected")
|
|
}
|
|
|
|
if subcommandRun == false {
|
|
t.Errorf("Subcommand not executed when expected")
|
|
}
|
|
|
|
// reset
|
|
afterRun, subcommandRun = false, false
|
|
|
|
// run with the Before() func failing
|
|
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
|
|
|
// should be the same error produced by the Before func
|
|
if err != afterError {
|
|
t.Errorf("Run error expected, but not received")
|
|
}
|
|
|
|
if afterRun == false {
|
|
t.Errorf("After() not executed when expected")
|
|
}
|
|
|
|
if subcommandRun == false {
|
|
t.Errorf("Subcommand not executed when expected")
|
|
}
|
|
}
|
|
|
|
func TestAppNoHelpFlag(t *testing.T) {
|
|
oldFlag := cli.HelpFlag
|
|
defer func() {
|
|
cli.HelpFlag = oldFlag
|
|
}()
|
|
|
|
cli.HelpFlag = cli.BoolFlag{}
|
|
|
|
app := cli.NewApp()
|
|
err := app.Run([]string{"test", "-h"})
|
|
|
|
if err != flag.ErrHelp {
|
|
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
|
|
}
|
|
}
|
|
|
|
func TestAppHelpPrinter(t *testing.T) {
|
|
oldPrinter := cli.HelpPrinter
|
|
defer func() {
|
|
cli.HelpPrinter = oldPrinter
|
|
}()
|
|
|
|
var wasCalled = false
|
|
cli.HelpPrinter = func(w io.Writer, template string, data interface{}) {
|
|
wasCalled = true
|
|
}
|
|
|
|
app := cli.NewApp()
|
|
app.Run([]string{"-h"})
|
|
|
|
if wasCalled == false {
|
|
t.Errorf("Help printer expected to be called, but was not")
|
|
}
|
|
}
|
|
|
|
func TestAppVersionPrinter(t *testing.T) {
|
|
oldPrinter := cli.VersionPrinter
|
|
defer func() {
|
|
cli.VersionPrinter = oldPrinter
|
|
}()
|
|
|
|
var wasCalled = false
|
|
cli.VersionPrinter = func(c *cli.Context) {
|
|
wasCalled = true
|
|
}
|
|
|
|
app := cli.NewApp()
|
|
ctx := cli.NewContext(app, nil, nil)
|
|
cli.ShowVersion(ctx)
|
|
|
|
if wasCalled == false {
|
|
t.Errorf("Version printer expected to be called, but was not")
|
|
}
|
|
}
|
|
|
|
func TestAppCommandNotFound(t *testing.T) {
|
|
beforeRun, subcommandRun := false, false
|
|
app := cli.NewApp()
|
|
|
|
app.CommandNotFound = func(c *cli.Context, command string) {
|
|
beforeRun = true
|
|
}
|
|
|
|
app.Commands = []cli.Command{
|
|
cli.Command{
|
|
Name: "bar",
|
|
Action: func(c *cli.Context) {
|
|
subcommandRun = true
|
|
},
|
|
},
|
|
}
|
|
|
|
app.Run([]string{"command", "foo"})
|
|
|
|
expect(t, beforeRun, true)
|
|
expect(t, subcommandRun, false)
|
|
}
|
|
|
|
func TestGlobalFlagsInSubcommands(t *testing.T) {
|
|
subcommandRun := false
|
|
app := cli.NewApp()
|
|
|
|
app.Flags = []cli.Flag{
|
|
cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
|
|
}
|
|
|
|
app.Commands = []cli.Command{
|
|
cli.Command{
|
|
Name: "foo",
|
|
Subcommands: []cli.Command{
|
|
{
|
|
Name: "bar",
|
|
Action: func(c *cli.Context) {
|
|
if c.GlobalBool("debug") {
|
|
subcommandRun = true
|
|
}
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
app.Run([]string{"command", "-d", "foo", "bar"})
|
|
|
|
expect(t, subcommandRun, true)
|
|
}
|