spf13--cobra/command_test.go
Tim Peoples eb58983359 Add CalledAs method to cobra.Command (w/ tests) (#567)
* Add `CalledAs` method to Command (w/ tests)

The `CalledAs` method returns the name of the command or alias that
invoked the command -- as long as the command was actually invoked.
Otherwise, it returns the empty string.

The opens up possibilies for commands to behave differently based on
which alias invoked the command (in the same vein as Linux programs
which adjust their behavior based on the value of argv[0]).

* Fixed formatting
2018-02-04 08:58:53 -08:00

1629 lines
43 KiB
Go

package cobra
import (
"bytes"
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/spf13/pflag"
)
func emptyRun(*Command, []string) {}
func executeCommand(root *Command, args ...string) (output string, err error) {
_, output, err = executeCommandC(root, args...)
return output, err
}
func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) {
buf := new(bytes.Buffer)
root.SetOutput(buf)
root.SetArgs(args)
c, err = root.ExecuteC()
return c, buf.String(), err
}
func resetCommandLineFlagSet() {
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
}
func checkStringContains(t *testing.T, got, expected string) {
if !strings.Contains(got, expected) {
t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got)
}
}
func checkStringOmits(t *testing.T, got, expected string) {
if strings.Contains(got, expected) {
t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got)
}
}
func TestSingleCommand(t *testing.T) {
var rootCmdArgs []string
rootCmd := &Command{
Use: "root",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { rootCmdArgs = args },
}
aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun}
bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun}
rootCmd.AddCommand(aCmd, bCmd)
output, err := executeCommand(rootCmd, "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(rootCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got)
}
}
func TestChildCommand(t *testing.T) {
var child1CmdArgs []string
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
child1Cmd := &Command{
Use: "child1",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { child1CmdArgs = args },
}
child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun}
rootCmd.AddCommand(child1Cmd, child2Cmd)
output, err := executeCommand(rootCmd, "child1", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(child1CmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got)
}
}
func TestCallCommandWithoutSubcommands(t *testing.T) {
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
_, err := executeCommand(rootCmd)
if err != nil {
t.Errorf("Calling command without subcommands should not have error: %v", err)
}
}
func TestRootExecuteUnknownCommand(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
output, _ := executeCommand(rootCmd, "unknown")
expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n"
if output != expected {
t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output)
}
}
func TestSubcommandExecuteC(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
rootCmd.AddCommand(childCmd)
c, output, err := executeCommandC(rootCmd, "child")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if c.Name() != "child" {
t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name())
}
}
func TestRootUnknownCommandSilenced(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.SilenceErrors = true
rootCmd.SilenceUsage = true
rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
output, _ := executeCommand(rootCmd, "unknown")
if output != "" {
t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output)
}
}
func TestCommandAlias(t *testing.T) {
var timesCmdArgs []string
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
echoCmd := &Command{
Use: "echo",
Aliases: []string{"say", "tell"},
Args: NoArgs,
Run: emptyRun,
}
timesCmd := &Command{
Use: "times",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { timesCmdArgs = args },
}
echoCmd.AddCommand(timesCmd)
rootCmd.AddCommand(echoCmd)
output, err := executeCommand(rootCmd, "tell", "times", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(timesCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
}
}
func TestEnablePrefixMatching(t *testing.T) {
EnablePrefixMatching = true
var aCmdArgs []string
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
aCmd := &Command{
Use: "aCmd",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { aCmdArgs = args },
}
bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun}
rootCmd.AddCommand(aCmd, bCmd)
output, err := executeCommand(rootCmd, "a", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(aCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("aCmdArgs expected: %q, got: %q", expected, got)
}
EnablePrefixMatching = false
}
func TestAliasPrefixMatching(t *testing.T) {
EnablePrefixMatching = true
var timesCmdArgs []string
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
echoCmd := &Command{
Use: "echo",
Aliases: []string{"say", "tell"},
Args: NoArgs,
Run: emptyRun,
}
timesCmd := &Command{
Use: "times",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { timesCmdArgs = args },
}
echoCmd.AddCommand(timesCmd)
rootCmd.AddCommand(echoCmd)
output, err := executeCommand(rootCmd, "sa", "times", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(timesCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
}
EnablePrefixMatching = false
}
// TestChildSameName checks the correct behaviour of cobra in cases,
// when an application with name "foo" and with subcommand "foo"
// is executed with args "foo foo".
func TestChildSameName(t *testing.T) {
var fooCmdArgs []string
rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
fooCmd := &Command{
Use: "foo",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { fooCmdArgs = args },
}
barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
rootCmd.AddCommand(fooCmd, barCmd)
output, err := executeCommand(rootCmd, "foo", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(fooCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
}
}
// TestGrandChildSameName checks the correct behaviour of cobra in cases,
// when user has a root command and a grand child
// with the same name.
func TestGrandChildSameName(t *testing.T) {
var fooCmdArgs []string
rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
fooCmd := &Command{
Use: "foo",
Args: ExactArgs(2),
Run: func(_ *Command, args []string) { fooCmdArgs = args },
}
barCmd.AddCommand(fooCmd)
rootCmd.AddCommand(barCmd)
output, err := executeCommand(rootCmd, "bar", "foo", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(fooCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
}
}
func TestFlagLong(t *testing.T) {
var cArgs []string
c := &Command{
Use: "c",
Args: ArbitraryArgs,
Run: func(_ *Command, args []string) { cArgs = args },
}
var intFlagValue int
var stringFlagValue string
c.Flags().IntVar(&intFlagValue, "intf", -1, "")
c.Flags().StringVar(&stringFlagValue, "sf", "", "")
output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two")
if output != "" {
t.Errorf("Unexpected output: %v", err)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if c.ArgsLenAtDash() != 1 {
t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash())
}
if intFlagValue != 7 {
t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue)
}
if stringFlagValue != "abc" {
t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
}
got := strings.Join(cArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("Expected arguments: %q, got %q", expected, got)
}
}
func TestFlagShort(t *testing.T) {
var cArgs []string
c := &Command{
Use: "c",
Args: ArbitraryArgs,
Run: func(_ *Command, args []string) { cArgs = args },
}
var intFlagValue int
var stringFlagValue string
c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "")
output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", err)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if intFlagValue != 7 {
t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
}
if stringFlagValue != "abc" {
t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
}
got := strings.Join(cArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("Expected arguments: %q, got %q", expected, got)
}
}
func TestChildFlag(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
rootCmd.AddCommand(childCmd)
var intFlagValue int
childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
output, err := executeCommand(rootCmd, "child", "-i7")
if output != "" {
t.Errorf("Unexpected output: %v", err)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if intFlagValue != 7 {
t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
}
}
func TestChildFlagWithParentLocalFlag(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
rootCmd.AddCommand(childCmd)
var intFlagValue int
rootCmd.Flags().StringP("sf", "s", "", "")
childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
_, err := executeCommand(rootCmd, "child", "-i7", "-sabc")
if err == nil {
t.Errorf("Invalid flag should generate error")
}
checkStringContains(t, err.Error(), "unknown shorthand")
if intFlagValue != 7 {
t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
}
}
func TestFlagInvalidInput(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.Flags().IntP("intf", "i", -1, "")
_, err := executeCommand(rootCmd, "-iabc")
if err == nil {
t.Errorf("Invalid flag value should generate error")
}
checkStringContains(t, err.Error(), "invalid syntax")
}
func TestFlagBeforeCommand(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
rootCmd.AddCommand(childCmd)
var flagValue int
childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
// With short flag.
_, err := executeCommand(rootCmd, "-i7", "child")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if flagValue != 7 {
t.Errorf("Expected flag value: %v, got %v", 7, flagValue)
}
// With long flag.
_, err = executeCommand(rootCmd, "--intf=8", "child")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if flagValue != 8 {
t.Errorf("Expected flag value: %v, got %v", 9, flagValue)
}
}
func TestStripFlags(t *testing.T) {
tests := []struct {
input []string
output []string
}{
{
[]string{"foo", "bar"},
[]string{"foo", "bar"},
},
{
[]string{"foo", "--str", "-s"},
[]string{"foo"},
},
{
[]string{"-s", "foo", "--str", "bar"},
[]string{},
},
{
[]string{"-i10", "echo"},
[]string{"echo"},
},
{
[]string{"-i=10", "echo"},
[]string{"echo"},
},
{
[]string{"--int=100", "echo"},
[]string{"echo"},
},
{
[]string{"-ib", "echo", "-sfoo", "baz"},
[]string{"echo", "baz"},
},
{
[]string{"-i=baz", "bar", "-i", "foo", "blah"},
[]string{"bar", "blah"},
},
{
[]string{"--int=baz", "-sbar", "-i", "foo", "blah"},
[]string{"blah"},
},
{
[]string{"--bool", "bar", "-i", "foo", "blah"},
[]string{"bar", "blah"},
},
{
[]string{"-b", "bar", "-i", "foo", "blah"},
[]string{"bar", "blah"},
},
{
[]string{"--persist", "bar"},
[]string{"bar"},
},
{
[]string{"-p", "bar"},
[]string{"bar"},
},
}
c := &Command{Use: "c", Run: emptyRun}
c.PersistentFlags().BoolP("persist", "p", false, "")
c.Flags().IntP("int", "i", -1, "")
c.Flags().StringP("str", "s", "", "")
c.Flags().BoolP("bool", "b", false, "")
for i, test := range tests {
got := stripFlags(test.input, c)
if !reflect.DeepEqual(test.output, got) {
t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got)
}
}
}
func TestDisableFlagParsing(t *testing.T) {
var cArgs []string
c := &Command{
Use: "c",
DisableFlagParsing: true,
Run: func(_ *Command, args []string) {
cArgs = args
},
}
args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
output, err := executeCommand(c, args...)
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(args, cArgs) {
t.Errorf("Expected: %v, got: %v", args, cArgs)
}
}
func TestPersistentFlagsOnSameCommand(t *testing.T) {
var rootCmdArgs []string
rootCmd := &Command{
Use: "root",
Args: ArbitraryArgs,
Run: func(_ *Command, args []string) { rootCmdArgs = args },
}
var flagValue int
rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "")
output, err := executeCommand(rootCmd, "-i7", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(rootCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("rootCmdArgs expected: %q, got %q", expected, got)
}
if flagValue != 7 {
t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
}
}
// TestEmptyInputs checks,
// if flags correctly parsed with blank strings in args.
func TestEmptyInputs(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun}
var flagValue int
c.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
output, err := executeCommand(c, "", "-i7", "")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if flagValue != 7 {
t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
}
}
func TestOverwrittenFlag(t *testing.T) {
// TODO: This test fails, but should work.
t.Skip()
parent := &Command{Use: "parent", Run: emptyRun}
child := &Command{Use: "child", Run: emptyRun}
parent.PersistentFlags().Bool("boolf", false, "")
parent.PersistentFlags().Int("intf", -1, "")
child.Flags().String("strf", "", "")
child.Flags().Int("intf", -1, "")
parent.AddCommand(child)
childInherited := child.InheritedFlags()
childLocal := child.LocalFlags()
if childLocal.Lookup("strf") == nil {
t.Error(`LocalFlags expected to contain "strf", got "nil"`)
}
if childInherited.Lookup("boolf") == nil {
t.Error(`InheritedFlags expected to contain "boolf", got "nil"`)
}
if childInherited.Lookup("intf") != nil {
t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`)
}
if childLocal.Lookup("intf") == nil {
t.Error(`LocalFlags expected to contain "intf", got "nil"`)
}
}
func TestPersistentFlagsOnChild(t *testing.T) {
var childCmdArgs []string
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{
Use: "child",
Args: ArbitraryArgs,
Run: func(_ *Command, args []string) { childCmdArgs = args },
}
rootCmd.AddCommand(childCmd)
var parentFlagValue int
var childFlagValue int
rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "")
childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "")
output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
got := strings.Join(childCmdArgs, " ")
expected := "one two"
if got != expected {
t.Errorf("childCmdArgs expected: %q, got %q", expected, got)
}
if parentFlagValue != 8 {
t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue)
}
if childFlagValue != 7 {
t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue)
}
}
func TestRequiredFlags(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun}
c.Flags().String("foo1", "", "")
c.MarkFlagRequired("foo1")
c.Flags().String("foo2", "", "")
c.MarkFlagRequired("foo2")
c.Flags().String("bar", "", "")
expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2")
_, err := executeCommand(c)
got := err.Error()
if got != expected {
t.Errorf("Expected error: %q, got: %q", expected, got)
}
}
func TestPersistentRequiredFlags(t *testing.T) {
parent := &Command{Use: "parent", Run: emptyRun}
parent.PersistentFlags().String("foo1", "", "")
parent.MarkPersistentFlagRequired("foo1")
parent.PersistentFlags().String("foo2", "", "")
parent.MarkPersistentFlagRequired("foo2")
parent.Flags().String("foo3", "", "")
child := &Command{Use: "child", Run: emptyRun}
child.Flags().String("bar1", "", "")
child.MarkFlagRequired("bar1")
child.Flags().String("bar2", "", "")
child.MarkFlagRequired("bar2")
child.Flags().String("bar3", "", "")
parent.AddCommand(child)
expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2")
_, err := executeCommand(parent, "child")
if err.Error() != expected {
t.Errorf("Expected %q, got %q", expected, err.Error())
}
}
func TestInitHelpFlagMergesFlags(t *testing.T) {
usage := "custom flag"
rootCmd := &Command{Use: "root"}
rootCmd.PersistentFlags().Bool("help", false, "custom flag")
childCmd := &Command{Use: "child"}
rootCmd.AddCommand(childCmd)
childCmd.InitDefaultHelpFlag()
got := childCmd.Flags().Lookup("help").Usage
if got != usage {
t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got)
}
}
func TestHelpCommandExecuted(t *testing.T) {
rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
output, err := executeCommand(rootCmd, "help")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, rootCmd.Long)
}
func TestHelpCommandExecutedOnChild(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
rootCmd.AddCommand(childCmd)
output, err := executeCommand(rootCmd, "help", "child")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, childCmd.Long)
}
func TestSetHelpCommand(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun}
c.AddCommand(&Command{Use: "empty", Run: emptyRun})
expected := "WORKS"
c.SetHelpCommand(&Command{
Use: "help [command]",
Short: "Help about any command",
Long: `Help provides help for any command in the application.
Simply type ` + c.Name() + ` help [path to command] for full details.`,
Run: func(c *Command, _ []string) { c.Print(expected) },
})
got, err := executeCommand(c, "help")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if got != expected {
t.Errorf("Expected to contain %q, got %q", expected, got)
}
}
func TestHelpFlagExecuted(t *testing.T) {
rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
output, err := executeCommand(rootCmd, "--help")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, rootCmd.Long)
}
func TestHelpFlagExecutedOnChild(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
rootCmd.AddCommand(childCmd)
output, err := executeCommand(rootCmd, "child", "--help")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, childCmd.Long)
}
// TestHelpFlagInHelp checks,
// if '--help' flag is shown in help for child (executing `parent help child`),
// that has no other flags.
// Related to https://github.com/spf13/cobra/issues/302.
func TestHelpFlagInHelp(t *testing.T) {
parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}}
childCmd := &Command{Use: "child", Run: func(*Command, []string) {}}
parentCmd.AddCommand(childCmd)
output, err := executeCommand(parentCmd, "help", "child")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, "[flags]")
}
func TestFlagsInUsage(t *testing.T) {
rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}}
output, err := executeCommand(rootCmd, "--help")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, "[flags]")
}
func TestHelpExecutedOnNonRunnableChild(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Long: "Long description"}
rootCmd.AddCommand(childCmd)
output, err := executeCommand(rootCmd, "child")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, childCmd.Long)
}
func TestVersionFlagExecuted(t *testing.T) {
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
output, err := executeCommand(rootCmd, "--version", "arg1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, "root version 1.0.0")
}
func TestVersionTemplate(t *testing.T) {
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
output, err := executeCommand(rootCmd, "--version", "arg1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, "customized version: 1.0.0")
}
func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
rootCmd := &Command{Use: "root", Version: "1.0.0"}
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
output, err := executeCommand(rootCmd, "--version", "sub")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, "root version 1.0.0")
}
func TestVersionFlagOnlyAddedToRoot(t *testing.T) {
rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
_, err := executeCommand(rootCmd, "sub", "--version")
if err == nil {
t.Errorf("Expected error")
}
checkStringContains(t, err.Error(), "unknown flag: --version")
}
func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
_, err := executeCommand(rootCmd, "--version")
if err == nil {
t.Errorf("Expected error")
}
checkStringContains(t, err.Error(), "unknown flag: --version")
}
func TestUsageIsNotPrintedTwice(t *testing.T) {
var cmd = &Command{Use: "root"}
var sub = &Command{Use: "sub"}
cmd.AddCommand(sub)
output, _ := executeCommand(cmd, "")
if strings.Count(output, "Usage:") != 1 {
t.Error("Usage output is not printed exactly once")
}
}
func TestVisitParents(t *testing.T) {
c := &Command{Use: "app"}
sub := &Command{Use: "sub"}
dsub := &Command{Use: "dsub"}
sub.AddCommand(dsub)
c.AddCommand(sub)
total := 0
add := func(x *Command) {
total++
}
sub.VisitParents(add)
if total != 1 {
t.Errorf("Should have visited 1 parent but visited %d", total)
}
total = 0
dsub.VisitParents(add)
if total != 2 {
t.Errorf("Should have visited 2 parents but visited %d", total)
}
total = 0
c.VisitParents(add)
if total != 0 {
t.Errorf("Should have visited no parents but visited %d", total)
}
}
func TestSuggestions(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
timesCmd := &Command{
Use: "times",
SuggestFor: []string{"counts"},
Run: emptyRun,
}
rootCmd.AddCommand(timesCmd)
templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
tests := map[string]string{
"time": "times",
"tiems": "times",
"tims": "times",
"timeS": "times",
"rimes": "times",
"ti": "times",
"t": "times",
"timely": "times",
"ri": "",
"timezone": "",
"foo": "",
"counts": "times",
}
for typo, suggestion := range tests {
for _, suggestionsDisabled := range []bool{true, false} {
rootCmd.DisableSuggestions = suggestionsDisabled
var expected string
output, _ := executeCommand(rootCmd, typo)
if suggestion == "" || suggestionsDisabled {
expected = fmt.Sprintf(templateWithoutSuggestions, typo)
} else {
expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion)
}
if output != expected {
t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
}
}
}
}
func TestRemoveCommand(t *testing.T) {
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
rootCmd.AddCommand(childCmd)
rootCmd.RemoveCommand(childCmd)
_, err := executeCommand(rootCmd, "child")
if err == nil {
t.Error("Expected error on calling removed command. Got nil.")
}
}
func TestReplaceCommandWithRemove(t *testing.T) {
childUsed := 0
rootCmd := &Command{Use: "root", Run: emptyRun}
child1Cmd := &Command{
Use: "child",
Run: func(*Command, []string) { childUsed = 1 },
}
child2Cmd := &Command{
Use: "child",
Run: func(*Command, []string) { childUsed = 2 },
}
rootCmd.AddCommand(child1Cmd)
rootCmd.RemoveCommand(child1Cmd)
rootCmd.AddCommand(child2Cmd)
output, err := executeCommand(rootCmd, "child")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if childUsed == 1 {
t.Error("Removed command shouldn't be called")
}
if childUsed != 2 {
t.Error("Replacing command should have been called but didn't")
}
}
func TestDeprecatedCommand(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
deprecatedCmd := &Command{
Use: "deprecated",
Deprecated: "This command is deprecated",
Run: emptyRun,
}
rootCmd.AddCommand(deprecatedCmd)
output, err := executeCommand(rootCmd, "deprecated")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
checkStringContains(t, output, deprecatedCmd.Deprecated)
}
func TestHooks(t *testing.T) {
var (
persPreArgs string
preArgs string
runArgs string
postArgs string
persPostArgs string
)
c := &Command{
Use: "c",
PersistentPreRun: func(_ *Command, args []string) {
persPreArgs = strings.Join(args, " ")
},
PreRun: func(_ *Command, args []string) {
preArgs = strings.Join(args, " ")
},
Run: func(_ *Command, args []string) {
runArgs = strings.Join(args, " ")
},
PostRun: func(_ *Command, args []string) {
postArgs = strings.Join(args, " ")
},
PersistentPostRun: func(_ *Command, args []string) {
persPostArgs = strings.Join(args, " ")
},
}
output, err := executeCommand(c, "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if persPreArgs != "one two" {
t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs)
}
if preArgs != "one two" {
t.Errorf("Expected preArgs %q, got %q", "one two", preArgs)
}
if runArgs != "one two" {
t.Errorf("Expected runArgs %q, got %q", "one two", runArgs)
}
if postArgs != "one two" {
t.Errorf("Expected postArgs %q, got %q", "one two", postArgs)
}
if persPostArgs != "one two" {
t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs)
}
}
func TestPersistentHooks(t *testing.T) {
var (
parentPersPreArgs string
parentPreArgs string
parentRunArgs string
parentPostArgs string
parentPersPostArgs string
)
var (
childPersPreArgs string
childPreArgs string
childRunArgs string
childPostArgs string
childPersPostArgs string
)
parentCmd := &Command{
Use: "parent",
PersistentPreRun: func(_ *Command, args []string) {
parentPersPreArgs = strings.Join(args, " ")
},
PreRun: func(_ *Command, args []string) {
parentPreArgs = strings.Join(args, " ")
},
Run: func(_ *Command, args []string) {
parentRunArgs = strings.Join(args, " ")
},
PostRun: func(_ *Command, args []string) {
parentPostArgs = strings.Join(args, " ")
},
PersistentPostRun: func(_ *Command, args []string) {
parentPersPostArgs = strings.Join(args, " ")
},
}
childCmd := &Command{
Use: "child",
PersistentPreRun: func(_ *Command, args []string) {
childPersPreArgs = strings.Join(args, " ")
},
PreRun: func(_ *Command, args []string) {
childPreArgs = strings.Join(args, " ")
},
Run: func(_ *Command, args []string) {
childRunArgs = strings.Join(args, " ")
},
PostRun: func(_ *Command, args []string) {
childPostArgs = strings.Join(args, " ")
},
PersistentPostRun: func(_ *Command, args []string) {
childPersPostArgs = strings.Join(args, " ")
},
}
parentCmd.AddCommand(childCmd)
output, err := executeCommand(parentCmd, "child", "one", "two")
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// TODO: This test fails, but should not.
// Related to https://github.com/spf13/cobra/issues/252.
//
// if parentPersPreArgs != "one two" {
// t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs)
// }
if parentPreArgs != "" {
t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs)
}
if parentRunArgs != "" {
t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs)
}
if parentPostArgs != "" {
t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs)
}
// TODO: This test fails, but should not.
// Related to https://github.com/spf13/cobra/issues/252.
//
// if parentPersPostArgs != "one two" {
// t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs)
// }
if childPersPreArgs != "one two" {
t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs)
}
if childPreArgs != "one two" {
t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs)
}
if childRunArgs != "one two" {
t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs)
}
if childPostArgs != "one two" {
t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs)
}
if childPersPostArgs != "one two" {
t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs)
}
}
// Related to https://github.com/spf13/cobra/issues/521.
func TestGlobalNormFuncPropagation(t *testing.T) {
normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(name)
}
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}
rootCmd.AddCommand(childCmd)
rootCmd.SetGlobalNormalizationFunc(normFunc)
if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
t.Error("rootCmd seems to have a wrong normalization function")
}
if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() {
t.Error("childCmd should have had the normalization function of rootCmd")
}
}
// Related to https://github.com/spf13/cobra/issues/521.
func TestNormPassedOnLocal(t *testing.T) {
toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(strings.ToUpper(name))
}
c := &Command{}
c.Flags().Bool("flagname", true, "this is a dummy flag")
c.SetGlobalNormalizationFunc(toUpper)
if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") {
t.Error("Normalization function should be passed on to Local flag set")
}
}
// Related to https://github.com/spf13/cobra/issues/521.
func TestNormPassedOnInherited(t *testing.T) {
toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(strings.ToUpper(name))
}
c := &Command{}
c.SetGlobalNormalizationFunc(toUpper)
child1 := &Command{}
c.AddCommand(child1)
c.PersistentFlags().Bool("flagname", true, "")
child2 := &Command{}
c.AddCommand(child2)
inherited := child1.InheritedFlags()
if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
t.Error("Normalization function should be passed on to inherited flag set in command added before flag")
}
inherited = child2.InheritedFlags()
if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
t.Error("Normalization function should be passed on to inherited flag set in command added after flag")
}
}
// Related to https://github.com/spf13/cobra/issues/521.
func TestConsistentNormalizedName(t *testing.T) {
toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(strings.ToUpper(name))
}
n := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(name)
}
c := &Command{}
c.Flags().Bool("flagname", true, "")
c.SetGlobalNormalizationFunc(toUpper)
c.SetGlobalNormalizationFunc(n)
if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") {
t.Error("Normalizing flag names should not result in duplicate flags")
}
}
func TestFlagOnPflagCommandLine(t *testing.T) {
flagName := "flagOnCommandLine"
pflag.String(flagName, "", "about my flag")
c := &Command{Use: "c", Run: emptyRun}
c.AddCommand(&Command{Use: "child", Run: emptyRun})
output, _ := executeCommand(c, "--help")
checkStringContains(t, output, flagName)
resetCommandLineFlagSet()
}
// TestHiddenCommandExecutes checks,
// if hidden commands run as intended.
func TestHiddenCommandExecutes(t *testing.T) {
executed := false
c := &Command{
Use: "c",
Hidden: true,
Run: func(*Command, []string) { executed = true },
}
output, err := executeCommand(c)
if output != "" {
t.Errorf("Unexpected output: %v", output)
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !executed {
t.Error("Hidden command should have been executed")
}
}
// test to ensure hidden commands do not show up in usage/help text
func TestHiddenCommandIsHidden(t *testing.T) {
c := &Command{Use: "c", Hidden: true, Run: emptyRun}
if c.IsAvailableCommand() {
t.Errorf("Hidden command should be unavailable")
}
}
func TestCommandsAreSorted(t *testing.T) {
EnableCommandSorting = true
originalNames := []string{"middle", "zlast", "afirst"}
expectedNames := []string{"afirst", "middle", "zlast"}
var rootCmd = &Command{Use: "root"}
for _, name := range originalNames {
rootCmd.AddCommand(&Command{Use: name})
}
for i, c := range rootCmd.Commands() {
got := c.Name()
if expectedNames[i] != got {
t.Errorf("Expected: %s, got: %s", expectedNames[i], got)
}
}
EnableCommandSorting = true
}
func TestEnableCommandSortingIsDisabled(t *testing.T) {
EnableCommandSorting = false
originalNames := []string{"middle", "zlast", "afirst"}
var rootCmd = &Command{Use: "root"}
for _, name := range originalNames {
rootCmd.AddCommand(&Command{Use: name})
}
for i, c := range rootCmd.Commands() {
got := c.Name()
if originalNames[i] != got {
t.Errorf("expected: %s, got: %s", originalNames[i], got)
}
}
EnableCommandSorting = true
}
func TestSetOutput(t *testing.T) {
c := &Command{}
c.SetOutput(nil)
if out := c.OutOrStdout(); out != os.Stdout {
t.Errorf("Expected setting output to nil to revert back to stdout")
}
}
func TestFlagErrorFunc(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun}
expectedFmt := "This is expected: %v"
c.SetFlagErrorFunc(func(_ *Command, err error) error {
return fmt.Errorf(expectedFmt, err)
})
_, err := executeCommand(c, "--unknown-flag")
got := err.Error()
expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag")
if got != expected {
t.Errorf("Expected %v, got %v", expected, got)
}
}
// TestSortedFlags checks,
// if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
// Related to https://github.com/spf13/cobra/issues/404.
func TestSortedFlags(t *testing.T) {
c := &Command{}
c.Flags().SortFlags = false
names := []string{"C", "B", "A", "D"}
for _, name := range names {
c.Flags().Bool(name, false, "")
}
i := 0
c.LocalFlags().VisitAll(func(f *pflag.Flag) {
if i == len(names) {
return
}
if stringInSlice(f.Name, names) {
if names[i] != f.Name {
t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
}
i++
}
})
}
// TestMergeCommandLineToFlags checks,
// if pflag.CommandLine is correctly merged to c.Flags() after first call
// of c.mergePersistentFlags.
// Related to https://github.com/spf13/cobra/issues/443.
func TestMergeCommandLineToFlags(t *testing.T) {
pflag.Bool("boolflag", false, "")
c := &Command{Use: "c", Run: emptyRun}
c.mergePersistentFlags()
if c.Flags().Lookup("boolflag") == nil {
t.Fatal("Expecting to have flag from CommandLine in c.Flags()")
}
resetCommandLineFlagSet()
}
// TestUseDeprecatedFlags checks,
// if cobra.Execute() prints a message, if a deprecated flag is used.
// Related to https://github.com/spf13/cobra/issues/463.
func TestUseDeprecatedFlags(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun}
c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")
output, err := executeCommand(c, "c", "-d")
if err != nil {
t.Error("Unexpected error:", err)
}
checkStringContains(t, output, "This flag is deprecated")
}
func TestTraverseWithParentFlags(t *testing.T) {
rootCmd := &Command{Use: "root", TraverseChildren: true}
rootCmd.Flags().String("str", "", "")
rootCmd.Flags().BoolP("bool", "b", false, "")
childCmd := &Command{Use: "child"}
childCmd.Flags().Int("int", -1, "")
rootCmd.AddCommand(childCmd)
c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(args) != 1 && args[0] != "--add" {
t.Errorf("Wrong args: %v", args)
}
if c.Name() != childCmd.Name() {
t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
}
}
func TestTraverseNoParentFlags(t *testing.T) {
rootCmd := &Command{Use: "root", TraverseChildren: true}
rootCmd.Flags().String("foo", "", "foo things")
childCmd := &Command{Use: "child"}
childCmd.Flags().String("str", "", "")
rootCmd.AddCommand(childCmd)
c, args, err := rootCmd.Traverse([]string{"child"})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(args) != 0 {
t.Errorf("Wrong args %v", args)
}
if c.Name() != childCmd.Name() {
t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
}
}
func TestTraverseWithBadParentFlags(t *testing.T) {
rootCmd := &Command{Use: "root", TraverseChildren: true}
childCmd := &Command{Use: "child"}
childCmd.Flags().String("str", "", "")
rootCmd.AddCommand(childCmd)
expected := "unknown flag: --str"
c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"})
if err == nil || !strings.Contains(err.Error(), expected) {
t.Errorf("Expected error, %q, got %q", expected, err)
}
if c != nil {
t.Errorf("Expected nil command")
}
}
func TestTraverseWithBadChildFlag(t *testing.T) {
rootCmd := &Command{Use: "root", TraverseChildren: true}
rootCmd.Flags().String("str", "", "")
childCmd := &Command{Use: "child"}
rootCmd.AddCommand(childCmd)
// Expect no error because the last commands args shouldn't be parsed in
// Traverse.
c, args, err := rootCmd.Traverse([]string{"child", "--str"})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(args) != 1 && args[0] != "--str" {
t.Errorf("Wrong args: %v", args)
}
if c.Name() != childCmd.Name() {
t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name())
}
}
func TestTraverseWithTwoSubcommands(t *testing.T) {
rootCmd := &Command{Use: "root", TraverseChildren: true}
subCmd := &Command{Use: "sub", TraverseChildren: true}
rootCmd.AddCommand(subCmd)
subsubCmd := &Command{
Use: "subsub",
}
subCmd.AddCommand(subsubCmd)
c, _, err := rootCmd.Traverse([]string{"sub", "subsub"})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if c.Name() != subsubCmd.Name() {
t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name())
}
}
// TestUpdateName checks if c.Name() updates on changed c.Use.
// Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
func TestUpdateName(t *testing.T) {
c := &Command{Use: "name xyz"}
originalName := c.Name()
c.Use = "changedName abc"
if originalName == c.Name() || c.Name() != "changedName" {
t.Error("c.Name() should be updated on changed c.Use")
}
}
type calledAsTestcase struct {
args []string
call string
want string
epm bool
tc bool
}
func (tc *calledAsTestcase) test(t *testing.T) {
defer func(ov bool) { EnablePrefixMatching = ov }(EnablePrefixMatching)
EnablePrefixMatching = tc.epm
var called *Command
run := func(c *Command, _ []string) { t.Logf("called: %q", c.Name()); called = c }
parent := &Command{Use: "parent", Run: run}
child1 := &Command{Use: "child1", Run: run, Aliases: []string{"this"}}
child2 := &Command{Use: "child2", Run: run, Aliases: []string{"that"}}
parent.AddCommand(child1)
parent.AddCommand(child2)
parent.SetArgs(tc.args)
output := new(bytes.Buffer)
parent.SetOutput(output)
parent.Execute()
if called == nil {
if tc.call != "" {
t.Errorf("missing expected call to command: %s", tc.call)
}
return
}
if called.Name() != tc.call {
t.Errorf("called command == %q; Wanted %q", called.Name(), tc.call)
} else if got := called.CalledAs(); got != tc.want {
t.Errorf("%s.CalledAs() == %q; Wanted: %q", tc.call, got, tc.want)
}
}
func TestCalledAs(t *testing.T) {
tests := map[string]calledAsTestcase{
"find/no-args": {nil, "parent", "parent", false, false},
"find/real-name": {[]string{"child1"}, "child1", "child1", false, false},
"find/full-alias": {[]string{"that"}, "child2", "that", false, false},
"find/part-no-prefix": {[]string{"thi"}, "", "", false, false},
"find/part-alias": {[]string{"thi"}, "child1", "this", true, false},
"find/conflict": {[]string{"th"}, "", "", true, false},
"traverse/no-args": {nil, "parent", "parent", false, true},
"traverse/real-name": {[]string{"child1"}, "child1", "child1", false, true},
"traverse/full-alias": {[]string{"that"}, "child2", "that", false, true},
"traverse/part-no-prefix": {[]string{"thi"}, "", "", false, true},
"traverse/part-alias": {[]string{"thi"}, "child1", "this", true, true},
"traverse/conflict": {[]string{"th"}, "", "", true, true},
}
for name, tc := range tests {
t.Run(name, tc.test)
}
}