2017-07-30 08:42:35 +00:00
|
|
|
package cobra
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-02-24 16:53:13 +00:00
|
|
|
"regexp"
|
2018-02-25 12:12:58 +00:00
|
|
|
"strings"
|
2017-07-30 08:42:35 +00:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2018-02-24 16:53:13 +00:00
|
|
|
func TestGenZshCompletion(t *testing.T) {
|
|
|
|
var debug bool
|
|
|
|
var option string
|
|
|
|
|
2017-07-30 08:42:35 +00:00
|
|
|
tcs := []struct {
|
|
|
|
name string
|
|
|
|
root *Command
|
|
|
|
expectedExpressions []string
|
|
|
|
}{
|
|
|
|
{
|
2018-02-24 16:53:13 +00:00
|
|
|
name: "simple command",
|
|
|
|
root: func() *Command {
|
|
|
|
r := &Command{
|
|
|
|
Use: "mycommand",
|
|
|
|
Long: "My Command long description",
|
2018-02-25 06:20:34 +00:00
|
|
|
Run: emptyRun,
|
2018-02-24 16:53:13 +00:00
|
|
|
}
|
|
|
|
r.Flags().BoolVar(&debug, "debug", debug, "description")
|
|
|
|
return r
|
|
|
|
}(),
|
|
|
|
expectedExpressions: []string{
|
2018-02-25 06:20:34 +00:00
|
|
|
`(?s)function _mycommand {\s+_arguments \\\s+"--debug\[description\]".*--help.*}`,
|
2018-02-24 16:53:13 +00:00
|
|
|
"#compdef _mycommand mycommand",
|
|
|
|
},
|
2017-07-30 08:42:35 +00:00
|
|
|
},
|
|
|
|
{
|
2018-02-24 16:53:13 +00:00
|
|
|
name: "flags with both long and short flags",
|
2017-07-30 08:42:35 +00:00
|
|
|
root: func() *Command {
|
2018-02-24 16:53:13 +00:00
|
|
|
r := &Command{
|
|
|
|
Use: "testcmd",
|
|
|
|
Long: "long description",
|
2018-02-25 06:20:34 +00:00
|
|
|
Run: emptyRun,
|
2018-02-24 16:53:13 +00:00
|
|
|
}
|
|
|
|
r.Flags().BoolVarP(&debug, "debug", "d", debug, "debug description")
|
2017-07-30 08:42:35 +00:00
|
|
|
return r
|
|
|
|
}(),
|
2018-02-24 16:53:13 +00:00
|
|
|
expectedExpressions: []string{
|
|
|
|
`"\(-d --debug\)"{-d,--debug}"\[debug description\]"`,
|
|
|
|
},
|
2017-07-30 08:42:35 +00:00
|
|
|
},
|
|
|
|
{
|
2018-02-24 16:53:13 +00:00
|
|
|
name: "command with subcommands",
|
2017-07-30 08:42:35 +00:00
|
|
|
root: func() *Command {
|
2018-02-24 16:53:13 +00:00
|
|
|
r := &Command{
|
|
|
|
Use: "rootcmd",
|
|
|
|
Long: "Long rootcmd description",
|
|
|
|
}
|
|
|
|
d := &Command{
|
|
|
|
Use: "subcmd1",
|
|
|
|
Short: "Subcmd1 short descrition",
|
2018-02-25 06:20:34 +00:00
|
|
|
Run: emptyRun,
|
2018-02-24 16:53:13 +00:00
|
|
|
}
|
|
|
|
e := &Command{
|
|
|
|
Use: "subcmd2",
|
|
|
|
Long: "Subcmd2 short description",
|
2018-02-25 06:20:34 +00:00
|
|
|
Run: emptyRun,
|
2018-02-24 16:53:13 +00:00
|
|
|
}
|
|
|
|
r.PersistentFlags().BoolVar(&debug, "debug", debug, "description")
|
|
|
|
d.Flags().StringVarP(&option, "option", "o", option, "option description")
|
|
|
|
r.AddCommand(d, e)
|
2017-07-30 08:42:35 +00:00
|
|
|
return r
|
|
|
|
}(),
|
2018-02-24 16:53:13 +00:00
|
|
|
expectedExpressions: []string{
|
2018-02-25 06:20:34 +00:00
|
|
|
`\\\n\s+"1: :\(help subcmd1 subcmd2\)" \\\n`,
|
2018-02-24 16:53:13 +00:00
|
|
|
`_arguments \\\n.*"--debug\[description]"`,
|
|
|
|
`_arguments -C \\\n.*"--debug\[description]"`,
|
|
|
|
`function _rootcmd_subcmd1 {`,
|
|
|
|
`function _rootcmd_subcmd1 {`,
|
|
|
|
`_arguments \\\n.*"\(-o --option\)"{-o,--option}"\[option description]" \\\n`,
|
|
|
|
},
|
2017-07-30 08:42:35 +00:00
|
|
|
},
|
|
|
|
{
|
2018-02-24 16:53:13 +00:00
|
|
|
name: "filename completion",
|
2017-07-30 08:42:35 +00:00
|
|
|
root: func() *Command {
|
2018-02-24 16:53:13 +00:00
|
|
|
var file string
|
|
|
|
r := &Command{
|
|
|
|
Use: "mycmd",
|
|
|
|
Short: "my command short description",
|
2018-02-25 06:20:34 +00:00
|
|
|
Run: emptyRun,
|
2018-02-24 16:53:13 +00:00
|
|
|
}
|
|
|
|
r.Flags().StringVarP(&file, "config", "c", file, "config file")
|
|
|
|
r.MarkFlagFilename("config", "ext")
|
2017-07-30 08:42:35 +00:00
|
|
|
return r
|
|
|
|
}(),
|
2018-02-24 16:53:13 +00:00
|
|
|
expectedExpressions: []string{
|
|
|
|
`\n +"\(-c --config\)"{-c,--config}"\[config file]:filename:_files"`,
|
|
|
|
},
|
2017-07-30 08:42:35 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tcs {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
2018-02-25 06:20:34 +00:00
|
|
|
tc.root.Execute()
|
2017-07-30 08:42:35 +00:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
tc.root.GenZshCompletion(buf)
|
2018-02-24 16:53:13 +00:00
|
|
|
output := buf.Bytes()
|
2017-10-31 18:58:37 +00:00
|
|
|
|
2018-02-24 16:53:13 +00:00
|
|
|
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)
|
2017-07-30 08:42:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-02-25 12:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2018-02-24 16:53:13 +00:00
|
|
|
|
2018-02-25 12:12:58 +00:00
|
|
|
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)
|
|
|
|
tc.root.GenZshCompletion(buf)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-02-24 16:53:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkConstructPath(b *testing.B) {
|
|
|
|
c := &Command{
|
|
|
|
Use: "main",
|
|
|
|
Long: "main long description which is very long",
|
|
|
|
Short: "main short description",
|
|
|
|
}
|
|
|
|
d := &Command{
|
|
|
|
Use: "hello",
|
|
|
|
}
|
|
|
|
e := &Command{
|
|
|
|
Use: "world",
|
|
|
|
}
|
|
|
|
c.AddCommand(d)
|
|
|
|
d.AddCommand(e)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
res := constructPath(e)
|
|
|
|
if res != "_main_hello_world" {
|
|
|
|
b.Errorf("expeced path to be '_main_hello_world', got %s", res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
2017-07-30 08:42:35 +00:00
|
|
|
}
|