11 func checkOmit(t *testing.T, found, unexpected string) {
12 if strings.Contains(found, unexpected) {
13 t.Errorf("Unexpected response.\nGot: %q\nBut should not have!\n", unexpected)
17 func check(t *testing.T, found, expected string) {
18 if !strings.Contains(found, expected) {
19 t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
23 func runShellCheck(s string) error {
25 "SC2034", // PREFIX appears unused. Verify it or export it.
27 cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", strings.Join(excluded, ","))
28 cmd.Stderr = os.Stderr
29 cmd.Stdout = os.Stdout
31 stdin, err := cmd.StdinPipe()
37 stdin.Write([]byte(s))
43 // World worst custom function, just keep telling you to enter hello!
45 bashCompletionFunc = `__custom_func() {
51 func TestBashCompletions(t *testing.T) {
52 c := initializeWithRootCmd()
53 cmdEcho.AddCommand(cmdTimes)
54 c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon)
56 // custom completion function
57 c.BashCompletionFunction = bashCompletionFunc
60 c.MarkFlagRequired("introot")
63 validArgs := []string{"pod", "node", "service", "replicationcontroller"}
64 c.ValidArgs = validArgs
67 argAliases := []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}
68 c.ArgAliases = argAliases
72 c.Flags().StringVar(&flagval, "filename", "", "Enter a filename")
73 c.MarkFlagFilename("filename", "json", "yaml", "yml")
75 // persistent filename
76 var flagvalPersistent string
77 c.PersistentFlags().StringVar(&flagvalPersistent, "persistent-filename", "", "Enter a filename")
78 c.MarkPersistentFlagFilename("persistent-filename")
79 c.MarkPersistentFlagRequired("persistent-filename")
81 // filename extensions
83 c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)")
84 c.MarkFlagFilename("filename-ext")
86 // filename extensions
87 var flagvalCustom string
88 c.Flags().StringVar(&flagvalCustom, "custom", "", "Enter a filename (extension limited)")
89 c.MarkFlagCustom("custom", "__complete_custom")
91 // subdirectories in a given directory
92 var flagvalTheme string
93 c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)")
94 c.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})
96 out := new(bytes.Buffer)
97 c.GenBashCompletion(out)
100 check(t, str, "_cobra-test")
101 check(t, str, "_cobra-test_echo")
102 check(t, str, "_cobra-test_echo_times")
103 check(t, str, "_cobra-test_print")
104 check(t, str, "_cobra-test_cmd__colon")
106 // check for required flags
107 check(t, str, `must_have_one_flag+=("--introot=")`)
108 check(t, str, `must_have_one_flag+=("--persistent-filename=")`)
109 // check for custom completion function
110 check(t, str, `COMPREPLY=( "hello" )`)
111 // check for required nouns
112 check(t, str, `must_have_one_noun+=("pod")`)
113 // check for noun aliases
114 check(t, str, `noun_aliases+=("pods")`)
115 check(t, str, `noun_aliases+=("rc")`)
116 checkOmit(t, str, `must_have_one_noun+=("pods")`)
117 // check for filename extension flags
118 check(t, str, `flags_completion+=("_filedir")`)
119 // check for filename extension flags
120 check(t, str, `must_have_one_noun+=("three")`)
121 // check for filename extension flags
122 check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
123 // check for custom flags
124 check(t, str, `flags_completion+=("__complete_custom")`)
125 // check for subdirs_in_dir flags
126 check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
128 checkOmit(t, str, cmdDeprecated.Name())
130 // if available, run shellcheck against the script
131 if err := exec.Command("which", "shellcheck").Run(); err != nil {
134 err := runShellCheck(str)
136 t.Fatalf("shellcheck failed: %v", err)
140 func TestBashCompletionHiddenFlag(t *testing.T) {
141 var cmdTrue = &Command{
143 Run: func(cmd *Command, args []string) {},
146 const flagName = "hidden-foo-bar-baz"
149 cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag")
150 cmdTrue.Flags().MarkHidden(flagName)
152 out := new(bytes.Buffer)
153 cmdTrue.GenBashCompletion(out)
154 bashCompletion := out.String()
155 if strings.Contains(bashCompletion, flagName) {
156 t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion)
160 func TestBashCompletionDeprecatedFlag(t *testing.T) {
161 var cmdTrue = &Command{
163 Run: func(cmd *Command, args []string) {},
166 const flagName = "deprecated-foo-bar-baz"
169 cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag")
170 cmdTrue.Flags().MarkDeprecated(flagName, "use --does-not-exist instead")
172 out := new(bytes.Buffer)
173 cmdTrue.GenBashCompletion(out)
174 bashCompletion := out.String()
175 if strings.Contains(bashCompletion, flagName) {
176 t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion)
180 func BenchmarkBashCompletion(b *testing.B) {
181 c := initializeWithRootCmd()
182 cmdEcho.AddCommand(cmdTimes)
183 c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon)
185 buf := new(bytes.Buffer)
188 for i := 0; i < b.N; i++ {
190 if err := c.GenBashCompletion(buf); err != nil {