...

Source file src/github.com/spf13/cobra/command_test.go

Documentation: github.com/spf13/cobra

     1  // Copyright 2013-2023 The Cobra Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cobra
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/spf13/pflag"
    28  )
    29  
    30  func emptyRun(*Command, []string) {}
    31  
    32  func executeCommand(root *Command, args ...string) (output string, err error) {
    33  	_, output, err = executeCommandC(root, args...)
    34  	return output, err
    35  }
    36  
    37  func executeCommandWithContext(ctx context.Context, root *Command, args ...string) (output string, err error) {
    38  	buf := new(bytes.Buffer)
    39  	root.SetOut(buf)
    40  	root.SetErr(buf)
    41  	root.SetArgs(args)
    42  
    43  	err = root.ExecuteContext(ctx)
    44  
    45  	return buf.String(), err
    46  }
    47  
    48  func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) {
    49  	buf := new(bytes.Buffer)
    50  	root.SetOut(buf)
    51  	root.SetErr(buf)
    52  	root.SetArgs(args)
    53  
    54  	c, err = root.ExecuteC()
    55  
    56  	return c, buf.String(), err
    57  }
    58  
    59  func executeCommandWithContextC(ctx context.Context, root *Command, args ...string) (c *Command, output string, err error) {
    60  	buf := new(bytes.Buffer)
    61  	root.SetOut(buf)
    62  	root.SetErr(buf)
    63  	root.SetArgs(args)
    64  
    65  	c, err = root.ExecuteContextC(ctx)
    66  
    67  	return c, buf.String(), err
    68  }
    69  
    70  func resetCommandLineFlagSet() {
    71  	pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
    72  }
    73  
    74  func checkStringContains(t *testing.T, got, expected string) {
    75  	if !strings.Contains(got, expected) {
    76  		t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got)
    77  	}
    78  }
    79  
    80  func checkStringOmits(t *testing.T, got, expected string) {
    81  	if strings.Contains(got, expected) {
    82  		t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got)
    83  	}
    84  }
    85  
    86  const onetwo = "one two"
    87  
    88  func TestSingleCommand(t *testing.T) {
    89  	var rootCmdArgs []string
    90  	rootCmd := &Command{
    91  		Use:  "root",
    92  		Args: ExactArgs(2),
    93  		Run:  func(_ *Command, args []string) { rootCmdArgs = args },
    94  	}
    95  	aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun}
    96  	bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun}
    97  	rootCmd.AddCommand(aCmd, bCmd)
    98  
    99  	output, err := executeCommand(rootCmd, "one", "two")
   100  	if output != "" {
   101  		t.Errorf("Unexpected output: %v", output)
   102  	}
   103  	if err != nil {
   104  		t.Errorf("Unexpected error: %v", err)
   105  	}
   106  
   107  	got := strings.Join(rootCmdArgs, " ")
   108  	if got != onetwo {
   109  		t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
   110  	}
   111  }
   112  
   113  func TestChildCommand(t *testing.T) {
   114  	var child1CmdArgs []string
   115  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
   116  	child1Cmd := &Command{
   117  		Use:  "child1",
   118  		Args: ExactArgs(2),
   119  		Run:  func(_ *Command, args []string) { child1CmdArgs = args },
   120  	}
   121  	child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun}
   122  	rootCmd.AddCommand(child1Cmd, child2Cmd)
   123  
   124  	output, err := executeCommand(rootCmd, "child1", "one", "two")
   125  	if output != "" {
   126  		t.Errorf("Unexpected output: %v", output)
   127  	}
   128  	if err != nil {
   129  		t.Errorf("Unexpected error: %v", err)
   130  	}
   131  
   132  	got := strings.Join(child1CmdArgs, " ")
   133  	if got != onetwo {
   134  		t.Errorf("child1CmdArgs expected: %q, got: %q", onetwo, got)
   135  	}
   136  }
   137  
   138  func TestCallCommandWithoutSubcommands(t *testing.T) {
   139  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
   140  	_, err := executeCommand(rootCmd)
   141  	if err != nil {
   142  		t.Errorf("Calling command without subcommands should not have error: %v", err)
   143  	}
   144  }
   145  
   146  func TestRootExecuteUnknownCommand(t *testing.T) {
   147  	rootCmd := &Command{Use: "root", Run: emptyRun}
   148  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
   149  
   150  	output, _ := executeCommand(rootCmd, "unknown")
   151  
   152  	expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n"
   153  
   154  	if output != expected {
   155  		t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output)
   156  	}
   157  }
   158  
   159  func TestSubcommandExecuteC(t *testing.T) {
   160  	rootCmd := &Command{Use: "root", Run: emptyRun}
   161  	childCmd := &Command{Use: "child", Run: emptyRun}
   162  	rootCmd.AddCommand(childCmd)
   163  
   164  	c, output, err := executeCommandC(rootCmd, "child")
   165  	if output != "" {
   166  		t.Errorf("Unexpected output: %v", output)
   167  	}
   168  	if err != nil {
   169  		t.Errorf("Unexpected error: %v", err)
   170  	}
   171  
   172  	if c.Name() != "child" {
   173  		t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name())
   174  	}
   175  }
   176  
   177  func TestExecuteContext(t *testing.T) {
   178  	ctx := context.TODO()
   179  
   180  	ctxRun := func(cmd *Command, args []string) {
   181  		if cmd.Context() != ctx {
   182  			t.Errorf("Command %q must have context when called with ExecuteContext", cmd.Use)
   183  		}
   184  	}
   185  
   186  	rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun}
   187  	childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun}
   188  	granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun}
   189  
   190  	childCmd.AddCommand(granchildCmd)
   191  	rootCmd.AddCommand(childCmd)
   192  
   193  	if _, err := executeCommandWithContext(ctx, rootCmd, ""); err != nil {
   194  		t.Errorf("Root command must not fail: %+v", err)
   195  	}
   196  
   197  	if _, err := executeCommandWithContext(ctx, rootCmd, "child"); err != nil {
   198  		t.Errorf("Subcommand must not fail: %+v", err)
   199  	}
   200  
   201  	if _, err := executeCommandWithContext(ctx, rootCmd, "child", "grandchild"); err != nil {
   202  		t.Errorf("Command child must not fail: %+v", err)
   203  	}
   204  }
   205  
   206  func TestExecuteContextC(t *testing.T) {
   207  	ctx := context.TODO()
   208  
   209  	ctxRun := func(cmd *Command, args []string) {
   210  		if cmd.Context() != ctx {
   211  			t.Errorf("Command %q must have context when called with ExecuteContext", cmd.Use)
   212  		}
   213  	}
   214  
   215  	rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun}
   216  	childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun}
   217  	granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun}
   218  
   219  	childCmd.AddCommand(granchildCmd)
   220  	rootCmd.AddCommand(childCmd)
   221  
   222  	if _, _, err := executeCommandWithContextC(ctx, rootCmd, ""); err != nil {
   223  		t.Errorf("Root command must not fail: %+v", err)
   224  	}
   225  
   226  	if _, _, err := executeCommandWithContextC(ctx, rootCmd, "child"); err != nil {
   227  		t.Errorf("Subcommand must not fail: %+v", err)
   228  	}
   229  
   230  	if _, _, err := executeCommandWithContextC(ctx, rootCmd, "child", "grandchild"); err != nil {
   231  		t.Errorf("Command child must not fail: %+v", err)
   232  	}
   233  }
   234  
   235  func TestExecute_NoContext(t *testing.T) {
   236  	run := func(cmd *Command, args []string) {
   237  		if cmd.Context() != context.Background() {
   238  			t.Errorf("Command %s must have background context", cmd.Use)
   239  		}
   240  	}
   241  
   242  	rootCmd := &Command{Use: "root", Run: run, PreRun: run}
   243  	childCmd := &Command{Use: "child", Run: run, PreRun: run}
   244  	granchildCmd := &Command{Use: "grandchild", Run: run, PreRun: run}
   245  
   246  	childCmd.AddCommand(granchildCmd)
   247  	rootCmd.AddCommand(childCmd)
   248  
   249  	if _, err := executeCommand(rootCmd, ""); err != nil {
   250  		t.Errorf("Root command must not fail: %+v", err)
   251  	}
   252  
   253  	if _, err := executeCommand(rootCmd, "child"); err != nil {
   254  		t.Errorf("Subcommand must not fail: %+v", err)
   255  	}
   256  
   257  	if _, err := executeCommand(rootCmd, "child", "grandchild"); err != nil {
   258  		t.Errorf("Command child must not fail: %+v", err)
   259  	}
   260  }
   261  
   262  func TestRootUnknownCommandSilenced(t *testing.T) {
   263  	rootCmd := &Command{Use: "root", Run: emptyRun}
   264  	rootCmd.SilenceErrors = true
   265  	rootCmd.SilenceUsage = true
   266  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
   267  
   268  	output, _ := executeCommand(rootCmd, "unknown")
   269  	if output != "" {
   270  		t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output)
   271  	}
   272  }
   273  
   274  func TestCommandAlias(t *testing.T) {
   275  	var timesCmdArgs []string
   276  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
   277  	echoCmd := &Command{
   278  		Use:     "echo",
   279  		Aliases: []string{"say", "tell"},
   280  		Args:    NoArgs,
   281  		Run:     emptyRun,
   282  	}
   283  	timesCmd := &Command{
   284  		Use:  "times",
   285  		Args: ExactArgs(2),
   286  		Run:  func(_ *Command, args []string) { timesCmdArgs = args },
   287  	}
   288  	echoCmd.AddCommand(timesCmd)
   289  	rootCmd.AddCommand(echoCmd)
   290  
   291  	output, err := executeCommand(rootCmd, "tell", "times", "one", "two")
   292  	if output != "" {
   293  		t.Errorf("Unexpected output: %v", output)
   294  	}
   295  	if err != nil {
   296  		t.Errorf("Unexpected error: %v", err)
   297  	}
   298  
   299  	got := strings.Join(timesCmdArgs, " ")
   300  	if got != onetwo {
   301  		t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got)
   302  	}
   303  }
   304  
   305  func TestEnablePrefixMatching(t *testing.T) {
   306  	EnablePrefixMatching = true
   307  
   308  	var aCmdArgs []string
   309  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
   310  	aCmd := &Command{
   311  		Use:  "aCmd",
   312  		Args: ExactArgs(2),
   313  		Run:  func(_ *Command, args []string) { aCmdArgs = args },
   314  	}
   315  	bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun}
   316  	rootCmd.AddCommand(aCmd, bCmd)
   317  
   318  	output, err := executeCommand(rootCmd, "a", "one", "two")
   319  	if output != "" {
   320  		t.Errorf("Unexpected output: %v", output)
   321  	}
   322  	if err != nil {
   323  		t.Errorf("Unexpected error: %v", err)
   324  	}
   325  
   326  	got := strings.Join(aCmdArgs, " ")
   327  	if got != onetwo {
   328  		t.Errorf("aCmdArgs expected: %q, got: %q", onetwo, got)
   329  	}
   330  
   331  	EnablePrefixMatching = defaultPrefixMatching
   332  }
   333  
   334  func TestAliasPrefixMatching(t *testing.T) {
   335  	EnablePrefixMatching = true
   336  
   337  	var timesCmdArgs []string
   338  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
   339  	echoCmd := &Command{
   340  		Use:     "echo",
   341  		Aliases: []string{"say", "tell"},
   342  		Args:    NoArgs,
   343  		Run:     emptyRun,
   344  	}
   345  	timesCmd := &Command{
   346  		Use:  "times",
   347  		Args: ExactArgs(2),
   348  		Run:  func(_ *Command, args []string) { timesCmdArgs = args },
   349  	}
   350  	echoCmd.AddCommand(timesCmd)
   351  	rootCmd.AddCommand(echoCmd)
   352  
   353  	output, err := executeCommand(rootCmd, "sa", "times", "one", "two")
   354  	if output != "" {
   355  		t.Errorf("Unexpected output: %v", output)
   356  	}
   357  	if err != nil {
   358  		t.Errorf("Unexpected error: %v", err)
   359  	}
   360  
   361  	got := strings.Join(timesCmdArgs, " ")
   362  	if got != onetwo {
   363  		t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got)
   364  	}
   365  
   366  	EnablePrefixMatching = defaultPrefixMatching
   367  }
   368  
   369  // TestPlugin checks usage as plugin for another command such as kubectl.  The
   370  // executable is `kubectl-plugin`, but we run it as `kubectl plugin`. The help
   371  // text should reflect the way we run the command.
   372  func TestPlugin(t *testing.T) {
   373  	rootCmd := &Command{
   374  		Use:  "plugin",
   375  		Args: NoArgs,
   376  		Annotations: map[string]string{
   377  			CommandDisplayNameAnnotation: "kubectl plugin",
   378  		},
   379  	}
   380  
   381  	subCmd := &Command{Use: "sub [flags]", Args: NoArgs, Run: emptyRun}
   382  	rootCmd.AddCommand(subCmd)
   383  
   384  	rootHelp, err := executeCommand(rootCmd, "-h")
   385  	if err != nil {
   386  		t.Errorf("Unexpected error: %v", err)
   387  	}
   388  
   389  	checkStringContains(t, rootHelp, "kubectl plugin [command]")
   390  
   391  	childHelp, err := executeCommand(rootCmd, "sub", "-h")
   392  	if err != nil {
   393  		t.Errorf("Unexpected error: %v", err)
   394  	}
   395  
   396  	checkStringContains(t, childHelp, "kubectl plugin sub [flags]")
   397  }
   398  
   399  // TestChildSameName checks the correct behaviour of cobra in cases,
   400  // when an application with name "foo" and with subcommand "foo"
   401  // is executed with args "foo foo".
   402  func TestChildSameName(t *testing.T) {
   403  	var fooCmdArgs []string
   404  	rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
   405  	fooCmd := &Command{
   406  		Use:  "foo",
   407  		Args: ExactArgs(2),
   408  		Run:  func(_ *Command, args []string) { fooCmdArgs = args },
   409  	}
   410  	barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
   411  	rootCmd.AddCommand(fooCmd, barCmd)
   412  
   413  	output, err := executeCommand(rootCmd, "foo", "one", "two")
   414  	if output != "" {
   415  		t.Errorf("Unexpected output: %v", output)
   416  	}
   417  	if err != nil {
   418  		t.Errorf("Unexpected error: %v", err)
   419  	}
   420  
   421  	got := strings.Join(fooCmdArgs, " ")
   422  	if got != onetwo {
   423  		t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got)
   424  	}
   425  }
   426  
   427  // TestGrandChildSameName checks the correct behaviour of cobra in cases,
   428  // when user has a root command and a grand child
   429  // with the same name.
   430  func TestGrandChildSameName(t *testing.T) {
   431  	var fooCmdArgs []string
   432  	rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
   433  	barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
   434  	fooCmd := &Command{
   435  		Use:  "foo",
   436  		Args: ExactArgs(2),
   437  		Run:  func(_ *Command, args []string) { fooCmdArgs = args },
   438  	}
   439  	barCmd.AddCommand(fooCmd)
   440  	rootCmd.AddCommand(barCmd)
   441  
   442  	output, err := executeCommand(rootCmd, "bar", "foo", "one", "two")
   443  	if output != "" {
   444  		t.Errorf("Unexpected output: %v", output)
   445  	}
   446  	if err != nil {
   447  		t.Errorf("Unexpected error: %v", err)
   448  	}
   449  
   450  	got := strings.Join(fooCmdArgs, " ")
   451  	if got != onetwo {
   452  		t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got)
   453  	}
   454  }
   455  
   456  func TestFlagLong(t *testing.T) {
   457  	var cArgs []string
   458  	c := &Command{
   459  		Use:  "c",
   460  		Args: ArbitraryArgs,
   461  		Run:  func(_ *Command, args []string) { cArgs = args },
   462  	}
   463  
   464  	var intFlagValue int
   465  	var stringFlagValue string
   466  	c.Flags().IntVar(&intFlagValue, "intf", -1, "")
   467  	c.Flags().StringVar(&stringFlagValue, "sf", "", "")
   468  
   469  	output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two")
   470  	if output != "" {
   471  		t.Errorf("Unexpected output: %v", output)
   472  	}
   473  	if err != nil {
   474  		t.Errorf("Unexpected error: %v", err)
   475  	}
   476  
   477  	if c.ArgsLenAtDash() != 1 {
   478  		t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash())
   479  	}
   480  	if intFlagValue != 7 {
   481  		t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue)
   482  	}
   483  	if stringFlagValue != "abc" {
   484  		t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
   485  	}
   486  
   487  	got := strings.Join(cArgs, " ")
   488  	if got != onetwo {
   489  		t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
   490  	}
   491  }
   492  
   493  func TestFlagShort(t *testing.T) {
   494  	var cArgs []string
   495  	c := &Command{
   496  		Use:  "c",
   497  		Args: ArbitraryArgs,
   498  		Run:  func(_ *Command, args []string) { cArgs = args },
   499  	}
   500  
   501  	var intFlagValue int
   502  	var stringFlagValue string
   503  	c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
   504  	c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "")
   505  
   506  	output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two")
   507  	if output != "" {
   508  		t.Errorf("Unexpected output: %v", output)
   509  	}
   510  	if err != nil {
   511  		t.Errorf("Unexpected error: %v", err)
   512  	}
   513  
   514  	if intFlagValue != 7 {
   515  		t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
   516  	}
   517  	if stringFlagValue != "abc" {
   518  		t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
   519  	}
   520  
   521  	got := strings.Join(cArgs, " ")
   522  	if got != onetwo {
   523  		t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
   524  	}
   525  }
   526  
   527  func TestChildFlag(t *testing.T) {
   528  	rootCmd := &Command{Use: "root", Run: emptyRun}
   529  	childCmd := &Command{Use: "child", Run: emptyRun}
   530  	rootCmd.AddCommand(childCmd)
   531  
   532  	var intFlagValue int
   533  	childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
   534  
   535  	output, err := executeCommand(rootCmd, "child", "-i7")
   536  	if output != "" {
   537  		t.Errorf("Unexpected output: %v", output)
   538  	}
   539  	if err != nil {
   540  		t.Errorf("Unexpected error: %v", err)
   541  	}
   542  
   543  	if intFlagValue != 7 {
   544  		t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
   545  	}
   546  }
   547  
   548  func TestChildFlagWithParentLocalFlag(t *testing.T) {
   549  	rootCmd := &Command{Use: "root", Run: emptyRun}
   550  	childCmd := &Command{Use: "child", Run: emptyRun}
   551  	rootCmd.AddCommand(childCmd)
   552  
   553  	var intFlagValue int
   554  	rootCmd.Flags().StringP("sf", "s", "", "")
   555  	childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
   556  
   557  	_, err := executeCommand(rootCmd, "child", "-i7", "-sabc")
   558  	if err == nil {
   559  		t.Errorf("Invalid flag should generate error")
   560  	}
   561  
   562  	checkStringContains(t, err.Error(), "unknown shorthand")
   563  
   564  	if intFlagValue != 7 {
   565  		t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
   566  	}
   567  }
   568  
   569  func TestFlagInvalidInput(t *testing.T) {
   570  	rootCmd := &Command{Use: "root", Run: emptyRun}
   571  	rootCmd.Flags().IntP("intf", "i", -1, "")
   572  
   573  	_, err := executeCommand(rootCmd, "-iabc")
   574  	if err == nil {
   575  		t.Errorf("Invalid flag value should generate error")
   576  	}
   577  
   578  	checkStringContains(t, err.Error(), "invalid syntax")
   579  }
   580  
   581  func TestFlagBeforeCommand(t *testing.T) {
   582  	rootCmd := &Command{Use: "root", Run: emptyRun}
   583  	childCmd := &Command{Use: "child", Run: emptyRun}
   584  	rootCmd.AddCommand(childCmd)
   585  
   586  	var flagValue int
   587  	childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
   588  
   589  	// With short flag.
   590  	_, err := executeCommand(rootCmd, "-i7", "child")
   591  	if err != nil {
   592  		t.Errorf("Unexpected error: %v", err)
   593  	}
   594  	if flagValue != 7 {
   595  		t.Errorf("Expected flag value: %v, got %v", 7, flagValue)
   596  	}
   597  
   598  	// With long flag.
   599  	_, err = executeCommand(rootCmd, "--intf=8", "child")
   600  	if err != nil {
   601  		t.Errorf("Unexpected error: %v", err)
   602  	}
   603  	if flagValue != 8 {
   604  		t.Errorf("Expected flag value: %v, got %v", 9, flagValue)
   605  	}
   606  }
   607  
   608  func TestStripFlags(t *testing.T) {
   609  	tests := []struct {
   610  		input  []string
   611  		output []string
   612  	}{
   613  		{
   614  			[]string{"foo", "bar"},
   615  			[]string{"foo", "bar"},
   616  		},
   617  		{
   618  			[]string{"foo", "--str", "-s"},
   619  			[]string{"foo"},
   620  		},
   621  		{
   622  			[]string{"-s", "foo", "--str", "bar"},
   623  			[]string{},
   624  		},
   625  		{
   626  			[]string{"-i10", "echo"},
   627  			[]string{"echo"},
   628  		},
   629  		{
   630  			[]string{"-i=10", "echo"},
   631  			[]string{"echo"},
   632  		},
   633  		{
   634  			[]string{"--int=100", "echo"},
   635  			[]string{"echo"},
   636  		},
   637  		{
   638  			[]string{"-ib", "echo", "-sfoo", "baz"},
   639  			[]string{"echo", "baz"},
   640  		},
   641  		{
   642  			[]string{"-i=baz", "bar", "-i", "foo", "blah"},
   643  			[]string{"bar", "blah"},
   644  		},
   645  		{
   646  			[]string{"--int=baz", "-sbar", "-i", "foo", "blah"},
   647  			[]string{"blah"},
   648  		},
   649  		{
   650  			[]string{"--bool", "bar", "-i", "foo", "blah"},
   651  			[]string{"bar", "blah"},
   652  		},
   653  		{
   654  			[]string{"-b", "bar", "-i", "foo", "blah"},
   655  			[]string{"bar", "blah"},
   656  		},
   657  		{
   658  			[]string{"--persist", "bar"},
   659  			[]string{"bar"},
   660  		},
   661  		{
   662  			[]string{"-p", "bar"},
   663  			[]string{"bar"},
   664  		},
   665  	}
   666  
   667  	c := &Command{Use: "c", Run: emptyRun}
   668  	c.PersistentFlags().BoolP("persist", "p", false, "")
   669  	c.Flags().IntP("int", "i", -1, "")
   670  	c.Flags().StringP("str", "s", "", "")
   671  	c.Flags().BoolP("bool", "b", false, "")
   672  
   673  	for i, test := range tests {
   674  		got := stripFlags(test.input, c)
   675  		if !reflect.DeepEqual(test.output, got) {
   676  			t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got)
   677  		}
   678  	}
   679  }
   680  
   681  func TestDisableFlagParsing(t *testing.T) {
   682  	var cArgs []string
   683  	c := &Command{
   684  		Use:                "c",
   685  		DisableFlagParsing: true,
   686  		Run: func(_ *Command, args []string) {
   687  			cArgs = args
   688  		},
   689  	}
   690  
   691  	args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
   692  	output, err := executeCommand(c, args...)
   693  	if output != "" {
   694  		t.Errorf("Unexpected output: %v", output)
   695  	}
   696  	if err != nil {
   697  		t.Errorf("Unexpected error: %v", err)
   698  	}
   699  
   700  	if !reflect.DeepEqual(args, cArgs) {
   701  		t.Errorf("Expected: %v, got: %v", args, cArgs)
   702  	}
   703  }
   704  
   705  func TestPersistentFlagsOnSameCommand(t *testing.T) {
   706  	var rootCmdArgs []string
   707  	rootCmd := &Command{
   708  		Use:  "root",
   709  		Args: ArbitraryArgs,
   710  		Run:  func(_ *Command, args []string) { rootCmdArgs = args },
   711  	}
   712  
   713  	var flagValue int
   714  	rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "")
   715  
   716  	output, err := executeCommand(rootCmd, "-i7", "one", "two")
   717  	if output != "" {
   718  		t.Errorf("Unexpected output: %v", output)
   719  	}
   720  	if err != nil {
   721  		t.Errorf("Unexpected error: %v", err)
   722  	}
   723  
   724  	got := strings.Join(rootCmdArgs, " ")
   725  	if got != onetwo {
   726  		t.Errorf("rootCmdArgs expected: %q, got %q", onetwo, got)
   727  	}
   728  	if flagValue != 7 {
   729  		t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
   730  	}
   731  }
   732  
   733  // TestEmptyInputs checks,
   734  // if flags correctly parsed with blank strings in args.
   735  func TestEmptyInputs(t *testing.T) {
   736  	c := &Command{Use: "c", Run: emptyRun}
   737  
   738  	var flagValue int
   739  	c.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
   740  
   741  	output, err := executeCommand(c, "", "-i7", "")
   742  	if output != "" {
   743  		t.Errorf("Unexpected output: %v", output)
   744  	}
   745  	if err != nil {
   746  		t.Errorf("Unexpected error: %v", err)
   747  	}
   748  
   749  	if flagValue != 7 {
   750  		t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
   751  	}
   752  }
   753  
   754  func TestChildFlagShadowsParentPersistentFlag(t *testing.T) {
   755  	parent := &Command{Use: "parent", Run: emptyRun}
   756  	child := &Command{Use: "child", Run: emptyRun}
   757  
   758  	parent.PersistentFlags().Bool("boolf", false, "")
   759  	parent.PersistentFlags().Int("intf", -1, "")
   760  	child.Flags().String("strf", "", "")
   761  	child.Flags().Int("intf", -1, "")
   762  
   763  	parent.AddCommand(child)
   764  
   765  	childInherited := child.InheritedFlags()
   766  	childLocal := child.LocalFlags()
   767  
   768  	if childLocal.Lookup("strf") == nil {
   769  		t.Error(`LocalFlags expected to contain "strf", got "nil"`)
   770  	}
   771  	if childInherited.Lookup("boolf") == nil {
   772  		t.Error(`InheritedFlags expected to contain "boolf", got "nil"`)
   773  	}
   774  
   775  	if childInherited.Lookup("intf") != nil {
   776  		t.Errorf(`InheritedFlags should not contain shadowed flag "intf"`)
   777  	}
   778  	if childLocal.Lookup("intf") == nil {
   779  		t.Error(`LocalFlags expected to contain "intf", got "nil"`)
   780  	}
   781  }
   782  
   783  func TestPersistentFlagsOnChild(t *testing.T) {
   784  	var childCmdArgs []string
   785  	rootCmd := &Command{Use: "root", Run: emptyRun}
   786  	childCmd := &Command{
   787  		Use:  "child",
   788  		Args: ArbitraryArgs,
   789  		Run:  func(_ *Command, args []string) { childCmdArgs = args },
   790  	}
   791  	rootCmd.AddCommand(childCmd)
   792  
   793  	var parentFlagValue int
   794  	var childFlagValue int
   795  	rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "")
   796  	childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "")
   797  
   798  	output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two")
   799  	if output != "" {
   800  		t.Errorf("Unexpected output: %v", output)
   801  	}
   802  	if err != nil {
   803  		t.Errorf("Unexpected error: %v", err)
   804  	}
   805  
   806  	got := strings.Join(childCmdArgs, " ")
   807  	if got != onetwo {
   808  		t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
   809  	}
   810  	if parentFlagValue != 8 {
   811  		t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue)
   812  	}
   813  	if childFlagValue != 7 {
   814  		t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue)
   815  	}
   816  }
   817  
   818  func TestRequiredFlags(t *testing.T) {
   819  	c := &Command{Use: "c", Run: emptyRun}
   820  	c.Flags().String("foo1", "", "")
   821  	assertNoErr(t, c.MarkFlagRequired("foo1"))
   822  	c.Flags().String("foo2", "", "")
   823  	assertNoErr(t, c.MarkFlagRequired("foo2"))
   824  	c.Flags().String("bar", "", "")
   825  
   826  	expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2")
   827  
   828  	_, err := executeCommand(c)
   829  	got := err.Error()
   830  
   831  	if got != expected {
   832  		t.Errorf("Expected error: %q, got: %q", expected, got)
   833  	}
   834  }
   835  
   836  func TestPersistentRequiredFlags(t *testing.T) {
   837  	parent := &Command{Use: "parent", Run: emptyRun}
   838  	parent.PersistentFlags().String("foo1", "", "")
   839  	assertNoErr(t, parent.MarkPersistentFlagRequired("foo1"))
   840  	parent.PersistentFlags().String("foo2", "", "")
   841  	assertNoErr(t, parent.MarkPersistentFlagRequired("foo2"))
   842  	parent.Flags().String("foo3", "", "")
   843  
   844  	child := &Command{Use: "child", Run: emptyRun}
   845  	child.Flags().String("bar1", "", "")
   846  	assertNoErr(t, child.MarkFlagRequired("bar1"))
   847  	child.Flags().String("bar2", "", "")
   848  	assertNoErr(t, child.MarkFlagRequired("bar2"))
   849  	child.Flags().String("bar3", "", "")
   850  
   851  	parent.AddCommand(child)
   852  
   853  	expected := fmt.Sprintf("required flag(s) %q, %q, %q, %q not set", "bar1", "bar2", "foo1", "foo2")
   854  
   855  	_, err := executeCommand(parent, "child")
   856  	if err.Error() != expected {
   857  		t.Errorf("Expected %q, got %q", expected, err.Error())
   858  	}
   859  }
   860  
   861  func TestPersistentRequiredFlagsWithDisableFlagParsing(t *testing.T) {
   862  	// Make sure a required persistent flag does not break
   863  	// commands that disable flag parsing
   864  
   865  	parent := &Command{Use: "parent", Run: emptyRun}
   866  	parent.PersistentFlags().Bool("foo", false, "")
   867  	flag := parent.PersistentFlags().Lookup("foo")
   868  	assertNoErr(t, parent.MarkPersistentFlagRequired("foo"))
   869  
   870  	child := &Command{Use: "child", Run: emptyRun}
   871  	child.DisableFlagParsing = true
   872  
   873  	parent.AddCommand(child)
   874  
   875  	if _, err := executeCommand(parent, "--foo", "child"); err != nil {
   876  		t.Errorf("Unexpected error: %v", err)
   877  	}
   878  
   879  	// Reset the flag or else it will remember the state from the previous command
   880  	flag.Changed = false
   881  	if _, err := executeCommand(parent, "child", "--foo"); err != nil {
   882  		t.Errorf("Unexpected error: %v", err)
   883  	}
   884  
   885  	// Reset the flag or else it will remember the state from the previous command
   886  	flag.Changed = false
   887  	if _, err := executeCommand(parent, "child"); err != nil {
   888  		t.Errorf("Unexpected error: %v", err)
   889  	}
   890  }
   891  
   892  func TestInitHelpFlagMergesFlags(t *testing.T) {
   893  	usage := "custom flag"
   894  	rootCmd := &Command{Use: "root"}
   895  	rootCmd.PersistentFlags().Bool("help", false, "custom flag")
   896  	childCmd := &Command{Use: "child"}
   897  	rootCmd.AddCommand(childCmd)
   898  
   899  	childCmd.InitDefaultHelpFlag()
   900  	got := childCmd.Flags().Lookup("help").Usage
   901  	if got != usage {
   902  		t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got)
   903  	}
   904  }
   905  
   906  func TestHelpCommandExecuted(t *testing.T) {
   907  	rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
   908  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
   909  
   910  	output, err := executeCommand(rootCmd, "help")
   911  	if err != nil {
   912  		t.Errorf("Unexpected error: %v", err)
   913  	}
   914  
   915  	checkStringContains(t, output, rootCmd.Long)
   916  }
   917  
   918  func TestHelpCommandExecutedOnChild(t *testing.T) {
   919  	rootCmd := &Command{Use: "root", Run: emptyRun}
   920  	childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
   921  	rootCmd.AddCommand(childCmd)
   922  
   923  	output, err := executeCommand(rootCmd, "help", "child")
   924  	if err != nil {
   925  		t.Errorf("Unexpected error: %v", err)
   926  	}
   927  
   928  	checkStringContains(t, output, childCmd.Long)
   929  }
   930  
   931  func TestHelpCommandExecutedOnChildWithFlagThatShadowsParentFlag(t *testing.T) {
   932  	parent := &Command{Use: "parent", Run: emptyRun}
   933  	child := &Command{Use: "child", Run: emptyRun}
   934  	parent.AddCommand(child)
   935  
   936  	parent.PersistentFlags().Bool("foo", false, "parent foo usage")
   937  	parent.PersistentFlags().Bool("bar", false, "parent bar usage")
   938  	child.Flags().Bool("foo", false, "child foo usage") // This shadows parent's foo flag
   939  	child.Flags().Bool("baz", false, "child baz usage")
   940  
   941  	got, err := executeCommand(parent, "help", "child")
   942  	if err != nil {
   943  		t.Errorf("Unexpected error: %v", err)
   944  	}
   945  
   946  	expected := `Usage:
   947    parent child [flags]
   948  
   949  Flags:
   950        --baz    child baz usage
   951        --foo    child foo usage
   952    -h, --help   help for child
   953  
   954  Global Flags:
   955        --bar   parent bar usage
   956  `
   957  
   958  	if got != expected {
   959  		t.Errorf("Help text mismatch.\nExpected:\n%s\n\nGot:\n%s\n", expected, got)
   960  	}
   961  }
   962  
   963  func TestSetHelpCommand(t *testing.T) {
   964  	c := &Command{Use: "c", Run: emptyRun}
   965  	c.AddCommand(&Command{Use: "empty", Run: emptyRun})
   966  
   967  	expected := "WORKS"
   968  	c.SetHelpCommand(&Command{
   969  		Use:   "help [command]",
   970  		Short: "Help about any command",
   971  		Long: `Help provides help for any command in the application.
   972  	Simply type ` + c.Name() + ` help [path to command] for full details.`,
   973  		Run: func(c *Command, _ []string) { c.Print(expected) },
   974  	})
   975  
   976  	got, err := executeCommand(c, "help")
   977  	if err != nil {
   978  		t.Errorf("Unexpected error: %v", err)
   979  	}
   980  
   981  	if got != expected {
   982  		t.Errorf("Expected to contain %q, got %q", expected, got)
   983  	}
   984  }
   985  
   986  func TestHelpFlagExecuted(t *testing.T) {
   987  	rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
   988  
   989  	output, err := executeCommand(rootCmd, "--help")
   990  	if err != nil {
   991  		t.Errorf("Unexpected error: %v", err)
   992  	}
   993  
   994  	checkStringContains(t, output, rootCmd.Long)
   995  }
   996  
   997  func TestHelpFlagExecutedOnChild(t *testing.T) {
   998  	rootCmd := &Command{Use: "root", Run: emptyRun}
   999  	childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
  1000  	rootCmd.AddCommand(childCmd)
  1001  
  1002  	output, err := executeCommand(rootCmd, "child", "--help")
  1003  	if err != nil {
  1004  		t.Errorf("Unexpected error: %v", err)
  1005  	}
  1006  
  1007  	checkStringContains(t, output, childCmd.Long)
  1008  }
  1009  
  1010  // TestHelpFlagInHelp checks,
  1011  // if '--help' flag is shown in help for child (executing `parent help child`),
  1012  // that has no other flags.
  1013  // Related to https://github.com/spf13/cobra/issues/302.
  1014  func TestHelpFlagInHelp(t *testing.T) {
  1015  	parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}}
  1016  
  1017  	childCmd := &Command{Use: "child", Run: func(*Command, []string) {}}
  1018  	parentCmd.AddCommand(childCmd)
  1019  
  1020  	output, err := executeCommand(parentCmd, "help", "child")
  1021  	if err != nil {
  1022  		t.Errorf("Unexpected error: %v", err)
  1023  	}
  1024  
  1025  	checkStringContains(t, output, "[flags]")
  1026  }
  1027  
  1028  func TestFlagsInUsage(t *testing.T) {
  1029  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}}
  1030  	output, err := executeCommand(rootCmd, "--help")
  1031  	if err != nil {
  1032  		t.Errorf("Unexpected error: %v", err)
  1033  	}
  1034  
  1035  	checkStringContains(t, output, "[flags]")
  1036  }
  1037  
  1038  func TestHelpExecutedOnNonRunnableChild(t *testing.T) {
  1039  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1040  	childCmd := &Command{Use: "child", Long: "Long description"}
  1041  	rootCmd.AddCommand(childCmd)
  1042  
  1043  	output, err := executeCommand(rootCmd, "child")
  1044  	if err != nil {
  1045  		t.Errorf("Unexpected error: %v", err)
  1046  	}
  1047  
  1048  	checkStringContains(t, output, childCmd.Long)
  1049  }
  1050  
  1051  func TestVersionFlagExecuted(t *testing.T) {
  1052  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1053  
  1054  	output, err := executeCommand(rootCmd, "--version", "arg1")
  1055  	if err != nil {
  1056  		t.Errorf("Unexpected error: %v", err)
  1057  	}
  1058  
  1059  	checkStringContains(t, output, "root version 1.0.0")
  1060  }
  1061  
  1062  func TestVersionFlagExecutedWithNoName(t *testing.T) {
  1063  	rootCmd := &Command{Version: "1.0.0", Run: emptyRun}
  1064  
  1065  	output, err := executeCommand(rootCmd, "--version", "arg1")
  1066  	if err != nil {
  1067  		t.Errorf("Unexpected error: %v", err)
  1068  	}
  1069  
  1070  	checkStringContains(t, output, "version 1.0.0")
  1071  }
  1072  
  1073  func TestShortAndLongVersionFlagInHelp(t *testing.T) {
  1074  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1075  
  1076  	output, err := executeCommand(rootCmd, "--help")
  1077  	if err != nil {
  1078  		t.Errorf("Unexpected error: %v", err)
  1079  	}
  1080  
  1081  	checkStringContains(t, output, "-v, --version")
  1082  }
  1083  
  1084  func TestLongVersionFlagOnlyInHelpWhenShortPredefined(t *testing.T) {
  1085  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1086  	rootCmd.Flags().StringP("foo", "v", "", "not a version flag")
  1087  
  1088  	output, err := executeCommand(rootCmd, "--help")
  1089  	if err != nil {
  1090  		t.Errorf("Unexpected error: %v", err)
  1091  	}
  1092  
  1093  	checkStringOmits(t, output, "-v, --version")
  1094  	checkStringContains(t, output, "--version")
  1095  }
  1096  
  1097  func TestShorthandVersionFlagExecuted(t *testing.T) {
  1098  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1099  
  1100  	output, err := executeCommand(rootCmd, "-v", "arg1")
  1101  	if err != nil {
  1102  		t.Errorf("Unexpected error: %v", err)
  1103  	}
  1104  
  1105  	checkStringContains(t, output, "root version 1.0.0")
  1106  }
  1107  
  1108  func TestVersionTemplate(t *testing.T) {
  1109  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1110  	rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
  1111  
  1112  	output, err := executeCommand(rootCmd, "--version", "arg1")
  1113  	if err != nil {
  1114  		t.Errorf("Unexpected error: %v", err)
  1115  	}
  1116  
  1117  	checkStringContains(t, output, "customized version: 1.0.0")
  1118  }
  1119  
  1120  func TestShorthandVersionTemplate(t *testing.T) {
  1121  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1122  	rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
  1123  
  1124  	output, err := executeCommand(rootCmd, "-v", "arg1")
  1125  	if err != nil {
  1126  		t.Errorf("Unexpected error: %v", err)
  1127  	}
  1128  
  1129  	checkStringContains(t, output, "customized version: 1.0.0")
  1130  }
  1131  
  1132  func TestRootErrPrefixExecutedOnSubcommand(t *testing.T) {
  1133  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1134  	rootCmd.SetErrPrefix("root error prefix:")
  1135  	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
  1136  
  1137  	output, err := executeCommand(rootCmd, "sub", "--unknown-flag")
  1138  	if err == nil {
  1139  		t.Errorf("Expected error")
  1140  	}
  1141  
  1142  	checkStringContains(t, output, "root error prefix: unknown flag: --unknown-flag")
  1143  }
  1144  
  1145  func TestRootAndSubErrPrefix(t *testing.T) {
  1146  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1147  	subCmd := &Command{Use: "sub", Run: emptyRun}
  1148  	rootCmd.AddCommand(subCmd)
  1149  	rootCmd.SetErrPrefix("root error prefix:")
  1150  	subCmd.SetErrPrefix("sub error prefix:")
  1151  
  1152  	if output, err := executeCommand(rootCmd, "--unknown-root-flag"); err == nil {
  1153  		t.Errorf("Expected error")
  1154  	} else {
  1155  		checkStringContains(t, output, "root error prefix: unknown flag: --unknown-root-flag")
  1156  	}
  1157  
  1158  	if output, err := executeCommand(rootCmd, "sub", "--unknown-sub-flag"); err == nil {
  1159  		t.Errorf("Expected error")
  1160  	} else {
  1161  		checkStringContains(t, output, "sub error prefix: unknown flag: --unknown-sub-flag")
  1162  	}
  1163  }
  1164  
  1165  func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
  1166  	rootCmd := &Command{Use: "root", Version: "1.0.0"}
  1167  	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
  1168  
  1169  	output, err := executeCommand(rootCmd, "--version", "sub")
  1170  	if err != nil {
  1171  		t.Errorf("Unexpected error: %v", err)
  1172  	}
  1173  
  1174  	checkStringContains(t, output, "root version 1.0.0")
  1175  }
  1176  
  1177  func TestShorthandVersionFlagExecutedOnSubcommand(t *testing.T) {
  1178  	rootCmd := &Command{Use: "root", Version: "1.0.0"}
  1179  	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
  1180  
  1181  	output, err := executeCommand(rootCmd, "-v", "sub")
  1182  	if err != nil {
  1183  		t.Errorf("Unexpected error: %v", err)
  1184  	}
  1185  
  1186  	checkStringContains(t, output, "root version 1.0.0")
  1187  }
  1188  
  1189  func TestVersionFlagOnlyAddedToRoot(t *testing.T) {
  1190  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1191  	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
  1192  
  1193  	_, err := executeCommand(rootCmd, "sub", "--version")
  1194  	if err == nil {
  1195  		t.Errorf("Expected error")
  1196  	}
  1197  
  1198  	checkStringContains(t, err.Error(), "unknown flag: --version")
  1199  }
  1200  
  1201  func TestShortVersionFlagOnlyAddedToRoot(t *testing.T) {
  1202  	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
  1203  	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
  1204  
  1205  	_, err := executeCommand(rootCmd, "sub", "-v")
  1206  	if err == nil {
  1207  		t.Errorf("Expected error")
  1208  	}
  1209  
  1210  	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
  1211  }
  1212  
  1213  func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
  1214  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1215  
  1216  	_, err := executeCommand(rootCmd, "--version")
  1217  	if err == nil {
  1218  		t.Errorf("Expected error")
  1219  	}
  1220  	checkStringContains(t, err.Error(), "unknown flag: --version")
  1221  }
  1222  
  1223  func TestShorthandVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
  1224  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1225  
  1226  	_, err := executeCommand(rootCmd, "-v")
  1227  	if err == nil {
  1228  		t.Errorf("Expected error")
  1229  	}
  1230  	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
  1231  }
  1232  
  1233  func TestShorthandVersionFlagOnlyAddedIfShorthandNotDefined(t *testing.T) {
  1234  	rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"}
  1235  	rootCmd.Flags().StringP("notversion", "v", "", "not a version flag")
  1236  
  1237  	_, err := executeCommand(rootCmd, "-v")
  1238  	if err == nil {
  1239  		t.Errorf("Expected error")
  1240  	}
  1241  	check(t, rootCmd.Flags().ShorthandLookup("v").Name, "notversion")
  1242  	checkStringContains(t, err.Error(), "flag needs an argument: 'v' in -v")
  1243  }
  1244  
  1245  func TestShorthandVersionFlagOnlyAddedIfVersionNotDefined(t *testing.T) {
  1246  	rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"}
  1247  	rootCmd.Flags().Bool("version", false, "a different kind of version flag")
  1248  
  1249  	_, err := executeCommand(rootCmd, "-v")
  1250  	if err == nil {
  1251  		t.Errorf("Expected error")
  1252  	}
  1253  	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
  1254  }
  1255  
  1256  func TestUsageIsNotPrintedTwice(t *testing.T) {
  1257  	var cmd = &Command{Use: "root"}
  1258  	var sub = &Command{Use: "sub"}
  1259  	cmd.AddCommand(sub)
  1260  
  1261  	output, _ := executeCommand(cmd, "")
  1262  	if strings.Count(output, "Usage:") != 1 {
  1263  		t.Error("Usage output is not printed exactly once")
  1264  	}
  1265  }
  1266  
  1267  func TestVisitParents(t *testing.T) {
  1268  	c := &Command{Use: "app"}
  1269  	sub := &Command{Use: "sub"}
  1270  	dsub := &Command{Use: "dsub"}
  1271  	sub.AddCommand(dsub)
  1272  	c.AddCommand(sub)
  1273  
  1274  	total := 0
  1275  	add := func(x *Command) {
  1276  		total++
  1277  	}
  1278  	sub.VisitParents(add)
  1279  	if total != 1 {
  1280  		t.Errorf("Should have visited 1 parent but visited %d", total)
  1281  	}
  1282  
  1283  	total = 0
  1284  	dsub.VisitParents(add)
  1285  	if total != 2 {
  1286  		t.Errorf("Should have visited 2 parents but visited %d", total)
  1287  	}
  1288  
  1289  	total = 0
  1290  	c.VisitParents(add)
  1291  	if total != 0 {
  1292  		t.Errorf("Should have visited no parents but visited %d", total)
  1293  	}
  1294  }
  1295  
  1296  func TestSuggestions(t *testing.T) {
  1297  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1298  	timesCmd := &Command{
  1299  		Use:        "times",
  1300  		SuggestFor: []string{"counts"},
  1301  		Run:        emptyRun,
  1302  	}
  1303  	rootCmd.AddCommand(timesCmd)
  1304  
  1305  	templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
  1306  	templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
  1307  
  1308  	tests := map[string]string{
  1309  		"time":     "times",
  1310  		"tiems":    "times",
  1311  		"tims":     "times",
  1312  		"timeS":    "times",
  1313  		"rimes":    "times",
  1314  		"ti":       "times",
  1315  		"t":        "times",
  1316  		"timely":   "times",
  1317  		"ri":       "",
  1318  		"timezone": "",
  1319  		"foo":      "",
  1320  		"counts":   "times",
  1321  	}
  1322  
  1323  	for typo, suggestion := range tests {
  1324  		for _, suggestionsDisabled := range []bool{true, false} {
  1325  			rootCmd.DisableSuggestions = suggestionsDisabled
  1326  
  1327  			var expected string
  1328  			output, _ := executeCommand(rootCmd, typo)
  1329  
  1330  			if suggestion == "" || suggestionsDisabled {
  1331  				expected = fmt.Sprintf(templateWithoutSuggestions, typo)
  1332  			} else {
  1333  				expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion)
  1334  			}
  1335  
  1336  			if output != expected {
  1337  				t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
  1338  			}
  1339  		}
  1340  	}
  1341  }
  1342  
  1343  func TestCaseInsensitive(t *testing.T) {
  1344  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1345  	childCmd := &Command{Use: "child", Run: emptyRun, Aliases: []string{"alternative"}}
  1346  	granchildCmd := &Command{Use: "GRANDCHILD", Run: emptyRun, Aliases: []string{"ALIAS"}}
  1347  
  1348  	childCmd.AddCommand(granchildCmd)
  1349  	rootCmd.AddCommand(childCmd)
  1350  
  1351  	tests := []struct {
  1352  		args                []string
  1353  		failWithoutEnabling bool
  1354  	}{
  1355  		{
  1356  			args:                []string{"child"},
  1357  			failWithoutEnabling: false,
  1358  		},
  1359  		{
  1360  			args:                []string{"CHILD"},
  1361  			failWithoutEnabling: true,
  1362  		},
  1363  		{
  1364  			args:                []string{"chILD"},
  1365  			failWithoutEnabling: true,
  1366  		},
  1367  		{
  1368  			args:                []string{"CHIld"},
  1369  			failWithoutEnabling: true,
  1370  		},
  1371  		{
  1372  			args:                []string{"alternative"},
  1373  			failWithoutEnabling: false,
  1374  		},
  1375  		{
  1376  			args:                []string{"ALTERNATIVE"},
  1377  			failWithoutEnabling: true,
  1378  		},
  1379  		{
  1380  			args:                []string{"ALTernatIVE"},
  1381  			failWithoutEnabling: true,
  1382  		},
  1383  		{
  1384  			args:                []string{"alternatiVE"},
  1385  			failWithoutEnabling: true,
  1386  		},
  1387  		{
  1388  			args:                []string{"child", "GRANDCHILD"},
  1389  			failWithoutEnabling: false,
  1390  		},
  1391  		{
  1392  			args:                []string{"child", "grandchild"},
  1393  			failWithoutEnabling: true,
  1394  		},
  1395  		{
  1396  			args:                []string{"CHIld", "GRANdchild"},
  1397  			failWithoutEnabling: true,
  1398  		},
  1399  		{
  1400  			args:                []string{"alternative", "ALIAS"},
  1401  			failWithoutEnabling: false,
  1402  		},
  1403  		{
  1404  			args:                []string{"alternative", "alias"},
  1405  			failWithoutEnabling: true,
  1406  		},
  1407  		{
  1408  			args:                []string{"CHILD", "alias"},
  1409  			failWithoutEnabling: true,
  1410  		},
  1411  		{
  1412  			args:                []string{"CHIld", "aliAS"},
  1413  			failWithoutEnabling: true,
  1414  		},
  1415  	}
  1416  
  1417  	for _, test := range tests {
  1418  		for _, enableCaseInsensitivity := range []bool{true, false} {
  1419  			EnableCaseInsensitive = enableCaseInsensitivity
  1420  
  1421  			output, err := executeCommand(rootCmd, test.args...)
  1422  			expectedFailure := test.failWithoutEnabling && !enableCaseInsensitivity
  1423  
  1424  			if !expectedFailure && output != "" {
  1425  				t.Errorf("Unexpected output: %v", output)
  1426  			}
  1427  			if !expectedFailure && err != nil {
  1428  				t.Errorf("Unexpected error: %v", err)
  1429  			}
  1430  		}
  1431  	}
  1432  
  1433  	EnableCaseInsensitive = defaultCaseInsensitive
  1434  }
  1435  
  1436  // This test make sure we keep backwards-compatibility with respect
  1437  // to command names case sensitivity behavior.
  1438  func TestCaseSensitivityBackwardCompatibility(t *testing.T) {
  1439  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1440  	childCmd := &Command{Use: "child", Run: emptyRun}
  1441  
  1442  	rootCmd.AddCommand(childCmd)
  1443  	_, err := executeCommand(rootCmd, strings.ToUpper(childCmd.Use))
  1444  	if err == nil {
  1445  		t.Error("Expected error on calling a command in upper case while command names are case sensitive. Got nil.")
  1446  	}
  1447  
  1448  }
  1449  
  1450  func TestRemoveCommand(t *testing.T) {
  1451  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1452  	childCmd := &Command{Use: "child", Run: emptyRun}
  1453  	rootCmd.AddCommand(childCmd)
  1454  	rootCmd.RemoveCommand(childCmd)
  1455  
  1456  	_, err := executeCommand(rootCmd, "child")
  1457  	if err == nil {
  1458  		t.Error("Expected error on calling removed command. Got nil.")
  1459  	}
  1460  }
  1461  
  1462  func TestReplaceCommandWithRemove(t *testing.T) {
  1463  	childUsed := 0
  1464  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1465  	child1Cmd := &Command{
  1466  		Use: "child",
  1467  		Run: func(*Command, []string) { childUsed = 1 },
  1468  	}
  1469  	child2Cmd := &Command{
  1470  		Use: "child",
  1471  		Run: func(*Command, []string) { childUsed = 2 },
  1472  	}
  1473  	rootCmd.AddCommand(child1Cmd)
  1474  	rootCmd.RemoveCommand(child1Cmd)
  1475  	rootCmd.AddCommand(child2Cmd)
  1476  
  1477  	output, err := executeCommand(rootCmd, "child")
  1478  	if output != "" {
  1479  		t.Errorf("Unexpected output: %v", output)
  1480  	}
  1481  	if err != nil {
  1482  		t.Errorf("Unexpected error: %v", err)
  1483  	}
  1484  
  1485  	if childUsed == 1 {
  1486  		t.Error("Removed command shouldn't be called")
  1487  	}
  1488  	if childUsed != 2 {
  1489  		t.Error("Replacing command should have been called but didn't")
  1490  	}
  1491  }
  1492  
  1493  func TestDeprecatedCommand(t *testing.T) {
  1494  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1495  	deprecatedCmd := &Command{
  1496  		Use:        "deprecated",
  1497  		Deprecated: "This command is deprecated",
  1498  		Run:        emptyRun,
  1499  	}
  1500  	rootCmd.AddCommand(deprecatedCmd)
  1501  
  1502  	output, err := executeCommand(rootCmd, "deprecated")
  1503  	if err != nil {
  1504  		t.Errorf("Unexpected error: %v", err)
  1505  	}
  1506  
  1507  	checkStringContains(t, output, deprecatedCmd.Deprecated)
  1508  }
  1509  
  1510  func TestHooks(t *testing.T) {
  1511  	var (
  1512  		persPreArgs  string
  1513  		preArgs      string
  1514  		runArgs      string
  1515  		postArgs     string
  1516  		persPostArgs string
  1517  	)
  1518  
  1519  	c := &Command{
  1520  		Use: "c",
  1521  		PersistentPreRun: func(_ *Command, args []string) {
  1522  			persPreArgs = strings.Join(args, " ")
  1523  		},
  1524  		PreRun: func(_ *Command, args []string) {
  1525  			preArgs = strings.Join(args, " ")
  1526  		},
  1527  		Run: func(_ *Command, args []string) {
  1528  			runArgs = strings.Join(args, " ")
  1529  		},
  1530  		PostRun: func(_ *Command, args []string) {
  1531  			postArgs = strings.Join(args, " ")
  1532  		},
  1533  		PersistentPostRun: func(_ *Command, args []string) {
  1534  			persPostArgs = strings.Join(args, " ")
  1535  		},
  1536  	}
  1537  
  1538  	output, err := executeCommand(c, "one", "two")
  1539  	if output != "" {
  1540  		t.Errorf("Unexpected output: %v", output)
  1541  	}
  1542  	if err != nil {
  1543  		t.Errorf("Unexpected error: %v", err)
  1544  	}
  1545  
  1546  	for _, v := range []struct {
  1547  		name string
  1548  		got  string
  1549  	}{
  1550  		{"persPreArgs", persPreArgs},
  1551  		{"preArgs", preArgs},
  1552  		{"runArgs", runArgs},
  1553  		{"postArgs", postArgs},
  1554  		{"persPostArgs", persPostArgs},
  1555  	} {
  1556  		if v.got != onetwo {
  1557  			t.Errorf("Expected %s %q, got %q", v.name, onetwo, v.got)
  1558  		}
  1559  	}
  1560  }
  1561  
  1562  func TestPersistentHooks(t *testing.T) {
  1563  	EnableTraverseRunHooks = true
  1564  	testPersistentHooks(t, []string{
  1565  		"parent PersistentPreRun",
  1566  		"child PersistentPreRun",
  1567  		"child PreRun",
  1568  		"child Run",
  1569  		"child PostRun",
  1570  		"child PersistentPostRun",
  1571  		"parent PersistentPostRun",
  1572  	})
  1573  
  1574  	EnableTraverseRunHooks = false
  1575  	testPersistentHooks(t, []string{
  1576  		"child PersistentPreRun",
  1577  		"child PreRun",
  1578  		"child Run",
  1579  		"child PostRun",
  1580  		"child PersistentPostRun",
  1581  	})
  1582  }
  1583  
  1584  func testPersistentHooks(t *testing.T, expectedHookRunOrder []string) {
  1585  	var hookRunOrder []string
  1586  
  1587  	validateHook := func(args []string, hookName string) {
  1588  		hookRunOrder = append(hookRunOrder, hookName)
  1589  		got := strings.Join(args, " ")
  1590  		if onetwo != got {
  1591  			t.Errorf("Expected %s %q, got %q", hookName, onetwo, got)
  1592  		}
  1593  	}
  1594  
  1595  	parentCmd := &Command{
  1596  		Use: "parent",
  1597  		PersistentPreRun: func(_ *Command, args []string) {
  1598  			validateHook(args, "parent PersistentPreRun")
  1599  		},
  1600  		PreRun: func(_ *Command, args []string) {
  1601  			validateHook(args, "parent PreRun")
  1602  		},
  1603  		Run: func(_ *Command, args []string) {
  1604  			validateHook(args, "parent Run")
  1605  		},
  1606  		PostRun: func(_ *Command, args []string) {
  1607  			validateHook(args, "parent PostRun")
  1608  		},
  1609  		PersistentPostRun: func(_ *Command, args []string) {
  1610  			validateHook(args, "parent PersistentPostRun")
  1611  		},
  1612  	}
  1613  
  1614  	childCmd := &Command{
  1615  		Use: "child",
  1616  		PersistentPreRun: func(_ *Command, args []string) {
  1617  			validateHook(args, "child PersistentPreRun")
  1618  		},
  1619  		PreRun: func(_ *Command, args []string) {
  1620  			validateHook(args, "child PreRun")
  1621  		},
  1622  		Run: func(_ *Command, args []string) {
  1623  			validateHook(args, "child Run")
  1624  		},
  1625  		PostRun: func(_ *Command, args []string) {
  1626  			validateHook(args, "child PostRun")
  1627  		},
  1628  		PersistentPostRun: func(_ *Command, args []string) {
  1629  			validateHook(args, "child PersistentPostRun")
  1630  		},
  1631  	}
  1632  	parentCmd.AddCommand(childCmd)
  1633  
  1634  	output, err := executeCommand(parentCmd, "child", "one", "two")
  1635  	if output != "" {
  1636  		t.Errorf("Unexpected output: %v", output)
  1637  	}
  1638  	if err != nil {
  1639  		t.Errorf("Unexpected error: %v", err)
  1640  	}
  1641  
  1642  	for idx, exp := range expectedHookRunOrder {
  1643  		if len(hookRunOrder) > idx {
  1644  			if act := hookRunOrder[idx]; act != exp {
  1645  				t.Errorf("Expected %q at %d, got %q", exp, idx, act)
  1646  			}
  1647  		} else {
  1648  			t.Errorf("Expected %q at %d, got nothing", exp, idx)
  1649  		}
  1650  	}
  1651  }
  1652  
  1653  // Related to https://github.com/spf13/cobra/issues/521.
  1654  func TestGlobalNormFuncPropagation(t *testing.T) {
  1655  	normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
  1656  		return pflag.NormalizedName(name)
  1657  	}
  1658  
  1659  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1660  	childCmd := &Command{Use: "child", Run: emptyRun}
  1661  	rootCmd.AddCommand(childCmd)
  1662  
  1663  	rootCmd.SetGlobalNormalizationFunc(normFunc)
  1664  	if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
  1665  		t.Error("rootCmd seems to have a wrong normalization function")
  1666  	}
  1667  
  1668  	if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() {
  1669  		t.Error("childCmd should have had the normalization function of rootCmd")
  1670  	}
  1671  }
  1672  
  1673  // Related to https://github.com/spf13/cobra/issues/521.
  1674  func TestNormPassedOnLocal(t *testing.T) {
  1675  	toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
  1676  		return pflag.NormalizedName(strings.ToUpper(name))
  1677  	}
  1678  
  1679  	c := &Command{}
  1680  	c.Flags().Bool("flagname", true, "this is a dummy flag")
  1681  	c.SetGlobalNormalizationFunc(toUpper)
  1682  	if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") {
  1683  		t.Error("Normalization function should be passed on to Local flag set")
  1684  	}
  1685  }
  1686  
  1687  // Related to https://github.com/spf13/cobra/issues/521.
  1688  func TestNormPassedOnInherited(t *testing.T) {
  1689  	toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
  1690  		return pflag.NormalizedName(strings.ToUpper(name))
  1691  	}
  1692  
  1693  	c := &Command{}
  1694  	c.SetGlobalNormalizationFunc(toUpper)
  1695  
  1696  	child1 := &Command{}
  1697  	c.AddCommand(child1)
  1698  
  1699  	c.PersistentFlags().Bool("flagname", true, "")
  1700  
  1701  	child2 := &Command{}
  1702  	c.AddCommand(child2)
  1703  
  1704  	inherited := child1.InheritedFlags()
  1705  	if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
  1706  		t.Error("Normalization function should be passed on to inherited flag set in command added before flag")
  1707  	}
  1708  
  1709  	inherited = child2.InheritedFlags()
  1710  	if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
  1711  		t.Error("Normalization function should be passed on to inherited flag set in command added after flag")
  1712  	}
  1713  }
  1714  
  1715  // Related to https://github.com/spf13/cobra/issues/521.
  1716  func TestConsistentNormalizedName(t *testing.T) {
  1717  	toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
  1718  		return pflag.NormalizedName(strings.ToUpper(name))
  1719  	}
  1720  	n := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
  1721  		return pflag.NormalizedName(name)
  1722  	}
  1723  
  1724  	c := &Command{}
  1725  	c.Flags().Bool("flagname", true, "")
  1726  	c.SetGlobalNormalizationFunc(toUpper)
  1727  	c.SetGlobalNormalizationFunc(n)
  1728  
  1729  	if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") {
  1730  		t.Error("Normalizing flag names should not result in duplicate flags")
  1731  	}
  1732  }
  1733  
  1734  func TestFlagOnPflagCommandLine(t *testing.T) {
  1735  	flagName := "flagOnCommandLine"
  1736  	pflag.String(flagName, "", "about my flag")
  1737  
  1738  	c := &Command{Use: "c", Run: emptyRun}
  1739  	c.AddCommand(&Command{Use: "child", Run: emptyRun})
  1740  
  1741  	output, _ := executeCommand(c, "--help")
  1742  	checkStringContains(t, output, flagName)
  1743  
  1744  	resetCommandLineFlagSet()
  1745  }
  1746  
  1747  // TestHiddenCommandExecutes checks,
  1748  // if hidden commands run as intended.
  1749  func TestHiddenCommandExecutes(t *testing.T) {
  1750  	executed := false
  1751  	c := &Command{
  1752  		Use:    "c",
  1753  		Hidden: true,
  1754  		Run:    func(*Command, []string) { executed = true },
  1755  	}
  1756  
  1757  	output, err := executeCommand(c)
  1758  	if output != "" {
  1759  		t.Errorf("Unexpected output: %v", output)
  1760  	}
  1761  	if err != nil {
  1762  		t.Errorf("Unexpected error: %v", err)
  1763  	}
  1764  
  1765  	if !executed {
  1766  		t.Error("Hidden command should have been executed")
  1767  	}
  1768  }
  1769  
  1770  // test to ensure hidden commands do not show up in usage/help text
  1771  func TestHiddenCommandIsHidden(t *testing.T) {
  1772  	c := &Command{Use: "c", Hidden: true, Run: emptyRun}
  1773  	if c.IsAvailableCommand() {
  1774  		t.Errorf("Hidden command should be unavailable")
  1775  	}
  1776  }
  1777  
  1778  func TestCommandsAreSorted(t *testing.T) {
  1779  	EnableCommandSorting = true
  1780  
  1781  	originalNames := []string{"middle", "zlast", "afirst"}
  1782  	expectedNames := []string{"afirst", "middle", "zlast"}
  1783  
  1784  	var rootCmd = &Command{Use: "root"}
  1785  
  1786  	for _, name := range originalNames {
  1787  		rootCmd.AddCommand(&Command{Use: name})
  1788  	}
  1789  
  1790  	for i, c := range rootCmd.Commands() {
  1791  		got := c.Name()
  1792  		if expectedNames[i] != got {
  1793  			t.Errorf("Expected: %s, got: %s", expectedNames[i], got)
  1794  		}
  1795  	}
  1796  
  1797  	EnableCommandSorting = defaultCommandSorting
  1798  }
  1799  
  1800  func TestEnableCommandSortingIsDisabled(t *testing.T) {
  1801  	EnableCommandSorting = false
  1802  
  1803  	originalNames := []string{"middle", "zlast", "afirst"}
  1804  
  1805  	var rootCmd = &Command{Use: "root"}
  1806  
  1807  	for _, name := range originalNames {
  1808  		rootCmd.AddCommand(&Command{Use: name})
  1809  	}
  1810  
  1811  	for i, c := range rootCmd.Commands() {
  1812  		got := c.Name()
  1813  		if originalNames[i] != got {
  1814  			t.Errorf("expected: %s, got: %s", originalNames[i], got)
  1815  		}
  1816  	}
  1817  
  1818  	EnableCommandSorting = defaultCommandSorting
  1819  }
  1820  
  1821  func TestUsageWithGroup(t *testing.T) {
  1822  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1823  	rootCmd.CompletionOptions.DisableDefaultCmd = true
  1824  
  1825  	rootCmd.AddGroup(&Group{ID: "group1", Title: "group1"})
  1826  	rootCmd.AddGroup(&Group{ID: "group2", Title: "group2"})
  1827  
  1828  	rootCmd.AddCommand(&Command{Use: "cmd1", GroupID: "group1", Run: emptyRun})
  1829  	rootCmd.AddCommand(&Command{Use: "cmd2", GroupID: "group2", Run: emptyRun})
  1830  
  1831  	output, err := executeCommand(rootCmd, "--help")
  1832  	if err != nil {
  1833  		t.Errorf("Unexpected error: %v", err)
  1834  	}
  1835  
  1836  	// help should be ungrouped here
  1837  	checkStringContains(t, output, "\nAdditional Commands:\n  help")
  1838  	checkStringContains(t, output, "\ngroup1\n  cmd1")
  1839  	checkStringContains(t, output, "\ngroup2\n  cmd2")
  1840  }
  1841  
  1842  func TestUsageHelpGroup(t *testing.T) {
  1843  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1844  	rootCmd.CompletionOptions.DisableDefaultCmd = true
  1845  
  1846  	rootCmd.AddGroup(&Group{ID: "group", Title: "group"})
  1847  	rootCmd.AddCommand(&Command{Use: "xxx", GroupID: "group", Run: emptyRun})
  1848  	rootCmd.SetHelpCommandGroupID("group")
  1849  
  1850  	output, err := executeCommand(rootCmd, "--help")
  1851  	if err != nil {
  1852  		t.Errorf("Unexpected error: %v", err)
  1853  	}
  1854  
  1855  	// now help should be grouped under "group"
  1856  	checkStringOmits(t, output, "\nAdditional Commands:\n  help")
  1857  	checkStringContains(t, output, "\ngroup\n  help")
  1858  }
  1859  
  1860  func TestUsageCompletionGroup(t *testing.T) {
  1861  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1862  
  1863  	rootCmd.AddGroup(&Group{ID: "group", Title: "group"})
  1864  	rootCmd.AddGroup(&Group{ID: "help", Title: "help"})
  1865  
  1866  	rootCmd.AddCommand(&Command{Use: "xxx", GroupID: "group", Run: emptyRun})
  1867  	rootCmd.SetHelpCommandGroupID("help")
  1868  	rootCmd.SetCompletionCommandGroupID("group")
  1869  
  1870  	output, err := executeCommand(rootCmd, "--help")
  1871  	if err != nil {
  1872  		t.Errorf("Unexpected error: %v", err)
  1873  	}
  1874  
  1875  	// now completion should be grouped under "group"
  1876  	checkStringOmits(t, output, "\nAdditional Commands:\n  completion")
  1877  	checkStringContains(t, output, "\ngroup\n  completion")
  1878  }
  1879  
  1880  func TestUngroupedCommand(t *testing.T) {
  1881  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1882  
  1883  	rootCmd.AddGroup(&Group{ID: "group", Title: "group"})
  1884  	rootCmd.AddGroup(&Group{ID: "help", Title: "help"})
  1885  
  1886  	rootCmd.AddCommand(&Command{Use: "xxx", GroupID: "group", Run: emptyRun})
  1887  	rootCmd.SetHelpCommandGroupID("help")
  1888  	rootCmd.SetCompletionCommandGroupID("group")
  1889  
  1890  	// Add a command without a group
  1891  	rootCmd.AddCommand(&Command{Use: "yyy", Run: emptyRun})
  1892  
  1893  	output, err := executeCommand(rootCmd, "--help")
  1894  	if err != nil {
  1895  		t.Errorf("Unexpected error: %v", err)
  1896  	}
  1897  
  1898  	// The yyy command should be in the additional command "group"
  1899  	checkStringContains(t, output, "\nAdditional Commands:\n  yyy")
  1900  }
  1901  
  1902  func TestAddGroup(t *testing.T) {
  1903  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1904  
  1905  	rootCmd.AddGroup(&Group{ID: "group", Title: "Test group"})
  1906  	rootCmd.AddCommand(&Command{Use: "cmd", GroupID: "group", Run: emptyRun})
  1907  
  1908  	output, err := executeCommand(rootCmd, "--help")
  1909  	if err != nil {
  1910  		t.Errorf("Unexpected error: %v", err)
  1911  	}
  1912  
  1913  	checkStringContains(t, output, "\nTest group\n  cmd")
  1914  }
  1915  
  1916  func TestWrongGroupFirstLevel(t *testing.T) {
  1917  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1918  
  1919  	rootCmd.AddGroup(&Group{ID: "group", Title: "Test group"})
  1920  	// Use the wrong group ID
  1921  	rootCmd.AddCommand(&Command{Use: "cmd", GroupID: "wrong", Run: emptyRun})
  1922  
  1923  	defer func() {
  1924  		if recover() == nil {
  1925  			t.Errorf("The code should have panicked due to a missing group")
  1926  		}
  1927  	}()
  1928  	_, err := executeCommand(rootCmd, "--help")
  1929  	if err != nil {
  1930  		t.Errorf("Unexpected error: %v", err)
  1931  	}
  1932  }
  1933  
  1934  func TestWrongGroupNestedLevel(t *testing.T) {
  1935  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1936  	var childCmd = &Command{Use: "child", Run: emptyRun}
  1937  	rootCmd.AddCommand(childCmd)
  1938  
  1939  	childCmd.AddGroup(&Group{ID: "group", Title: "Test group"})
  1940  	// Use the wrong group ID
  1941  	childCmd.AddCommand(&Command{Use: "cmd", GroupID: "wrong", Run: emptyRun})
  1942  
  1943  	defer func() {
  1944  		if recover() == nil {
  1945  			t.Errorf("The code should have panicked due to a missing group")
  1946  		}
  1947  	}()
  1948  	_, err := executeCommand(rootCmd, "child", "--help")
  1949  	if err != nil {
  1950  		t.Errorf("Unexpected error: %v", err)
  1951  	}
  1952  }
  1953  
  1954  func TestWrongGroupForHelp(t *testing.T) {
  1955  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1956  	var childCmd = &Command{Use: "child", Run: emptyRun}
  1957  	rootCmd.AddCommand(childCmd)
  1958  
  1959  	rootCmd.AddGroup(&Group{ID: "group", Title: "Test group"})
  1960  	// Use the wrong group ID
  1961  	rootCmd.SetHelpCommandGroupID("wrong")
  1962  
  1963  	defer func() {
  1964  		if recover() == nil {
  1965  			t.Errorf("The code should have panicked due to a missing group")
  1966  		}
  1967  	}()
  1968  	_, err := executeCommand(rootCmd, "--help")
  1969  	if err != nil {
  1970  		t.Errorf("Unexpected error: %v", err)
  1971  	}
  1972  }
  1973  
  1974  func TestWrongGroupForCompletion(t *testing.T) {
  1975  	var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun}
  1976  	var childCmd = &Command{Use: "child", Run: emptyRun}
  1977  	rootCmd.AddCommand(childCmd)
  1978  
  1979  	rootCmd.AddGroup(&Group{ID: "group", Title: "Test group"})
  1980  	// Use the wrong group ID
  1981  	rootCmd.SetCompletionCommandGroupID("wrong")
  1982  
  1983  	defer func() {
  1984  		if recover() == nil {
  1985  			t.Errorf("The code should have panicked due to a missing group")
  1986  		}
  1987  	}()
  1988  	_, err := executeCommand(rootCmd, "--help")
  1989  	if err != nil {
  1990  		t.Errorf("Unexpected error: %v", err)
  1991  	}
  1992  }
  1993  
  1994  func TestSetOutput(t *testing.T) {
  1995  	c := &Command{}
  1996  	c.SetOutput(nil)
  1997  	if out := c.OutOrStdout(); out != os.Stdout {
  1998  		t.Errorf("Expected setting output to nil to revert back to stdout")
  1999  	}
  2000  }
  2001  
  2002  func TestSetOut(t *testing.T) {
  2003  	c := &Command{}
  2004  	c.SetOut(nil)
  2005  	if out := c.OutOrStdout(); out != os.Stdout {
  2006  		t.Errorf("Expected setting output to nil to revert back to stdout")
  2007  	}
  2008  }
  2009  
  2010  func TestSetErr(t *testing.T) {
  2011  	c := &Command{}
  2012  	c.SetErr(nil)
  2013  	if out := c.ErrOrStderr(); out != os.Stderr {
  2014  		t.Errorf("Expected setting error to nil to revert back to stderr")
  2015  	}
  2016  }
  2017  
  2018  func TestSetIn(t *testing.T) {
  2019  	c := &Command{}
  2020  	c.SetIn(nil)
  2021  	if out := c.InOrStdin(); out != os.Stdin {
  2022  		t.Errorf("Expected setting input to nil to revert back to stdin")
  2023  	}
  2024  }
  2025  
  2026  func TestUsageStringRedirected(t *testing.T) {
  2027  	c := &Command{}
  2028  
  2029  	c.usageFunc = func(cmd *Command) error {
  2030  		cmd.Print("[stdout1]")
  2031  		cmd.PrintErr("[stderr2]")
  2032  		cmd.Print("[stdout3]")
  2033  		return nil
  2034  	}
  2035  
  2036  	expected := "[stdout1][stderr2][stdout3]"
  2037  	if got := c.UsageString(); got != expected {
  2038  		t.Errorf("Expected usage string to consider both stdout and stderr")
  2039  	}
  2040  }
  2041  
  2042  func TestCommandPrintRedirection(t *testing.T) {
  2043  	errBuff, outBuff := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
  2044  	root := &Command{
  2045  		Run: func(cmd *Command, args []string) {
  2046  
  2047  			cmd.PrintErr("PrintErr")
  2048  			cmd.PrintErrln("PrintErr", "line")
  2049  			cmd.PrintErrf("PrintEr%s", "r")
  2050  
  2051  			cmd.Print("Print")
  2052  			cmd.Println("Print", "line")
  2053  			cmd.Printf("Prin%s", "t")
  2054  		},
  2055  	}
  2056  
  2057  	root.SetErr(errBuff)
  2058  	root.SetOut(outBuff)
  2059  
  2060  	if err := root.Execute(); err != nil {
  2061  		t.Error(err)
  2062  	}
  2063  
  2064  	gotErrBytes, err := ioutil.ReadAll(errBuff)
  2065  	if err != nil {
  2066  		t.Error(err)
  2067  	}
  2068  
  2069  	gotOutBytes, err := ioutil.ReadAll(outBuff)
  2070  	if err != nil {
  2071  		t.Error(err)
  2072  	}
  2073  
  2074  	if wantErr := []byte("PrintErrPrintErr line\nPrintErr"); !bytes.Equal(gotErrBytes, wantErr) {
  2075  		t.Errorf("got: '%s' want: '%s'", gotErrBytes, wantErr)
  2076  	}
  2077  
  2078  	if wantOut := []byte("PrintPrint line\nPrint"); !bytes.Equal(gotOutBytes, wantOut) {
  2079  		t.Errorf("got: '%s' want: '%s'", gotOutBytes, wantOut)
  2080  	}
  2081  }
  2082  
  2083  func TestFlagErrorFunc(t *testing.T) {
  2084  	c := &Command{Use: "c", Run: emptyRun}
  2085  
  2086  	expectedFmt := "This is expected: %v"
  2087  	c.SetFlagErrorFunc(func(_ *Command, err error) error {
  2088  		return fmt.Errorf(expectedFmt, err)
  2089  	})
  2090  
  2091  	_, err := executeCommand(c, "--unknown-flag")
  2092  
  2093  	got := err.Error()
  2094  	expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag")
  2095  	if got != expected {
  2096  		t.Errorf("Expected %v, got %v", expected, got)
  2097  	}
  2098  }
  2099  
  2100  func TestFlagErrorFuncHelp(t *testing.T) {
  2101  	c := &Command{Use: "c", Run: emptyRun}
  2102  	c.PersistentFlags().Bool("help", false, "help for c")
  2103  	c.SetFlagErrorFunc(func(_ *Command, err error) error {
  2104  		return fmt.Errorf("wrap error: %w", err)
  2105  	})
  2106  
  2107  	out, err := executeCommand(c, "--help")
  2108  	if err != nil {
  2109  		t.Errorf("--help should not fail: %v", err)
  2110  	}
  2111  
  2112  	expected := `Usage:
  2113    c [flags]
  2114  
  2115  Flags:
  2116        --help   help for c
  2117  `
  2118  	if out != expected {
  2119  		t.Errorf("Expected: %v, got: %v", expected, out)
  2120  	}
  2121  
  2122  	out, err = executeCommand(c, "-h")
  2123  	if err != nil {
  2124  		t.Errorf("-h should not fail: %v", err)
  2125  	}
  2126  
  2127  	if out != expected {
  2128  		t.Errorf("Expected: %v, got: %v", expected, out)
  2129  	}
  2130  }
  2131  
  2132  // TestSortedFlags checks,
  2133  // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
  2134  // Related to https://github.com/spf13/cobra/issues/404.
  2135  func TestSortedFlags(t *testing.T) {
  2136  	c := &Command{}
  2137  	c.Flags().SortFlags = false
  2138  	names := []string{"C", "B", "A", "D"}
  2139  	for _, name := range names {
  2140  		c.Flags().Bool(name, false, "")
  2141  	}
  2142  
  2143  	i := 0
  2144  	c.LocalFlags().VisitAll(func(f *pflag.Flag) {
  2145  		if i == len(names) {
  2146  			return
  2147  		}
  2148  		if stringInSlice(f.Name, names) {
  2149  			if names[i] != f.Name {
  2150  				t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
  2151  			}
  2152  			i++
  2153  		}
  2154  	})
  2155  }
  2156  
  2157  // TestMergeCommandLineToFlags checks,
  2158  // if pflag.CommandLine is correctly merged to c.Flags() after first call
  2159  // of c.mergePersistentFlags.
  2160  // Related to https://github.com/spf13/cobra/issues/443.
  2161  func TestMergeCommandLineToFlags(t *testing.T) {
  2162  	pflag.Bool("boolflag", false, "")
  2163  	c := &Command{Use: "c", Run: emptyRun}
  2164  	c.mergePersistentFlags()
  2165  	if c.Flags().Lookup("boolflag") == nil {
  2166  		t.Fatal("Expecting to have flag from CommandLine in c.Flags()")
  2167  	}
  2168  
  2169  	resetCommandLineFlagSet()
  2170  }
  2171  
  2172  // TestUseDeprecatedFlags checks,
  2173  // if cobra.Execute() prints a message, if a deprecated flag is used.
  2174  // Related to https://github.com/spf13/cobra/issues/463.
  2175  func TestUseDeprecatedFlags(t *testing.T) {
  2176  	c := &Command{Use: "c", Run: emptyRun}
  2177  	c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
  2178  	assertNoErr(t, c.Flags().MarkDeprecated("deprecated", "This flag is deprecated"))
  2179  
  2180  	output, err := executeCommand(c, "c", "-d")
  2181  	if err != nil {
  2182  		t.Error("Unexpected error:", err)
  2183  	}
  2184  	checkStringContains(t, output, "This flag is deprecated")
  2185  }
  2186  
  2187  func TestTraverseWithParentFlags(t *testing.T) {
  2188  	rootCmd := &Command{Use: "root", TraverseChildren: true}
  2189  	rootCmd.Flags().String("str", "", "")
  2190  	rootCmd.Flags().BoolP("bool", "b", false, "")
  2191  
  2192  	childCmd := &Command{Use: "child"}
  2193  	childCmd.Flags().Int("int", -1, "")
  2194  
  2195  	rootCmd.AddCommand(childCmd)
  2196  
  2197  	c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"})
  2198  	if err != nil {
  2199  		t.Errorf("Unexpected error: %v", err)
  2200  	}
  2201  	if len(args) != 1 && args[0] != "--add" {
  2202  		t.Errorf("Wrong args: %v", args)
  2203  	}
  2204  	if c.Name() != childCmd.Name() {
  2205  		t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
  2206  	}
  2207  }
  2208  
  2209  func TestTraverseNoParentFlags(t *testing.T) {
  2210  	rootCmd := &Command{Use: "root", TraverseChildren: true}
  2211  	rootCmd.Flags().String("foo", "", "foo things")
  2212  
  2213  	childCmd := &Command{Use: "child"}
  2214  	childCmd.Flags().String("str", "", "")
  2215  	rootCmd.AddCommand(childCmd)
  2216  
  2217  	c, args, err := rootCmd.Traverse([]string{"child"})
  2218  	if err != nil {
  2219  		t.Errorf("Unexpected error: %v", err)
  2220  	}
  2221  	if len(args) != 0 {
  2222  		t.Errorf("Wrong args %v", args)
  2223  	}
  2224  	if c.Name() != childCmd.Name() {
  2225  		t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
  2226  	}
  2227  }
  2228  
  2229  func TestTraverseWithBadParentFlags(t *testing.T) {
  2230  	rootCmd := &Command{Use: "root", TraverseChildren: true}
  2231  
  2232  	childCmd := &Command{Use: "child"}
  2233  	childCmd.Flags().String("str", "", "")
  2234  	rootCmd.AddCommand(childCmd)
  2235  
  2236  	expected := "unknown flag: --str"
  2237  
  2238  	c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"})
  2239  	if err == nil || !strings.Contains(err.Error(), expected) {
  2240  		t.Errorf("Expected error, %q, got %q", expected, err)
  2241  	}
  2242  	if c != nil {
  2243  		t.Errorf("Expected nil command")
  2244  	}
  2245  }
  2246  
  2247  func TestTraverseWithBadChildFlag(t *testing.T) {
  2248  	rootCmd := &Command{Use: "root", TraverseChildren: true}
  2249  	rootCmd.Flags().String("str", "", "")
  2250  
  2251  	childCmd := &Command{Use: "child"}
  2252  	rootCmd.AddCommand(childCmd)
  2253  
  2254  	// Expect no error because the last commands args shouldn't be parsed in
  2255  	// Traverse.
  2256  	c, args, err := rootCmd.Traverse([]string{"child", "--str"})
  2257  	if err != nil {
  2258  		t.Errorf("Unexpected error: %v", err)
  2259  	}
  2260  	if len(args) != 1 && args[0] != "--str" {
  2261  		t.Errorf("Wrong args: %v", args)
  2262  	}
  2263  	if c.Name() != childCmd.Name() {
  2264  		t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name())
  2265  	}
  2266  }
  2267  
  2268  func TestTraverseWithTwoSubcommands(t *testing.T) {
  2269  	rootCmd := &Command{Use: "root", TraverseChildren: true}
  2270  
  2271  	subCmd := &Command{Use: "sub", TraverseChildren: true}
  2272  	rootCmd.AddCommand(subCmd)
  2273  
  2274  	subsubCmd := &Command{
  2275  		Use: "subsub",
  2276  	}
  2277  	subCmd.AddCommand(subsubCmd)
  2278  
  2279  	c, _, err := rootCmd.Traverse([]string{"sub", "subsub"})
  2280  	if err != nil {
  2281  		t.Fatalf("Unexpected error: %v", err)
  2282  	}
  2283  	if c.Name() != subsubCmd.Name() {
  2284  		t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name())
  2285  	}
  2286  }
  2287  
  2288  // TestUpdateName checks if c.Name() updates on changed c.Use.
  2289  // Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
  2290  func TestUpdateName(t *testing.T) {
  2291  	c := &Command{Use: "name xyz"}
  2292  	originalName := c.Name()
  2293  
  2294  	c.Use = "changedName abc"
  2295  	if originalName == c.Name() || c.Name() != "changedName" {
  2296  		t.Error("c.Name() should be updated on changed c.Use")
  2297  	}
  2298  }
  2299  
  2300  type calledAsTestcase struct {
  2301  	args []string
  2302  	call string
  2303  	want string
  2304  	epm  bool
  2305  }
  2306  
  2307  func (tc *calledAsTestcase) test(t *testing.T) {
  2308  	defer func(ov bool) { EnablePrefixMatching = ov }(EnablePrefixMatching)
  2309  	EnablePrefixMatching = tc.epm
  2310  
  2311  	var called *Command
  2312  	run := func(c *Command, _ []string) { t.Logf("called: %q", c.Name()); called = c }
  2313  
  2314  	parent := &Command{Use: "parent", Run: run}
  2315  	child1 := &Command{Use: "child1", Run: run, Aliases: []string{"this"}}
  2316  	child2 := &Command{Use: "child2", Run: run, Aliases: []string{"that"}}
  2317  
  2318  	parent.AddCommand(child1)
  2319  	parent.AddCommand(child2)
  2320  	parent.SetArgs(tc.args)
  2321  
  2322  	output := new(bytes.Buffer)
  2323  	parent.SetOut(output)
  2324  	parent.SetErr(output)
  2325  
  2326  	_ = parent.Execute()
  2327  
  2328  	if called == nil {
  2329  		if tc.call != "" {
  2330  			t.Errorf("missing expected call to command: %s", tc.call)
  2331  		}
  2332  		return
  2333  	}
  2334  
  2335  	if called.Name() != tc.call {
  2336  		t.Errorf("called command == %q; Wanted %q", called.Name(), tc.call)
  2337  	} else if got := called.CalledAs(); got != tc.want {
  2338  		t.Errorf("%s.CalledAs() == %q; Wanted: %q", tc.call, got, tc.want)
  2339  	}
  2340  }
  2341  
  2342  func TestCalledAs(t *testing.T) {
  2343  	tests := map[string]calledAsTestcase{
  2344  		"find/no-args":            {nil, "parent", "parent", false},
  2345  		"find/real-name":          {[]string{"child1"}, "child1", "child1", false},
  2346  		"find/full-alias":         {[]string{"that"}, "child2", "that", false},
  2347  		"find/part-no-prefix":     {[]string{"thi"}, "", "", false},
  2348  		"find/part-alias":         {[]string{"thi"}, "child1", "this", true},
  2349  		"find/conflict":           {[]string{"th"}, "", "", true},
  2350  		"traverse/no-args":        {nil, "parent", "parent", false},
  2351  		"traverse/real-name":      {[]string{"child1"}, "child1", "child1", false},
  2352  		"traverse/full-alias":     {[]string{"that"}, "child2", "that", false},
  2353  		"traverse/part-no-prefix": {[]string{"thi"}, "", "", false},
  2354  		"traverse/part-alias":     {[]string{"thi"}, "child1", "this", true},
  2355  		"traverse/conflict":       {[]string{"th"}, "", "", true},
  2356  	}
  2357  
  2358  	for name, tc := range tests {
  2359  		t.Run(name, tc.test)
  2360  	}
  2361  }
  2362  
  2363  func TestFParseErrWhitelistBackwardCompatibility(t *testing.T) {
  2364  	c := &Command{Use: "c", Run: emptyRun}
  2365  	c.Flags().BoolP("boola", "a", false, "a boolean flag")
  2366  
  2367  	output, err := executeCommand(c, "c", "-a", "--unknown", "flag")
  2368  	if err == nil {
  2369  		t.Error("expected unknown flag error")
  2370  	}
  2371  	checkStringContains(t, output, "unknown flag: --unknown")
  2372  }
  2373  
  2374  func TestFParseErrWhitelistSameCommand(t *testing.T) {
  2375  	c := &Command{
  2376  		Use: "c",
  2377  		Run: emptyRun,
  2378  		FParseErrWhitelist: FParseErrWhitelist{
  2379  			UnknownFlags: true,
  2380  		},
  2381  	}
  2382  	c.Flags().BoolP("boola", "a", false, "a boolean flag")
  2383  
  2384  	_, err := executeCommand(c, "c", "-a", "--unknown", "flag")
  2385  	if err != nil {
  2386  		t.Error("unexpected error: ", err)
  2387  	}
  2388  }
  2389  
  2390  func TestFParseErrWhitelistParentCommand(t *testing.T) {
  2391  	root := &Command{
  2392  		Use: "root",
  2393  		Run: emptyRun,
  2394  		FParseErrWhitelist: FParseErrWhitelist{
  2395  			UnknownFlags: true,
  2396  		},
  2397  	}
  2398  
  2399  	c := &Command{
  2400  		Use: "child",
  2401  		Run: emptyRun,
  2402  	}
  2403  	c.Flags().BoolP("boola", "a", false, "a boolean flag")
  2404  
  2405  	root.AddCommand(c)
  2406  
  2407  	output, err := executeCommand(root, "child", "-a", "--unknown", "flag")
  2408  	if err == nil {
  2409  		t.Error("expected unknown flag error")
  2410  	}
  2411  	checkStringContains(t, output, "unknown flag: --unknown")
  2412  }
  2413  
  2414  func TestFParseErrWhitelistChildCommand(t *testing.T) {
  2415  	root := &Command{
  2416  		Use: "root",
  2417  		Run: emptyRun,
  2418  	}
  2419  
  2420  	c := &Command{
  2421  		Use: "child",
  2422  		Run: emptyRun,
  2423  		FParseErrWhitelist: FParseErrWhitelist{
  2424  			UnknownFlags: true,
  2425  		},
  2426  	}
  2427  	c.Flags().BoolP("boola", "a", false, "a boolean flag")
  2428  
  2429  	root.AddCommand(c)
  2430  
  2431  	_, err := executeCommand(root, "child", "-a", "--unknown", "flag")
  2432  	if err != nil {
  2433  		t.Error("unexpected error: ", err.Error())
  2434  	}
  2435  }
  2436  
  2437  func TestFParseErrWhitelistSiblingCommand(t *testing.T) {
  2438  	root := &Command{
  2439  		Use: "root",
  2440  		Run: emptyRun,
  2441  	}
  2442  
  2443  	c := &Command{
  2444  		Use: "child",
  2445  		Run: emptyRun,
  2446  		FParseErrWhitelist: FParseErrWhitelist{
  2447  			UnknownFlags: true,
  2448  		},
  2449  	}
  2450  	c.Flags().BoolP("boola", "a", false, "a boolean flag")
  2451  
  2452  	s := &Command{
  2453  		Use: "sibling",
  2454  		Run: emptyRun,
  2455  	}
  2456  	s.Flags().BoolP("boolb", "b", false, "a boolean flag")
  2457  
  2458  	root.AddCommand(c)
  2459  	root.AddCommand(s)
  2460  
  2461  	output, err := executeCommand(root, "sibling", "-b", "--unknown", "flag")
  2462  	if err == nil {
  2463  		t.Error("expected unknown flag error")
  2464  	}
  2465  	checkStringContains(t, output, "unknown flag: --unknown")
  2466  }
  2467  
  2468  func TestSetContext(t *testing.T) {
  2469  	type key struct{}
  2470  	val := "foobar"
  2471  	root := &Command{
  2472  		Use: "root",
  2473  		Run: func(cmd *Command, args []string) {
  2474  			key := cmd.Context().Value(key{})
  2475  			got, ok := key.(string)
  2476  			if !ok {
  2477  				t.Error("key not found in context")
  2478  			}
  2479  			if got != val {
  2480  				t.Errorf("Expected value: \n %v\nGot:\n %v\n", val, got)
  2481  			}
  2482  		},
  2483  	}
  2484  
  2485  	ctx := context.WithValue(context.Background(), key{}, val)
  2486  	root.SetContext(ctx)
  2487  	err := root.Execute()
  2488  	if err != nil {
  2489  		t.Error(err)
  2490  	}
  2491  }
  2492  
  2493  func TestSetContextPreRun(t *testing.T) {
  2494  	type key struct{}
  2495  	val := "barr"
  2496  	root := &Command{
  2497  		Use: "root",
  2498  		PreRun: func(cmd *Command, args []string) {
  2499  			ctx := context.WithValue(cmd.Context(), key{}, val)
  2500  			cmd.SetContext(ctx)
  2501  		},
  2502  		Run: func(cmd *Command, args []string) {
  2503  			val := cmd.Context().Value(key{})
  2504  			got, ok := val.(string)
  2505  			if !ok {
  2506  				t.Error("key not found in context")
  2507  			}
  2508  			if got != val {
  2509  				t.Errorf("Expected value: \n %v\nGot:\n %v\n", val, got)
  2510  			}
  2511  		},
  2512  	}
  2513  	err := root.Execute()
  2514  	if err != nil {
  2515  		t.Error(err)
  2516  	}
  2517  }
  2518  
  2519  func TestSetContextPreRunOverwrite(t *testing.T) {
  2520  	type key struct{}
  2521  	val := "blah"
  2522  	root := &Command{
  2523  		Use: "root",
  2524  		Run: func(cmd *Command, args []string) {
  2525  			key := cmd.Context().Value(key{})
  2526  			_, ok := key.(string)
  2527  			if ok {
  2528  				t.Error("key found in context when not expected")
  2529  			}
  2530  		},
  2531  	}
  2532  	ctx := context.WithValue(context.Background(), key{}, val)
  2533  	root.SetContext(ctx)
  2534  	err := root.ExecuteContext(context.Background())
  2535  	if err != nil {
  2536  		t.Error(err)
  2537  	}
  2538  }
  2539  
  2540  func TestSetContextPersistentPreRun(t *testing.T) {
  2541  	type key struct{}
  2542  	val := "barbar"
  2543  	root := &Command{
  2544  		Use: "root",
  2545  		PersistentPreRun: func(cmd *Command, args []string) {
  2546  			ctx := context.WithValue(cmd.Context(), key{}, val)
  2547  			cmd.SetContext(ctx)
  2548  		},
  2549  	}
  2550  	child := &Command{
  2551  		Use: "child",
  2552  		Run: func(cmd *Command, args []string) {
  2553  			key := cmd.Context().Value(key{})
  2554  			got, ok := key.(string)
  2555  			if !ok {
  2556  				t.Error("key not found in context")
  2557  			}
  2558  			if got != val {
  2559  				t.Errorf("Expected value: \n %v\nGot:\n %v\n", val, got)
  2560  			}
  2561  		},
  2562  	}
  2563  	root.AddCommand(child)
  2564  	root.SetArgs([]string{"child"})
  2565  	err := root.Execute()
  2566  	if err != nil {
  2567  		t.Error(err)
  2568  	}
  2569  }
  2570  
  2571  const VersionFlag = "--version"
  2572  const HelpFlag = "--help"
  2573  
  2574  func TestNoRootRunCommandExecutedWithVersionSet(t *testing.T) {
  2575  	rootCmd := &Command{Use: "root", Version: "1.0.0", Long: "Long description"}
  2576  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
  2577  
  2578  	output, err := executeCommand(rootCmd)
  2579  	if err != nil {
  2580  		t.Errorf("Unexpected error: %v", err)
  2581  	}
  2582  
  2583  	checkStringContains(t, output, rootCmd.Long)
  2584  	checkStringContains(t, output, HelpFlag)
  2585  	checkStringContains(t, output, VersionFlag)
  2586  }
  2587  
  2588  func TestNoRootRunCommandExecutedWithoutVersionSet(t *testing.T) {
  2589  	rootCmd := &Command{Use: "root", Long: "Long description"}
  2590  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
  2591  
  2592  	output, err := executeCommand(rootCmd)
  2593  	if err != nil {
  2594  		t.Errorf("Unexpected error: %v", err)
  2595  	}
  2596  
  2597  	checkStringContains(t, output, rootCmd.Long)
  2598  	checkStringContains(t, output, HelpFlag)
  2599  	checkStringOmits(t, output, VersionFlag)
  2600  }
  2601  
  2602  func TestHelpCommandExecutedWithVersionSet(t *testing.T) {
  2603  	rootCmd := &Command{Use: "root", Version: "1.0.0", Long: "Long description", Run: emptyRun}
  2604  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
  2605  
  2606  	output, err := executeCommand(rootCmd, "help")
  2607  	if err != nil {
  2608  		t.Errorf("Unexpected error: %v", err)
  2609  	}
  2610  
  2611  	checkStringContains(t, output, rootCmd.Long)
  2612  	checkStringContains(t, output, HelpFlag)
  2613  	checkStringContains(t, output, VersionFlag)
  2614  }
  2615  
  2616  func TestHelpCommandExecutedWithoutVersionSet(t *testing.T) {
  2617  	rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
  2618  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
  2619  
  2620  	output, err := executeCommand(rootCmd, "help")
  2621  	if err != nil {
  2622  		t.Errorf("Unexpected error: %v", err)
  2623  	}
  2624  
  2625  	checkStringContains(t, output, rootCmd.Long)
  2626  	checkStringContains(t, output, HelpFlag)
  2627  	checkStringOmits(t, output, VersionFlag)
  2628  }
  2629  
  2630  func TestHelpflagCommandExecutedWithVersionSet(t *testing.T) {
  2631  	rootCmd := &Command{Use: "root", Version: "1.0.0", Long: "Long description", Run: emptyRun}
  2632  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
  2633  
  2634  	output, err := executeCommand(rootCmd, HelpFlag)
  2635  	if err != nil {
  2636  		t.Errorf("Unexpected error: %v", err)
  2637  	}
  2638  
  2639  	checkStringContains(t, output, rootCmd.Long)
  2640  	checkStringContains(t, output, HelpFlag)
  2641  	checkStringContains(t, output, VersionFlag)
  2642  }
  2643  
  2644  func TestHelpflagCommandExecutedWithoutVersionSet(t *testing.T) {
  2645  	rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
  2646  	rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
  2647  
  2648  	output, err := executeCommand(rootCmd, HelpFlag)
  2649  	if err != nil {
  2650  		t.Errorf("Unexpected error: %v", err)
  2651  	}
  2652  
  2653  	checkStringContains(t, output, rootCmd.Long)
  2654  	checkStringContains(t, output, HelpFlag)
  2655  	checkStringOmits(t, output, VersionFlag)
  2656  }
  2657  
  2658  func TestFind(t *testing.T) {
  2659  	var foo, bar string
  2660  	root := &Command{
  2661  		Use: "root",
  2662  	}
  2663  	root.PersistentFlags().StringVarP(&foo, "foo", "f", "", "")
  2664  	root.PersistentFlags().StringVarP(&bar, "bar", "b", "something", "")
  2665  
  2666  	child := &Command{
  2667  		Use: "child",
  2668  	}
  2669  	root.AddCommand(child)
  2670  
  2671  	testCases := []struct {
  2672  		args              []string
  2673  		expectedFoundArgs []string
  2674  	}{
  2675  		{
  2676  			[]string{"child"},
  2677  			[]string{},
  2678  		},
  2679  		{
  2680  			[]string{"child", "child"},
  2681  			[]string{"child"},
  2682  		},
  2683  		{
  2684  			[]string{"child", "foo", "child", "bar", "child", "baz", "child"},
  2685  			[]string{"foo", "child", "bar", "child", "baz", "child"},
  2686  		},
  2687  		{
  2688  			[]string{"-f", "child", "child"},
  2689  			[]string{"-f", "child"},
  2690  		},
  2691  		{
  2692  			[]string{"child", "-f", "child"},
  2693  			[]string{"-f", "child"},
  2694  		},
  2695  		{
  2696  			[]string{"-b", "child", "child"},
  2697  			[]string{"-b", "child"},
  2698  		},
  2699  		{
  2700  			[]string{"child", "-b", "child"},
  2701  			[]string{"-b", "child"},
  2702  		},
  2703  		{
  2704  			[]string{"child", "-b"},
  2705  			[]string{"-b"},
  2706  		},
  2707  		{
  2708  			[]string{"-b", "-f", "child", "child"},
  2709  			[]string{"-b", "-f", "child"},
  2710  		},
  2711  		{
  2712  			[]string{"-f", "child", "-b", "something", "child"},
  2713  			[]string{"-f", "child", "-b", "something"},
  2714  		},
  2715  		{
  2716  			[]string{"-f", "child", "child", "-b"},
  2717  			[]string{"-f", "child", "-b"},
  2718  		},
  2719  		{
  2720  			[]string{"-f=child", "-b=something", "child"},
  2721  			[]string{"-f=child", "-b=something"},
  2722  		},
  2723  		{
  2724  			[]string{"--foo", "child", "--bar", "something", "child"},
  2725  			[]string{"--foo", "child", "--bar", "something"},
  2726  		},
  2727  	}
  2728  
  2729  	for _, tc := range testCases {
  2730  		t.Run(fmt.Sprintf("%v", tc.args), func(t *testing.T) {
  2731  			cmd, foundArgs, err := root.Find(tc.args)
  2732  			if err != nil {
  2733  				t.Fatal(err)
  2734  			}
  2735  
  2736  			if cmd != child {
  2737  				t.Fatal("Expected cmd to be child, but it was not")
  2738  			}
  2739  
  2740  			if !reflect.DeepEqual(tc.expectedFoundArgs, foundArgs) {
  2741  				t.Fatalf("Wrong args\nExpected: %v\nGot: %v", tc.expectedFoundArgs, foundArgs)
  2742  			}
  2743  		})
  2744  	}
  2745  }
  2746  
  2747  func TestUnknownFlagShouldReturnSameErrorRegardlessOfArgPosition(t *testing.T) {
  2748  	testCases := [][]string{
  2749  		//{"--unknown", "--namespace", "foo", "child", "--bar"}, // FIXME: This test case fails, returning the error `unknown command "foo" for "root"` instead of the expected error `unknown flag: --unknown`
  2750  		{"--namespace", "foo", "--unknown", "child", "--bar"},
  2751  		{"--namespace", "foo", "child", "--unknown", "--bar"},
  2752  		{"--namespace", "foo", "child", "--bar", "--unknown"},
  2753  
  2754  		{"--unknown", "--namespace=foo", "child", "--bar"},
  2755  		{"--namespace=foo", "--unknown", "child", "--bar"},
  2756  		{"--namespace=foo", "child", "--unknown", "--bar"},
  2757  		{"--namespace=foo", "child", "--bar", "--unknown"},
  2758  
  2759  		{"--unknown", "--namespace=foo", "child", "--bar=true"},
  2760  		{"--namespace=foo", "--unknown", "child", "--bar=true"},
  2761  		{"--namespace=foo", "child", "--unknown", "--bar=true"},
  2762  		{"--namespace=foo", "child", "--bar=true", "--unknown"},
  2763  	}
  2764  
  2765  	root := &Command{
  2766  		Use: "root",
  2767  		Run: emptyRun,
  2768  	}
  2769  	root.PersistentFlags().String("namespace", "", "a string flag")
  2770  
  2771  	c := &Command{
  2772  		Use: "child",
  2773  		Run: emptyRun,
  2774  	}
  2775  	c.Flags().Bool("bar", false, "a boolean flag")
  2776  
  2777  	root.AddCommand(c)
  2778  
  2779  	for _, tc := range testCases {
  2780  		t.Run(strings.Join(tc, " "), func(t *testing.T) {
  2781  			output, err := executeCommand(root, tc...)
  2782  			if err == nil {
  2783  				t.Error("expected unknown flag error")
  2784  			}
  2785  			checkStringContains(t, output, "unknown flag: --unknown")
  2786  		})
  2787  	}
  2788  }
  2789  

View as plain text