444 lines
8.6 KiB
Go
444 lines
8.6 KiB
Go
|
package cli
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestCLIIsHelp(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
args []string
|
||
|
isHelp bool
|
||
|
}{
|
||
|
{[]string{"-h"}, true},
|
||
|
{[]string{"-help"}, true},
|
||
|
{[]string{"--help"}, true},
|
||
|
{[]string{"-h", "foo"}, true},
|
||
|
{[]string{"foo", "bar"}, false},
|
||
|
{[]string{"-v", "bar"}, false},
|
||
|
{[]string{"foo", "-h"}, false},
|
||
|
{[]string{"foo", "-help"}, false},
|
||
|
{[]string{"foo", "--help"}, false},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
cli := &CLI{Args: testCase.args}
|
||
|
result := cli.IsHelp()
|
||
|
|
||
|
if result != testCase.isHelp {
|
||
|
t.Errorf("Expected '%#v'. Args: %#v", testCase.isHelp, testCase.args)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIIsVersion(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
args []string
|
||
|
isVersion bool
|
||
|
}{
|
||
|
{[]string{"-v"}, true},
|
||
|
{[]string{"-version"}, true},
|
||
|
{[]string{"--version"}, true},
|
||
|
{[]string{"-v", "foo"}, true},
|
||
|
{[]string{"foo", "bar"}, false},
|
||
|
{[]string{"-h", "bar"}, false},
|
||
|
{[]string{"foo", "-v"}, false},
|
||
|
{[]string{"foo", "-version"}, false},
|
||
|
{[]string{"foo", "--version"}, false},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
cli := &CLI{Args: testCase.args}
|
||
|
result := cli.IsVersion()
|
||
|
|
||
|
if result != testCase.isVersion {
|
||
|
t.Errorf("Expected '%#v'. Args: %#v", testCase.isVersion, testCase.args)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun(t *testing.T) {
|
||
|
command := new(MockCommand)
|
||
|
cli := &CLI{
|
||
|
Args: []string{"foo", "-bar", "-baz"},
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return command, nil
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != command.RunResult {
|
||
|
t.Fatalf("bad: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if !command.RunCalled {
|
||
|
t.Fatalf("run should be called")
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(command.RunArgs, []string{"-bar", "-baz"}) {
|
||
|
t.Fatalf("bad args: %#v", command.RunArgs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_blank(t *testing.T) {
|
||
|
command := new(MockCommand)
|
||
|
cli := &CLI{
|
||
|
Args: []string{"", "foo", "-bar", "-baz"},
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return command, nil
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != command.RunResult {
|
||
|
t.Fatalf("bad: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if !command.RunCalled {
|
||
|
t.Fatalf("run should be called")
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(command.RunArgs, []string{"-bar", "-baz"}) {
|
||
|
t.Fatalf("bad args: %#v", command.RunArgs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_default(t *testing.T) {
|
||
|
commandBar := new(MockCommand)
|
||
|
commandBar.RunResult = 42
|
||
|
|
||
|
cli := &CLI{
|
||
|
Args: []string{"-bar", "-baz"},
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"": func() (Command, error) {
|
||
|
return commandBar, nil
|
||
|
},
|
||
|
"foo": func() (Command, error) {
|
||
|
return new(MockCommand), nil
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != commandBar.RunResult {
|
||
|
t.Fatalf("bad: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if !commandBar.RunCalled {
|
||
|
t.Fatalf("run should be called")
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(commandBar.RunArgs, []string{"-bar", "-baz"}) {
|
||
|
t.Fatalf("bad args: %#v", commandBar.RunArgs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_nested(t *testing.T) {
|
||
|
command := new(MockCommand)
|
||
|
cli := &CLI{
|
||
|
Args: []string{"foo", "bar", "-bar", "-baz"},
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return new(MockCommand), nil
|
||
|
},
|
||
|
"foo bar": func() (Command, error) {
|
||
|
return command, nil
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != command.RunResult {
|
||
|
t.Fatalf("bad: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if !command.RunCalled {
|
||
|
t.Fatalf("run should be called")
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(command.RunArgs, []string{"-bar", "-baz"}) {
|
||
|
t.Fatalf("bad args: %#v", command.RunArgs)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_nestedMissingParent(t *testing.T) {
|
||
|
buf := new(bytes.Buffer)
|
||
|
cli := &CLI{
|
||
|
Args: []string{"foo"},
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo bar": func() (Command, error) {
|
||
|
return &MockCommand{SynopsisText: "hi!"}, nil
|
||
|
},
|
||
|
},
|
||
|
HelpWriter: buf,
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != 1 {
|
||
|
t.Fatalf("bad exit code: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if buf.String() != testCommandNestedMissingParent {
|
||
|
t.Fatalf("bad: %#v", buf.String())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_printHelp(t *testing.T) {
|
||
|
testCases := [][]string{
|
||
|
{},
|
||
|
{"-h"},
|
||
|
{"i-dont-exist"},
|
||
|
{"-bad-flag", "foo"},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
buf := new(bytes.Buffer)
|
||
|
helpText := "foo"
|
||
|
|
||
|
cli := &CLI{
|
||
|
Args: testCase,
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return new(MockCommand), nil
|
||
|
},
|
||
|
},
|
||
|
HelpFunc: func(map[string]CommandFactory) string {
|
||
|
return helpText
|
||
|
},
|
||
|
HelpWriter: buf,
|
||
|
}
|
||
|
|
||
|
code, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Errorf("Args: %#v. Error: %s", testCase, err)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if code != 1 {
|
||
|
t.Errorf("Args: %#v. Code: %d", testCase, code)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if !strings.Contains(buf.String(), helpText) {
|
||
|
t.Errorf("Args: %#v. Text: %v", testCase, buf.String())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_printCommandHelp(t *testing.T) {
|
||
|
testCases := [][]string{
|
||
|
{"--help", "foo"},
|
||
|
{"-h", "foo"},
|
||
|
}
|
||
|
|
||
|
for _, args := range testCases {
|
||
|
command := &MockCommand{
|
||
|
HelpText: "donuts",
|
||
|
}
|
||
|
|
||
|
buf := new(bytes.Buffer)
|
||
|
cli := &CLI{
|
||
|
Args: args,
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return command, nil
|
||
|
},
|
||
|
},
|
||
|
HelpWriter: buf,
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != 1 {
|
||
|
t.Fatalf("bad exit code: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if buf.String() != (command.HelpText + "\n") {
|
||
|
t.Fatalf("bad: %#v", buf.String())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_printCommandHelpSubcommands(t *testing.T) {
|
||
|
testCases := [][]string{
|
||
|
{"--help", "foo"},
|
||
|
{"-h", "foo"},
|
||
|
}
|
||
|
|
||
|
for _, args := range testCases {
|
||
|
command := &MockCommand{
|
||
|
HelpText: "donuts",
|
||
|
}
|
||
|
|
||
|
buf := new(bytes.Buffer)
|
||
|
cli := &CLI{
|
||
|
Args: args,
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return command, nil
|
||
|
},
|
||
|
"foo bar": func() (Command, error) {
|
||
|
return &MockCommand{SynopsisText: "hi!"}, nil
|
||
|
},
|
||
|
"foo longer": func() (Command, error) {
|
||
|
return &MockCommand{SynopsisText: "hi!"}, nil
|
||
|
},
|
||
|
},
|
||
|
HelpWriter: buf,
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != 1 {
|
||
|
t.Fatalf("bad exit code: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if buf.String() != testCommandHelpSubcommandsOutput {
|
||
|
t.Fatalf("bad: %#v", buf.String())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLIRun_printCommandHelpTemplate(t *testing.T) {
|
||
|
testCases := [][]string{
|
||
|
{"--help", "foo"},
|
||
|
{"-h", "foo"},
|
||
|
}
|
||
|
|
||
|
for _, args := range testCases {
|
||
|
command := &MockCommandHelpTemplate{
|
||
|
MockCommand: MockCommand{
|
||
|
HelpText: "donuts",
|
||
|
},
|
||
|
|
||
|
HelpTemplateText: "hello {{.Help}}",
|
||
|
}
|
||
|
|
||
|
buf := new(bytes.Buffer)
|
||
|
cli := &CLI{
|
||
|
Args: args,
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo": func() (Command, error) {
|
||
|
return command, nil
|
||
|
},
|
||
|
},
|
||
|
HelpWriter: buf,
|
||
|
}
|
||
|
|
||
|
exitCode, err := cli.Run()
|
||
|
if err != nil {
|
||
|
t.Fatalf("err: %s", err)
|
||
|
}
|
||
|
|
||
|
if exitCode != 1 {
|
||
|
t.Fatalf("bad exit code: %d", exitCode)
|
||
|
}
|
||
|
|
||
|
if buf.String() != "hello "+command.HelpText+"\n" {
|
||
|
t.Fatalf("bad: %#v", buf.String())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLISubcommand(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
args []string
|
||
|
subcommand string
|
||
|
}{
|
||
|
{[]string{"bar"}, "bar"},
|
||
|
{[]string{"foo", "-h"}, "foo"},
|
||
|
{[]string{"-h", "bar"}, "bar"},
|
||
|
{[]string{"foo", "bar", "-h"}, "foo"},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
cli := &CLI{Args: testCase.args}
|
||
|
result := cli.Subcommand()
|
||
|
|
||
|
if result != testCase.subcommand {
|
||
|
t.Errorf("Expected %#v, got %#v. Args: %#v",
|
||
|
testCase.subcommand, result, testCase.args)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCLISubcommand_nested(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
args []string
|
||
|
subcommand string
|
||
|
}{
|
||
|
{[]string{"bar"}, "bar"},
|
||
|
{[]string{"foo", "-h"}, "foo"},
|
||
|
{[]string{"-h", "bar"}, "bar"},
|
||
|
{[]string{"foo", "bar", "-h"}, "foo bar"},
|
||
|
{[]string{"foo", "bar", "baz", "-h"}, "foo bar"},
|
||
|
{[]string{"foo", "bar", "-h", "baz"}, "foo bar"},
|
||
|
}
|
||
|
|
||
|
for _, testCase := range testCases {
|
||
|
cli := &CLI{
|
||
|
Args: testCase.args,
|
||
|
Commands: map[string]CommandFactory{
|
||
|
"foo bar": func() (Command, error) {
|
||
|
return new(MockCommand), nil
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
result := cli.Subcommand()
|
||
|
|
||
|
if result != testCase.subcommand {
|
||
|
t.Errorf("Expected %#v, got %#v. Args: %#v",
|
||
|
testCase.subcommand, result, testCase.args)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const testCommandNestedMissingParent = `This command is accessed by using one of the subcommands below.
|
||
|
|
||
|
Subcommands:
|
||
|
|
||
|
bar hi!
|
||
|
|
||
|
`
|
||
|
|
||
|
const testCommandHelpSubcommandsOutput = `donuts
|
||
|
|
||
|
Subcommands:
|
||
|
|
||
|
bar hi!
|
||
|
longer hi!
|
||
|
|
||
|
`
|