OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / spf13 / cobra / command_test.go
1 package cobra
2
3 import (
4         "bytes"
5         "fmt"
6         "os"
7         "reflect"
8         "strings"
9         "testing"
10
11         "github.com/spf13/pflag"
12 )
13
14 // test to ensure hidden commands run as intended
15 func TestHiddenCommandExecutes(t *testing.T) {
16
17         // ensure that outs does not already equal what the command will be setting it
18         // to, if it did this test would not actually be testing anything...
19         if outs == "hidden" {
20                 t.Errorf("outs should NOT EQUAL hidden")
21         }
22
23         cmdHidden.Execute()
24
25         // upon running the command, the value of outs should now be 'hidden'
26         if outs != "hidden" {
27                 t.Errorf("Hidden command failed to run!")
28         }
29 }
30
31 // test to ensure hidden commands do not show up in usage/help text
32 func TestHiddenCommandIsHidden(t *testing.T) {
33         if cmdHidden.IsAvailableCommand() {
34                 t.Errorf("Hidden command found!")
35         }
36 }
37
38 func TestStripFlags(t *testing.T) {
39         tests := []struct {
40                 input  []string
41                 output []string
42         }{
43                 {
44                         []string{"foo", "bar"},
45                         []string{"foo", "bar"},
46                 },
47                 {
48                         []string{"foo", "--bar", "-b"},
49                         []string{"foo"},
50                 },
51                 {
52                         []string{"-b", "foo", "--bar", "bar"},
53                         []string{},
54                 },
55                 {
56                         []string{"-i10", "echo"},
57                         []string{"echo"},
58                 },
59                 {
60                         []string{"-i=10", "echo"},
61                         []string{"echo"},
62                 },
63                 {
64                         []string{"--int=100", "echo"},
65                         []string{"echo"},
66                 },
67                 {
68                         []string{"-ib", "echo", "-bfoo", "baz"},
69                         []string{"echo", "baz"},
70                 },
71                 {
72                         []string{"-i=baz", "bar", "-i", "foo", "blah"},
73                         []string{"bar", "blah"},
74                 },
75                 {
76                         []string{"--int=baz", "-bbar", "-i", "foo", "blah"},
77                         []string{"blah"},
78                 },
79                 {
80                         []string{"--cat", "bar", "-i", "foo", "blah"},
81                         []string{"bar", "blah"},
82                 },
83                 {
84                         []string{"-c", "bar", "-i", "foo", "blah"},
85                         []string{"bar", "blah"},
86                 },
87                 {
88                         []string{"--persist", "bar"},
89                         []string{"bar"},
90                 },
91                 {
92                         []string{"-p", "bar"},
93                         []string{"bar"},
94                 },
95         }
96
97         cmdPrint := &Command{
98                 Use:   "print [string to print]",
99                 Short: "Print anything to the screen",
100                 Long:  `an utterly useless command for testing.`,
101                 Run: func(cmd *Command, args []string) {
102                         tp = args
103                 },
104         }
105
106         var flagi int
107         var flagstr string
108         var flagbool bool
109         cmdPrint.PersistentFlags().BoolVarP(&flagbool, "persist", "p", false, "help for persistent one")
110         cmdPrint.Flags().IntVarP(&flagi, "int", "i", 345, "help message for flag int")
111         cmdPrint.Flags().StringVarP(&flagstr, "bar", "b", "bar", "help message for flag string")
112         cmdPrint.Flags().BoolVarP(&flagbool, "cat", "c", false, "help message for flag bool")
113
114         for _, test := range tests {
115                 output := stripFlags(test.input, cmdPrint)
116                 if !reflect.DeepEqual(test.output, output) {
117                         t.Errorf("expected: %v, got: %v", test.output, output)
118                 }
119         }
120 }
121
122 func TestDisableFlagParsing(t *testing.T) {
123         targs := []string{}
124         cmdPrint := &Command{
125                 DisableFlagParsing: true,
126                 Run: func(cmd *Command, args []string) {
127                         targs = args
128                 },
129         }
130         args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
131         cmdPrint.SetArgs(args)
132         err := cmdPrint.Execute()
133         if err != nil {
134                 t.Error(err)
135         }
136         if !reflect.DeepEqual(args, targs) {
137                 t.Errorf("expected: %v, got: %v", args, targs)
138         }
139 }
140
141 func TestInitHelpFlagMergesFlags(t *testing.T) {
142         usage := "custom flag"
143         baseCmd := Command{Use: "testcmd"}
144         baseCmd.PersistentFlags().Bool("help", false, usage)
145         cmd := Command{Use: "do"}
146         baseCmd.AddCommand(&cmd)
147
148         cmd.InitDefaultHelpFlag()
149         actual := cmd.Flags().Lookup("help").Usage
150         if actual != usage {
151                 t.Fatalf("Expected the help flag from the base command with usage '%s', but got the default with usage '%s'", usage, actual)
152         }
153 }
154
155 func TestCommandsAreSorted(t *testing.T) {
156         EnableCommandSorting = true
157
158         originalNames := []string{"middle", "zlast", "afirst"}
159         expectedNames := []string{"afirst", "middle", "zlast"}
160
161         var tmpCommand = &Command{Use: "tmp"}
162
163         for _, name := range originalNames {
164                 tmpCommand.AddCommand(&Command{Use: name})
165         }
166
167         for i, c := range tmpCommand.Commands() {
168                 if expectedNames[i] != c.Name() {
169                         t.Errorf("expected: %s, got: %s", expectedNames[i], c.Name())
170                 }
171         }
172
173         EnableCommandSorting = true
174 }
175
176 func TestEnableCommandSortingIsDisabled(t *testing.T) {
177         EnableCommandSorting = false
178
179         originalNames := []string{"middle", "zlast", "afirst"}
180
181         var tmpCommand = &Command{Use: "tmp"}
182
183         for _, name := range originalNames {
184                 tmpCommand.AddCommand(&Command{Use: name})
185         }
186
187         for i, c := range tmpCommand.Commands() {
188                 if originalNames[i] != c.Name() {
189                         t.Errorf("expected: %s, got: %s", originalNames[i], c.Name())
190                 }
191         }
192
193         EnableCommandSorting = true
194 }
195
196 func TestSetOutput(t *testing.T) {
197         cmd := &Command{}
198         cmd.SetOutput(nil)
199         if out := cmd.OutOrStdout(); out != os.Stdout {
200                 t.Fatalf("expected setting output to nil to revert back to stdout, got %v", out)
201         }
202 }
203
204 func TestFlagErrorFunc(t *testing.T) {
205         cmd := &Command{
206                 Use: "print",
207                 RunE: func(cmd *Command, args []string) error {
208                         return nil
209                 },
210         }
211         expectedFmt := "This is expected: %s"
212
213         cmd.SetFlagErrorFunc(func(c *Command, err error) error {
214                 return fmt.Errorf(expectedFmt, err)
215         })
216         cmd.SetArgs([]string{"--bogus-flag"})
217         cmd.SetOutput(new(bytes.Buffer))
218
219         err := cmd.Execute()
220
221         expected := fmt.Sprintf(expectedFmt, "unknown flag: --bogus-flag")
222         if err.Error() != expected {
223                 t.Errorf("expected %v, got %v", expected, err.Error())
224         }
225 }
226
227 // TestSortedFlags checks,
228 // if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
229 // Related to https://github.com/spf13/cobra/issues/404.
230 func TestSortedFlags(t *testing.T) {
231         cmd := &Command{}
232         cmd.Flags().SortFlags = false
233         names := []string{"C", "B", "A", "D"}
234         for _, name := range names {
235                 cmd.Flags().Bool(name, false, "")
236         }
237
238         i := 0
239         cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
240                 if i == len(names) {
241                         return
242                 }
243                 if isStringInStringSlice(f.Name, names) {
244                         if names[i] != f.Name {
245                                 t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
246                         }
247                         i++
248                 }
249         })
250 }
251
252 // contains checks, if s is in ss.
253 func isStringInStringSlice(s string, ss []string) bool {
254         for _, v := range ss {
255                 if v == s {
256                         return true
257                 }
258         }
259         return false
260 }
261
262 // TestHelpFlagInHelp checks,
263 // if '--help' flag is shown in help for child (executing `parent help child`),
264 // that has no other flags.
265 // Related to https://github.com/spf13/cobra/issues/302.
266 func TestHelpFlagInHelp(t *testing.T) {
267         output := new(bytes.Buffer)
268         parent := &Command{Use: "parent", Run: func(*Command, []string) {}}
269         parent.SetOutput(output)
270
271         child := &Command{Use: "child", Run: func(*Command, []string) {}}
272         parent.AddCommand(child)
273
274         parent.SetArgs([]string{"help", "child"})
275         err := parent.Execute()
276         if err != nil {
277                 t.Fatal(err)
278         }
279
280         if !strings.Contains(output.String(), "[flags]") {
281                 t.Errorf("\nExpecting to contain: %v\nGot: %v", "[flags]", output.String())
282         }
283 }
284
285 // TestMergeCommandLineToFlags checks,
286 // if pflag.CommandLine is correctly merged to c.Flags() after first call
287 // of c.mergePersistentFlags.
288 // Related to https://github.com/spf13/cobra/issues/443.
289 func TestMergeCommandLineToFlags(t *testing.T) {
290         pflag.Bool("boolflag", false, "")
291         c := &Command{Use: "c", Run: func(*Command, []string) {}}
292         c.mergePersistentFlags()
293         if c.Flags().Lookup("boolflag") == nil {
294                 t.Fatal("Expecting to have flag from CommandLine in c.Flags()")
295         }
296
297         // Reset pflag.CommandLine flagset.
298         pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
299 }
300
301 // TestUseDeprecatedFlags checks,
302 // if cobra.Execute() prints a message, if a deprecated flag is used.
303 // Related to https://github.com/spf13/cobra/issues/463.
304 func TestUseDeprecatedFlags(t *testing.T) {
305         c := &Command{Use: "c", Run: func(*Command, []string) {}}
306         output := new(bytes.Buffer)
307         c.SetOutput(output)
308         c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
309         c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")
310
311         c.SetArgs([]string{"c", "-d"})
312         if err := c.Execute(); err != nil {
313                 t.Error("Unexpected error:", err)
314         }
315         if !strings.Contains(output.String(), "This flag is deprecated") {
316                 t.Errorf("Expected to contain deprecated message, but got %q", output.String())
317         }
318 }
319
320 // TestSetHelpCommand checks, if SetHelpCommand works correctly.
321 func TestSetHelpCommand(t *testing.T) {
322         c := &Command{Use: "c", Run: func(*Command, []string) {}}
323         output := new(bytes.Buffer)
324         c.SetOutput(output)
325         c.SetArgs([]string{"help"})
326
327         // Help will not be shown, if c has no subcommands.
328         c.AddCommand(&Command{
329                 Use: "empty",
330                 Run: func(cmd *Command, args []string) {},
331         })
332
333         correctMessage := "WORKS"
334         c.SetHelpCommand(&Command{
335                 Use:   "help [command]",
336                 Short: "Help about any command",
337                 Long: `Help provides help for any command in the application.
338         Simply type ` + c.Name() + ` help [path to command] for full details.`,
339                 Run: func(c *Command, args []string) { c.Print(correctMessage) },
340         })
341
342         if err := c.Execute(); err != nil {
343                 t.Error("Unexpected error:", err)
344         }
345
346         if output.String() != correctMessage {
347                 t.Errorf("Expected to contain %q message, but got %q", correctMessage, output.String())
348         }
349 }
350
351 func TestTraverseWithParentFlags(t *testing.T) {
352         cmd := &Command{
353                 Use:              "do",
354                 TraverseChildren: true,
355         }
356         cmd.Flags().String("foo", "", "foo things")
357         cmd.Flags().BoolP("goo", "g", false, "foo things")
358
359         sub := &Command{Use: "next"}
360         sub.Flags().String("add", "", "add things")
361         cmd.AddCommand(sub)
362
363         c, args, err := cmd.Traverse([]string{"-g", "--foo", "ok", "next", "--add"})
364         if err != nil {
365                 t.Fatalf("Expected no error: %s", err)
366         }
367         if len(args) != 1 && args[0] != "--add" {
368                 t.Fatalf("wrong args %s", args)
369         }
370         if c.Name() != sub.Name() {
371                 t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name())
372         }
373 }
374
375 func TestTraverseNoParentFlags(t *testing.T) {
376         cmd := &Command{
377                 Use:              "do",
378                 TraverseChildren: true,
379         }
380         cmd.Flags().String("foo", "", "foo things")
381
382         sub := &Command{Use: "next"}
383         sub.Flags().String("add", "", "add things")
384         cmd.AddCommand(sub)
385
386         c, args, err := cmd.Traverse([]string{"next"})
387         if err != nil {
388                 t.Fatalf("Expected no error: %s", err)
389         }
390         if len(args) != 0 {
391                 t.Fatalf("wrong args %s", args)
392         }
393         if c.Name() != sub.Name() {
394                 t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name())
395         }
396 }
397
398 func TestTraverseWithBadParentFlags(t *testing.T) {
399         cmd := &Command{
400                 Use:              "do",
401                 TraverseChildren: true,
402         }
403         sub := &Command{Use: "next"}
404         sub.Flags().String("add", "", "add things")
405         cmd.AddCommand(sub)
406
407         expected := "got unknown flag: --add"
408
409         c, _, err := cmd.Traverse([]string{"--add", "ok", "next"})
410         if err == nil || strings.Contains(err.Error(), expected) {
411                 t.Fatalf("Expected error %s got %s", expected, err)
412         }
413         if c != nil {
414                 t.Fatalf("Expected nil command")
415         }
416 }
417
418 func TestTraverseWithBadChildFlag(t *testing.T) {
419         cmd := &Command{
420                 Use:              "do",
421                 TraverseChildren: true,
422         }
423         cmd.Flags().String("foo", "", "foo things")
424
425         sub := &Command{Use: "next"}
426         cmd.AddCommand(sub)
427
428         // Expect no error because the last commands args shouldn't be parsed in
429         // Traverse
430         c, args, err := cmd.Traverse([]string{"next", "--add"})
431         if err != nil {
432                 t.Fatalf("Expected no error: %s", err)
433         }
434         if len(args) != 1 && args[0] != "--add" {
435                 t.Fatalf("wrong args %s", args)
436         }
437         if c.Name() != sub.Name() {
438                 t.Fatalf("wrong command %q expected %q", c.Name(), sub.Name())
439         }
440 }
441
442 func TestTraverseWithTwoSubcommands(t *testing.T) {
443         cmd := &Command{
444                 Use:              "do",
445                 TraverseChildren: true,
446         }
447
448         sub := &Command{
449                 Use:              "sub",
450                 TraverseChildren: true,
451         }
452         cmd.AddCommand(sub)
453
454         subsub := &Command{
455                 Use: "subsub",
456         }
457         sub.AddCommand(subsub)
458
459         c, _, err := cmd.Traverse([]string{"sub", "subsub"})
460         if err != nil {
461                 t.Fatalf("Expected no error: %s", err)
462         }
463         if c.Name() != subsub.Name() {
464                 t.Fatalf("wrong command %q expected %q", c.Name(), subsub.Name())
465         }
466 }
467
468 func TestRequiredFlags(t *testing.T) {
469         c := &Command{Use: "c", Run: func(*Command, []string) {}}
470         output := new(bytes.Buffer)
471         c.SetOutput(output)
472         c.Flags().String("foo1", "", "required foo1")
473         c.MarkFlagRequired("foo1")
474         c.Flags().String("foo2", "", "required foo2")
475         c.MarkFlagRequired("foo2")
476         c.Flags().String("bar", "", "optional bar")
477
478         expected := fmt.Sprintf("Required flag(s) %q, %q have/has not been set", "foo1", "foo2")
479
480         if err := c.Execute(); err != nil {
481                 if err.Error() != expected {
482                         t.Errorf("expected %v, got %v", expected, err.Error())
483                 }
484         }
485 }
486
487 func TestPersistentRequiredFlags(t *testing.T) {
488         parent := &Command{Use: "parent", Run: func(*Command, []string) {}}
489         output := new(bytes.Buffer)
490         parent.SetOutput(output)
491         parent.PersistentFlags().String("foo1", "", "required foo1")
492         parent.MarkPersistentFlagRequired("foo1")
493         parent.PersistentFlags().String("foo2", "", "required foo2")
494         parent.MarkPersistentFlagRequired("foo2")
495         parent.Flags().String("foo3", "", "optional foo3")
496
497         child := &Command{Use: "child", Run: func(*Command, []string) {}}
498         child.Flags().String("bar1", "", "required bar1")
499         child.MarkFlagRequired("bar1")
500         child.Flags().String("bar2", "", "required bar2")
501         child.MarkFlagRequired("bar2")
502         child.Flags().String("bar3", "", "optional bar3")
503
504         parent.AddCommand(child)
505         parent.SetArgs([]string{"child"})
506
507         expected := fmt.Sprintf("Required flag(s) %q, %q, %q, %q have/has not been set", "bar1", "bar2", "foo1", "foo2")
508
509         if err := parent.Execute(); err != nil {
510                 if err.Error() != expected {
511                         t.Errorf("expected %v, got %v", expected, err.Error())
512                 }
513         }
514 }
515
516 // TestUpdateName checks if c.Name() updates on changed c.Use.
517 // Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
518 func TestUpdateName(t *testing.T) {
519         c := &Command{Use: "name xyz"}
520         originalName := c.Name()
521
522         c.Use = "changedName abc"
523         if originalName == c.Name() || c.Name() != "changedName" {
524                 t.Error("c.Name() should be updated on changed c.Use")
525         }
526 }