mirror of
https://github.com/spf13/cobra.git
synced 2024-11-15 17:58:18 -07:00
91e80cc4a4
I thought there was a bug in the boolSlice definition but it seems It was my mistake in identifying what's going on. Also removed the provisioning to skip tests (doesn't seem to be needed anymore).
301 lines
7.5 KiB
Go
301 lines
7.5 KiB
Go
package cobra
|
|
|
|
import (
|
|
"bytes"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestGenZshCompletion(t *testing.T) {
|
|
var debug bool
|
|
var option string
|
|
|
|
tcs := []struct {
|
|
name string
|
|
root *Command
|
|
expectedExpressions []string
|
|
}{
|
|
{
|
|
name: "simple command",
|
|
root: func() *Command {
|
|
r := &Command{
|
|
Use: "mycommand",
|
|
Long: "My Command long description",
|
|
Run: emptyRun,
|
|
}
|
|
r.Flags().BoolVar(&debug, "debug", debug, "description")
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
`(?s)function _mycommand {\s+_arguments \\\s+'--debug\[description\]'.*--help.*}`,
|
|
"#compdef _mycommand mycommand",
|
|
},
|
|
},
|
|
{
|
|
name: "flags with both long and short flags",
|
|
root: func() *Command {
|
|
r := &Command{
|
|
Use: "testcmd",
|
|
Long: "long description",
|
|
Run: emptyRun,
|
|
}
|
|
r.Flags().BoolVarP(&debug, "debug", "d", debug, "debug description")
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
`'\(-d --debug\)'{-d,--debug}'\[debug description\]'`,
|
|
},
|
|
},
|
|
{
|
|
name: "command with subcommands and flags with values",
|
|
root: func() *Command {
|
|
r := &Command{
|
|
Use: "rootcmd",
|
|
Long: "Long rootcmd description",
|
|
}
|
|
d := &Command{
|
|
Use: "subcmd1",
|
|
Short: "Subcmd1 short descrition",
|
|
Run: emptyRun,
|
|
}
|
|
e := &Command{
|
|
Use: "subcmd2",
|
|
Long: "Subcmd2 short description",
|
|
Run: emptyRun,
|
|
}
|
|
r.PersistentFlags().BoolVar(&debug, "debug", debug, "description")
|
|
d.Flags().StringVarP(&option, "option", "o", option, "option description")
|
|
r.AddCommand(d, e)
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
`commands=\(\n\s+"help:.*\n\s+"subcmd1:.*\n\s+"subcmd2:.*\n\s+\)`,
|
|
`_arguments \\\n.*'--debug\[description]'`,
|
|
`_arguments -C \\\n.*'--debug\[description]'`,
|
|
`function _rootcmd_subcmd1 {`,
|
|
`function _rootcmd_subcmd1 {`,
|
|
`_arguments \\\n.*'\(-o --option\)'{-o,--option}'\[option description]:' \\\n`,
|
|
},
|
|
},
|
|
{
|
|
name: "filename completion with and without globs",
|
|
root: func() *Command {
|
|
var file string
|
|
r := &Command{
|
|
Use: "mycmd",
|
|
Short: "my command short description",
|
|
Run: emptyRun,
|
|
}
|
|
r.Flags().StringVarP(&file, "config", "c", file, "config file")
|
|
r.MarkFlagFilename("config")
|
|
r.Flags().String("output", "", "output file")
|
|
r.MarkFlagFilename("output", "*.log", "*.txt")
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
`\n +'\(-c --config\)'{-c,--config}'\[config file]:filename:_files'`,
|
|
`:_files -g "\*.log" -g "\*.txt"`,
|
|
},
|
|
},
|
|
{
|
|
name: "repeated variables both with and without value",
|
|
root: func() *Command {
|
|
r := genTestCommand("mycmd", true)
|
|
_ = r.Flags().BoolSliceP("debug", "d", []bool{}, "debug usage")
|
|
_ = r.Flags().StringArray("option", []string{}, "options")
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
`'\*--option\[options]`,
|
|
`'\(\*-d \*--debug\)'{\\\*-d,\\\*--debug}`,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tcs {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tc.root.Execute()
|
|
buf := new(bytes.Buffer)
|
|
if err := tc.root.GenZshCompletion(buf); err != nil {
|
|
t.Error(err)
|
|
}
|
|
output := buf.Bytes()
|
|
|
|
for _, expr := range tc.expectedExpressions {
|
|
rgx, err := regexp.Compile(expr)
|
|
if err != nil {
|
|
t.Errorf("error compiling expression (%s): %v", expr, err)
|
|
}
|
|
if !rgx.Match(output) {
|
|
t.Errorf("expeced completion (%s) to match '%s'", buf.String(), expr)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenZshCompletionHidden(t *testing.T) {
|
|
tcs := []struct {
|
|
name string
|
|
root *Command
|
|
expectedExpressions []string
|
|
}{
|
|
{
|
|
name: "hidden commmands",
|
|
root: func() *Command {
|
|
r := &Command{
|
|
Use: "main",
|
|
Short: "main short description",
|
|
}
|
|
s1 := &Command{
|
|
Use: "sub1",
|
|
Hidden: true,
|
|
Run: emptyRun,
|
|
}
|
|
s2 := &Command{
|
|
Use: "sub2",
|
|
Short: "short sub2 description",
|
|
Run: emptyRun,
|
|
}
|
|
r.AddCommand(s1, s2)
|
|
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
"sub1",
|
|
},
|
|
},
|
|
{
|
|
name: "hidden flags",
|
|
root: func() *Command {
|
|
var hidden string
|
|
r := &Command{
|
|
Use: "root",
|
|
Short: "root short description",
|
|
Run: emptyRun,
|
|
}
|
|
r.Flags().StringVarP(&hidden, "hidden", "H", hidden, "hidden usage")
|
|
if err := r.Flags().MarkHidden("hidden"); err != nil {
|
|
t.Errorf("Error setting flag hidden: %v\n", err)
|
|
}
|
|
return r
|
|
}(),
|
|
expectedExpressions: []string{
|
|
"--hidden",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tcs {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
tc.root.Execute()
|
|
buf := new(bytes.Buffer)
|
|
if err := tc.root.GenZshCompletion(buf); err != nil {
|
|
t.Error(err)
|
|
}
|
|
output := buf.String()
|
|
|
|
for _, expr := range tc.expectedExpressions {
|
|
if strings.Contains(output, expr) {
|
|
t.Errorf("Expected completion (%s) not to contain '%s' but it does", output, expr)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkMediumSizeConstruct(b *testing.B) {
|
|
root := constructLargeCommandHeirarchy()
|
|
// if err := root.GenZshCompletionFile("_mycmd"); err != nil {
|
|
// b.Error(err)
|
|
// }
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
buf := new(bytes.Buffer)
|
|
err := root.GenZshCompletion(buf)
|
|
if err != nil {
|
|
b.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExtractFlags(t *testing.T) {
|
|
var debug, cmdc, cmdd bool
|
|
c := &Command{
|
|
Use: "cmdC",
|
|
Long: "Command C",
|
|
}
|
|
c.PersistentFlags().BoolVarP(&debug, "debug", "d", debug, "debug mode")
|
|
c.Flags().BoolVar(&cmdc, "cmd-c", cmdc, "Command C")
|
|
d := &Command{
|
|
Use: "CmdD",
|
|
Long: "Command D",
|
|
}
|
|
d.Flags().BoolVar(&cmdd, "cmd-d", cmdd, "Command D")
|
|
c.AddCommand(d)
|
|
|
|
resC := extractFlags(c)
|
|
resD := extractFlags(d)
|
|
|
|
if len(resC) != 2 {
|
|
t.Errorf("expected Command C to return 2 flags, got %d", len(resC))
|
|
}
|
|
if len(resD) != 2 {
|
|
t.Errorf("expected Command D to return 2 flags, got %d", len(resD))
|
|
}
|
|
}
|
|
|
|
func constructLargeCommandHeirarchy() *Command {
|
|
var config, st1, st2 string
|
|
var long, debug bool
|
|
var in1, in2 int
|
|
var verbose []bool
|
|
|
|
r := genTestCommand("mycmd", false)
|
|
r.PersistentFlags().StringVarP(&config, "config", "c", config, "config usage")
|
|
if err := r.MarkPersistentFlagFilename("config", "*"); err != nil {
|
|
panic(err)
|
|
}
|
|
s1 := genTestCommand("sub1", true)
|
|
s1.Flags().BoolVar(&long, "long", long, "long descriptin")
|
|
s1.Flags().BoolSliceVar(&verbose, "verbose", verbose, "verbose description")
|
|
s1.Flags().StringArray("option", []string{}, "various options")
|
|
s2 := genTestCommand("sub2", true)
|
|
s2.PersistentFlags().BoolVar(&debug, "debug", debug, "debug description")
|
|
s3 := genTestCommand("sub3", true)
|
|
s3.Hidden = true
|
|
s1_1 := genTestCommand("sub1sub1", true)
|
|
s1_1.Flags().StringVar(&st1, "st1", st1, "st1 description")
|
|
s1_1.Flags().StringVar(&st2, "st2", st2, "st2 description")
|
|
s1_2 := genTestCommand("sub1sub2", true)
|
|
s1_3 := genTestCommand("sub1sub3", true)
|
|
s1_3.Flags().IntVar(&in1, "int1", in1, "int1 descriptionn")
|
|
s1_3.Flags().IntVar(&in2, "int2", in2, "int2 descriptionn")
|
|
s1_3.Flags().StringArrayP("option", "O", []string{}, "more options")
|
|
s2_1 := genTestCommand("sub2sub1", true)
|
|
s2_2 := genTestCommand("sub2sub2", true)
|
|
s2_3 := genTestCommand("sub2sub3", true)
|
|
s2_4 := genTestCommand("sub2sub4", true)
|
|
s2_5 := genTestCommand("sub2sub5", true)
|
|
|
|
s1.AddCommand(s1_1, s1_2, s1_3)
|
|
s2.AddCommand(s2_1, s2_2, s2_3, s2_4, s2_5)
|
|
r.AddCommand(s1, s2, s3)
|
|
r.Execute()
|
|
return r
|
|
}
|
|
|
|
func genTestCommand(name string, withRun bool) *Command {
|
|
r := &Command{
|
|
Use: name,
|
|
Short: name + " short description",
|
|
Long: "Long description for " + name,
|
|
}
|
|
if withRun {
|
|
r.Run = emptyRun
|
|
}
|
|
|
|
return r
|
|
}
|