git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/cobra/completions_test.go (about)

     1  // Copyright 2013-2022 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  	"strings"
    21  	"testing"
    22  )
    23  
    24  func validArgsFunc(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
    25  	if len(args) != 0 {
    26  		return nil, ShellCompDirectiveNoFileComp
    27  	}
    28  
    29  	var completions []string
    30  	for _, comp := range []string{"one\tThe first", "two\tThe second"} {
    31  		if strings.HasPrefix(comp, toComplete) {
    32  			completions = append(completions, comp)
    33  		}
    34  	}
    35  	return completions, ShellCompDirectiveDefault
    36  }
    37  
    38  func validArgsFunc2(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
    39  	if len(args) != 0 {
    40  		return nil, ShellCompDirectiveNoFileComp
    41  	}
    42  
    43  	var completions []string
    44  	for _, comp := range []string{"three\tThe third", "four\tThe fourth"} {
    45  		if strings.HasPrefix(comp, toComplete) {
    46  			completions = append(completions, comp)
    47  		}
    48  	}
    49  	return completions, ShellCompDirectiveDefault
    50  }
    51  
    52  func TestCmdNameCompletionInGo(t *testing.T) {
    53  	rootCmd := &Command{
    54  		Use: "root",
    55  		Run: emptyRun,
    56  	}
    57  	childCmd1 := &Command{
    58  		Use:   "firstChild",
    59  		Short: "First command",
    60  		Run:   emptyRun,
    61  	}
    62  	childCmd2 := &Command{
    63  		Use: "secondChild",
    64  		Run: emptyRun,
    65  	}
    66  	hiddenCmd := &Command{
    67  		Use:    "testHidden",
    68  		Hidden: true, // Not completed
    69  		Run:    emptyRun,
    70  	}
    71  	deprecatedCmd := &Command{
    72  		Use:        "testDeprecated",
    73  		Deprecated: "deprecated", // Not completed
    74  		Run:        emptyRun,
    75  	}
    76  	aliasedCmd := &Command{
    77  		Use:     "aliased",
    78  		Short:   "A command with aliases",
    79  		Aliases: []string{"testAlias", "testSynonym"}, // Not completed
    80  		Run:     emptyRun,
    81  	}
    82  
    83  	rootCmd.AddCommand(childCmd1, childCmd2, hiddenCmd, deprecatedCmd, aliasedCmd)
    84  
    85  	// Test that sub-command names are completed
    86  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
    87  	if err != nil {
    88  		t.Errorf("Unexpected error: %v", err)
    89  	}
    90  
    91  	expected := strings.Join([]string{
    92  		"aliased",
    93  		"completion",
    94  		"firstChild",
    95  		"help",
    96  		"secondChild",
    97  		":4",
    98  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
    99  
   100  	if output != expected {
   101  		t.Errorf("expected: %q, got: %q", expected, output)
   102  	}
   103  
   104  	// Test that sub-command names are completed with prefix
   105  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "s")
   106  	if err != nil {
   107  		t.Errorf("Unexpected error: %v", err)
   108  	}
   109  
   110  	expected = strings.Join([]string{
   111  		"secondChild",
   112  		":4",
   113  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   114  
   115  	if output != expected {
   116  		t.Errorf("expected: %q, got: %q", expected, output)
   117  	}
   118  
   119  	// Test that even with no valid sub-command matches, hidden, deprecated and
   120  	// aliases are not completed
   121  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "test")
   122  	if err != nil {
   123  		t.Errorf("Unexpected error: %v", err)
   124  	}
   125  
   126  	expected = strings.Join([]string{
   127  		":4",
   128  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   129  
   130  	if output != expected {
   131  		t.Errorf("expected: %q, got: %q", expected, output)
   132  	}
   133  
   134  	// Test that sub-command names are completed with description
   135  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "")
   136  	if err != nil {
   137  		t.Errorf("Unexpected error: %v", err)
   138  	}
   139  
   140  	expected = strings.Join([]string{
   141  		"aliased\tA command with aliases",
   142  		"completion\tGenerate the autocompletion script for the specified shell",
   143  		"firstChild\tFirst command",
   144  		"help\tHelp about any command",
   145  		"secondChild",
   146  		":4",
   147  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   148  
   149  	if output != expected {
   150  		t.Errorf("expected: %q, got: %q", expected, output)
   151  	}
   152  }
   153  
   154  func TestNoCmdNameCompletionInGo(t *testing.T) {
   155  	rootCmd := &Command{
   156  		Use: "root",
   157  		Run: emptyRun,
   158  	}
   159  	rootCmd.Flags().String("localroot", "", "local root flag")
   160  
   161  	childCmd1 := &Command{
   162  		Use:   "childCmd1",
   163  		Short: "First command",
   164  		Args:  MinimumNArgs(0),
   165  		Run:   emptyRun,
   166  	}
   167  	rootCmd.AddCommand(childCmd1)
   168  	childCmd1.PersistentFlags().StringP("persistent", "p", "", "persistent flag")
   169  	persistentFlag := childCmd1.PersistentFlags().Lookup("persistent")
   170  	childCmd1.Flags().StringP("nonPersistent", "n", "", "non-persistent flag")
   171  	nonPersistentFlag := childCmd1.Flags().Lookup("nonPersistent")
   172  
   173  	childCmd2 := &Command{
   174  		Use: "childCmd2",
   175  		Run: emptyRun,
   176  	}
   177  	childCmd1.AddCommand(childCmd2)
   178  
   179  	// Test that sub-command names are not completed if there is an argument already
   180  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "arg1", "")
   181  	if err != nil {
   182  		t.Errorf("Unexpected error: %v", err)
   183  	}
   184  
   185  	expected := strings.Join([]string{
   186  		":0",
   187  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   188  
   189  	if output != expected {
   190  		t.Errorf("expected: %q, got: %q", expected, output)
   191  	}
   192  
   193  	// Test that sub-command names are not completed if a local non-persistent flag is present
   194  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--nonPersistent", "value", "")
   195  	if err != nil {
   196  		t.Errorf("Unexpected error: %v", err)
   197  	}
   198  	// Reset the flag for the next command
   199  	nonPersistentFlag.Changed = false
   200  
   201  	expected = strings.Join([]string{
   202  		":0",
   203  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   204  
   205  	if output != expected {
   206  		t.Errorf("expected: %q, got: %q", expected, output)
   207  	}
   208  
   209  	// Test that sub-command names are completed if a local non-persistent flag is present and TraverseChildren is set to true
   210  	// set TraverseChildren to true on the root cmd
   211  	rootCmd.TraverseChildren = true
   212  
   213  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "")
   214  	if err != nil {
   215  		t.Errorf("Unexpected error: %v", err)
   216  	}
   217  	// Reset TraverseChildren for next command
   218  	rootCmd.TraverseChildren = false
   219  
   220  	expected = strings.Join([]string{
   221  		"childCmd1",
   222  		"completion",
   223  		"help",
   224  		":4",
   225  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   226  
   227  	if output != expected {
   228  		t.Errorf("expected: %q, got: %q", expected, output)
   229  	}
   230  
   231  	// Test that sub-command names from a child cmd are completed if a local non-persistent flag is present
   232  	// and TraverseChildren is set to true on the root cmd
   233  	rootCmd.TraverseChildren = true
   234  
   235  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "--nonPersistent", "value", "")
   236  	if err != nil {
   237  		t.Errorf("Unexpected error: %v", err)
   238  	}
   239  	// Reset TraverseChildren for next command
   240  	rootCmd.TraverseChildren = false
   241  	// Reset the flag for the next command
   242  	nonPersistentFlag.Changed = false
   243  
   244  	expected = strings.Join([]string{
   245  		"childCmd2",
   246  		":4",
   247  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   248  
   249  	if output != expected {
   250  		t.Errorf("expected: %q, got: %q", expected, output)
   251  	}
   252  
   253  	// Test that we don't use Traverse when we shouldn't.
   254  	// This command should not return a completion since the command line is invalid without TraverseChildren.
   255  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "")
   256  	if err != nil {
   257  		t.Errorf("Unexpected error: %v", err)
   258  	}
   259  
   260  	expected = strings.Join([]string{
   261  		":0",
   262  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   263  
   264  	if output != expected {
   265  		t.Errorf("expected: %q, got: %q", expected, output)
   266  	}
   267  
   268  	// Test that sub-command names are not completed if a local non-persistent short flag is present
   269  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-n", "value", "")
   270  	if err != nil {
   271  		t.Errorf("Unexpected error: %v", err)
   272  	}
   273  	// Reset the flag for the next command
   274  	nonPersistentFlag.Changed = false
   275  
   276  	expected = strings.Join([]string{
   277  		":0",
   278  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   279  
   280  	if output != expected {
   281  		t.Errorf("expected: %q, got: %q", expected, output)
   282  	}
   283  
   284  	// Test that sub-command names are completed with a persistent flag
   285  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--persistent", "value", "")
   286  	if err != nil {
   287  		t.Errorf("Unexpected error: %v", err)
   288  	}
   289  	// Reset the flag for the next command
   290  	persistentFlag.Changed = false
   291  
   292  	expected = strings.Join([]string{
   293  		"childCmd2",
   294  		":4",
   295  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   296  
   297  	if output != expected {
   298  		t.Errorf("expected: %q, got: %q", expected, output)
   299  	}
   300  
   301  	// Test that sub-command names are completed with a persistent short flag
   302  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-p", "value", "")
   303  	if err != nil {
   304  		t.Errorf("Unexpected error: %v", err)
   305  	}
   306  	// Reset the flag for the next command
   307  	persistentFlag.Changed = false
   308  
   309  	expected = strings.Join([]string{
   310  		"childCmd2",
   311  		":4",
   312  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   313  
   314  	if output != expected {
   315  		t.Errorf("expected: %q, got: %q", expected, output)
   316  	}
   317  }
   318  
   319  func TestValidArgsCompletionInGo(t *testing.T) {
   320  	rootCmd := &Command{
   321  		Use:       "root",
   322  		ValidArgs: []string{"one", "two", "three"},
   323  		Args:      MinimumNArgs(1),
   324  	}
   325  
   326  	// Test that validArgs are completed
   327  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
   328  	if err != nil {
   329  		t.Errorf("Unexpected error: %v", err)
   330  	}
   331  
   332  	expected := strings.Join([]string{
   333  		"one",
   334  		"two",
   335  		"three",
   336  		":4",
   337  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   338  
   339  	if output != expected {
   340  		t.Errorf("expected: %q, got: %q", expected, output)
   341  	}
   342  
   343  	// Test that validArgs are completed with prefix
   344  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "o")
   345  	if err != nil {
   346  		t.Errorf("Unexpected error: %v", err)
   347  	}
   348  
   349  	expected = strings.Join([]string{
   350  		"one",
   351  		":4",
   352  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   353  
   354  	if output != expected {
   355  		t.Errorf("expected: %q, got: %q", expected, output)
   356  	}
   357  
   358  	// Test that validArgs don't repeat
   359  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "one", "")
   360  	if err != nil {
   361  		t.Errorf("Unexpected error: %v", err)
   362  	}
   363  
   364  	expected = strings.Join([]string{
   365  		":0",
   366  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   367  
   368  	if output != expected {
   369  		t.Errorf("expected: %q, got: %q", expected, output)
   370  	}
   371  }
   372  
   373  func TestValidArgsAndCmdCompletionInGo(t *testing.T) {
   374  	rootCmd := &Command{
   375  		Use:       "root",
   376  		ValidArgs: []string{"one", "two"},
   377  		Run:       emptyRun,
   378  	}
   379  
   380  	childCmd := &Command{
   381  		Use: "thechild",
   382  		Run: emptyRun,
   383  	}
   384  
   385  	rootCmd.AddCommand(childCmd)
   386  
   387  	// Test that both sub-commands and validArgs are completed
   388  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
   389  	if err != nil {
   390  		t.Errorf("Unexpected error: %v", err)
   391  	}
   392  
   393  	expected := strings.Join([]string{
   394  		"completion",
   395  		"help",
   396  		"thechild",
   397  		"one",
   398  		"two",
   399  		":4",
   400  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   401  
   402  	if output != expected {
   403  		t.Errorf("expected: %q, got: %q", expected, output)
   404  	}
   405  
   406  	// Test that both sub-commands and validArgs are completed with prefix
   407  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
   408  	if err != nil {
   409  		t.Errorf("Unexpected error: %v", err)
   410  	}
   411  
   412  	expected = strings.Join([]string{
   413  		"thechild",
   414  		"two",
   415  		":4",
   416  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   417  
   418  	if output != expected {
   419  		t.Errorf("expected: %q, got: %q", expected, output)
   420  	}
   421  }
   422  
   423  func TestValidArgsFuncAndCmdCompletionInGo(t *testing.T) {
   424  	rootCmd := &Command{
   425  		Use:               "root",
   426  		ValidArgsFunction: validArgsFunc,
   427  		Run:               emptyRun,
   428  	}
   429  
   430  	childCmd := &Command{
   431  		Use:   "thechild",
   432  		Short: "The child command",
   433  		Run:   emptyRun,
   434  	}
   435  
   436  	rootCmd.AddCommand(childCmd)
   437  
   438  	// Test that both sub-commands and validArgsFunction are completed
   439  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
   440  	if err != nil {
   441  		t.Errorf("Unexpected error: %v", err)
   442  	}
   443  
   444  	expected := strings.Join([]string{
   445  		"completion",
   446  		"help",
   447  		"thechild",
   448  		"one",
   449  		"two",
   450  		":0",
   451  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   452  
   453  	if output != expected {
   454  		t.Errorf("expected: %q, got: %q", expected, output)
   455  	}
   456  
   457  	// Test that both sub-commands and validArgs are completed with prefix
   458  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
   459  	if err != nil {
   460  		t.Errorf("Unexpected error: %v", err)
   461  	}
   462  
   463  	expected = strings.Join([]string{
   464  		"thechild",
   465  		"two",
   466  		":0",
   467  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   468  
   469  	if output != expected {
   470  		t.Errorf("expected: %q, got: %q", expected, output)
   471  	}
   472  
   473  	// Test that both sub-commands and validArgs are completed with description
   474  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "t")
   475  	if err != nil {
   476  		t.Errorf("Unexpected error: %v", err)
   477  	}
   478  
   479  	expected = strings.Join([]string{
   480  		"thechild\tThe child command",
   481  		"two\tThe second",
   482  		":0",
   483  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
   484  
   485  	if output != expected {
   486  		t.Errorf("expected: %q, got: %q", expected, output)
   487  	}
   488  }
   489  
   490  func TestFlagNameCompletionInGo(t *testing.T) {
   491  	rootCmd := &Command{
   492  		Use: "root",
   493  		Run: emptyRun,
   494  	}
   495  	childCmd := &Command{
   496  		Use:     "childCmd",
   497  		Version: "1.2.3",
   498  		Run:     emptyRun,
   499  	}
   500  	rootCmd.AddCommand(childCmd)
   501  
   502  	rootCmd.Flags().IntP("first", "f", -1, "first flag")
   503  	rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag")
   504  	childCmd.Flags().String("subFlag", "", "sub flag")
   505  
   506  	// Test that flag names are not shown if the user has not given the '-' prefix
   507  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
   508  	if err != nil {
   509  		t.Errorf("Unexpected error: %v", err)
   510  	}
   511  
   512  	expected := strings.Join([]string{
   513  		"childCmd",
   514  		"completion",
   515  		"help",
   516  		":4",
   517  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   518  
   519  	if output != expected {
   520  		t.Errorf("expected: %q, got: %q", expected, output)
   521  	}
   522  
   523  	// Test that flag names are completed
   524  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-")
   525  	if err != nil {
   526  		t.Errorf("Unexpected error: %v", err)
   527  	}
   528  
   529  	expected = strings.Join([]string{
   530  		"--first",
   531  		"-f",
   532  		"--help",
   533  		"-h",
   534  		"--second",
   535  		"-s",
   536  		":4",
   537  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   538  
   539  	if output != expected {
   540  		t.Errorf("expected: %q, got: %q", expected, output)
   541  	}
   542  
   543  	// Test that flag names are completed when a prefix is given
   544  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--f")
   545  	if err != nil {
   546  		t.Errorf("Unexpected error: %v", err)
   547  	}
   548  
   549  	expected = strings.Join([]string{
   550  		"--first",
   551  		":4",
   552  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   553  
   554  	if output != expected {
   555  		t.Errorf("expected: %q, got: %q", expected, output)
   556  	}
   557  
   558  	// Test that flag names are completed in a sub-cmd
   559  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-")
   560  	if err != nil {
   561  		t.Errorf("Unexpected error: %v", err)
   562  	}
   563  
   564  	expected = strings.Join([]string{
   565  		"--second",
   566  		"-s",
   567  		"--help",
   568  		"-h",
   569  		"--subFlag",
   570  		"--version",
   571  		"-v",
   572  		":4",
   573  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   574  
   575  	if output != expected {
   576  		t.Errorf("expected: %q, got: %q", expected, output)
   577  	}
   578  }
   579  
   580  func TestFlagNameCompletionInGoWithDesc(t *testing.T) {
   581  	rootCmd := &Command{
   582  		Use: "root",
   583  		Run: emptyRun,
   584  	}
   585  	childCmd := &Command{
   586  		Use:     "childCmd",
   587  		Short:   "first command",
   588  		Version: "1.2.3",
   589  		Run:     emptyRun,
   590  	}
   591  	rootCmd.AddCommand(childCmd)
   592  
   593  	rootCmd.Flags().IntP("first", "f", -1, "first flag\nlonger description for flag")
   594  	rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag")
   595  	childCmd.Flags().String("subFlag", "", "sub flag")
   596  
   597  	// Test that flag names are not shown if the user has not given the '-' prefix
   598  	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "")
   599  	if err != nil {
   600  		t.Errorf("Unexpected error: %v", err)
   601  	}
   602  
   603  	expected := strings.Join([]string{
   604  		"childCmd\tfirst command",
   605  		"completion\tGenerate the autocompletion script for the specified shell",
   606  		"help\tHelp about any command",
   607  		":4",
   608  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   609  
   610  	if output != expected {
   611  		t.Errorf("expected: %q, got: %q", expected, output)
   612  	}
   613  
   614  	// Test that flag names are completed
   615  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "-")
   616  	if err != nil {
   617  		t.Errorf("Unexpected error: %v", err)
   618  	}
   619  
   620  	expected = strings.Join([]string{
   621  		"--first\tfirst flag",
   622  		"-f\tfirst flag",
   623  		"--help\thelp for root",
   624  		"-h\thelp for root",
   625  		"--second\tsecond flag",
   626  		"-s\tsecond flag",
   627  		":4",
   628  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   629  
   630  	if output != expected {
   631  		t.Errorf("expected: %q, got: %q", expected, output)
   632  	}
   633  
   634  	// Test that flag names are completed when a prefix is given
   635  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--f")
   636  	if err != nil {
   637  		t.Errorf("Unexpected error: %v", err)
   638  	}
   639  
   640  	expected = strings.Join([]string{
   641  		"--first\tfirst flag",
   642  		":4",
   643  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   644  
   645  	if output != expected {
   646  		t.Errorf("expected: %q, got: %q", expected, output)
   647  	}
   648  
   649  	// Test that flag names are completed in a sub-cmd
   650  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "childCmd", "-")
   651  	if err != nil {
   652  		t.Errorf("Unexpected error: %v", err)
   653  	}
   654  
   655  	expected = strings.Join([]string{
   656  		"--second\tsecond flag",
   657  		"-s\tsecond flag",
   658  		"--help\thelp for childCmd",
   659  		"-h\thelp for childCmd",
   660  		"--subFlag\tsub flag",
   661  		"--version\tversion for childCmd",
   662  		"-v\tversion for childCmd",
   663  		":4",
   664  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   665  
   666  	if output != expected {
   667  		t.Errorf("expected: %q, got: %q", expected, output)
   668  	}
   669  }
   670  
   671  func TestFlagNameCompletionRepeat(t *testing.T) {
   672  	rootCmd := &Command{
   673  		Use: "root",
   674  		Run: emptyRun,
   675  	}
   676  	childCmd := &Command{
   677  		Use:   "childCmd",
   678  		Short: "first command",
   679  		Run:   emptyRun,
   680  	}
   681  	rootCmd.AddCommand(childCmd)
   682  
   683  	rootCmd.Flags().IntP("first", "f", -1, "first flag")
   684  	firstFlag := rootCmd.Flags().Lookup("first")
   685  	rootCmd.Flags().BoolP("second", "s", false, "second flag")
   686  	secondFlag := rootCmd.Flags().Lookup("second")
   687  	rootCmd.Flags().StringArrayP("array", "a", nil, "array flag")
   688  	arrayFlag := rootCmd.Flags().Lookup("array")
   689  	rootCmd.Flags().IntSliceP("slice", "l", nil, "slice flag")
   690  	sliceFlag := rootCmd.Flags().Lookup("slice")
   691  	rootCmd.Flags().BoolSliceP("bslice", "b", nil, "bool slice flag")
   692  	bsliceFlag := rootCmd.Flags().Lookup("bslice")
   693  
   694  	// Test that flag names are not repeated unless they are an array or slice
   695  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--")
   696  	if err != nil {
   697  		t.Errorf("Unexpected error: %v", err)
   698  	}
   699  	// Reset the flag for the next command
   700  	firstFlag.Changed = false
   701  
   702  	expected := strings.Join([]string{
   703  		"--array",
   704  		"--bslice",
   705  		"--help",
   706  		"--second",
   707  		"--slice",
   708  		":4",
   709  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   710  
   711  	if output != expected {
   712  		t.Errorf("expected: %q, got: %q", expected, output)
   713  	}
   714  
   715  	// Test that flag names are not repeated unless they are an array or slice
   716  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--second=false", "--")
   717  	if err != nil {
   718  		t.Errorf("Unexpected error: %v", err)
   719  	}
   720  	// Reset the flag for the next command
   721  	firstFlag.Changed = false
   722  	secondFlag.Changed = false
   723  
   724  	expected = strings.Join([]string{
   725  		"--array",
   726  		"--bslice",
   727  		"--help",
   728  		"--slice",
   729  		":4",
   730  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   731  
   732  	if output != expected {
   733  		t.Errorf("expected: %q, got: %q", expected, output)
   734  	}
   735  
   736  	// Test that flag names are not repeated unless they are an array or slice
   737  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--slice", "1", "--slice=2", "--array", "val", "--bslice", "true", "--")
   738  	if err != nil {
   739  		t.Errorf("Unexpected error: %v", err)
   740  	}
   741  	// Reset the flag for the next command
   742  	sliceFlag.Changed = false
   743  	arrayFlag.Changed = false
   744  	bsliceFlag.Changed = false
   745  
   746  	expected = strings.Join([]string{
   747  		"--array",
   748  		"--bslice",
   749  		"--first",
   750  		"--help",
   751  		"--second",
   752  		"--slice",
   753  		":4",
   754  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   755  
   756  	if output != expected {
   757  		t.Errorf("expected: %q, got: %q", expected, output)
   758  	}
   759  
   760  	// Test that flag names are not repeated unless they are an array or slice, using shortname
   761  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-")
   762  	if err != nil {
   763  		t.Errorf("Unexpected error: %v", err)
   764  	}
   765  	// Reset the flag for the next command
   766  	sliceFlag.Changed = false
   767  	arrayFlag.Changed = false
   768  
   769  	expected = strings.Join([]string{
   770  		"--array",
   771  		"-a",
   772  		"--bslice",
   773  		"-b",
   774  		"--first",
   775  		"-f",
   776  		"--help",
   777  		"-h",
   778  		"--second",
   779  		"-s",
   780  		"--slice",
   781  		"-l",
   782  		":4",
   783  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   784  
   785  	if output != expected {
   786  		t.Errorf("expected: %q, got: %q", expected, output)
   787  	}
   788  
   789  	// Test that flag names are not repeated unless they are an array or slice, using shortname with prefix
   790  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-a")
   791  	if err != nil {
   792  		t.Errorf("Unexpected error: %v", err)
   793  	}
   794  	// Reset the flag for the next command
   795  	sliceFlag.Changed = false
   796  	arrayFlag.Changed = false
   797  
   798  	expected = strings.Join([]string{
   799  		"-a",
   800  		":4",
   801  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   802  
   803  	if output != expected {
   804  		t.Errorf("expected: %q, got: %q", expected, output)
   805  	}
   806  }
   807  
   808  func TestRequiredFlagNameCompletionInGo(t *testing.T) {
   809  	rootCmd := &Command{
   810  		Use:       "root",
   811  		ValidArgs: []string{"realArg"},
   812  		Run:       emptyRun,
   813  	}
   814  	childCmd := &Command{
   815  		Use: "childCmd",
   816  		ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
   817  			return []string{"subArg"}, ShellCompDirectiveNoFileComp
   818  		},
   819  		Run: emptyRun,
   820  	}
   821  	rootCmd.AddCommand(childCmd)
   822  
   823  	rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag")
   824  	assertNoErr(t, rootCmd.MarkFlagRequired("requiredFlag"))
   825  	requiredFlag := rootCmd.Flags().Lookup("requiredFlag")
   826  
   827  	rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent")
   828  	assertNoErr(t, rootCmd.MarkPersistentFlagRequired("requiredPersistent"))
   829  	requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent")
   830  
   831  	rootCmd.Flags().StringP("release", "R", "", "Release name")
   832  
   833  	childCmd.Flags().BoolP("subRequired", "s", false, "sub required flag")
   834  	assertNoErr(t, childCmd.MarkFlagRequired("subRequired"))
   835  	childCmd.Flags().BoolP("subNotRequired", "n", false, "sub not required flag")
   836  
   837  	// Test that a required flag is suggested even without the - prefix
   838  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
   839  	if err != nil {
   840  		t.Errorf("Unexpected error: %v", err)
   841  	}
   842  
   843  	expected := strings.Join([]string{
   844  		"childCmd",
   845  		"completion",
   846  		"help",
   847  		"--requiredFlag",
   848  		"-r",
   849  		"--requiredPersistent",
   850  		"-p",
   851  		"realArg",
   852  		":4",
   853  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   854  
   855  	if output != expected {
   856  		t.Errorf("expected: %q, got: %q", expected, output)
   857  	}
   858  
   859  	// Test that a required flag is suggested without other flags when using the '-' prefix
   860  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-")
   861  	if err != nil {
   862  		t.Errorf("Unexpected error: %v", err)
   863  	}
   864  
   865  	expected = strings.Join([]string{
   866  		"--requiredFlag",
   867  		"-r",
   868  		"--requiredPersistent",
   869  		"-p",
   870  		":4",
   871  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   872  
   873  	if output != expected {
   874  		t.Errorf("expected: %q, got: %q", expected, output)
   875  	}
   876  
   877  	// Test that if no required flag matches, the normal flags are suggested
   878  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--relea")
   879  	if err != nil {
   880  		t.Errorf("Unexpected error: %v", err)
   881  	}
   882  
   883  	expected = strings.Join([]string{
   884  		"--release",
   885  		":4",
   886  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   887  
   888  	if output != expected {
   889  		t.Errorf("expected: %q, got: %q", expected, output)
   890  	}
   891  
   892  	// Test required flags for sub-commands
   893  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "")
   894  	if err != nil {
   895  		t.Errorf("Unexpected error: %v", err)
   896  	}
   897  
   898  	expected = strings.Join([]string{
   899  		"--requiredPersistent",
   900  		"-p",
   901  		"--subRequired",
   902  		"-s",
   903  		"subArg",
   904  		":4",
   905  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   906  
   907  	if output != expected {
   908  		t.Errorf("expected: %q, got: %q", expected, output)
   909  	}
   910  
   911  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-")
   912  	if err != nil {
   913  		t.Errorf("Unexpected error: %v", err)
   914  	}
   915  
   916  	expected = strings.Join([]string{
   917  		"--requiredPersistent",
   918  		"-p",
   919  		"--subRequired",
   920  		"-s",
   921  		":4",
   922  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   923  
   924  	if output != expected {
   925  		t.Errorf("expected: %q, got: %q", expected, output)
   926  	}
   927  
   928  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "--subNot")
   929  	if err != nil {
   930  		t.Errorf("Unexpected error: %v", err)
   931  	}
   932  
   933  	expected = strings.Join([]string{
   934  		"--subNotRequired",
   935  		":4",
   936  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   937  
   938  	if output != expected {
   939  		t.Errorf("expected: %q, got: %q", expected, output)
   940  	}
   941  
   942  	// Test that when a required flag is present, it is not suggested anymore
   943  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "")
   944  	if err != nil {
   945  		t.Errorf("Unexpected error: %v", err)
   946  	}
   947  	// Reset the flag for the next command
   948  	requiredFlag.Changed = false
   949  
   950  	expected = strings.Join([]string{
   951  		"--requiredPersistent",
   952  		"-p",
   953  		"realArg",
   954  		":4",
   955  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   956  
   957  	if output != expected {
   958  		t.Errorf("expected: %q, got: %q", expected, output)
   959  	}
   960  
   961  	// Test that when a persistent required flag is present, it is not suggested anymore
   962  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredPersistent", "1", "")
   963  	if err != nil {
   964  		t.Errorf("Unexpected error: %v", err)
   965  	}
   966  	// Reset the flag for the next command
   967  	requiredPersistent.Changed = false
   968  
   969  	expected = strings.Join([]string{
   970  		"childCmd",
   971  		"completion",
   972  		"help",
   973  		"--requiredFlag",
   974  		"-r",
   975  		"realArg",
   976  		":4",
   977  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   978  
   979  	if output != expected {
   980  		t.Errorf("expected: %q, got: %q", expected, output)
   981  	}
   982  
   983  	// Test that when all required flags are present, normal completion is done
   984  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "--requiredPersistent", "1", "")
   985  	if err != nil {
   986  		t.Errorf("Unexpected error: %v", err)
   987  	}
   988  	// Reset the flags for the next command
   989  	requiredFlag.Changed = false
   990  	requiredPersistent.Changed = false
   991  
   992  	expected = strings.Join([]string{
   993  		"realArg",
   994  		":4",
   995  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
   996  
   997  	if output != expected {
   998  		t.Errorf("expected: %q, got: %q", expected, output)
   999  	}
  1000  }
  1001  
  1002  func TestFlagFileExtFilterCompletionInGo(t *testing.T) {
  1003  	rootCmd := &Command{
  1004  		Use: "root",
  1005  		Run: emptyRun,
  1006  	}
  1007  
  1008  	// No extensions.  Should be ignored.
  1009  	rootCmd.Flags().StringP("file", "f", "", "file flag")
  1010  	assertNoErr(t, rootCmd.MarkFlagFilename("file"))
  1011  
  1012  	// Single extension
  1013  	rootCmd.Flags().StringP("log", "l", "", "log flag")
  1014  	assertNoErr(t, rootCmd.MarkFlagFilename("log", "log"))
  1015  
  1016  	// Multiple extensions
  1017  	rootCmd.Flags().StringP("yaml", "y", "", "yaml flag")
  1018  	assertNoErr(t, rootCmd.MarkFlagFilename("yaml", "yaml", "yml"))
  1019  
  1020  	// Directly using annotation
  1021  	rootCmd.Flags().StringP("text", "t", "", "text flag")
  1022  	assertNoErr(t, rootCmd.Flags().SetAnnotation("text", BashCompFilenameExt, []string{"txt"}))
  1023  
  1024  	// Test that the completion logic returns the proper info for the completion
  1025  	// script to handle the file filtering
  1026  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--file", "")
  1027  	if err != nil {
  1028  		t.Errorf("Unexpected error: %v", err)
  1029  	}
  1030  
  1031  	expected := strings.Join([]string{
  1032  		":0",
  1033  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1034  
  1035  	if output != expected {
  1036  		t.Errorf("expected: %q, got: %q", expected, output)
  1037  	}
  1038  
  1039  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--log", "")
  1040  	if err != nil {
  1041  		t.Errorf("Unexpected error: %v", err)
  1042  	}
  1043  
  1044  	expected = strings.Join([]string{
  1045  		"log",
  1046  		":8",
  1047  		"Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
  1048  
  1049  	if output != expected {
  1050  		t.Errorf("expected: %q, got: %q", expected, output)
  1051  	}
  1052  
  1053  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml", "")
  1054  	if err != nil {
  1055  		t.Errorf("Unexpected error: %v", err)
  1056  	}
  1057  
  1058  	expected = strings.Join([]string{
  1059  		"yaml", "yml",
  1060  		":8",
  1061  		"Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
  1062  
  1063  	if output != expected {
  1064  		t.Errorf("expected: %q, got: %q", expected, output)
  1065  	}
  1066  
  1067  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml=")
  1068  	if err != nil {
  1069  		t.Errorf("Unexpected error: %v", err)
  1070  	}
  1071  
  1072  	expected = strings.Join([]string{
  1073  		"yaml", "yml",
  1074  		":8",
  1075  		"Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
  1076  
  1077  	if output != expected {
  1078  		t.Errorf("expected: %q, got: %q", expected, output)
  1079  	}
  1080  
  1081  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y", "")
  1082  	if err != nil {
  1083  		t.Errorf("Unexpected error: %v", err)
  1084  	}
  1085  
  1086  	expected = strings.Join([]string{
  1087  		"yaml", "yml",
  1088  		":8",
  1089  		"Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
  1090  
  1091  	if output != expected {
  1092  		t.Errorf("expected: %q, got: %q", expected, output)
  1093  	}
  1094  
  1095  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y=")
  1096  	if err != nil {
  1097  		t.Errorf("Unexpected error: %v", err)
  1098  	}
  1099  
  1100  	expected = strings.Join([]string{
  1101  		"yaml", "yml",
  1102  		":8",
  1103  		"Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
  1104  
  1105  	if output != expected {
  1106  		t.Errorf("expected: %q, got: %q", expected, output)
  1107  	}
  1108  
  1109  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--text", "")
  1110  	if err != nil {
  1111  		t.Errorf("Unexpected error: %v", err)
  1112  	}
  1113  
  1114  	expected = strings.Join([]string{
  1115  		"txt",
  1116  		":8",
  1117  		"Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
  1118  
  1119  	if output != expected {
  1120  		t.Errorf("expected: %q, got: %q", expected, output)
  1121  	}
  1122  }
  1123  
  1124  func TestFlagDirFilterCompletionInGo(t *testing.T) {
  1125  	rootCmd := &Command{
  1126  		Use: "root",
  1127  		Run: emptyRun,
  1128  	}
  1129  
  1130  	// Filter directories
  1131  	rootCmd.Flags().StringP("dir", "d", "", "dir flag")
  1132  	assertNoErr(t, rootCmd.MarkFlagDirname("dir"))
  1133  
  1134  	// Filter directories within a directory
  1135  	rootCmd.Flags().StringP("subdir", "s", "", "subdir")
  1136  	assertNoErr(t, rootCmd.Flags().SetAnnotation("subdir", BashCompSubdirsInDir, []string{"themes"}))
  1137  
  1138  	// Multiple directory specification get ignored
  1139  	rootCmd.Flags().StringP("manydir", "m", "", "manydir")
  1140  	assertNoErr(t, rootCmd.Flags().SetAnnotation("manydir", BashCompSubdirsInDir, []string{"themes", "colors"}))
  1141  
  1142  	// Test that the completion logic returns the proper info for the completion
  1143  	// script to handle the directory filtering
  1144  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--dir", "")
  1145  	if err != nil {
  1146  		t.Errorf("Unexpected error: %v", err)
  1147  	}
  1148  
  1149  	expected := strings.Join([]string{
  1150  		":16",
  1151  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1152  
  1153  	if output != expected {
  1154  		t.Errorf("expected: %q, got: %q", expected, output)
  1155  	}
  1156  
  1157  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-d", "")
  1158  	if err != nil {
  1159  		t.Errorf("Unexpected error: %v", err)
  1160  	}
  1161  
  1162  	expected = strings.Join([]string{
  1163  		":16",
  1164  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1165  
  1166  	if output != expected {
  1167  		t.Errorf("expected: %q, got: %q", expected, output)
  1168  	}
  1169  
  1170  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir", "")
  1171  	if err != nil {
  1172  		t.Errorf("Unexpected error: %v", err)
  1173  	}
  1174  
  1175  	expected = strings.Join([]string{
  1176  		"themes",
  1177  		":16",
  1178  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1179  
  1180  	if output != expected {
  1181  		t.Errorf("expected: %q, got: %q", expected, output)
  1182  	}
  1183  
  1184  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir=")
  1185  	if err != nil {
  1186  		t.Errorf("Unexpected error: %v", err)
  1187  	}
  1188  
  1189  	expected = strings.Join([]string{
  1190  		"themes",
  1191  		":16",
  1192  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1193  
  1194  	if output != expected {
  1195  		t.Errorf("expected: %q, got: %q", expected, output)
  1196  	}
  1197  
  1198  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "")
  1199  	if err != nil {
  1200  		t.Errorf("Unexpected error: %v", err)
  1201  	}
  1202  
  1203  	expected = strings.Join([]string{
  1204  		"themes",
  1205  		":16",
  1206  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1207  
  1208  	if output != expected {
  1209  		t.Errorf("expected: %q, got: %q", expected, output)
  1210  	}
  1211  
  1212  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s=")
  1213  	if err != nil {
  1214  		t.Errorf("Unexpected error: %v", err)
  1215  	}
  1216  
  1217  	expected = strings.Join([]string{
  1218  		"themes",
  1219  		":16",
  1220  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1221  
  1222  	if output != expected {
  1223  		t.Errorf("expected: %q, got: %q", expected, output)
  1224  	}
  1225  
  1226  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--manydir", "")
  1227  	if err != nil {
  1228  		t.Errorf("Unexpected error: %v", err)
  1229  	}
  1230  
  1231  	expected = strings.Join([]string{
  1232  		":16",
  1233  		"Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
  1234  
  1235  	if output != expected {
  1236  		t.Errorf("expected: %q, got: %q", expected, output)
  1237  	}
  1238  }
  1239  
  1240  func TestValidArgsFuncCmdContext(t *testing.T) {
  1241  	validArgsFunc := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1242  		ctx := cmd.Context()
  1243  
  1244  		if ctx == nil {
  1245  			t.Error("Received nil context in completion func")
  1246  		} else if ctx.Value("testKey") != "123" {
  1247  			t.Error("Received invalid context")
  1248  		}
  1249  
  1250  		return nil, ShellCompDirectiveDefault
  1251  	}
  1252  
  1253  	rootCmd := &Command{
  1254  		Use: "root",
  1255  		Run: emptyRun,
  1256  	}
  1257  	childCmd := &Command{
  1258  		Use:               "childCmd",
  1259  		ValidArgsFunction: validArgsFunc,
  1260  		Run:               emptyRun,
  1261  	}
  1262  	rootCmd.AddCommand(childCmd)
  1263  
  1264  	//nolint:golint,staticcheck // We can safely use a basic type as key in tests.
  1265  	ctx := context.WithValue(context.Background(), "testKey", "123")
  1266  
  1267  	// Test completing an empty string on the childCmd
  1268  	_, output, err := executeCommandWithContextC(ctx, rootCmd, ShellCompNoDescRequestCmd, "childCmd", "")
  1269  	if err != nil {
  1270  		t.Errorf("Unexpected error: %v", err)
  1271  	}
  1272  
  1273  	expected := strings.Join([]string{
  1274  		":0",
  1275  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1276  
  1277  	if output != expected {
  1278  		t.Errorf("expected: %q, got: %q", expected, output)
  1279  	}
  1280  }
  1281  
  1282  func TestValidArgsFuncSingleCmd(t *testing.T) {
  1283  	rootCmd := &Command{
  1284  		Use:               "root",
  1285  		ValidArgsFunction: validArgsFunc,
  1286  		Run:               emptyRun,
  1287  	}
  1288  
  1289  	// Test completing an empty string
  1290  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
  1291  	if err != nil {
  1292  		t.Errorf("Unexpected error: %v", err)
  1293  	}
  1294  
  1295  	expected := strings.Join([]string{
  1296  		"one",
  1297  		"two",
  1298  		":0",
  1299  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1300  
  1301  	if output != expected {
  1302  		t.Errorf("expected: %q, got: %q", expected, output)
  1303  	}
  1304  
  1305  	// Check completing with a prefix
  1306  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
  1307  	if err != nil {
  1308  		t.Errorf("Unexpected error: %v", err)
  1309  	}
  1310  
  1311  	expected = strings.Join([]string{
  1312  		"two",
  1313  		":0",
  1314  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1315  
  1316  	if output != expected {
  1317  		t.Errorf("expected: %q, got: %q", expected, output)
  1318  	}
  1319  }
  1320  
  1321  func TestValidArgsFuncSingleCmdInvalidArg(t *testing.T) {
  1322  	rootCmd := &Command{
  1323  		Use: "root",
  1324  		// If we don't specify a value for Args, this test fails.
  1325  		// This is only true for a root command without any subcommands, and is caused
  1326  		// by the fact that the __complete command becomes a subcommand when there should not be one.
  1327  		// The problem is in the implementation of legacyArgs().
  1328  		Args:              MinimumNArgs(1),
  1329  		ValidArgsFunction: validArgsFunc,
  1330  		Run:               emptyRun,
  1331  	}
  1332  
  1333  	// Check completing with wrong number of args
  1334  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "unexpectedArg", "t")
  1335  	if err != nil {
  1336  		t.Errorf("Unexpected error: %v", err)
  1337  	}
  1338  
  1339  	expected := strings.Join([]string{
  1340  		":4",
  1341  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1342  
  1343  	if output != expected {
  1344  		t.Errorf("expected: %q, got: %q", expected, output)
  1345  	}
  1346  }
  1347  
  1348  func TestValidArgsFuncChildCmds(t *testing.T) {
  1349  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1350  	child1Cmd := &Command{
  1351  		Use:               "child1",
  1352  		ValidArgsFunction: validArgsFunc,
  1353  		Run:               emptyRun,
  1354  	}
  1355  	child2Cmd := &Command{
  1356  		Use:               "child2",
  1357  		ValidArgsFunction: validArgsFunc2,
  1358  		Run:               emptyRun,
  1359  	}
  1360  	rootCmd.AddCommand(child1Cmd, child2Cmd)
  1361  
  1362  	// Test completion of first sub-command with empty argument
  1363  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "")
  1364  	if err != nil {
  1365  		t.Errorf("Unexpected error: %v", err)
  1366  	}
  1367  
  1368  	expected := strings.Join([]string{
  1369  		"one",
  1370  		"two",
  1371  		":0",
  1372  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1373  
  1374  	if output != expected {
  1375  		t.Errorf("expected: %q, got: %q", expected, output)
  1376  	}
  1377  
  1378  	// Test completion of first sub-command with a prefix to complete
  1379  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "t")
  1380  	if err != nil {
  1381  		t.Errorf("Unexpected error: %v", err)
  1382  	}
  1383  
  1384  	expected = strings.Join([]string{
  1385  		"two",
  1386  		":0",
  1387  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1388  
  1389  	if output != expected {
  1390  		t.Errorf("expected: %q, got: %q", expected, output)
  1391  	}
  1392  
  1393  	// Check completing with wrong number of args
  1394  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "unexpectedArg", "t")
  1395  	if err != nil {
  1396  		t.Errorf("Unexpected error: %v", err)
  1397  	}
  1398  
  1399  	expected = strings.Join([]string{
  1400  		":4",
  1401  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1402  
  1403  	if output != expected {
  1404  		t.Errorf("expected: %q, got: %q", expected, output)
  1405  	}
  1406  
  1407  	// Test completion of second sub-command with empty argument
  1408  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "")
  1409  	if err != nil {
  1410  		t.Errorf("Unexpected error: %v", err)
  1411  	}
  1412  
  1413  	expected = strings.Join([]string{
  1414  		"three",
  1415  		"four",
  1416  		":0",
  1417  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1418  
  1419  	if output != expected {
  1420  		t.Errorf("expected: %q, got: %q", expected, output)
  1421  	}
  1422  
  1423  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "t")
  1424  	if err != nil {
  1425  		t.Errorf("Unexpected error: %v", err)
  1426  	}
  1427  
  1428  	expected = strings.Join([]string{
  1429  		"three",
  1430  		":0",
  1431  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1432  
  1433  	if output != expected {
  1434  		t.Errorf("expected: %q, got: %q", expected, output)
  1435  	}
  1436  
  1437  	// Check completing with wrong number of args
  1438  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "unexpectedArg", "t")
  1439  	if err != nil {
  1440  		t.Errorf("Unexpected error: %v", err)
  1441  	}
  1442  
  1443  	expected = strings.Join([]string{
  1444  		":4",
  1445  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1446  
  1447  	if output != expected {
  1448  		t.Errorf("expected: %q, got: %q", expected, output)
  1449  	}
  1450  }
  1451  
  1452  func TestValidArgsFuncAliases(t *testing.T) {
  1453  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1454  	child := &Command{
  1455  		Use:               "child",
  1456  		Aliases:           []string{"son", "daughter"},
  1457  		ValidArgsFunction: validArgsFunc,
  1458  		Run:               emptyRun,
  1459  	}
  1460  	rootCmd.AddCommand(child)
  1461  
  1462  	// Test completion of first sub-command with empty argument
  1463  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "")
  1464  	if err != nil {
  1465  		t.Errorf("Unexpected error: %v", err)
  1466  	}
  1467  
  1468  	expected := strings.Join([]string{
  1469  		"one",
  1470  		"two",
  1471  		":0",
  1472  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1473  
  1474  	if output != expected {
  1475  		t.Errorf("expected: %q, got: %q", expected, output)
  1476  	}
  1477  
  1478  	// Test completion of first sub-command with a prefix to complete
  1479  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "daughter", "t")
  1480  	if err != nil {
  1481  		t.Errorf("Unexpected error: %v", err)
  1482  	}
  1483  
  1484  	expected = strings.Join([]string{
  1485  		"two",
  1486  		":0",
  1487  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1488  
  1489  	if output != expected {
  1490  		t.Errorf("expected: %q, got: %q", expected, output)
  1491  	}
  1492  
  1493  	// Check completing with wrong number of args
  1494  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "unexpectedArg", "t")
  1495  	if err != nil {
  1496  		t.Errorf("Unexpected error: %v", err)
  1497  	}
  1498  
  1499  	expected = strings.Join([]string{
  1500  		":4",
  1501  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1502  
  1503  	if output != expected {
  1504  		t.Errorf("expected: %q, got: %q", expected, output)
  1505  	}
  1506  }
  1507  
  1508  func TestValidArgsFuncInBashScript(t *testing.T) {
  1509  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1510  	child := &Command{
  1511  		Use:               "child",
  1512  		ValidArgsFunction: validArgsFunc,
  1513  		Run:               emptyRun,
  1514  	}
  1515  	rootCmd.AddCommand(child)
  1516  
  1517  	buf := new(bytes.Buffer)
  1518  	assertNoErr(t, rootCmd.GenBashCompletion(buf))
  1519  	output := buf.String()
  1520  
  1521  	check(t, output, "has_completion_function=1")
  1522  }
  1523  
  1524  func TestNoValidArgsFuncInBashScript(t *testing.T) {
  1525  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1526  	child := &Command{
  1527  		Use: "child",
  1528  		Run: emptyRun,
  1529  	}
  1530  	rootCmd.AddCommand(child)
  1531  
  1532  	buf := new(bytes.Buffer)
  1533  	assertNoErr(t, rootCmd.GenBashCompletion(buf))
  1534  	output := buf.String()
  1535  
  1536  	checkOmit(t, output, "has_completion_function=1")
  1537  }
  1538  
  1539  func TestCompleteCmdInBashScript(t *testing.T) {
  1540  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1541  	child := &Command{
  1542  		Use:               "child",
  1543  		ValidArgsFunction: validArgsFunc,
  1544  		Run:               emptyRun,
  1545  	}
  1546  	rootCmd.AddCommand(child)
  1547  
  1548  	buf := new(bytes.Buffer)
  1549  	assertNoErr(t, rootCmd.GenBashCompletion(buf))
  1550  	output := buf.String()
  1551  
  1552  	check(t, output, ShellCompNoDescRequestCmd)
  1553  }
  1554  
  1555  func TestCompleteNoDesCmdInZshScript(t *testing.T) {
  1556  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1557  	child := &Command{
  1558  		Use:               "child",
  1559  		ValidArgsFunction: validArgsFunc,
  1560  		Run:               emptyRun,
  1561  	}
  1562  	rootCmd.AddCommand(child)
  1563  
  1564  	buf := new(bytes.Buffer)
  1565  	assertNoErr(t, rootCmd.GenZshCompletionNoDesc(buf))
  1566  	output := buf.String()
  1567  
  1568  	check(t, output, ShellCompNoDescRequestCmd)
  1569  }
  1570  
  1571  func TestCompleteCmdInZshScript(t *testing.T) {
  1572  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1573  	child := &Command{
  1574  		Use:               "child",
  1575  		ValidArgsFunction: validArgsFunc,
  1576  		Run:               emptyRun,
  1577  	}
  1578  	rootCmd.AddCommand(child)
  1579  
  1580  	buf := new(bytes.Buffer)
  1581  	assertNoErr(t, rootCmd.GenZshCompletion(buf))
  1582  	output := buf.String()
  1583  
  1584  	check(t, output, ShellCompRequestCmd)
  1585  	checkOmit(t, output, ShellCompNoDescRequestCmd)
  1586  }
  1587  
  1588  func TestFlagCompletionInGo(t *testing.T) {
  1589  	rootCmd := &Command{
  1590  		Use: "root",
  1591  		Run: emptyRun,
  1592  	}
  1593  	rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
  1594  	assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1595  		completions := []string{}
  1596  		for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
  1597  			if strings.HasPrefix(comp, toComplete) {
  1598  				completions = append(completions, comp)
  1599  			}
  1600  		}
  1601  		return completions, ShellCompDirectiveDefault
  1602  	}))
  1603  	rootCmd.Flags().String("filename", "", "Enter a filename")
  1604  	assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1605  		completions := []string{}
  1606  		for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
  1607  			if strings.HasPrefix(comp, toComplete) {
  1608  				completions = append(completions, comp)
  1609  			}
  1610  		}
  1611  		return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
  1612  	}))
  1613  
  1614  	// Test completing an empty string
  1615  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "")
  1616  	if err != nil {
  1617  		t.Errorf("Unexpected error: %v", err)
  1618  	}
  1619  
  1620  	expected := strings.Join([]string{
  1621  		"1",
  1622  		"2",
  1623  		"10",
  1624  		":0",
  1625  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1626  
  1627  	if output != expected {
  1628  		t.Errorf("expected: %q, got: %q", expected, output)
  1629  	}
  1630  
  1631  	// Check completing with a prefix
  1632  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "1")
  1633  	if err != nil {
  1634  		t.Errorf("Unexpected error: %v", err)
  1635  	}
  1636  
  1637  	expected = strings.Join([]string{
  1638  		"1",
  1639  		"10",
  1640  		":0",
  1641  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1642  
  1643  	if output != expected {
  1644  		t.Errorf("expected: %q, got: %q", expected, output)
  1645  	}
  1646  
  1647  	// Test completing an empty string
  1648  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "")
  1649  	if err != nil {
  1650  		t.Errorf("Unexpected error: %v", err)
  1651  	}
  1652  
  1653  	expected = strings.Join([]string{
  1654  		"file.yaml",
  1655  		"myfile.json",
  1656  		"file.xml",
  1657  		":6",
  1658  		"Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
  1659  
  1660  	if output != expected {
  1661  		t.Errorf("expected: %q, got: %q", expected, output)
  1662  	}
  1663  
  1664  	// Check completing with a prefix
  1665  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "f")
  1666  	if err != nil {
  1667  		t.Errorf("Unexpected error: %v", err)
  1668  	}
  1669  
  1670  	expected = strings.Join([]string{
  1671  		"file.yaml",
  1672  		"file.xml",
  1673  		":6",
  1674  		"Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
  1675  
  1676  	if output != expected {
  1677  		t.Errorf("expected: %q, got: %q", expected, output)
  1678  	}
  1679  }
  1680  
  1681  func TestValidArgsFuncChildCmdsWithDesc(t *testing.T) {
  1682  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  1683  	child1Cmd := &Command{
  1684  		Use:               "child1",
  1685  		ValidArgsFunction: validArgsFunc,
  1686  		Run:               emptyRun,
  1687  	}
  1688  	child2Cmd := &Command{
  1689  		Use:               "child2",
  1690  		ValidArgsFunction: validArgsFunc2,
  1691  		Run:               emptyRun,
  1692  	}
  1693  	rootCmd.AddCommand(child1Cmd, child2Cmd)
  1694  
  1695  	// Test completion of first sub-command with empty argument
  1696  	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child1", "")
  1697  	if err != nil {
  1698  		t.Errorf("Unexpected error: %v", err)
  1699  	}
  1700  
  1701  	expected := strings.Join([]string{
  1702  		"one\tThe first",
  1703  		"two\tThe second",
  1704  		":0",
  1705  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1706  
  1707  	if output != expected {
  1708  		t.Errorf("expected: %q, got: %q", expected, output)
  1709  	}
  1710  
  1711  	// Test completion of first sub-command with a prefix to complete
  1712  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "t")
  1713  	if err != nil {
  1714  		t.Errorf("Unexpected error: %v", err)
  1715  	}
  1716  
  1717  	expected = strings.Join([]string{
  1718  		"two\tThe second",
  1719  		":0",
  1720  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1721  
  1722  	if output != expected {
  1723  		t.Errorf("expected: %q, got: %q", expected, output)
  1724  	}
  1725  
  1726  	// Check completing with wrong number of args
  1727  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "unexpectedArg", "t")
  1728  	if err != nil {
  1729  		t.Errorf("Unexpected error: %v", err)
  1730  	}
  1731  
  1732  	expected = strings.Join([]string{
  1733  		":4",
  1734  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1735  
  1736  	if output != expected {
  1737  		t.Errorf("expected: %q, got: %q", expected, output)
  1738  	}
  1739  
  1740  	// Test completion of second sub-command with empty argument
  1741  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "")
  1742  	if err != nil {
  1743  		t.Errorf("Unexpected error: %v", err)
  1744  	}
  1745  
  1746  	expected = strings.Join([]string{
  1747  		"three\tThe third",
  1748  		"four\tThe fourth",
  1749  		":0",
  1750  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1751  
  1752  	if output != expected {
  1753  		t.Errorf("expected: %q, got: %q", expected, output)
  1754  	}
  1755  
  1756  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "t")
  1757  	if err != nil {
  1758  		t.Errorf("Unexpected error: %v", err)
  1759  	}
  1760  
  1761  	expected = strings.Join([]string{
  1762  		"three\tThe third",
  1763  		":0",
  1764  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1765  
  1766  	if output != expected {
  1767  		t.Errorf("expected: %q, got: %q", expected, output)
  1768  	}
  1769  
  1770  	// Check completing with wrong number of args
  1771  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "unexpectedArg", "t")
  1772  	if err != nil {
  1773  		t.Errorf("Unexpected error: %v", err)
  1774  	}
  1775  
  1776  	expected = strings.Join([]string{
  1777  		":4",
  1778  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1779  
  1780  	if output != expected {
  1781  		t.Errorf("expected: %q, got: %q", expected, output)
  1782  	}
  1783  }
  1784  
  1785  func TestFlagCompletionWithNotInterspersedArgs(t *testing.T) {
  1786  	rootCmd := &Command{Use: "root", Run: emptyRun}
  1787  	childCmd := &Command{
  1788  		Use: "child",
  1789  		Run: emptyRun,
  1790  		ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1791  			return []string{"--validarg", "test"}, ShellCompDirectiveDefault
  1792  		},
  1793  	}
  1794  	childCmd2 := &Command{
  1795  		Use:       "child2",
  1796  		Run:       emptyRun,
  1797  		ValidArgs: []string{"arg1", "arg2"},
  1798  	}
  1799  	rootCmd.AddCommand(childCmd, childCmd2)
  1800  	childCmd.Flags().Bool("bool", false, "test bool flag")
  1801  	childCmd.Flags().String("string", "", "test string flag")
  1802  	_ = childCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1803  		return []string{"myval"}, ShellCompDirectiveDefault
  1804  	})
  1805  
  1806  	// Test flag completion with no argument
  1807  	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--")
  1808  	if err != nil {
  1809  		t.Errorf("Unexpected error: %v", err)
  1810  	}
  1811  
  1812  	expected := strings.Join([]string{
  1813  		"--bool\ttest bool flag",
  1814  		"--help\thelp for child",
  1815  		"--string\ttest string flag",
  1816  		":4",
  1817  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1818  
  1819  	if output != expected {
  1820  		t.Errorf("expected: %q, got: %q", expected, output)
  1821  	}
  1822  
  1823  	// Test that no flags are completed after the -- arg
  1824  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "-")
  1825  	if err != nil {
  1826  		t.Errorf("Unexpected error: %v", err)
  1827  	}
  1828  
  1829  	expected = strings.Join([]string{
  1830  		"--validarg",
  1831  		"test",
  1832  		":0",
  1833  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1834  
  1835  	if output != expected {
  1836  		t.Errorf("expected: %q, got: %q", expected, output)
  1837  	}
  1838  
  1839  	// Test that no flags are completed after the -- arg with a flag set
  1840  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--bool", "--", "-")
  1841  	if err != nil {
  1842  		t.Errorf("Unexpected error: %v", err)
  1843  	}
  1844  
  1845  	expected = strings.Join([]string{
  1846  		"--validarg",
  1847  		"test",
  1848  		":0",
  1849  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1850  
  1851  	if output != expected {
  1852  		t.Errorf("expected: %q, got: %q", expected, output)
  1853  	}
  1854  
  1855  	// set Interspersed to false which means that no flags should be completed after the first arg
  1856  	childCmd.Flags().SetInterspersed(false)
  1857  
  1858  	// Test that no flags are completed after the first arg
  1859  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "arg", "--")
  1860  	if err != nil {
  1861  		t.Errorf("Unexpected error: %v", err)
  1862  	}
  1863  
  1864  	expected = strings.Join([]string{
  1865  		"--validarg",
  1866  		"test",
  1867  		":0",
  1868  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1869  
  1870  	if output != expected {
  1871  		t.Errorf("expected: %q, got: %q", expected, output)
  1872  	}
  1873  
  1874  	// Test that no flags are completed after the fist arg with a flag set
  1875  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "t", "arg", "--")
  1876  	if err != nil {
  1877  		t.Errorf("Unexpected error: %v", err)
  1878  	}
  1879  
  1880  	expected = strings.Join([]string{
  1881  		"--validarg",
  1882  		"test",
  1883  		":0",
  1884  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1885  
  1886  	if output != expected {
  1887  		t.Errorf("expected: %q, got: %q", expected, output)
  1888  	}
  1889  
  1890  	// Check that args are still completed after --
  1891  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "")
  1892  	if err != nil {
  1893  		t.Errorf("Unexpected error: %v", err)
  1894  	}
  1895  
  1896  	expected = strings.Join([]string{
  1897  		"--validarg",
  1898  		"test",
  1899  		":0",
  1900  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1901  
  1902  	if output != expected {
  1903  		t.Errorf("expected: %q, got: %q", expected, output)
  1904  	}
  1905  
  1906  	// Check that args are still completed even if flagname with ValidArgsFunction exists
  1907  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--string", "")
  1908  	if err != nil {
  1909  		t.Errorf("Unexpected error: %v", err)
  1910  	}
  1911  
  1912  	expected = strings.Join([]string{
  1913  		"--validarg",
  1914  		"test",
  1915  		":0",
  1916  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1917  
  1918  	if output != expected {
  1919  		t.Errorf("expected: %q, got: %q", expected, output)
  1920  	}
  1921  
  1922  	// Check that args are still completed even if flagname with ValidArgsFunction exists
  1923  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "--", "a")
  1924  	if err != nil {
  1925  		t.Errorf("Unexpected error: %v", err)
  1926  	}
  1927  
  1928  	expected = strings.Join([]string{
  1929  		"arg1",
  1930  		"arg2",
  1931  		":4",
  1932  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  1933  
  1934  	if output != expected {
  1935  		t.Errorf("expected: %q, got: %q", expected, output)
  1936  	}
  1937  
  1938  	// Check that --validarg is not parsed as flag after --
  1939  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "")
  1940  	if err != nil {
  1941  		t.Errorf("Unexpected error: %v", err)
  1942  	}
  1943  
  1944  	expected = strings.Join([]string{
  1945  		"--validarg",
  1946  		"test",
  1947  		":0",
  1948  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1949  
  1950  	if output != expected {
  1951  		t.Errorf("expected: %q, got: %q", expected, output)
  1952  	}
  1953  
  1954  	// Check that --validarg is not parsed as flag after an arg
  1955  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "arg", "--validarg", "")
  1956  	if err != nil {
  1957  		t.Errorf("Unexpected error: %v", err)
  1958  	}
  1959  
  1960  	expected = strings.Join([]string{
  1961  		"--validarg",
  1962  		"test",
  1963  		":0",
  1964  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1965  
  1966  	if output != expected {
  1967  		t.Errorf("expected: %q, got: %q", expected, output)
  1968  	}
  1969  
  1970  	// Check that --validarg is added to args for the ValidArgsFunction
  1971  	childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1972  		return args, ShellCompDirectiveDefault
  1973  	}
  1974  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "")
  1975  	if err != nil {
  1976  		t.Errorf("Unexpected error: %v", err)
  1977  	}
  1978  
  1979  	expected = strings.Join([]string{
  1980  		"--validarg",
  1981  		":0",
  1982  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  1983  
  1984  	if output != expected {
  1985  		t.Errorf("expected: %q, got: %q", expected, output)
  1986  	}
  1987  
  1988  	// Check that --validarg is added to args for the ValidArgsFunction and toComplete is also set correctly
  1989  	childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  1990  		return append(args, toComplete), ShellCompDirectiveDefault
  1991  	}
  1992  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "--toComp=ab")
  1993  	if err != nil {
  1994  		t.Errorf("Unexpected error: %v", err)
  1995  	}
  1996  
  1997  	expected = strings.Join([]string{
  1998  		"--validarg",
  1999  		"--toComp=ab",
  2000  		":0",
  2001  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  2002  
  2003  	if output != expected {
  2004  		t.Errorf("expected: %q, got: %q", expected, output)
  2005  	}
  2006  }
  2007  
  2008  func TestFlagCompletionWorksRootCommandAddedAfterFlags(t *testing.T) {
  2009  	rootCmd := &Command{Use: "root", Run: emptyRun}
  2010  	childCmd := &Command{
  2011  		Use: "child",
  2012  		Run: emptyRun,
  2013  		ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2014  			return []string{"--validarg", "test"}, ShellCompDirectiveDefault
  2015  		},
  2016  	}
  2017  	childCmd.Flags().Bool("bool", false, "test bool flag")
  2018  	childCmd.Flags().String("string", "", "test string flag")
  2019  	_ = childCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2020  		return []string{"myval"}, ShellCompDirectiveDefault
  2021  	})
  2022  
  2023  	// Important: This is a test for https://github.com/spf13/cobra/issues/1437
  2024  	// Only add the subcommand after RegisterFlagCompletionFunc was called, do not change this order!
  2025  	rootCmd.AddCommand(childCmd)
  2026  
  2027  	// Test that flag completion works for the subcmd
  2028  	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "")
  2029  	if err != nil {
  2030  		t.Errorf("Unexpected error: %v", err)
  2031  	}
  2032  
  2033  	expected := strings.Join([]string{
  2034  		"myval",
  2035  		":0",
  2036  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  2037  
  2038  	if output != expected {
  2039  		t.Errorf("expected: %q, got: %q", expected, output)
  2040  	}
  2041  }
  2042  
  2043  func TestFlagCompletionInGoWithDesc(t *testing.T) {
  2044  	rootCmd := &Command{
  2045  		Use: "root",
  2046  		Run: emptyRun,
  2047  	}
  2048  	rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
  2049  	assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2050  		completions := []string{}
  2051  		for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
  2052  			if strings.HasPrefix(comp, toComplete) {
  2053  				completions = append(completions, comp)
  2054  			}
  2055  		}
  2056  		return completions, ShellCompDirectiveDefault
  2057  	}))
  2058  	rootCmd.Flags().String("filename", "", "Enter a filename")
  2059  	assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2060  		completions := []string{}
  2061  		for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
  2062  			if strings.HasPrefix(comp, toComplete) {
  2063  				completions = append(completions, comp)
  2064  			}
  2065  		}
  2066  		return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
  2067  	}))
  2068  
  2069  	// Test completing an empty string
  2070  	output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "")
  2071  	if err != nil {
  2072  		t.Errorf("Unexpected error: %v", err)
  2073  	}
  2074  
  2075  	expected := strings.Join([]string{
  2076  		"1\tThe first",
  2077  		"2\tThe second",
  2078  		"10\tThe tenth",
  2079  		":0",
  2080  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  2081  
  2082  	if output != expected {
  2083  		t.Errorf("expected: %q, got: %q", expected, output)
  2084  	}
  2085  
  2086  	// Check completing with a prefix
  2087  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "1")
  2088  	if err != nil {
  2089  		t.Errorf("Unexpected error: %v", err)
  2090  	}
  2091  
  2092  	expected = strings.Join([]string{
  2093  		"1\tThe first",
  2094  		"10\tThe tenth",
  2095  		":0",
  2096  		"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
  2097  
  2098  	if output != expected {
  2099  		t.Errorf("expected: %q, got: %q", expected, output)
  2100  	}
  2101  
  2102  	// Test completing an empty string
  2103  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "")
  2104  	if err != nil {
  2105  		t.Errorf("Unexpected error: %v", err)
  2106  	}
  2107  
  2108  	expected = strings.Join([]string{
  2109  		"file.yaml\tYAML format",
  2110  		"myfile.json\tJSON format",
  2111  		"file.xml\tXML format",
  2112  		":6",
  2113  		"Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
  2114  
  2115  	if output != expected {
  2116  		t.Errorf("expected: %q, got: %q", expected, output)
  2117  	}
  2118  
  2119  	// Check completing with a prefix
  2120  	output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "f")
  2121  	if err != nil {
  2122  		t.Errorf("Unexpected error: %v", err)
  2123  	}
  2124  
  2125  	expected = strings.Join([]string{
  2126  		"file.yaml\tYAML format",
  2127  		"file.xml\tXML format",
  2128  		":6",
  2129  		"Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
  2130  
  2131  	if output != expected {
  2132  		t.Errorf("expected: %q, got: %q", expected, output)
  2133  	}
  2134  }
  2135  
  2136  func TestValidArgsNotValidArgsFunc(t *testing.T) {
  2137  	rootCmd := &Command{
  2138  		Use:       "root",
  2139  		ValidArgs: []string{"one", "two"},
  2140  		ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2141  			return []string{"three", "four"}, ShellCompDirectiveNoFileComp
  2142  		},
  2143  		Run: emptyRun,
  2144  	}
  2145  
  2146  	// Test that if both ValidArgs and ValidArgsFunction are present
  2147  	// only ValidArgs is considered
  2148  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
  2149  	if err != nil {
  2150  		t.Errorf("Unexpected error: %v", err)
  2151  	}
  2152  
  2153  	expected := strings.Join([]string{
  2154  		"one",
  2155  		"two",
  2156  		":4",
  2157  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2158  
  2159  	if output != expected {
  2160  		t.Errorf("expected: %q, got: %q", expected, output)
  2161  	}
  2162  
  2163  	// Check completing with a prefix
  2164  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
  2165  	if err != nil {
  2166  		t.Errorf("Unexpected error: %v", err)
  2167  	}
  2168  
  2169  	expected = strings.Join([]string{
  2170  		"two",
  2171  		":4",
  2172  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2173  
  2174  	if output != expected {
  2175  		t.Errorf("expected: %q, got: %q", expected, output)
  2176  	}
  2177  }
  2178  
  2179  func TestArgAliasesCompletionInGo(t *testing.T) {
  2180  	rootCmd := &Command{
  2181  		Use:        "root",
  2182  		Args:       OnlyValidArgs,
  2183  		ValidArgs:  []string{"one", "two", "three"},
  2184  		ArgAliases: []string{"un", "deux", "trois"},
  2185  		Run:        emptyRun,
  2186  	}
  2187  
  2188  	// Test that argaliases are not completed when there are validargs that match
  2189  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
  2190  	if err != nil {
  2191  		t.Errorf("Unexpected error: %v", err)
  2192  	}
  2193  
  2194  	expected := strings.Join([]string{
  2195  		"one",
  2196  		"two",
  2197  		"three",
  2198  		":4",
  2199  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2200  
  2201  	if output != expected {
  2202  		t.Errorf("expected: %q, got: %q", expected, output)
  2203  	}
  2204  
  2205  	// Test that argaliases are not completed when there are validargs that match using a prefix
  2206  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
  2207  	if err != nil {
  2208  		t.Errorf("Unexpected error: %v", err)
  2209  	}
  2210  
  2211  	expected = strings.Join([]string{
  2212  		"two",
  2213  		"three",
  2214  		":4",
  2215  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2216  
  2217  	if output != expected {
  2218  		t.Errorf("expected: %q, got: %q", expected, output)
  2219  	}
  2220  
  2221  	// Test that argaliases are completed when there are no validargs that match
  2222  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "tr")
  2223  	if err != nil {
  2224  		t.Errorf("Unexpected error: %v", err)
  2225  	}
  2226  
  2227  	expected = strings.Join([]string{
  2228  		"trois",
  2229  		":4",
  2230  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2231  
  2232  	if output != expected {
  2233  		t.Errorf("expected: %q, got: %q", expected, output)
  2234  	}
  2235  }
  2236  
  2237  func TestCompleteHelp(t *testing.T) {
  2238  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  2239  	child1Cmd := &Command{
  2240  		Use: "child1",
  2241  		Run: emptyRun,
  2242  	}
  2243  	child2Cmd := &Command{
  2244  		Use: "child2",
  2245  		Run: emptyRun,
  2246  	}
  2247  	rootCmd.AddCommand(child1Cmd, child2Cmd)
  2248  
  2249  	child3Cmd := &Command{
  2250  		Use: "child3",
  2251  		Run: emptyRun,
  2252  	}
  2253  	child1Cmd.AddCommand(child3Cmd)
  2254  
  2255  	// Test that completion includes the help command
  2256  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
  2257  	if err != nil {
  2258  		t.Errorf("Unexpected error: %v", err)
  2259  	}
  2260  
  2261  	expected := strings.Join([]string{
  2262  		"child1",
  2263  		"child2",
  2264  		"completion",
  2265  		"help",
  2266  		":4",
  2267  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2268  
  2269  	if output != expected {
  2270  		t.Errorf("expected: %q, got: %q", expected, output)
  2271  	}
  2272  
  2273  	// Test sub-commands are completed on first level of help command
  2274  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "")
  2275  	if err != nil {
  2276  		t.Errorf("Unexpected error: %v", err)
  2277  	}
  2278  
  2279  	expected = strings.Join([]string{
  2280  		"child1",
  2281  		"child2",
  2282  		"completion",
  2283  		"help", // "<program> help help" is a valid command, so should be completed
  2284  		":4",
  2285  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2286  
  2287  	if output != expected {
  2288  		t.Errorf("expected: %q, got: %q", expected, output)
  2289  	}
  2290  
  2291  	// Test sub-commands are completed on first level of help command
  2292  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "child1", "")
  2293  	if err != nil {
  2294  		t.Errorf("Unexpected error: %v", err)
  2295  	}
  2296  
  2297  	expected = strings.Join([]string{
  2298  		"child3",
  2299  		":4",
  2300  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2301  
  2302  	if output != expected {
  2303  		t.Errorf("expected: %q, got: %q", expected, output)
  2304  	}
  2305  }
  2306  
  2307  func removeCompCmd(rootCmd *Command) {
  2308  	// Remove completion command for the next test
  2309  	for _, cmd := range rootCmd.commands {
  2310  		if cmd.Name() == compCmdName {
  2311  			rootCmd.RemoveCommand(cmd)
  2312  			return
  2313  		}
  2314  	}
  2315  }
  2316  
  2317  func TestDefaultCompletionCmd(t *testing.T) {
  2318  	rootCmd := &Command{
  2319  		Use:  "root",
  2320  		Args: NoArgs,
  2321  		Run:  emptyRun,
  2322  	}
  2323  
  2324  	// Test that no completion command is created if there are not other sub-commands
  2325  	assertNoErr(t, rootCmd.Execute())
  2326  	for _, cmd := range rootCmd.commands {
  2327  		if cmd.Name() == compCmdName {
  2328  			t.Errorf("Should not have a 'completion' command when there are no other sub-commands of root")
  2329  			break
  2330  		}
  2331  	}
  2332  
  2333  	subCmd := &Command{
  2334  		Use: "sub",
  2335  		Run: emptyRun,
  2336  	}
  2337  	rootCmd.AddCommand(subCmd)
  2338  
  2339  	// Test that a completion command is created if there are other sub-commands
  2340  	found := false
  2341  	assertNoErr(t, rootCmd.Execute())
  2342  	for _, cmd := range rootCmd.commands {
  2343  		if cmd.Name() == compCmdName {
  2344  			found = true
  2345  			break
  2346  		}
  2347  	}
  2348  	if !found {
  2349  		t.Errorf("Should have a 'completion' command when there are other sub-commands of root")
  2350  	}
  2351  	// Remove completion command for the next test
  2352  	removeCompCmd(rootCmd)
  2353  
  2354  	// Test that the default completion command can be disabled
  2355  	rootCmd.CompletionOptions.DisableDefaultCmd = true
  2356  	assertNoErr(t, rootCmd.Execute())
  2357  	for _, cmd := range rootCmd.commands {
  2358  		if cmd.Name() == compCmdName {
  2359  			t.Errorf("Should not have a 'completion' command when the feature is disabled")
  2360  			break
  2361  		}
  2362  	}
  2363  	// Re-enable for next test
  2364  	rootCmd.CompletionOptions.DisableDefaultCmd = false
  2365  
  2366  	// Test that completion descriptions are enabled by default
  2367  	output, err := executeCommand(rootCmd, compCmdName, "zsh")
  2368  	if err != nil {
  2369  		t.Errorf("Unexpected error: %v", err)
  2370  	}
  2371  
  2372  	check(t, output, ShellCompRequestCmd)
  2373  	checkOmit(t, output, ShellCompNoDescRequestCmd)
  2374  	// Remove completion command for the next test
  2375  	removeCompCmd(rootCmd)
  2376  
  2377  	// Test that completion descriptions can be disabled completely
  2378  	rootCmd.CompletionOptions.DisableDescriptions = true
  2379  	output, err = executeCommand(rootCmd, compCmdName, "zsh")
  2380  	if err != nil {
  2381  		t.Errorf("Unexpected error: %v", err)
  2382  	}
  2383  
  2384  	check(t, output, ShellCompNoDescRequestCmd)
  2385  	// Re-enable for next test
  2386  	rootCmd.CompletionOptions.DisableDescriptions = false
  2387  	// Remove completion command for the next test
  2388  	removeCompCmd(rootCmd)
  2389  
  2390  	var compCmd *Command
  2391  	// Test that the --no-descriptions flag is present on all shells
  2392  	assertNoErr(t, rootCmd.Execute())
  2393  	for _, shell := range []string{"bash", "fish", "powershell", "zsh"} {
  2394  		if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil {
  2395  			t.Errorf("Unexpected error: %v", err)
  2396  		}
  2397  		if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag == nil {
  2398  			t.Errorf("Missing --%s flag for %s shell", compCmdNoDescFlagName, shell)
  2399  		}
  2400  	}
  2401  	// Remove completion command for the next test
  2402  	removeCompCmd(rootCmd)
  2403  
  2404  	// Test that the '--no-descriptions' flag can be disabled
  2405  	rootCmd.CompletionOptions.DisableNoDescFlag = true
  2406  	assertNoErr(t, rootCmd.Execute())
  2407  	for _, shell := range []string{"fish", "zsh", "bash", "powershell"} {
  2408  		if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil {
  2409  			t.Errorf("Unexpected error: %v", err)
  2410  		}
  2411  		if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag != nil {
  2412  			t.Errorf("Unexpected --%s flag for %s shell", compCmdNoDescFlagName, shell)
  2413  		}
  2414  	}
  2415  	// Re-enable for next test
  2416  	rootCmd.CompletionOptions.DisableNoDescFlag = false
  2417  	// Remove completion command for the next test
  2418  	removeCompCmd(rootCmd)
  2419  
  2420  	// Test that the '--no-descriptions' flag is disabled when descriptions are disabled
  2421  	rootCmd.CompletionOptions.DisableDescriptions = true
  2422  	assertNoErr(t, rootCmd.Execute())
  2423  	for _, shell := range []string{"fish", "zsh", "bash", "powershell"} {
  2424  		if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil {
  2425  			t.Errorf("Unexpected error: %v", err)
  2426  		}
  2427  		if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag != nil {
  2428  			t.Errorf("Unexpected --%s flag for %s shell", compCmdNoDescFlagName, shell)
  2429  		}
  2430  	}
  2431  	// Re-enable for next test
  2432  	rootCmd.CompletionOptions.DisableDescriptions = false
  2433  	// Remove completion command for the next test
  2434  	removeCompCmd(rootCmd)
  2435  
  2436  	// Test that the 'completion' command can be hidden
  2437  	rootCmd.CompletionOptions.HiddenDefaultCmd = true
  2438  	assertNoErr(t, rootCmd.Execute())
  2439  	compCmd, _, err = rootCmd.Find([]string{compCmdName})
  2440  	if err != nil {
  2441  		t.Errorf("Unexpected error: %v", err)
  2442  	}
  2443  	if compCmd.Hidden == false {
  2444  		t.Error("Default 'completion' command should be hidden but it is not")
  2445  	}
  2446  	// Re-enable for next test
  2447  	rootCmd.CompletionOptions.HiddenDefaultCmd = false
  2448  	// Remove completion command for the next test
  2449  	removeCompCmd(rootCmd)
  2450  }
  2451  
  2452  func TestCompleteCompletion(t *testing.T) {
  2453  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  2454  	subCmd := &Command{
  2455  		Use: "sub",
  2456  		Run: emptyRun,
  2457  	}
  2458  	rootCmd.AddCommand(subCmd)
  2459  
  2460  	// Test sub-commands of the completion command
  2461  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
  2462  	if err != nil {
  2463  		t.Errorf("Unexpected error: %v", err)
  2464  	}
  2465  
  2466  	expected := strings.Join([]string{
  2467  		"bash",
  2468  		"fish",
  2469  		"powershell",
  2470  		"zsh",
  2471  		":4",
  2472  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2473  
  2474  	if output != expected {
  2475  		t.Errorf("expected: %q, got: %q", expected, output)
  2476  	}
  2477  
  2478  	// Test there are no completions for the sub-commands of the completion command
  2479  	var compCmd *Command
  2480  	for _, cmd := range rootCmd.Commands() {
  2481  		if cmd.Name() == compCmdName {
  2482  			compCmd = cmd
  2483  			break
  2484  		}
  2485  	}
  2486  
  2487  	for _, shell := range compCmd.Commands() {
  2488  		output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, compCmdName, shell.Name(), "")
  2489  		if err != nil {
  2490  			t.Errorf("Unexpected error: %v", err)
  2491  		}
  2492  
  2493  		expected = strings.Join([]string{
  2494  			":4",
  2495  			"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2496  
  2497  		if output != expected {
  2498  			t.Errorf("expected: %q, got: %q", expected, output)
  2499  		}
  2500  	}
  2501  }
  2502  
  2503  func TestMultipleShorthandFlagCompletion(t *testing.T) {
  2504  	rootCmd := &Command{
  2505  		Use:       "root",
  2506  		ValidArgs: []string{"foo", "bar"},
  2507  		Run:       emptyRun,
  2508  	}
  2509  	f := rootCmd.Flags()
  2510  	f.BoolP("short", "s", false, "short flag 1")
  2511  	f.BoolP("short2", "d", false, "short flag 2")
  2512  	f.StringP("short3", "f", "", "short flag 3")
  2513  	_ = rootCmd.RegisterFlagCompletionFunc("short3", func(*Command, []string, string) ([]string, ShellCompDirective) {
  2514  		return []string{"works"}, ShellCompDirectiveNoFileComp
  2515  	})
  2516  
  2517  	// Test that a single shorthand flag works
  2518  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "")
  2519  	if err != nil {
  2520  		t.Errorf("Unexpected error: %v", err)
  2521  	}
  2522  
  2523  	expected := strings.Join([]string{
  2524  		"foo",
  2525  		"bar",
  2526  		":4",
  2527  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2528  
  2529  	if output != expected {
  2530  		t.Errorf("expected: %q, got: %q", expected, output)
  2531  	}
  2532  
  2533  	// Test that multiple boolean shorthand flags work
  2534  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sd", "")
  2535  	if err != nil {
  2536  		t.Errorf("Unexpected error: %v", err)
  2537  	}
  2538  
  2539  	expected = strings.Join([]string{
  2540  		"foo",
  2541  		"bar",
  2542  		":4",
  2543  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2544  
  2545  	if output != expected {
  2546  		t.Errorf("expected: %q, got: %q", expected, output)
  2547  	}
  2548  
  2549  	// Test that multiple boolean + string shorthand flags work
  2550  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf", "")
  2551  	if err != nil {
  2552  		t.Errorf("Unexpected error: %v", err)
  2553  	}
  2554  
  2555  	expected = strings.Join([]string{
  2556  		"works",
  2557  		":4",
  2558  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2559  
  2560  	if output != expected {
  2561  		t.Errorf("expected: %q, got: %q", expected, output)
  2562  	}
  2563  
  2564  	// Test that multiple boolean + string with equal sign shorthand flags work
  2565  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf=")
  2566  	if err != nil {
  2567  		t.Errorf("Unexpected error: %v", err)
  2568  	}
  2569  
  2570  	expected = strings.Join([]string{
  2571  		"works",
  2572  		":4",
  2573  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2574  
  2575  	if output != expected {
  2576  		t.Errorf("expected: %q, got: %q", expected, output)
  2577  	}
  2578  
  2579  	// Test that multiple boolean + string with equal sign with value shorthand flags work
  2580  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf=abc", "")
  2581  	if err != nil {
  2582  		t.Errorf("Unexpected error: %v", err)
  2583  	}
  2584  
  2585  	expected = strings.Join([]string{
  2586  		"foo",
  2587  		"bar",
  2588  		":4",
  2589  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2590  
  2591  	if output != expected {
  2592  		t.Errorf("expected: %q, got: %q", expected, output)
  2593  	}
  2594  }
  2595  
  2596  func TestCompleteWithDisableFlagParsing(t *testing.T) {
  2597  
  2598  	flagValidArgs := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2599  		return []string{"--flag", "-f"}, ShellCompDirectiveNoFileComp
  2600  	}
  2601  
  2602  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  2603  	childCmd := &Command{
  2604  		Use:                "child",
  2605  		Run:                emptyRun,
  2606  		DisableFlagParsing: true,
  2607  		ValidArgsFunction:  flagValidArgs,
  2608  	}
  2609  	rootCmd.AddCommand(childCmd)
  2610  
  2611  	rootCmd.PersistentFlags().StringP("persistent", "p", "", "persistent flag")
  2612  	childCmd.Flags().StringP("nonPersistent", "n", "", "non-persistent flag")
  2613  
  2614  	// Test that when DisableFlagParsing==true, ValidArgsFunction is called to complete flag names,
  2615  	// after Cobra tried to complete the flags it knows about.
  2616  	childCmd.DisableFlagParsing = true
  2617  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-")
  2618  	if err != nil {
  2619  		t.Errorf("Unexpected error: %v", err)
  2620  	}
  2621  
  2622  	expected := strings.Join([]string{
  2623  		"--persistent",
  2624  		"-p",
  2625  		"--help",
  2626  		"-h",
  2627  		"--nonPersistent",
  2628  		"-n",
  2629  		"--flag",
  2630  		"-f",
  2631  		":4",
  2632  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2633  
  2634  	if output != expected {
  2635  		t.Errorf("expected: %q, got: %q", expected, output)
  2636  	}
  2637  
  2638  	// Test that when DisableFlagParsing==false, Cobra completes the flags itself and ValidArgsFunction is not called
  2639  	childCmd.DisableFlagParsing = false
  2640  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-")
  2641  	if err != nil {
  2642  		t.Errorf("Unexpected error: %v", err)
  2643  	}
  2644  
  2645  	// Cobra was not told of any flags, so it returns nothing
  2646  	expected = strings.Join([]string{
  2647  		"--persistent",
  2648  		"-p",
  2649  		"--help",
  2650  		"-h",
  2651  		"--nonPersistent",
  2652  		"-n",
  2653  		":4",
  2654  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2655  
  2656  	if output != expected {
  2657  		t.Errorf("expected: %q, got: %q", expected, output)
  2658  	}
  2659  }
  2660  
  2661  func TestCompleteWithRootAndLegacyArgs(t *testing.T) {
  2662  	// Test a lonely root command which uses legacyArgs().  In such a case, the root
  2663  	// command should accept any number of arguments and completion should behave accordingly.
  2664  	rootCmd := &Command{
  2665  		Use:  "root",
  2666  		Args: nil, // Args must be nil to trigger the legacyArgs() function
  2667  		Run:  emptyRun,
  2668  		ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2669  			return []string{"arg1", "arg2"}, ShellCompDirectiveNoFileComp
  2670  		},
  2671  	}
  2672  
  2673  	// Make sure the first arg is completed
  2674  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
  2675  	if err != nil {
  2676  		t.Errorf("Unexpected error: %v", err)
  2677  	}
  2678  
  2679  	expected := strings.Join([]string{
  2680  		"arg1",
  2681  		"arg2",
  2682  		":4",
  2683  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2684  
  2685  	if output != expected {
  2686  		t.Errorf("expected: %q, got: %q", expected, output)
  2687  	}
  2688  
  2689  	// Make sure the completion of arguments continues
  2690  	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "arg1", "")
  2691  	if err != nil {
  2692  		t.Errorf("Unexpected error: %v", err)
  2693  	}
  2694  
  2695  	expected = strings.Join([]string{
  2696  		"arg1",
  2697  		"arg2",
  2698  		":4",
  2699  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2700  
  2701  	if output != expected {
  2702  		t.Errorf("expected: %q, got: %q", expected, output)
  2703  	}
  2704  }
  2705  
  2706  func TestFixedCompletions(t *testing.T) {
  2707  	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
  2708  	choices := []string{"apple", "banana", "orange"}
  2709  	childCmd := &Command{
  2710  		Use:               "child",
  2711  		ValidArgsFunction: FixedCompletions(choices, ShellCompDirectiveNoFileComp),
  2712  		Run:               emptyRun,
  2713  	}
  2714  	rootCmd.AddCommand(childCmd)
  2715  
  2716  	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "a")
  2717  	if err != nil {
  2718  		t.Errorf("Unexpected error: %v", err)
  2719  	}
  2720  
  2721  	expected := strings.Join([]string{
  2722  		"apple",
  2723  		"banana",
  2724  		"orange",
  2725  		":4",
  2726  		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
  2727  
  2728  	if output != expected {
  2729  		t.Errorf("expected: %q, got: %q", expected, output)
  2730  	}
  2731  }
  2732  
  2733  func TestCompletionForGroupedFlags(t *testing.T) {
  2734  	getCmd := func() *Command {
  2735  		rootCmd := &Command{
  2736  			Use: "root",
  2737  			Run: emptyRun,
  2738  		}
  2739  		childCmd := &Command{
  2740  			Use: "child",
  2741  			ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2742  				return []string{"subArg"}, ShellCompDirectiveNoFileComp
  2743  			},
  2744  			Run: emptyRun,
  2745  		}
  2746  		rootCmd.AddCommand(childCmd)
  2747  
  2748  		rootCmd.PersistentFlags().Int("ingroup1", -1, "ingroup1")
  2749  		rootCmd.PersistentFlags().String("ingroup2", "", "ingroup2")
  2750  
  2751  		childCmd.Flags().Bool("ingroup3", false, "ingroup3")
  2752  		childCmd.Flags().Bool("nogroup", false, "nogroup")
  2753  
  2754  		// Add flags to a group
  2755  		childCmd.MarkFlagsRequiredTogether("ingroup1", "ingroup2", "ingroup3")
  2756  
  2757  		return rootCmd
  2758  	}
  2759  
  2760  	// Each test case uses a unique command from the function above.
  2761  	testcases := []struct {
  2762  		desc           string
  2763  		args           []string
  2764  		expectedOutput string
  2765  	}{
  2766  		{
  2767  			desc: "flags in group not suggested without - prefix",
  2768  			args: []string{"child", ""},
  2769  			expectedOutput: strings.Join([]string{
  2770  				"subArg",
  2771  				":4",
  2772  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2773  		},
  2774  		{
  2775  			desc: "flags in group suggested with - prefix",
  2776  			args: []string{"child", "-"},
  2777  			expectedOutput: strings.Join([]string{
  2778  				"--ingroup1",
  2779  				"--ingroup2",
  2780  				"--help",
  2781  				"-h",
  2782  				"--ingroup3",
  2783  				"--nogroup",
  2784  				":4",
  2785  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2786  		},
  2787  		{
  2788  			desc: "when flag in group present, other flags in group suggested even without - prefix",
  2789  			args: []string{"child", "--ingroup2", "value", ""},
  2790  			expectedOutput: strings.Join([]string{
  2791  				"--ingroup1",
  2792  				"--ingroup3",
  2793  				"subArg",
  2794  				":4",
  2795  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2796  		},
  2797  		{
  2798  			desc: "when all flags in group present, flags not suggested without - prefix",
  2799  			args: []string{"child", "--ingroup1", "8", "--ingroup2", "value2", "--ingroup3", ""},
  2800  			expectedOutput: strings.Join([]string{
  2801  				"subArg",
  2802  				":4",
  2803  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2804  		},
  2805  		{
  2806  			desc: "group ignored if some flags not applicable",
  2807  			args: []string{"--ingroup2", "value", ""},
  2808  			expectedOutput: strings.Join([]string{
  2809  				"child",
  2810  				"completion",
  2811  				"help",
  2812  				":4",
  2813  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2814  		},
  2815  	}
  2816  
  2817  	for _, tc := range testcases {
  2818  		t.Run(tc.desc, func(t *testing.T) {
  2819  			c := getCmd()
  2820  			args := []string{ShellCompNoDescRequestCmd}
  2821  			args = append(args, tc.args...)
  2822  			output, err := executeCommand(c, args...)
  2823  			switch {
  2824  			case err == nil && output != tc.expectedOutput:
  2825  				t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
  2826  			case err != nil:
  2827  				t.Errorf("Unexpected error %q", err)
  2828  			}
  2829  		})
  2830  	}
  2831  }
  2832  
  2833  func TestCompletionForMutuallyExclusiveFlags(t *testing.T) {
  2834  	getCmd := func() *Command {
  2835  		rootCmd := &Command{
  2836  			Use: "root",
  2837  			Run: emptyRun,
  2838  		}
  2839  		childCmd := &Command{
  2840  			Use: "child",
  2841  			ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2842  				return []string{"subArg"}, ShellCompDirectiveNoFileComp
  2843  			},
  2844  			Run: emptyRun,
  2845  		}
  2846  		rootCmd.AddCommand(childCmd)
  2847  
  2848  		rootCmd.PersistentFlags().IntSlice("ingroup1", []int{1}, "ingroup1")
  2849  		rootCmd.PersistentFlags().String("ingroup2", "", "ingroup2")
  2850  
  2851  		childCmd.Flags().Bool("ingroup3", false, "ingroup3")
  2852  		childCmd.Flags().Bool("nogroup", false, "nogroup")
  2853  
  2854  		// Add flags to a group
  2855  		childCmd.MarkFlagsMutuallyExclusive("ingroup1", "ingroup2", "ingroup3")
  2856  
  2857  		return rootCmd
  2858  	}
  2859  
  2860  	// Each test case uses a unique command from the function above.
  2861  	testcases := []struct {
  2862  		desc           string
  2863  		args           []string
  2864  		expectedOutput string
  2865  	}{
  2866  		{
  2867  			desc: "flags in mutually exclusive group not suggested without the - prefix",
  2868  			args: []string{"child", ""},
  2869  			expectedOutput: strings.Join([]string{
  2870  				"subArg",
  2871  				":4",
  2872  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2873  		},
  2874  		{
  2875  			desc: "flags in mutually exclusive group suggested with the - prefix",
  2876  			args: []string{"child", "-"},
  2877  			expectedOutput: strings.Join([]string{
  2878  				"--ingroup1",
  2879  				"--ingroup2",
  2880  				"--help",
  2881  				"-h",
  2882  				"--ingroup3",
  2883  				"--nogroup",
  2884  				":4",
  2885  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2886  		},
  2887  		{
  2888  			desc: "when flag in mutually exclusive group present, other flags in group not suggested even with the - prefix",
  2889  			args: []string{"child", "--ingroup1", "8", "-"},
  2890  			expectedOutput: strings.Join([]string{
  2891  				"--ingroup1", // Should be suggested again since it is a slice
  2892  				"--help",
  2893  				"-h",
  2894  				"--nogroup",
  2895  				":4",
  2896  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2897  		},
  2898  		{
  2899  			desc: "group ignored if some flags not applicable",
  2900  			args: []string{"--ingroup1", "8", "-"},
  2901  			expectedOutput: strings.Join([]string{
  2902  				"--help",
  2903  				"-h",
  2904  				"--ingroup1",
  2905  				"--ingroup2",
  2906  				":4",
  2907  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2908  		},
  2909  	}
  2910  
  2911  	for _, tc := range testcases {
  2912  		t.Run(tc.desc, func(t *testing.T) {
  2913  			c := getCmd()
  2914  			args := []string{ShellCompNoDescRequestCmd}
  2915  			args = append(args, tc.args...)
  2916  			output, err := executeCommand(c, args...)
  2917  			switch {
  2918  			case err == nil && output != tc.expectedOutput:
  2919  				t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
  2920  			case err != nil:
  2921  				t.Errorf("Unexpected error %q", err)
  2922  			}
  2923  		})
  2924  	}
  2925  }
  2926  
  2927  func TestCompletionCobraFlags(t *testing.T) {
  2928  	getCmd := func() *Command {
  2929  		rootCmd := &Command{
  2930  			Use:     "root",
  2931  			Version: "1.1.1",
  2932  			Run:     emptyRun,
  2933  		}
  2934  		childCmd := &Command{
  2935  			Use:     "child",
  2936  			Version: "1.1.1",
  2937  			Run:     emptyRun,
  2938  			ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2939  				return []string{"extra"}, ShellCompDirectiveNoFileComp
  2940  			},
  2941  		}
  2942  		childCmd2 := &Command{
  2943  			Use:     "child2",
  2944  			Version: "1.1.1",
  2945  			Run:     emptyRun,
  2946  			ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2947  				return []string{"extra2"}, ShellCompDirectiveNoFileComp
  2948  			},
  2949  		}
  2950  		childCmd3 := &Command{
  2951  			Use:     "child3",
  2952  			Version: "1.1.1",
  2953  			Run:     emptyRun,
  2954  			ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
  2955  				return []string{"extra3"}, ShellCompDirectiveNoFileComp
  2956  			},
  2957  		}
  2958  
  2959  		rootCmd.AddCommand(childCmd, childCmd2, childCmd3)
  2960  
  2961  		_ = childCmd.Flags().Bool("bool", false, "A bool flag")
  2962  		_ = childCmd.MarkFlagRequired("bool")
  2963  
  2964  		// Have a command that adds its own help and version flag
  2965  		_ = childCmd2.Flags().BoolP("help", "h", false, "My own help")
  2966  		_ = childCmd2.Flags().BoolP("version", "v", false, "My own version")
  2967  
  2968  		// Have a command that only adds its own -v flag
  2969  		_ = childCmd3.Flags().BoolP("verbose", "v", false, "Not a version flag")
  2970  
  2971  		return rootCmd
  2972  	}
  2973  
  2974  	// Each test case uses a unique command from the function above.
  2975  	testcases := []struct {
  2976  		desc           string
  2977  		args           []string
  2978  		expectedOutput string
  2979  	}{
  2980  		{
  2981  			desc: "completion of help and version flags",
  2982  			args: []string{"-"},
  2983  			expectedOutput: strings.Join([]string{
  2984  				"--help",
  2985  				"-h",
  2986  				"--version",
  2987  				"-v",
  2988  				":4",
  2989  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2990  		},
  2991  		{
  2992  			desc: "no completion after --help flag",
  2993  			args: []string{"--help", ""},
  2994  			expectedOutput: strings.Join([]string{
  2995  				":4",
  2996  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  2997  		},
  2998  		{
  2999  			desc: "no completion after -h flag",
  3000  			args: []string{"-h", ""},
  3001  			expectedOutput: strings.Join([]string{
  3002  				":4",
  3003  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3004  		},
  3005  		{
  3006  			desc: "no completion after --version flag",
  3007  			args: []string{"--version", ""},
  3008  			expectedOutput: strings.Join([]string{
  3009  				":4",
  3010  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3011  		},
  3012  		{
  3013  			desc: "no completion after -v flag",
  3014  			args: []string{"-v", ""},
  3015  			expectedOutput: strings.Join([]string{
  3016  				":4",
  3017  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3018  		},
  3019  		{
  3020  			desc: "no completion after --help flag even with other completions",
  3021  			args: []string{"child", "--help", ""},
  3022  			expectedOutput: strings.Join([]string{
  3023  				":4",
  3024  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3025  		},
  3026  		{
  3027  			desc: "no completion after -h flag even with other completions",
  3028  			args: []string{"child", "-h", ""},
  3029  			expectedOutput: strings.Join([]string{
  3030  				":4",
  3031  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3032  		},
  3033  		{
  3034  			desc: "no completion after --version flag even with other completions",
  3035  			args: []string{"child", "--version", ""},
  3036  			expectedOutput: strings.Join([]string{
  3037  				":4",
  3038  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3039  		},
  3040  		{
  3041  			desc: "no completion after -v flag even with other completions",
  3042  			args: []string{"child", "-v", ""},
  3043  			expectedOutput: strings.Join([]string{
  3044  				":4",
  3045  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3046  		},
  3047  		{
  3048  			desc: "no completion after -v flag even with other flag completions",
  3049  			args: []string{"child", "-v", "-"},
  3050  			expectedOutput: strings.Join([]string{
  3051  				":4",
  3052  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3053  		},
  3054  		{
  3055  			desc: "completion after --help flag when created by program",
  3056  			args: []string{"child2", "--help", ""},
  3057  			expectedOutput: strings.Join([]string{
  3058  				"extra2",
  3059  				":4",
  3060  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3061  		},
  3062  		{
  3063  			desc: "completion after -h flag when created by program",
  3064  			args: []string{"child2", "-h", ""},
  3065  			expectedOutput: strings.Join([]string{
  3066  				"extra2",
  3067  				":4",
  3068  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3069  		},
  3070  		{
  3071  			desc: "completion after --version flag when created by program",
  3072  			args: []string{"child2", "--version", ""},
  3073  			expectedOutput: strings.Join([]string{
  3074  				"extra2",
  3075  				":4",
  3076  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3077  		},
  3078  		{
  3079  			desc: "completion after -v flag when created by program",
  3080  			args: []string{"child2", "-v", ""},
  3081  			expectedOutput: strings.Join([]string{
  3082  				"extra2",
  3083  				":4",
  3084  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3085  		},
  3086  		{
  3087  			desc: "completion after --version when only -v flag was created by program",
  3088  			args: []string{"child3", "--version", ""},
  3089  			expectedOutput: strings.Join([]string{
  3090  				":4",
  3091  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3092  		},
  3093  		{
  3094  			desc: "completion after -v flag when only -v flag was created by program",
  3095  			args: []string{"child3", "-v", ""},
  3096  			expectedOutput: strings.Join([]string{
  3097  				"extra3",
  3098  				":4",
  3099  				"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
  3100  		},
  3101  	}
  3102  
  3103  	for _, tc := range testcases {
  3104  		t.Run(tc.desc, func(t *testing.T) {
  3105  			c := getCmd()
  3106  			args := []string{ShellCompNoDescRequestCmd}
  3107  			args = append(args, tc.args...)
  3108  			output, err := executeCommand(c, args...)
  3109  			switch {
  3110  			case err == nil && output != tc.expectedOutput:
  3111  				t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
  3112  			case err != nil:
  3113  				t.Errorf("Unexpected error %q", err)
  3114  			}
  3115  		})
  3116  	}
  3117  }