Improve tests

This commit is contained in:
Albert Nigmatzianov 2017-10-31 19:58:37 +01:00
parent 099c5aef9e
commit 65c8acb228
6 changed files with 1428 additions and 1711 deletions

View file

@ -10,13 +10,13 @@ import (
func checkOmit(t *testing.T, found, unexpected string) { func checkOmit(t *testing.T, found, unexpected string) {
if strings.Contains(found, unexpected) { if strings.Contains(found, unexpected) {
t.Errorf("Unexpected response.\nGot: %q\nBut should not have!\n", unexpected) t.Errorf("Got: %q\nBut should not have!\n", unexpected)
} }
} }
func check(t *testing.T, found, expected string) { func check(t *testing.T, found, expected string) {
if !strings.Contains(found, expected) { if !strings.Contains(found, expected) {
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) t.Errorf("Expecting to contain: \n %q\nGot:\n %q\n", expected, found)
} }
} }
@ -33,162 +33,164 @@ func runShellCheck(s string) error {
return err return err
} }
go func() { go func() {
defer stdin.Close()
stdin.Write([]byte(s)) stdin.Write([]byte(s))
stdin.Close()
}() }()
return cmd.Run() return cmd.Run()
} }
// World worst custom function, just keep telling you to enter hello! // World worst custom function, just keep telling you to enter hello!
const ( const bashCompletionFunc = `__custom_func() {
bashCompletionFunc = `__custom_func() {
COMPREPLY=( "hello" ) COMPREPLY=( "hello" )
} }
` `
)
func TestBashCompletions(t *testing.T) { func TestBashCompletions(t *testing.T) {
c := initializeWithRootCmd() rootCmd := &Command{
cmdEcho.AddCommand(cmdTimes) Use: "root",
c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon) 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")
// custom completion function // Filename.
c.BashCompletionFunction = bashCompletionFunc rootCmd.Flags().String("filename", "", "Enter a filename")
rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")
// required flag // Persistent filename.
c.MarkFlagRequired("introot") rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename")
rootCmd.MarkPersistentFlagFilename("persistent-filename")
rootCmd.MarkPersistentFlagRequired("persistent-filename")
// valid nouns // Filename extensions.
validArgs := []string{"pod", "node", "service", "replicationcontroller"} rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)")
c.ValidArgs = validArgs rootCmd.MarkFlagFilename("filename-ext")
rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)")
rootCmd.MarkFlagCustom("custom", "__complete_custom")
// noun aliases // Subdirectories in a given directory.
argAliases := []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"} rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)")
c.ArgAliases = argAliases rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})
// filename echoCmd := &Command{
var flagval string Use: "echo [string to echo]",
c.Flags().StringVar(&flagval, "filename", "", "Enter a filename") Aliases: []string{"say"},
c.MarkFlagFilename("filename", "json", "yaml", "yml") Short: "Echo anything to the screen",
Long: "an utterly useless command for testing.",
Example: "Just run cobra-test echo",
Run: emptyRun,
}
// persistent filename printCmd := &Command{
var flagvalPersistent string Use: "print [string to print]",
c.PersistentFlags().StringVar(&flagvalPersistent, "persistent-filename", "", "Enter a filename") Args: MinimumNArgs(1),
c.MarkPersistentFlagFilename("persistent-filename") Short: "Print anything to the screen",
c.MarkPersistentFlagRequired("persistent-filename") Long: "an absolutely utterly useless command for testing.",
Run: emptyRun,
}
// filename extensions deprecatedCmd := &Command{
var flagvalExt string Use: "deprecated [can't do anything here]",
c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)") Args: NoArgs,
c.MarkFlagFilename("filename-ext") Short: "A command which is deprecated",
Long: "an absolutely utterly useless command for testing deprecation!.",
Deprecated: "Please use echo instead",
Run: emptyRun,
}
// filename extensions colonCmd := &Command{
var flagvalCustom string Use: "cmd:colon",
c.Flags().StringVar(&flagvalCustom, "custom", "", "Enter a filename (extension limited)") Run: emptyRun,
c.MarkFlagCustom("custom", "__complete_custom") }
// subdirectories in a given directory timesCmd := &Command{
var flagvalTheme string Use: "times [# times] [string to echo]",
c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)") SuggestFor: []string{"counts"},
c.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) 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,
}
out := new(bytes.Buffer) echoCmd.AddCommand(timesCmd)
c.GenBashCompletion(out) rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd)
str := out.String()
check(t, str, "_cobra-test") buf := new(bytes.Buffer)
check(t, str, "_cobra-test_echo") rootCmd.GenBashCompletion(buf)
check(t, str, "_cobra-test_echo_times") output := buf.String()
check(t, str, "_cobra-test_print")
check(t, str, "_cobra-test_cmd__colon") 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 for required flags
check(t, str, `must_have_one_flag+=("--introot=")`) check(t, output, `must_have_one_flag+=("--introot=")`)
check(t, str, `must_have_one_flag+=("--persistent-filename=")`) check(t, output, `must_have_one_flag+=("--persistent-filename=")`)
// check for custom completion function // check for custom completion function
check(t, str, `COMPREPLY=( "hello" )`) check(t, output, `COMPREPLY=( "hello" )`)
// check for required nouns // check for required nouns
check(t, str, `must_have_one_noun+=("pod")`) check(t, output, `must_have_one_noun+=("pod")`)
// check for noun aliases // check for noun aliases
check(t, str, `noun_aliases+=("pods")`) check(t, output, `noun_aliases+=("pods")`)
check(t, str, `noun_aliases+=("rc")`) check(t, output, `noun_aliases+=("rc")`)
checkOmit(t, str, `must_have_one_noun+=("pods")`) checkOmit(t, output, `must_have_one_noun+=("pods")`)
// check for filename extension flags // check for filename extension flags
check(t, str, `flags_completion+=("_filedir")`) check(t, output, `flags_completion+=("_filedir")`)
// check for filename extension flags // check for filename extension flags
check(t, str, `must_have_one_noun+=("three")`) check(t, output, `must_have_one_noun+=("three")`)
// check for filename extension flags // check for filename extension flags
check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`) check(t, output, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
// check for custom flags // check for custom flags
check(t, str, `flags_completion+=("__complete_custom")`) check(t, output, `flags_completion+=("__complete_custom")`)
// check for subdirs_in_dir flags // check for subdirs_in_dir flags
check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`) check(t, output, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
checkOmit(t, str, cmdDeprecated.Name()) checkOmit(t, output, deprecatedCmd.Name())
// if available, run shellcheck against the script // If available, run shellcheck against the script.
if err := exec.Command("which", "shellcheck").Run(); err != nil { if err := exec.Command("which", "shellcheck").Run(); err != nil {
return return
} }
err := runShellCheck(str) if err := runShellCheck(output); err != nil {
if err != nil {
t.Fatalf("shellcheck failed: %v", err) t.Fatalf("shellcheck failed: %v", err)
} }
} }
func TestBashCompletionHiddenFlag(t *testing.T) { func TestBashCompletionHiddenFlag(t *testing.T) {
var cmdTrue = &Command{ c := &Command{Use: "c", Run: emptyRun}
Use: "does nothing",
Run: func(cmd *Command, args []string) {},
}
const flagName = "hidden-foo-bar-baz" const flagName = "hiddenFlag"
c.Flags().Bool(flagName, false, "")
c.Flags().MarkHidden(flagName)
var flagValue bool buf := new(bytes.Buffer)
cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag") c.GenBashCompletion(buf)
cmdTrue.Flags().MarkHidden(flagName) output := buf.String()
out := new(bytes.Buffer) if strings.Contains(output, flagName) {
cmdTrue.GenBashCompletion(out) t.Errorf("Expected completion to not include %q flag: Got %v", flagName, output)
bashCompletion := out.String()
if strings.Contains(bashCompletion, flagName) {
t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion)
} }
} }
func TestBashCompletionDeprecatedFlag(t *testing.T) { func TestBashCompletionDeprecatedFlag(t *testing.T) {
var cmdTrue = &Command{ c := &Command{Use: "c", Run: emptyRun}
Use: "does nothing",
Run: func(cmd *Command, args []string) {},
}
const flagName = "deprecated-foo-bar-baz" const flagName = "deprecated-flag"
c.Flags().Bool(flagName, false, "")
var flagValue bool c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead")
cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag")
cmdTrue.Flags().MarkDeprecated(flagName, "use --does-not-exist instead")
out := new(bytes.Buffer)
cmdTrue.GenBashCompletion(out)
bashCompletion := out.String()
if strings.Contains(bashCompletion, flagName) {
t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion)
}
}
func BenchmarkBashCompletion(b *testing.B) {
c := initializeWithRootCmd()
cmdEcho.AddCommand(cmdTimes)
c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
c.GenBashCompletion(buf)
output := buf.String()
b.ResetTimer() if strings.Contains(output, flagName) {
for i := 0; i < b.N; i++ { t.Errorf("expected completion to not include %q flag: Got %v", flagName, output)
buf.Reset()
if err := c.GenBashCompletion(buf); err != nil {
b.Fatal(err)
}
} }
} }

View file

@ -188,3 +188,12 @@ func ld(s, t string, ignoreCase bool) int {
} }
return d[len(s)][len(t)] return d[len(s)][len(t)]
} }
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}

File diff suppressed because it is too large Load diff

View file

@ -621,10 +621,8 @@ func (c *Command) Root() *Command {
return c return c
} }
// ArgsLenAtDash will return the length of f.Args at the moment when a -- was // ArgsLenAtDash will return the length of c.Flags().Args at the moment
// found during arg parsing. This allows your program to know which args were // when a -- was found during args parsing.
// before the -- and which came after. (Description from
// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash).
func (c *Command) ArgsLenAtDash() int { func (c *Command) ArgsLenAtDash() int {
return c.Flags().ArgsLenAtDash() return c.Flags().ArgsLenAtDash()
} }

File diff suppressed because it is too large Load diff

View file

@ -77,10 +77,11 @@ func TestZshCompletion(t *testing.T) {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
tc.root.GenZshCompletion(buf) tc.root.GenZshCompletion(buf)
completion := buf.String() output := buf.String()
for _, expectedExpression := range tc.expectedExpressions { for _, expectedExpression := range tc.expectedExpressions {
if !strings.Contains(completion, expectedExpression) { if !strings.Contains(output, expectedExpression) {
t.Errorf("expected completion to contain '%v' somewhere; got '%v'", expectedExpression, completion) t.Errorf("Expected completion to contain %q somewhere; got %q", expectedExpression, output)
} }
} }
}) })