mirror of
https://github.com/spf13/cobra
synced 2024-11-13 01:07:20 +00:00
fd32f09af1
* Make preamble functions unique to command Prior to this commit the functions in the preamble had names that didn't vary based on the command for which the bash completion was generated. This meant that if you had two bash completions with differences in the preamble functions then only the last loaded function would be available. This commit prefixes all of these functions with the name of the command so that multiple cobra generated completion files won't clash. Signed-off-by: John McCabe <john@johnmccabe.net> * Fix function names in writeFlagHandler The references to the `__handle_filename_extension_flag` and `__handle_subdirs_in_dir_flag` functions in `writeFlagHandler` hadn't been updated correctly in the previous commits. Signed-off-by: John McCabe <john@johnmccabe.net> * Pass cmd into writeFlagHandler This commit passes the cmd pointer into the writeFlagHandler so that the `__handle_filename_extension_flag` and `__handle_subdirs_in_dir_flag` functions can have the `cmd.Name()` prefixed. * Update Bash completion tests Prefixes the tested `__handle_filename_extension_flag` and `__handle_subdirs_in_dir_flag` functions with the command name.
197 lines
5.8 KiB
Go
197 lines
5.8 KiB
Go
package cobra
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func checkOmit(t *testing.T, found, unexpected string) {
|
|
if strings.Contains(found, unexpected) {
|
|
t.Errorf("Got: %q\nBut should not have!\n", unexpected)
|
|
}
|
|
}
|
|
|
|
func check(t *testing.T, found, expected string) {
|
|
if !strings.Contains(found, expected) {
|
|
t.Errorf("Expecting to contain: \n %q\nGot:\n %q\n", expected, found)
|
|
}
|
|
}
|
|
|
|
func runShellCheck(s string) error {
|
|
excluded := []string{
|
|
"SC2034", // PREFIX appears unused. Verify it or export it.
|
|
}
|
|
cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", strings.Join(excluded, ","))
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Stdout = os.Stdout
|
|
|
|
stdin, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
go func() {
|
|
stdin.Write([]byte(s))
|
|
stdin.Close()
|
|
}()
|
|
|
|
return cmd.Run()
|
|
}
|
|
|
|
// World worst custom function, just keep telling you to enter hello!
|
|
const bashCompletionFunc = `__custom_func() {
|
|
COMPREPLY=( "hello" )
|
|
}
|
|
`
|
|
|
|
func TestBashCompletions(t *testing.T) {
|
|
rootCmd := &Command{
|
|
Use: "root",
|
|
ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"},
|
|
ValidArgs: []string{"pod", "node", "service", "replicationcontroller"},
|
|
BashCompletionFunction: bashCompletionFunc,
|
|
Run: emptyRun,
|
|
}
|
|
rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
|
|
rootCmd.MarkFlagRequired("introot")
|
|
|
|
// Filename.
|
|
rootCmd.Flags().String("filename", "", "Enter a filename")
|
|
rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")
|
|
|
|
// Persistent filename.
|
|
rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename")
|
|
rootCmd.MarkPersistentFlagFilename("persistent-filename")
|
|
rootCmd.MarkPersistentFlagRequired("persistent-filename")
|
|
|
|
// Filename extensions.
|
|
rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)")
|
|
rootCmd.MarkFlagFilename("filename-ext")
|
|
rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)")
|
|
rootCmd.MarkFlagCustom("custom", "__complete_custom")
|
|
|
|
// Subdirectories in a given directory.
|
|
rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)")
|
|
rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})
|
|
|
|
echoCmd := &Command{
|
|
Use: "echo [string to echo]",
|
|
Aliases: []string{"say"},
|
|
Short: "Echo anything to the screen",
|
|
Long: "an utterly useless command for testing.",
|
|
Example: "Just run cobra-test echo",
|
|
Run: emptyRun,
|
|
}
|
|
|
|
printCmd := &Command{
|
|
Use: "print [string to print]",
|
|
Args: MinimumNArgs(1),
|
|
Short: "Print anything to the screen",
|
|
Long: "an absolutely utterly useless command for testing.",
|
|
Run: emptyRun,
|
|
}
|
|
|
|
deprecatedCmd := &Command{
|
|
Use: "deprecated [can't do anything here]",
|
|
Args: NoArgs,
|
|
Short: "A command which is deprecated",
|
|
Long: "an absolutely utterly useless command for testing deprecation!.",
|
|
Deprecated: "Please use echo instead",
|
|
Run: emptyRun,
|
|
}
|
|
|
|
colonCmd := &Command{
|
|
Use: "cmd:colon",
|
|
Run: emptyRun,
|
|
}
|
|
|
|
timesCmd := &Command{
|
|
Use: "times [# times] [string to echo]",
|
|
SuggestFor: []string{"counts"},
|
|
Args: OnlyValidArgs,
|
|
ValidArgs: []string{"one", "two", "three", "four"},
|
|
Short: "Echo anything to the screen more times",
|
|
Long: "a slightly useless command for testing.",
|
|
Run: emptyRun,
|
|
}
|
|
|
|
echoCmd.AddCommand(timesCmd)
|
|
rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd)
|
|
|
|
buf := new(bytes.Buffer)
|
|
rootCmd.GenBashCompletion(buf)
|
|
output := buf.String()
|
|
|
|
check(t, output, "_root")
|
|
check(t, output, "_root_echo")
|
|
check(t, output, "_root_echo_times")
|
|
check(t, output, "_root_print")
|
|
check(t, output, "_root_cmd__colon")
|
|
|
|
// check for required flags
|
|
check(t, output, `must_have_one_flag+=("--introot=")`)
|
|
check(t, output, `must_have_one_flag+=("--persistent-filename=")`)
|
|
// check for custom completion function
|
|
check(t, output, `COMPREPLY=( "hello" )`)
|
|
// check for required nouns
|
|
check(t, output, `must_have_one_noun+=("pod")`)
|
|
// check for noun aliases
|
|
check(t, output, `noun_aliases+=("pods")`)
|
|
check(t, output, `noun_aliases+=("rc")`)
|
|
checkOmit(t, output, `must_have_one_noun+=("pods")`)
|
|
// check for filename extension flags
|
|
check(t, output, `flags_completion+=("_filedir")`)
|
|
// check for filename extension flags
|
|
check(t, output, `must_have_one_noun+=("three")`)
|
|
// check for filename extension flags
|
|
check(t, output, fmt.Sprintf(`flags_completion+=("__%s_handle_filename_extension_flag json|yaml|yml")`, rootCmd.Name()))
|
|
// check for custom flags
|
|
check(t, output, `flags_completion+=("__complete_custom")`)
|
|
// check for subdirs_in_dir flags
|
|
check(t, output, fmt.Sprintf(`flags_completion+=("__%s_handle_subdirs_in_dir_flag themes")`, rootCmd.Name()))
|
|
|
|
checkOmit(t, output, deprecatedCmd.Name())
|
|
|
|
// If available, run shellcheck against the script.
|
|
if err := exec.Command("which", "shellcheck").Run(); err != nil {
|
|
return
|
|
}
|
|
if err := runShellCheck(output); err != nil {
|
|
t.Fatalf("shellcheck failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestBashCompletionHiddenFlag(t *testing.T) {
|
|
c := &Command{Use: "c", Run: emptyRun}
|
|
|
|
const flagName = "hiddenFlag"
|
|
c.Flags().Bool(flagName, false, "")
|
|
c.Flags().MarkHidden(flagName)
|
|
|
|
buf := new(bytes.Buffer)
|
|
c.GenBashCompletion(buf)
|
|
output := buf.String()
|
|
|
|
if strings.Contains(output, flagName) {
|
|
t.Errorf("Expected completion to not include %q flag: Got %v", flagName, output)
|
|
}
|
|
}
|
|
|
|
func TestBashCompletionDeprecatedFlag(t *testing.T) {
|
|
c := &Command{Use: "c", Run: emptyRun}
|
|
|
|
const flagName = "deprecated-flag"
|
|
c.Flags().Bool(flagName, false, "")
|
|
c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead")
|
|
|
|
buf := new(bytes.Buffer)
|
|
c.GenBashCompletion(buf)
|
|
output := buf.String()
|
|
|
|
if strings.Contains(output, flagName) {
|
|
t.Errorf("expected completion to not include %q flag: Got %v", flagName, output)
|
|
}
|
|
}
|