1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package cobra
16
17 import (
18 "bytes"
19 "context"
20 "fmt"
21 "strings"
22 "sync"
23 "testing"
24 )
25
26 func validArgsFunc(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
27 if len(args) != 0 {
28 return nil, ShellCompDirectiveNoFileComp
29 }
30
31 var completions []string
32 for _, comp := range []string{"one\tThe first", "two\tThe second"} {
33 if strings.HasPrefix(comp, toComplete) {
34 completions = append(completions, comp)
35 }
36 }
37 return completions, ShellCompDirectiveDefault
38 }
39
40 func validArgsFunc2(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
41 if len(args) != 0 {
42 return nil, ShellCompDirectiveNoFileComp
43 }
44
45 var completions []string
46 for _, comp := range []string{"three\tThe third", "four\tThe fourth"} {
47 if strings.HasPrefix(comp, toComplete) {
48 completions = append(completions, comp)
49 }
50 }
51 return completions, ShellCompDirectiveDefault
52 }
53
54 func TestCmdNameCompletionInGo(t *testing.T) {
55 rootCmd := &Command{
56 Use: "root",
57 Run: emptyRun,
58 }
59 childCmd1 := &Command{
60 Use: "firstChild",
61 Short: "First command",
62 Run: emptyRun,
63 }
64 childCmd2 := &Command{
65 Use: "secondChild",
66 Run: emptyRun,
67 }
68 hiddenCmd := &Command{
69 Use: "testHidden",
70 Hidden: true,
71 Run: emptyRun,
72 }
73 deprecatedCmd := &Command{
74 Use: "testDeprecated",
75 Deprecated: "deprecated",
76 Run: emptyRun,
77 }
78 aliasedCmd := &Command{
79 Use: "aliased",
80 Short: "A command with aliases",
81 Aliases: []string{"testAlias", "testSynonym"},
82 Run: emptyRun,
83 }
84
85 rootCmd.AddCommand(childCmd1, childCmd2, hiddenCmd, deprecatedCmd, aliasedCmd)
86
87
88 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
89 if err != nil {
90 t.Errorf("Unexpected error: %v", err)
91 }
92
93 expected := strings.Join([]string{
94 "aliased",
95 "completion",
96 "firstChild",
97 "help",
98 "secondChild",
99 ":4",
100 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
101
102 if output != expected {
103 t.Errorf("expected: %q, got: %q", expected, output)
104 }
105
106
107 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "s")
108 if err != nil {
109 t.Errorf("Unexpected error: %v", err)
110 }
111
112 expected = strings.Join([]string{
113 "secondChild",
114 ":4",
115 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
116
117 if output != expected {
118 t.Errorf("expected: %q, got: %q", expected, output)
119 }
120
121
122
123 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "test")
124 if err != nil {
125 t.Errorf("Unexpected error: %v", err)
126 }
127
128 expected = strings.Join([]string{
129 ":4",
130 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
131
132 if output != expected {
133 t.Errorf("expected: %q, got: %q", expected, output)
134 }
135
136
137 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "")
138 if err != nil {
139 t.Errorf("Unexpected error: %v", err)
140 }
141
142 expected = strings.Join([]string{
143 "aliased\tA command with aliases",
144 "completion\tGenerate the autocompletion script for the specified shell",
145 "firstChild\tFirst command",
146 "help\tHelp about any command",
147 "secondChild",
148 ":4",
149 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
150
151 if output != expected {
152 t.Errorf("expected: %q, got: %q", expected, output)
153 }
154 }
155
156 func TestNoCmdNameCompletionInGo(t *testing.T) {
157 rootCmd := &Command{
158 Use: "root",
159 Run: emptyRun,
160 }
161 rootCmd.Flags().String("localroot", "", "local root flag")
162
163 childCmd1 := &Command{
164 Use: "childCmd1",
165 Short: "First command",
166 Args: MinimumNArgs(0),
167 Run: emptyRun,
168 }
169 rootCmd.AddCommand(childCmd1)
170 childCmd1.PersistentFlags().StringP("persistent", "p", "", "persistent flag")
171 persistentFlag := childCmd1.PersistentFlags().Lookup("persistent")
172 childCmd1.Flags().StringP("nonPersistent", "n", "", "non-persistent flag")
173 nonPersistentFlag := childCmd1.Flags().Lookup("nonPersistent")
174
175 childCmd2 := &Command{
176 Use: "childCmd2",
177 Run: emptyRun,
178 }
179 childCmd1.AddCommand(childCmd2)
180
181
182 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "arg1", "")
183 if err != nil {
184 t.Errorf("Unexpected error: %v", err)
185 }
186
187 expected := strings.Join([]string{
188 ":0",
189 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
190
191 if output != expected {
192 t.Errorf("expected: %q, got: %q", expected, output)
193 }
194
195
196 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--nonPersistent", "value", "")
197 if err != nil {
198 t.Errorf("Unexpected error: %v", err)
199 }
200
201 nonPersistentFlag.Changed = false
202
203 expected = strings.Join([]string{
204 ":0",
205 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
206
207 if output != expected {
208 t.Errorf("expected: %q, got: %q", expected, output)
209 }
210
211
212
213 rootCmd.TraverseChildren = true
214
215 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "")
216 if err != nil {
217 t.Errorf("Unexpected error: %v", err)
218 }
219
220 rootCmd.TraverseChildren = false
221
222 expected = strings.Join([]string{
223 "childCmd1",
224 "completion",
225 "help",
226 ":4",
227 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
228
229 if output != expected {
230 t.Errorf("expected: %q, got: %q", expected, output)
231 }
232
233
234
235 rootCmd.TraverseChildren = true
236
237 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "--nonPersistent", "value", "")
238 if err != nil {
239 t.Errorf("Unexpected error: %v", err)
240 }
241
242 rootCmd.TraverseChildren = false
243
244 nonPersistentFlag.Changed = false
245
246 expected = strings.Join([]string{
247 "childCmd2",
248 ":4",
249 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
250
251 if output != expected {
252 t.Errorf("expected: %q, got: %q", expected, output)
253 }
254
255
256
257 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "")
258 if err != nil {
259 t.Errorf("Unexpected error: %v", err)
260 }
261
262 expected = strings.Join([]string{
263 ":0",
264 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
265
266 if output != expected {
267 t.Errorf("expected: %q, got: %q", expected, output)
268 }
269
270
271 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-n", "value", "")
272 if err != nil {
273 t.Errorf("Unexpected error: %v", err)
274 }
275
276 nonPersistentFlag.Changed = false
277
278 expected = strings.Join([]string{
279 ":0",
280 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
281
282 if output != expected {
283 t.Errorf("expected: %q, got: %q", expected, output)
284 }
285
286
287 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--persistent", "value", "")
288 if err != nil {
289 t.Errorf("Unexpected error: %v", err)
290 }
291
292 persistentFlag.Changed = false
293
294 expected = strings.Join([]string{
295 "childCmd2",
296 ":4",
297 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
298
299 if output != expected {
300 t.Errorf("expected: %q, got: %q", expected, output)
301 }
302
303
304 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-p", "value", "")
305 if err != nil {
306 t.Errorf("Unexpected error: %v", err)
307 }
308
309 persistentFlag.Changed = false
310
311 expected = strings.Join([]string{
312 "childCmd2",
313 ":4",
314 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
315
316 if output != expected {
317 t.Errorf("expected: %q, got: %q", expected, output)
318 }
319 }
320
321 func TestValidArgsCompletionInGo(t *testing.T) {
322 rootCmd := &Command{
323 Use: "root",
324 ValidArgs: []string{"one", "two", "three"},
325 Args: MinimumNArgs(1),
326 }
327
328
329 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
330 if err != nil {
331 t.Errorf("Unexpected error: %v", err)
332 }
333
334 expected := strings.Join([]string{
335 "one",
336 "two",
337 "three",
338 ":4",
339 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
340
341 if output != expected {
342 t.Errorf("expected: %q, got: %q", expected, output)
343 }
344
345
346 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "o")
347 if err != nil {
348 t.Errorf("Unexpected error: %v", err)
349 }
350
351 expected = strings.Join([]string{
352 "one",
353 ":4",
354 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
355
356 if output != expected {
357 t.Errorf("expected: %q, got: %q", expected, output)
358 }
359
360
361 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "one", "")
362 if err != nil {
363 t.Errorf("Unexpected error: %v", err)
364 }
365
366 expected = strings.Join([]string{
367 ":0",
368 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
369
370 if output != expected {
371 t.Errorf("expected: %q, got: %q", expected, output)
372 }
373 }
374
375 func TestValidArgsAndCmdCompletionInGo(t *testing.T) {
376 rootCmd := &Command{
377 Use: "root",
378 ValidArgs: []string{"one", "two"},
379 Run: emptyRun,
380 }
381
382 childCmd := &Command{
383 Use: "thechild",
384 Run: emptyRun,
385 }
386
387 rootCmd.AddCommand(childCmd)
388
389
390 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
391 if err != nil {
392 t.Errorf("Unexpected error: %v", err)
393 }
394
395 expected := strings.Join([]string{
396 "completion",
397 "help",
398 "thechild",
399 "one",
400 "two",
401 ":4",
402 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
403
404 if output != expected {
405 t.Errorf("expected: %q, got: %q", expected, output)
406 }
407
408
409 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
410 if err != nil {
411 t.Errorf("Unexpected error: %v", err)
412 }
413
414 expected = strings.Join([]string{
415 "thechild",
416 "two",
417 ":4",
418 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
419
420 if output != expected {
421 t.Errorf("expected: %q, got: %q", expected, output)
422 }
423 }
424
425 func TestValidArgsFuncAndCmdCompletionInGo(t *testing.T) {
426 rootCmd := &Command{
427 Use: "root",
428 ValidArgsFunction: validArgsFunc,
429 Run: emptyRun,
430 }
431
432 childCmd := &Command{
433 Use: "thechild",
434 Short: "The child command",
435 Run: emptyRun,
436 }
437
438 rootCmd.AddCommand(childCmd)
439
440
441 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
442 if err != nil {
443 t.Errorf("Unexpected error: %v", err)
444 }
445
446 expected := strings.Join([]string{
447 "completion",
448 "help",
449 "thechild",
450 "one",
451 "two",
452 ":0",
453 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
454
455 if output != expected {
456 t.Errorf("expected: %q, got: %q", expected, output)
457 }
458
459
460 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
461 if err != nil {
462 t.Errorf("Unexpected error: %v", err)
463 }
464
465 expected = strings.Join([]string{
466 "thechild",
467 "two",
468 ":0",
469 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
470
471 if output != expected {
472 t.Errorf("expected: %q, got: %q", expected, output)
473 }
474
475
476 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "t")
477 if err != nil {
478 t.Errorf("Unexpected error: %v", err)
479 }
480
481 expected = strings.Join([]string{
482 "thechild\tThe child command",
483 "two\tThe second",
484 ":0",
485 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
486
487 if output != expected {
488 t.Errorf("expected: %q, got: %q", expected, output)
489 }
490 }
491
492 func TestFlagNameCompletionInGo(t *testing.T) {
493 rootCmd := &Command{
494 Use: "root",
495 Run: emptyRun,
496 }
497 childCmd := &Command{
498 Use: "childCmd",
499 Version: "1.2.3",
500 Run: emptyRun,
501 }
502 rootCmd.AddCommand(childCmd)
503
504 rootCmd.Flags().IntP("first", "f", -1, "first flag")
505 rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag")
506 childCmd.Flags().String("subFlag", "", "sub flag")
507
508
509 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
510 if err != nil {
511 t.Errorf("Unexpected error: %v", err)
512 }
513
514 expected := strings.Join([]string{
515 "childCmd",
516 "completion",
517 "help",
518 ":4",
519 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
520
521 if output != expected {
522 t.Errorf("expected: %q, got: %q", expected, output)
523 }
524
525
526 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-")
527 if err != nil {
528 t.Errorf("Unexpected error: %v", err)
529 }
530
531 expected = strings.Join([]string{
532 "--first",
533 "-f",
534 "--help",
535 "-h",
536 "--second",
537 "-s",
538 ":4",
539 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
540
541 if output != expected {
542 t.Errorf("expected: %q, got: %q", expected, output)
543 }
544
545
546 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--f")
547 if err != nil {
548 t.Errorf("Unexpected error: %v", err)
549 }
550
551 expected = strings.Join([]string{
552 "--first",
553 ":4",
554 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
555
556 if output != expected {
557 t.Errorf("expected: %q, got: %q", expected, output)
558 }
559
560
561 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-")
562 if err != nil {
563 t.Errorf("Unexpected error: %v", err)
564 }
565
566 expected = strings.Join([]string{
567 "--second",
568 "-s",
569 "--help",
570 "-h",
571 "--subFlag",
572 "--version",
573 "-v",
574 ":4",
575 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
576
577 if output != expected {
578 t.Errorf("expected: %q, got: %q", expected, output)
579 }
580 }
581
582 func TestFlagNameCompletionInGoWithDesc(t *testing.T) {
583 rootCmd := &Command{
584 Use: "root",
585 Run: emptyRun,
586 }
587 childCmd := &Command{
588 Use: "childCmd",
589 Short: "first command",
590 Version: "1.2.3",
591 Run: emptyRun,
592 }
593 rootCmd.AddCommand(childCmd)
594
595 rootCmd.Flags().IntP("first", "f", -1, "first flag\nlonger description for flag")
596 rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag")
597 childCmd.Flags().String("subFlag", "", "sub flag")
598
599
600 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "")
601 if err != nil {
602 t.Errorf("Unexpected error: %v", err)
603 }
604
605 expected := strings.Join([]string{
606 "childCmd\tfirst command",
607 "completion\tGenerate the autocompletion script for the specified shell",
608 "help\tHelp about any command",
609 ":4",
610 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
611
612 if output != expected {
613 t.Errorf("expected: %q, got: %q", expected, output)
614 }
615
616
617 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "-")
618 if err != nil {
619 t.Errorf("Unexpected error: %v", err)
620 }
621
622 expected = strings.Join([]string{
623 "--first\tfirst flag",
624 "-f\tfirst flag",
625 "--help\thelp for root",
626 "-h\thelp for root",
627 "--second\tsecond flag",
628 "-s\tsecond flag",
629 ":4",
630 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
631
632 if output != expected {
633 t.Errorf("expected: %q, got: %q", expected, output)
634 }
635
636
637 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--f")
638 if err != nil {
639 t.Errorf("Unexpected error: %v", err)
640 }
641
642 expected = strings.Join([]string{
643 "--first\tfirst flag",
644 ":4",
645 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
646
647 if output != expected {
648 t.Errorf("expected: %q, got: %q", expected, output)
649 }
650
651
652 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "childCmd", "-")
653 if err != nil {
654 t.Errorf("Unexpected error: %v", err)
655 }
656
657 expected = strings.Join([]string{
658 "--second\tsecond flag",
659 "-s\tsecond flag",
660 "--help\thelp for childCmd",
661 "-h\thelp for childCmd",
662 "--subFlag\tsub flag",
663 "--version\tversion for childCmd",
664 "-v\tversion for childCmd",
665 ":4",
666 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
667
668 if output != expected {
669 t.Errorf("expected: %q, got: %q", expected, output)
670 }
671 }
672
673 func TestFlagNameCompletionRepeat(t *testing.T) {
674 rootCmd := &Command{
675 Use: "root",
676 Run: emptyRun,
677 }
678 childCmd := &Command{
679 Use: "childCmd",
680 Short: "first command",
681 Run: emptyRun,
682 }
683 rootCmd.AddCommand(childCmd)
684
685 rootCmd.Flags().IntP("first", "f", -1, "first flag")
686 firstFlag := rootCmd.Flags().Lookup("first")
687 rootCmd.Flags().BoolP("second", "s", false, "second flag")
688 secondFlag := rootCmd.Flags().Lookup("second")
689 rootCmd.Flags().StringArrayP("array", "a", nil, "array flag")
690 arrayFlag := rootCmd.Flags().Lookup("array")
691 rootCmd.Flags().IntSliceP("slice", "l", nil, "slice flag")
692 sliceFlag := rootCmd.Flags().Lookup("slice")
693 rootCmd.Flags().BoolSliceP("bslice", "b", nil, "bool slice flag")
694 bsliceFlag := rootCmd.Flags().Lookup("bslice")
695
696
697 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--")
698 if err != nil {
699 t.Errorf("Unexpected error: %v", err)
700 }
701
702 firstFlag.Changed = false
703
704 expected := strings.Join([]string{
705 "--array",
706 "--bslice",
707 "--help",
708 "--second",
709 "--slice",
710 ":4",
711 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
712
713 if output != expected {
714 t.Errorf("expected: %q, got: %q", expected, output)
715 }
716
717
718 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--second=false", "--")
719 if err != nil {
720 t.Errorf("Unexpected error: %v", err)
721 }
722
723 firstFlag.Changed = false
724 secondFlag.Changed = false
725
726 expected = strings.Join([]string{
727 "--array",
728 "--bslice",
729 "--help",
730 "--slice",
731 ":4",
732 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
733
734 if output != expected {
735 t.Errorf("expected: %q, got: %q", expected, output)
736 }
737
738
739 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--slice", "1", "--slice=2", "--array", "val", "--bslice", "true", "--")
740 if err != nil {
741 t.Errorf("Unexpected error: %v", err)
742 }
743
744 sliceFlag.Changed = false
745 arrayFlag.Changed = false
746 bsliceFlag.Changed = false
747
748 expected = strings.Join([]string{
749 "--array",
750 "--bslice",
751 "--first",
752 "--help",
753 "--second",
754 "--slice",
755 ":4",
756 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
757
758 if output != expected {
759 t.Errorf("expected: %q, got: %q", expected, output)
760 }
761
762
763 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-")
764 if err != nil {
765 t.Errorf("Unexpected error: %v", err)
766 }
767
768 sliceFlag.Changed = false
769 arrayFlag.Changed = false
770
771 expected = strings.Join([]string{
772 "--array",
773 "-a",
774 "--bslice",
775 "-b",
776 "--first",
777 "-f",
778 "--help",
779 "-h",
780 "--second",
781 "-s",
782 "--slice",
783 "-l",
784 ":4",
785 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
786
787 if output != expected {
788 t.Errorf("expected: %q, got: %q", expected, output)
789 }
790
791
792 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-a")
793 if err != nil {
794 t.Errorf("Unexpected error: %v", err)
795 }
796
797 sliceFlag.Changed = false
798 arrayFlag.Changed = false
799
800 expected = strings.Join([]string{
801 "-a",
802 ":4",
803 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
804
805 if output != expected {
806 t.Errorf("expected: %q, got: %q", expected, output)
807 }
808 }
809
810 func TestRequiredFlagNameCompletionInGo(t *testing.T) {
811 rootCmd := &Command{
812 Use: "root",
813 ValidArgs: []string{"realArg"},
814 Run: emptyRun,
815 }
816 childCmd := &Command{
817 Use: "childCmd",
818 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
819 return []string{"subArg"}, ShellCompDirectiveNoFileComp
820 },
821 Run: emptyRun,
822 }
823 rootCmd.AddCommand(childCmd)
824
825 rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag")
826 assertNoErr(t, rootCmd.MarkFlagRequired("requiredFlag"))
827 requiredFlag := rootCmd.Flags().Lookup("requiredFlag")
828
829 rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent")
830 assertNoErr(t, rootCmd.MarkPersistentFlagRequired("requiredPersistent"))
831 requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent")
832
833 rootCmd.Flags().StringP("release", "R", "", "Release name")
834
835 childCmd.Flags().BoolP("subRequired", "s", false, "sub required flag")
836 assertNoErr(t, childCmd.MarkFlagRequired("subRequired"))
837 childCmd.Flags().BoolP("subNotRequired", "n", false, "sub not required flag")
838
839
840 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
841 if err != nil {
842 t.Errorf("Unexpected error: %v", err)
843 }
844
845 expected := strings.Join([]string{
846 "childCmd",
847 "completion",
848 "help",
849 "--requiredFlag",
850 "-r",
851 "--requiredPersistent",
852 "-p",
853 "realArg",
854 ":4",
855 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
856
857 if output != expected {
858 t.Errorf("expected: %q, got: %q", expected, output)
859 }
860
861
862 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-")
863 if err != nil {
864 t.Errorf("Unexpected error: %v", err)
865 }
866
867 expected = strings.Join([]string{
868 "--requiredFlag",
869 "-r",
870 "--requiredPersistent",
871 "-p",
872 ":4",
873 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
874
875 if output != expected {
876 t.Errorf("expected: %q, got: %q", expected, output)
877 }
878
879
880 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--relea")
881 if err != nil {
882 t.Errorf("Unexpected error: %v", err)
883 }
884
885 expected = strings.Join([]string{
886 "--release",
887 ":4",
888 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
889
890 if output != expected {
891 t.Errorf("expected: %q, got: %q", expected, output)
892 }
893
894
895 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "")
896 if err != nil {
897 t.Errorf("Unexpected error: %v", err)
898 }
899
900 expected = strings.Join([]string{
901 "--requiredPersistent",
902 "-p",
903 "--subRequired",
904 "-s",
905 "subArg",
906 ":4",
907 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
908
909 if output != expected {
910 t.Errorf("expected: %q, got: %q", expected, output)
911 }
912
913 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-")
914 if err != nil {
915 t.Errorf("Unexpected error: %v", err)
916 }
917
918 expected = strings.Join([]string{
919 "--requiredPersistent",
920 "-p",
921 "--subRequired",
922 "-s",
923 ":4",
924 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
925
926 if output != expected {
927 t.Errorf("expected: %q, got: %q", expected, output)
928 }
929
930 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "--subNot")
931 if err != nil {
932 t.Errorf("Unexpected error: %v", err)
933 }
934
935 expected = strings.Join([]string{
936 "--subNotRequired",
937 ":4",
938 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
939
940 if output != expected {
941 t.Errorf("expected: %q, got: %q", expected, output)
942 }
943
944
945 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "")
946 if err != nil {
947 t.Errorf("Unexpected error: %v", err)
948 }
949
950 requiredFlag.Changed = false
951
952 expected = strings.Join([]string{
953 "--requiredPersistent",
954 "-p",
955 "realArg",
956 ":4",
957 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
958
959 if output != expected {
960 t.Errorf("expected: %q, got: %q", expected, output)
961 }
962
963
964 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredPersistent", "1", "")
965 if err != nil {
966 t.Errorf("Unexpected error: %v", err)
967 }
968
969 requiredPersistent.Changed = false
970
971 expected = strings.Join([]string{
972 "childCmd",
973 "completion",
974 "help",
975 "--requiredFlag",
976 "-r",
977 "realArg",
978 ":4",
979 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
980
981 if output != expected {
982 t.Errorf("expected: %q, got: %q", expected, output)
983 }
984
985
986 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "--requiredPersistent", "1", "")
987 if err != nil {
988 t.Errorf("Unexpected error: %v", err)
989 }
990
991 requiredFlag.Changed = false
992 requiredPersistent.Changed = false
993
994 expected = strings.Join([]string{
995 "realArg",
996 ":4",
997 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
998
999 if output != expected {
1000 t.Errorf("expected: %q, got: %q", expected, output)
1001 }
1002 }
1003
1004 func TestFlagFileExtFilterCompletionInGo(t *testing.T) {
1005 rootCmd := &Command{
1006 Use: "root",
1007 Run: emptyRun,
1008 }
1009
1010
1011 rootCmd.Flags().StringP("file", "f", "", "file flag")
1012 assertNoErr(t, rootCmd.MarkFlagFilename("file"))
1013
1014
1015 rootCmd.Flags().StringP("log", "l", "", "log flag")
1016 assertNoErr(t, rootCmd.MarkFlagFilename("log", "log"))
1017
1018
1019 rootCmd.Flags().StringP("yaml", "y", "", "yaml flag")
1020 assertNoErr(t, rootCmd.MarkFlagFilename("yaml", "yaml", "yml"))
1021
1022
1023 rootCmd.Flags().StringP("text", "t", "", "text flag")
1024 assertNoErr(t, rootCmd.Flags().SetAnnotation("text", BashCompFilenameExt, []string{"txt"}))
1025
1026
1027
1028 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--file", "")
1029 if err != nil {
1030 t.Errorf("Unexpected error: %v", err)
1031 }
1032
1033 expected := strings.Join([]string{
1034 ":0",
1035 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1036
1037 if output != expected {
1038 t.Errorf("expected: %q, got: %q", expected, output)
1039 }
1040
1041 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--log", "")
1042 if err != nil {
1043 t.Errorf("Unexpected error: %v", err)
1044 }
1045
1046 expected = strings.Join([]string{
1047 "log",
1048 ":8",
1049 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
1050
1051 if output != expected {
1052 t.Errorf("expected: %q, got: %q", expected, output)
1053 }
1054
1055 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml", "")
1056 if err != nil {
1057 t.Errorf("Unexpected error: %v", err)
1058 }
1059
1060 expected = strings.Join([]string{
1061 "yaml", "yml",
1062 ":8",
1063 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
1064
1065 if output != expected {
1066 t.Errorf("expected: %q, got: %q", expected, output)
1067 }
1068
1069 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml=")
1070 if err != nil {
1071 t.Errorf("Unexpected error: %v", err)
1072 }
1073
1074 expected = strings.Join([]string{
1075 "yaml", "yml",
1076 ":8",
1077 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
1078
1079 if output != expected {
1080 t.Errorf("expected: %q, got: %q", expected, output)
1081 }
1082
1083 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y", "")
1084 if err != nil {
1085 t.Errorf("Unexpected error: %v", err)
1086 }
1087
1088 expected = strings.Join([]string{
1089 "yaml", "yml",
1090 ":8",
1091 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
1092
1093 if output != expected {
1094 t.Errorf("expected: %q, got: %q", expected, output)
1095 }
1096
1097 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y=")
1098 if err != nil {
1099 t.Errorf("Unexpected error: %v", err)
1100 }
1101
1102 expected = strings.Join([]string{
1103 "yaml", "yml",
1104 ":8",
1105 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
1106
1107 if output != expected {
1108 t.Errorf("expected: %q, got: %q", expected, output)
1109 }
1110
1111 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--text", "")
1112 if err != nil {
1113 t.Errorf("Unexpected error: %v", err)
1114 }
1115
1116 expected = strings.Join([]string{
1117 "txt",
1118 ":8",
1119 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n")
1120
1121 if output != expected {
1122 t.Errorf("expected: %q, got: %q", expected, output)
1123 }
1124 }
1125
1126 func TestFlagDirFilterCompletionInGo(t *testing.T) {
1127 rootCmd := &Command{
1128 Use: "root",
1129 Run: emptyRun,
1130 }
1131
1132
1133 rootCmd.Flags().StringP("dir", "d", "", "dir flag")
1134 assertNoErr(t, rootCmd.MarkFlagDirname("dir"))
1135
1136
1137 rootCmd.Flags().StringP("subdir", "s", "", "subdir")
1138 assertNoErr(t, rootCmd.Flags().SetAnnotation("subdir", BashCompSubdirsInDir, []string{"themes"}))
1139
1140
1141 rootCmd.Flags().StringP("manydir", "m", "", "manydir")
1142 assertNoErr(t, rootCmd.Flags().SetAnnotation("manydir", BashCompSubdirsInDir, []string{"themes", "colors"}))
1143
1144
1145
1146 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--dir", "")
1147 if err != nil {
1148 t.Errorf("Unexpected error: %v", err)
1149 }
1150
1151 expected := strings.Join([]string{
1152 ":16",
1153 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1154
1155 if output != expected {
1156 t.Errorf("expected: %q, got: %q", expected, output)
1157 }
1158
1159 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-d", "")
1160 if err != nil {
1161 t.Errorf("Unexpected error: %v", err)
1162 }
1163
1164 expected = strings.Join([]string{
1165 ":16",
1166 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1167
1168 if output != expected {
1169 t.Errorf("expected: %q, got: %q", expected, output)
1170 }
1171
1172 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir", "")
1173 if err != nil {
1174 t.Errorf("Unexpected error: %v", err)
1175 }
1176
1177 expected = strings.Join([]string{
1178 "themes",
1179 ":16",
1180 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1181
1182 if output != expected {
1183 t.Errorf("expected: %q, got: %q", expected, output)
1184 }
1185
1186 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir=")
1187 if err != nil {
1188 t.Errorf("Unexpected error: %v", err)
1189 }
1190
1191 expected = strings.Join([]string{
1192 "themes",
1193 ":16",
1194 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1195
1196 if output != expected {
1197 t.Errorf("expected: %q, got: %q", expected, output)
1198 }
1199
1200 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "")
1201 if err != nil {
1202 t.Errorf("Unexpected error: %v", err)
1203 }
1204
1205 expected = strings.Join([]string{
1206 "themes",
1207 ":16",
1208 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1209
1210 if output != expected {
1211 t.Errorf("expected: %q, got: %q", expected, output)
1212 }
1213
1214 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s=")
1215 if err != nil {
1216 t.Errorf("Unexpected error: %v", err)
1217 }
1218
1219 expected = strings.Join([]string{
1220 "themes",
1221 ":16",
1222 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1223
1224 if output != expected {
1225 t.Errorf("expected: %q, got: %q", expected, output)
1226 }
1227
1228 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--manydir", "")
1229 if err != nil {
1230 t.Errorf("Unexpected error: %v", err)
1231 }
1232
1233 expected = strings.Join([]string{
1234 ":16",
1235 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n")
1236
1237 if output != expected {
1238 t.Errorf("expected: %q, got: %q", expected, output)
1239 }
1240 }
1241
1242 func TestValidArgsFuncCmdContext(t *testing.T) {
1243 validArgsFunc := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1244 ctx := cmd.Context()
1245
1246 if ctx == nil {
1247 t.Error("Received nil context in completion func")
1248 } else if ctx.Value("testKey") != "123" {
1249 t.Error("Received invalid context")
1250 }
1251
1252 return nil, ShellCompDirectiveDefault
1253 }
1254
1255 rootCmd := &Command{
1256 Use: "root",
1257 Run: emptyRun,
1258 }
1259 childCmd := &Command{
1260 Use: "childCmd",
1261 ValidArgsFunction: validArgsFunc,
1262 Run: emptyRun,
1263 }
1264 rootCmd.AddCommand(childCmd)
1265
1266
1267 ctx := context.WithValue(context.Background(), "testKey", "123")
1268
1269
1270 _, output, err := executeCommandWithContextC(ctx, rootCmd, ShellCompNoDescRequestCmd, "childCmd", "")
1271 if err != nil {
1272 t.Errorf("Unexpected error: %v", err)
1273 }
1274
1275 expected := strings.Join([]string{
1276 ":0",
1277 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1278
1279 if output != expected {
1280 t.Errorf("expected: %q, got: %q", expected, output)
1281 }
1282 }
1283
1284 func TestValidArgsFuncSingleCmd(t *testing.T) {
1285 rootCmd := &Command{
1286 Use: "root",
1287 ValidArgsFunction: validArgsFunc,
1288 Run: emptyRun,
1289 }
1290
1291
1292 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
1293 if err != nil {
1294 t.Errorf("Unexpected error: %v", err)
1295 }
1296
1297 expected := strings.Join([]string{
1298 "one",
1299 "two",
1300 ":0",
1301 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1302
1303 if output != expected {
1304 t.Errorf("expected: %q, got: %q", expected, output)
1305 }
1306
1307
1308 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
1309 if err != nil {
1310 t.Errorf("Unexpected error: %v", err)
1311 }
1312
1313 expected = strings.Join([]string{
1314 "two",
1315 ":0",
1316 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1317
1318 if output != expected {
1319 t.Errorf("expected: %q, got: %q", expected, output)
1320 }
1321 }
1322
1323 func TestValidArgsFuncSingleCmdInvalidArg(t *testing.T) {
1324 rootCmd := &Command{
1325 Use: "root",
1326
1327
1328
1329
1330 Args: MinimumNArgs(1),
1331 ValidArgsFunction: validArgsFunc,
1332 Run: emptyRun,
1333 }
1334
1335
1336 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "unexpectedArg", "t")
1337 if err != nil {
1338 t.Errorf("Unexpected error: %v", err)
1339 }
1340
1341 expected := strings.Join([]string{
1342 ":4",
1343 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1344
1345 if output != expected {
1346 t.Errorf("expected: %q, got: %q", expected, output)
1347 }
1348 }
1349
1350 func TestValidArgsFuncChildCmds(t *testing.T) {
1351 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1352 child1Cmd := &Command{
1353 Use: "child1",
1354 ValidArgsFunction: validArgsFunc,
1355 Run: emptyRun,
1356 }
1357 child2Cmd := &Command{
1358 Use: "child2",
1359 ValidArgsFunction: validArgsFunc2,
1360 Run: emptyRun,
1361 }
1362 rootCmd.AddCommand(child1Cmd, child2Cmd)
1363
1364
1365 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "")
1366 if err != nil {
1367 t.Errorf("Unexpected error: %v", err)
1368 }
1369
1370 expected := strings.Join([]string{
1371 "one",
1372 "two",
1373 ":0",
1374 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1375
1376 if output != expected {
1377 t.Errorf("expected: %q, got: %q", expected, output)
1378 }
1379
1380
1381 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "t")
1382 if err != nil {
1383 t.Errorf("Unexpected error: %v", err)
1384 }
1385
1386 expected = strings.Join([]string{
1387 "two",
1388 ":0",
1389 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1390
1391 if output != expected {
1392 t.Errorf("expected: %q, got: %q", expected, output)
1393 }
1394
1395
1396 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "unexpectedArg", "t")
1397 if err != nil {
1398 t.Errorf("Unexpected error: %v", err)
1399 }
1400
1401 expected = strings.Join([]string{
1402 ":4",
1403 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1404
1405 if output != expected {
1406 t.Errorf("expected: %q, got: %q", expected, output)
1407 }
1408
1409
1410 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "")
1411 if err != nil {
1412 t.Errorf("Unexpected error: %v", err)
1413 }
1414
1415 expected = strings.Join([]string{
1416 "three",
1417 "four",
1418 ":0",
1419 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1420
1421 if output != expected {
1422 t.Errorf("expected: %q, got: %q", expected, output)
1423 }
1424
1425 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "t")
1426 if err != nil {
1427 t.Errorf("Unexpected error: %v", err)
1428 }
1429
1430 expected = strings.Join([]string{
1431 "three",
1432 ":0",
1433 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1434
1435 if output != expected {
1436 t.Errorf("expected: %q, got: %q", expected, output)
1437 }
1438
1439
1440 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "unexpectedArg", "t")
1441 if err != nil {
1442 t.Errorf("Unexpected error: %v", err)
1443 }
1444
1445 expected = strings.Join([]string{
1446 ":4",
1447 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1448
1449 if output != expected {
1450 t.Errorf("expected: %q, got: %q", expected, output)
1451 }
1452 }
1453
1454 func TestValidArgsFuncAliases(t *testing.T) {
1455 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1456 child := &Command{
1457 Use: "child",
1458 Aliases: []string{"son", "daughter"},
1459 ValidArgsFunction: validArgsFunc,
1460 Run: emptyRun,
1461 }
1462 rootCmd.AddCommand(child)
1463
1464
1465 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "")
1466 if err != nil {
1467 t.Errorf("Unexpected error: %v", err)
1468 }
1469
1470 expected := strings.Join([]string{
1471 "one",
1472 "two",
1473 ":0",
1474 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1475
1476 if output != expected {
1477 t.Errorf("expected: %q, got: %q", expected, output)
1478 }
1479
1480
1481 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "daughter", "t")
1482 if err != nil {
1483 t.Errorf("Unexpected error: %v", err)
1484 }
1485
1486 expected = strings.Join([]string{
1487 "two",
1488 ":0",
1489 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1490
1491 if output != expected {
1492 t.Errorf("expected: %q, got: %q", expected, output)
1493 }
1494
1495
1496 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "unexpectedArg", "t")
1497 if err != nil {
1498 t.Errorf("Unexpected error: %v", err)
1499 }
1500
1501 expected = strings.Join([]string{
1502 ":4",
1503 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1504
1505 if output != expected {
1506 t.Errorf("expected: %q, got: %q", expected, output)
1507 }
1508 }
1509
1510 func TestValidArgsFuncInBashScript(t *testing.T) {
1511 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1512 child := &Command{
1513 Use: "child",
1514 ValidArgsFunction: validArgsFunc,
1515 Run: emptyRun,
1516 }
1517 rootCmd.AddCommand(child)
1518
1519 buf := new(bytes.Buffer)
1520 assertNoErr(t, rootCmd.GenBashCompletion(buf))
1521 output := buf.String()
1522
1523 check(t, output, "has_completion_function=1")
1524 }
1525
1526 func TestNoValidArgsFuncInBashScript(t *testing.T) {
1527 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1528 child := &Command{
1529 Use: "child",
1530 Run: emptyRun,
1531 }
1532 rootCmd.AddCommand(child)
1533
1534 buf := new(bytes.Buffer)
1535 assertNoErr(t, rootCmd.GenBashCompletion(buf))
1536 output := buf.String()
1537
1538 checkOmit(t, output, "has_completion_function=1")
1539 }
1540
1541 func TestCompleteCmdInBashScript(t *testing.T) {
1542 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1543 child := &Command{
1544 Use: "child",
1545 ValidArgsFunction: validArgsFunc,
1546 Run: emptyRun,
1547 }
1548 rootCmd.AddCommand(child)
1549
1550 buf := new(bytes.Buffer)
1551 assertNoErr(t, rootCmd.GenBashCompletion(buf))
1552 output := buf.String()
1553
1554 check(t, output, ShellCompNoDescRequestCmd)
1555 }
1556
1557 func TestCompleteNoDesCmdInZshScript(t *testing.T) {
1558 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1559 child := &Command{
1560 Use: "child",
1561 ValidArgsFunction: validArgsFunc,
1562 Run: emptyRun,
1563 }
1564 rootCmd.AddCommand(child)
1565
1566 buf := new(bytes.Buffer)
1567 assertNoErr(t, rootCmd.GenZshCompletionNoDesc(buf))
1568 output := buf.String()
1569
1570 check(t, output, ShellCompNoDescRequestCmd)
1571 }
1572
1573 func TestCompleteCmdInZshScript(t *testing.T) {
1574 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1575 child := &Command{
1576 Use: "child",
1577 ValidArgsFunction: validArgsFunc,
1578 Run: emptyRun,
1579 }
1580 rootCmd.AddCommand(child)
1581
1582 buf := new(bytes.Buffer)
1583 assertNoErr(t, rootCmd.GenZshCompletion(buf))
1584 output := buf.String()
1585
1586 check(t, output, ShellCompRequestCmd)
1587 checkOmit(t, output, ShellCompNoDescRequestCmd)
1588 }
1589
1590 func TestFlagCompletionInGo(t *testing.T) {
1591 rootCmd := &Command{
1592 Use: "root",
1593 Run: emptyRun,
1594 }
1595 rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
1596 assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1597 completions := []string{}
1598 for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
1599 if strings.HasPrefix(comp, toComplete) {
1600 completions = append(completions, comp)
1601 }
1602 }
1603 return completions, ShellCompDirectiveDefault
1604 }))
1605 rootCmd.Flags().String("filename", "", "Enter a filename")
1606 assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1607 completions := []string{}
1608 for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
1609 if strings.HasPrefix(comp, toComplete) {
1610 completions = append(completions, comp)
1611 }
1612 }
1613 return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
1614 }))
1615
1616
1617 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "")
1618 if err != nil {
1619 t.Errorf("Unexpected error: %v", err)
1620 }
1621
1622 expected := strings.Join([]string{
1623 "1",
1624 "2",
1625 "10",
1626 ":0",
1627 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1628
1629 if output != expected {
1630 t.Errorf("expected: %q, got: %q", expected, output)
1631 }
1632
1633
1634 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "1")
1635 if err != nil {
1636 t.Errorf("Unexpected error: %v", err)
1637 }
1638
1639 expected = strings.Join([]string{
1640 "1",
1641 "10",
1642 ":0",
1643 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1644
1645 if output != expected {
1646 t.Errorf("expected: %q, got: %q", expected, output)
1647 }
1648
1649
1650 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "")
1651 if err != nil {
1652 t.Errorf("Unexpected error: %v", err)
1653 }
1654
1655 expected = strings.Join([]string{
1656 "file.yaml",
1657 "myfile.json",
1658 "file.xml",
1659 ":6",
1660 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
1661
1662 if output != expected {
1663 t.Errorf("expected: %q, got: %q", expected, output)
1664 }
1665
1666
1667 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "f")
1668 if err != nil {
1669 t.Errorf("Unexpected error: %v", err)
1670 }
1671
1672 expected = strings.Join([]string{
1673 "file.yaml",
1674 "file.xml",
1675 ":6",
1676 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
1677
1678 if output != expected {
1679 t.Errorf("expected: %q, got: %q", expected, output)
1680 }
1681 }
1682
1683 func TestValidArgsFuncChildCmdsWithDesc(t *testing.T) {
1684 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
1685 child1Cmd := &Command{
1686 Use: "child1",
1687 ValidArgsFunction: validArgsFunc,
1688 Run: emptyRun,
1689 }
1690 child2Cmd := &Command{
1691 Use: "child2",
1692 ValidArgsFunction: validArgsFunc2,
1693 Run: emptyRun,
1694 }
1695 rootCmd.AddCommand(child1Cmd, child2Cmd)
1696
1697
1698 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child1", "")
1699 if err != nil {
1700 t.Errorf("Unexpected error: %v", err)
1701 }
1702
1703 expected := strings.Join([]string{
1704 "one\tThe first",
1705 "two\tThe second",
1706 ":0",
1707 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1708
1709 if output != expected {
1710 t.Errorf("expected: %q, got: %q", expected, output)
1711 }
1712
1713
1714 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "t")
1715 if err != nil {
1716 t.Errorf("Unexpected error: %v", err)
1717 }
1718
1719 expected = strings.Join([]string{
1720 "two\tThe second",
1721 ":0",
1722 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1723
1724 if output != expected {
1725 t.Errorf("expected: %q, got: %q", expected, output)
1726 }
1727
1728
1729 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "unexpectedArg", "t")
1730 if err != nil {
1731 t.Errorf("Unexpected error: %v", err)
1732 }
1733
1734 expected = strings.Join([]string{
1735 ":4",
1736 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1737
1738 if output != expected {
1739 t.Errorf("expected: %q, got: %q", expected, output)
1740 }
1741
1742
1743 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "")
1744 if err != nil {
1745 t.Errorf("Unexpected error: %v", err)
1746 }
1747
1748 expected = strings.Join([]string{
1749 "three\tThe third",
1750 "four\tThe fourth",
1751 ":0",
1752 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1753
1754 if output != expected {
1755 t.Errorf("expected: %q, got: %q", expected, output)
1756 }
1757
1758 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "t")
1759 if err != nil {
1760 t.Errorf("Unexpected error: %v", err)
1761 }
1762
1763 expected = strings.Join([]string{
1764 "three\tThe third",
1765 ":0",
1766 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1767
1768 if output != expected {
1769 t.Errorf("expected: %q, got: %q", expected, output)
1770 }
1771
1772
1773 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "unexpectedArg", "t")
1774 if err != nil {
1775 t.Errorf("Unexpected error: %v", err)
1776 }
1777
1778 expected = strings.Join([]string{
1779 ":4",
1780 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1781
1782 if output != expected {
1783 t.Errorf("expected: %q, got: %q", expected, output)
1784 }
1785 }
1786
1787 func TestFlagCompletionWithNotInterspersedArgs(t *testing.T) {
1788 rootCmd := &Command{Use: "root", Run: emptyRun}
1789 childCmd := &Command{
1790 Use: "child",
1791 Run: emptyRun,
1792 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1793 return []string{"--validarg", "test"}, ShellCompDirectiveDefault
1794 },
1795 }
1796 childCmd2 := &Command{
1797 Use: "child2",
1798 Run: emptyRun,
1799 ValidArgs: []string{"arg1", "arg2"},
1800 }
1801 rootCmd.AddCommand(childCmd, childCmd2)
1802 childCmd.Flags().Bool("bool", false, "test bool flag")
1803 childCmd.Flags().String("string", "", "test string flag")
1804 _ = childCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1805 return []string{"myval"}, ShellCompDirectiveDefault
1806 })
1807
1808
1809 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--")
1810 if err != nil {
1811 t.Errorf("Unexpected error: %v", err)
1812 }
1813
1814 expected := strings.Join([]string{
1815 "--bool\ttest bool flag",
1816 "--help\thelp for child",
1817 "--string\ttest string flag",
1818 ":4",
1819 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1820
1821 if output != expected {
1822 t.Errorf("expected: %q, got: %q", expected, output)
1823 }
1824
1825
1826 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "-")
1827 if err != nil {
1828 t.Errorf("Unexpected error: %v", err)
1829 }
1830
1831 expected = strings.Join([]string{
1832 "--validarg",
1833 "test",
1834 ":0",
1835 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1836
1837 if output != expected {
1838 t.Errorf("expected: %q, got: %q", expected, output)
1839 }
1840
1841
1842 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--bool", "--", "-")
1843 if err != nil {
1844 t.Errorf("Unexpected error: %v", err)
1845 }
1846
1847 expected = strings.Join([]string{
1848 "--validarg",
1849 "test",
1850 ":0",
1851 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1852
1853 if output != expected {
1854 t.Errorf("expected: %q, got: %q", expected, output)
1855 }
1856
1857
1858 childCmd.Flags().SetInterspersed(false)
1859
1860
1861 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "arg", "--")
1862 if err != nil {
1863 t.Errorf("Unexpected error: %v", err)
1864 }
1865
1866 expected = strings.Join([]string{
1867 "--validarg",
1868 "test",
1869 ":0",
1870 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1871
1872 if output != expected {
1873 t.Errorf("expected: %q, got: %q", expected, output)
1874 }
1875
1876
1877 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "t", "arg", "--")
1878 if err != nil {
1879 t.Errorf("Unexpected error: %v", err)
1880 }
1881
1882 expected = strings.Join([]string{
1883 "--validarg",
1884 "test",
1885 ":0",
1886 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1887
1888 if output != expected {
1889 t.Errorf("expected: %q, got: %q", expected, output)
1890 }
1891
1892
1893 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "")
1894 if err != nil {
1895 t.Errorf("Unexpected error: %v", err)
1896 }
1897
1898 expected = strings.Join([]string{
1899 "--validarg",
1900 "test",
1901 ":0",
1902 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1903
1904 if output != expected {
1905 t.Errorf("expected: %q, got: %q", expected, output)
1906 }
1907
1908
1909 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--string", "")
1910 if err != nil {
1911 t.Errorf("Unexpected error: %v", err)
1912 }
1913
1914 expected = strings.Join([]string{
1915 "--validarg",
1916 "test",
1917 ":0",
1918 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1919
1920 if output != expected {
1921 t.Errorf("expected: %q, got: %q", expected, output)
1922 }
1923
1924
1925 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "--", "a")
1926 if err != nil {
1927 t.Errorf("Unexpected error: %v", err)
1928 }
1929
1930 expected = strings.Join([]string{
1931 "arg1",
1932 "arg2",
1933 ":4",
1934 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
1935
1936 if output != expected {
1937 t.Errorf("expected: %q, got: %q", expected, output)
1938 }
1939
1940
1941 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "")
1942 if err != nil {
1943 t.Errorf("Unexpected error: %v", err)
1944 }
1945
1946 expected = strings.Join([]string{
1947 "--validarg",
1948 "test",
1949 ":0",
1950 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1951
1952 if output != expected {
1953 t.Errorf("expected: %q, got: %q", expected, output)
1954 }
1955
1956
1957 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "arg", "--validarg", "")
1958 if err != nil {
1959 t.Errorf("Unexpected error: %v", err)
1960 }
1961
1962 expected = strings.Join([]string{
1963 "--validarg",
1964 "test",
1965 ":0",
1966 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1967
1968 if output != expected {
1969 t.Errorf("expected: %q, got: %q", expected, output)
1970 }
1971
1972
1973 childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1974 return args, ShellCompDirectiveDefault
1975 }
1976 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "")
1977 if err != nil {
1978 t.Errorf("Unexpected error: %v", err)
1979 }
1980
1981 expected = strings.Join([]string{
1982 "--validarg",
1983 ":0",
1984 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
1985
1986 if output != expected {
1987 t.Errorf("expected: %q, got: %q", expected, output)
1988 }
1989
1990
1991 childCmd.ValidArgsFunction = func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
1992 return append(args, toComplete), ShellCompDirectiveDefault
1993 }
1994 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--", "--validarg", "--toComp=ab")
1995 if err != nil {
1996 t.Errorf("Unexpected error: %v", err)
1997 }
1998
1999 expected = strings.Join([]string{
2000 "--validarg",
2001 "--toComp=ab",
2002 ":0",
2003 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
2004
2005 if output != expected {
2006 t.Errorf("expected: %q, got: %q", expected, output)
2007 }
2008 }
2009
2010 func TestFlagCompletionWorksRootCommandAddedAfterFlags(t *testing.T) {
2011 rootCmd := &Command{Use: "root", Run: emptyRun}
2012 childCmd := &Command{
2013 Use: "child",
2014 Run: emptyRun,
2015 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2016 return []string{"--validarg", "test"}, ShellCompDirectiveDefault
2017 },
2018 }
2019 childCmd.Flags().Bool("bool", false, "test bool flag")
2020 childCmd.Flags().String("string", "", "test string flag")
2021 _ = childCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2022 return []string{"myval"}, ShellCompDirectiveDefault
2023 })
2024
2025
2026
2027 rootCmd.AddCommand(childCmd)
2028
2029
2030 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "")
2031 if err != nil {
2032 t.Errorf("Unexpected error: %v", err)
2033 }
2034
2035 expected := strings.Join([]string{
2036 "myval",
2037 ":0",
2038 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
2039
2040 if output != expected {
2041 t.Errorf("expected: %q, got: %q", expected, output)
2042 }
2043 }
2044
2045 func TestFlagCompletionForPersistentFlagsCalledFromSubCmd(t *testing.T) {
2046 rootCmd := &Command{Use: "root", Run: emptyRun}
2047 rootCmd.PersistentFlags().String("string", "", "test string flag")
2048 _ = rootCmd.RegisterFlagCompletionFunc("string", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2049 return []string{"myval"}, ShellCompDirectiveDefault
2050 })
2051
2052 childCmd := &Command{
2053 Use: "child",
2054 Run: emptyRun,
2055 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2056 return []string{"--validarg", "test"}, ShellCompDirectiveDefault
2057 },
2058 }
2059 childCmd.Flags().Bool("bool", false, "test bool flag")
2060 rootCmd.AddCommand(childCmd)
2061
2062
2063 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child", "--string", "")
2064 if err != nil {
2065 t.Errorf("Unexpected error: %v", err)
2066 }
2067
2068 expected := strings.Join([]string{
2069 "myval",
2070 ":0",
2071 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
2072
2073 if output != expected {
2074 t.Errorf("expected: %q, got: %q", expected, output)
2075 }
2076 }
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087 func TestFlagCompletionConcurrentRegistration(t *testing.T) {
2088 rootCmd := &Command{Use: "root", Run: emptyRun}
2089 const maxFlags = 50
2090 for i := 1; i < maxFlags; i += 2 {
2091 flagName := fmt.Sprintf("flag%d", i)
2092 rootCmd.Flags().String(flagName, "", fmt.Sprintf("test %s flag on root", flagName))
2093 }
2094
2095 childCmd := &Command{
2096 Use: "child",
2097 Run: emptyRun,
2098 }
2099 for i := 2; i <= maxFlags; i += 2 {
2100 flagName := fmt.Sprintf("flag%d", i)
2101 childCmd.Flags().String(flagName, "", fmt.Sprintf("test %s flag on child", flagName))
2102 }
2103
2104 rootCmd.AddCommand(childCmd)
2105
2106
2107 var wg sync.WaitGroup
2108 for i := 1; i <= maxFlags; i++ {
2109 index := i
2110 flagName := fmt.Sprintf("flag%d", i)
2111 wg.Add(1)
2112 go func() {
2113 defer wg.Done()
2114 cmd := rootCmd
2115 if index%2 == 0 {
2116 cmd = childCmd
2117 }
2118 _ = cmd.RegisterFlagCompletionFunc(flagName, func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2119 return []string{fmt.Sprintf("flag%d", index)}, ShellCompDirectiveDefault
2120 })
2121 }()
2122 }
2123
2124 wg.Wait()
2125
2126
2127 for i := 1; i <= 6; i++ {
2128 var output string
2129 var err error
2130 flagName := fmt.Sprintf("flag%d", i)
2131
2132 if i%2 == 1 {
2133 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--"+flagName, "")
2134 } else {
2135 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child", "--"+flagName, "")
2136 }
2137
2138 if err != nil {
2139 t.Errorf("Unexpected error: %v", err)
2140 }
2141
2142 expected := strings.Join([]string{
2143 flagName,
2144 ":0",
2145 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
2146
2147 if output != expected {
2148 t.Errorf("expected: %q, got: %q", expected, output)
2149 }
2150 }
2151 }
2152
2153 func TestFlagCompletionInGoWithDesc(t *testing.T) {
2154 rootCmd := &Command{
2155 Use: "root",
2156 Run: emptyRun,
2157 }
2158 rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
2159 assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2160 completions := []string{}
2161 for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
2162 if strings.HasPrefix(comp, toComplete) {
2163 completions = append(completions, comp)
2164 }
2165 }
2166 return completions, ShellCompDirectiveDefault
2167 }))
2168 rootCmd.Flags().String("filename", "", "Enter a filename")
2169 assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2170 completions := []string{}
2171 for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
2172 if strings.HasPrefix(comp, toComplete) {
2173 completions = append(completions, comp)
2174 }
2175 }
2176 return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
2177 }))
2178
2179
2180 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "")
2181 if err != nil {
2182 t.Errorf("Unexpected error: %v", err)
2183 }
2184
2185 expected := strings.Join([]string{
2186 "1\tThe first",
2187 "2\tThe second",
2188 "10\tThe tenth",
2189 ":0",
2190 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
2191
2192 if output != expected {
2193 t.Errorf("expected: %q, got: %q", expected, output)
2194 }
2195
2196
2197 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "1")
2198 if err != nil {
2199 t.Errorf("Unexpected error: %v", err)
2200 }
2201
2202 expected = strings.Join([]string{
2203 "1\tThe first",
2204 "10\tThe tenth",
2205 ":0",
2206 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
2207
2208 if output != expected {
2209 t.Errorf("expected: %q, got: %q", expected, output)
2210 }
2211
2212
2213 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "")
2214 if err != nil {
2215 t.Errorf("Unexpected error: %v", err)
2216 }
2217
2218 expected = strings.Join([]string{
2219 "file.yaml\tYAML format",
2220 "myfile.json\tJSON format",
2221 "file.xml\tXML format",
2222 ":6",
2223 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
2224
2225 if output != expected {
2226 t.Errorf("expected: %q, got: %q", expected, output)
2227 }
2228
2229
2230 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "f")
2231 if err != nil {
2232 t.Errorf("Unexpected error: %v", err)
2233 }
2234
2235 expected = strings.Join([]string{
2236 "file.yaml\tYAML format",
2237 "file.xml\tXML format",
2238 ":6",
2239 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n")
2240
2241 if output != expected {
2242 t.Errorf("expected: %q, got: %q", expected, output)
2243 }
2244 }
2245
2246 func TestValidArgsNotValidArgsFunc(t *testing.T) {
2247 rootCmd := &Command{
2248 Use: "root",
2249 ValidArgs: []string{"one", "two"},
2250 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2251 return []string{"three", "four"}, ShellCompDirectiveNoFileComp
2252 },
2253 Run: emptyRun,
2254 }
2255
2256
2257
2258 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
2259 if err != nil {
2260 t.Errorf("Unexpected error: %v", err)
2261 }
2262
2263 expected := strings.Join([]string{
2264 "one",
2265 "two",
2266 ":4",
2267 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2268
2269 if output != expected {
2270 t.Errorf("expected: %q, got: %q", expected, output)
2271 }
2272
2273
2274 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
2275 if err != nil {
2276 t.Errorf("Unexpected error: %v", err)
2277 }
2278
2279 expected = strings.Join([]string{
2280 "two",
2281 ":4",
2282 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2283
2284 if output != expected {
2285 t.Errorf("expected: %q, got: %q", expected, output)
2286 }
2287 }
2288
2289 func TestArgAliasesCompletionInGo(t *testing.T) {
2290 rootCmd := &Command{
2291 Use: "root",
2292 Args: OnlyValidArgs,
2293 ValidArgs: []string{"one", "two", "three"},
2294 ArgAliases: []string{"un", "deux", "trois"},
2295 Run: emptyRun,
2296 }
2297
2298
2299 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
2300 if err != nil {
2301 t.Errorf("Unexpected error: %v", err)
2302 }
2303
2304 expected := strings.Join([]string{
2305 "one",
2306 "two",
2307 "three",
2308 ":4",
2309 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2310
2311 if output != expected {
2312 t.Errorf("expected: %q, got: %q", expected, output)
2313 }
2314
2315
2316 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t")
2317 if err != nil {
2318 t.Errorf("Unexpected error: %v", err)
2319 }
2320
2321 expected = strings.Join([]string{
2322 "two",
2323 "three",
2324 ":4",
2325 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2326
2327 if output != expected {
2328 t.Errorf("expected: %q, got: %q", expected, output)
2329 }
2330
2331
2332 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "tr")
2333 if err != nil {
2334 t.Errorf("Unexpected error: %v", err)
2335 }
2336
2337 expected = strings.Join([]string{
2338 "trois",
2339 ":4",
2340 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2341
2342 if output != expected {
2343 t.Errorf("expected: %q, got: %q", expected, output)
2344 }
2345 }
2346
2347 func TestCompleteHelp(t *testing.T) {
2348 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
2349 child1Cmd := &Command{
2350 Use: "child1",
2351 Run: emptyRun,
2352 }
2353 child2Cmd := &Command{
2354 Use: "child2",
2355 Run: emptyRun,
2356 }
2357 rootCmd.AddCommand(child1Cmd, child2Cmd)
2358
2359 child3Cmd := &Command{
2360 Use: "child3",
2361 Run: emptyRun,
2362 }
2363 child1Cmd.AddCommand(child3Cmd)
2364
2365
2366 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
2367 if err != nil {
2368 t.Errorf("Unexpected error: %v", err)
2369 }
2370
2371 expected := strings.Join([]string{
2372 "child1",
2373 "child2",
2374 "completion",
2375 "help",
2376 ":4",
2377 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2378
2379 if output != expected {
2380 t.Errorf("expected: %q, got: %q", expected, output)
2381 }
2382
2383
2384 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "")
2385 if err != nil {
2386 t.Errorf("Unexpected error: %v", err)
2387 }
2388
2389 expected = strings.Join([]string{
2390 "child1",
2391 "child2",
2392 "completion",
2393 "help",
2394 ":4",
2395 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2396
2397 if output != expected {
2398 t.Errorf("expected: %q, got: %q", expected, output)
2399 }
2400
2401
2402 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "child1", "")
2403 if err != nil {
2404 t.Errorf("Unexpected error: %v", err)
2405 }
2406
2407 expected = strings.Join([]string{
2408 "child3",
2409 ":4",
2410 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2411
2412 if output != expected {
2413 t.Errorf("expected: %q, got: %q", expected, output)
2414 }
2415 }
2416
2417 func removeCompCmd(rootCmd *Command) {
2418
2419 for _, cmd := range rootCmd.commands {
2420 if cmd.Name() == compCmdName {
2421 rootCmd.RemoveCommand(cmd)
2422 return
2423 }
2424 }
2425 }
2426
2427 func TestDefaultCompletionCmd(t *testing.T) {
2428 rootCmd := &Command{
2429 Use: "root",
2430 Args: NoArgs,
2431 Run: emptyRun,
2432 }
2433
2434
2435 assertNoErr(t, rootCmd.Execute())
2436 for _, cmd := range rootCmd.commands {
2437 if cmd.Name() == compCmdName {
2438 t.Errorf("Should not have a 'completion' command when there are no other sub-commands of root")
2439 break
2440 }
2441 }
2442
2443 subCmd := &Command{
2444 Use: "sub",
2445 Run: emptyRun,
2446 }
2447 rootCmd.AddCommand(subCmd)
2448
2449
2450 found := false
2451 assertNoErr(t, rootCmd.Execute())
2452 for _, cmd := range rootCmd.commands {
2453 if cmd.Name() == compCmdName {
2454 found = true
2455 break
2456 }
2457 }
2458 if !found {
2459 t.Errorf("Should have a 'completion' command when there are other sub-commands of root")
2460 }
2461
2462 removeCompCmd(rootCmd)
2463
2464
2465 rootCmd.CompletionOptions.DisableDefaultCmd = true
2466 assertNoErr(t, rootCmd.Execute())
2467 for _, cmd := range rootCmd.commands {
2468 if cmd.Name() == compCmdName {
2469 t.Errorf("Should not have a 'completion' command when the feature is disabled")
2470 break
2471 }
2472 }
2473
2474 rootCmd.CompletionOptions.DisableDefaultCmd = false
2475
2476
2477 output, err := executeCommand(rootCmd, compCmdName, "zsh")
2478 if err != nil {
2479 t.Errorf("Unexpected error: %v", err)
2480 }
2481
2482 check(t, output, ShellCompRequestCmd)
2483 checkOmit(t, output, ShellCompNoDescRequestCmd)
2484
2485 removeCompCmd(rootCmd)
2486
2487
2488 rootCmd.CompletionOptions.DisableDescriptions = true
2489 output, err = executeCommand(rootCmd, compCmdName, "zsh")
2490 if err != nil {
2491 t.Errorf("Unexpected error: %v", err)
2492 }
2493
2494 check(t, output, ShellCompNoDescRequestCmd)
2495
2496 rootCmd.CompletionOptions.DisableDescriptions = false
2497
2498 removeCompCmd(rootCmd)
2499
2500 var compCmd *Command
2501
2502 assertNoErr(t, rootCmd.Execute())
2503 for _, shell := range []string{"bash", "fish", "powershell", "zsh"} {
2504 if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil {
2505 t.Errorf("Unexpected error: %v", err)
2506 }
2507 if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag == nil {
2508 t.Errorf("Missing --%s flag for %s shell", compCmdNoDescFlagName, shell)
2509 }
2510 }
2511
2512 removeCompCmd(rootCmd)
2513
2514
2515 rootCmd.CompletionOptions.DisableNoDescFlag = true
2516 assertNoErr(t, rootCmd.Execute())
2517 for _, shell := range []string{"fish", "zsh", "bash", "powershell"} {
2518 if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil {
2519 t.Errorf("Unexpected error: %v", err)
2520 }
2521 if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag != nil {
2522 t.Errorf("Unexpected --%s flag for %s shell", compCmdNoDescFlagName, shell)
2523 }
2524 }
2525
2526 rootCmd.CompletionOptions.DisableNoDescFlag = false
2527
2528 removeCompCmd(rootCmd)
2529
2530
2531 rootCmd.CompletionOptions.DisableDescriptions = true
2532 assertNoErr(t, rootCmd.Execute())
2533 for _, shell := range []string{"fish", "zsh", "bash", "powershell"} {
2534 if compCmd, _, err = rootCmd.Find([]string{compCmdName, shell}); err != nil {
2535 t.Errorf("Unexpected error: %v", err)
2536 }
2537 if flag := compCmd.Flags().Lookup(compCmdNoDescFlagName); flag != nil {
2538 t.Errorf("Unexpected --%s flag for %s shell", compCmdNoDescFlagName, shell)
2539 }
2540 }
2541
2542 rootCmd.CompletionOptions.DisableDescriptions = false
2543
2544 removeCompCmd(rootCmd)
2545
2546
2547 rootCmd.CompletionOptions.HiddenDefaultCmd = true
2548 assertNoErr(t, rootCmd.Execute())
2549 compCmd, _, err = rootCmd.Find([]string{compCmdName})
2550 if err != nil {
2551 t.Errorf("Unexpected error: %v", err)
2552 }
2553 if compCmd.Hidden == false {
2554 t.Error("Default 'completion' command should be hidden but it is not")
2555 }
2556
2557 rootCmd.CompletionOptions.HiddenDefaultCmd = false
2558
2559 removeCompCmd(rootCmd)
2560 }
2561
2562 func TestCompleteCompletion(t *testing.T) {
2563 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
2564 subCmd := &Command{
2565 Use: "sub",
2566 Run: emptyRun,
2567 }
2568 rootCmd.AddCommand(subCmd)
2569
2570
2571 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
2572 if err != nil {
2573 t.Errorf("Unexpected error: %v", err)
2574 }
2575
2576 expected := strings.Join([]string{
2577 "bash",
2578 "fish",
2579 "powershell",
2580 "zsh",
2581 ":4",
2582 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2583
2584 if output != expected {
2585 t.Errorf("expected: %q, got: %q", expected, output)
2586 }
2587
2588
2589 var compCmd *Command
2590 for _, cmd := range rootCmd.Commands() {
2591 if cmd.Name() == compCmdName {
2592 compCmd = cmd
2593 break
2594 }
2595 }
2596
2597 for _, shell := range compCmd.Commands() {
2598 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, compCmdName, shell.Name(), "")
2599 if err != nil {
2600 t.Errorf("Unexpected error: %v", err)
2601 }
2602
2603 expected = strings.Join([]string{
2604 ":4",
2605 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2606
2607 if output != expected {
2608 t.Errorf("expected: %q, got: %q", expected, output)
2609 }
2610 }
2611 }
2612
2613 func TestMultipleShorthandFlagCompletion(t *testing.T) {
2614 rootCmd := &Command{
2615 Use: "root",
2616 ValidArgs: []string{"foo", "bar"},
2617 Run: emptyRun,
2618 }
2619 f := rootCmd.Flags()
2620 f.BoolP("short", "s", false, "short flag 1")
2621 f.BoolP("short2", "d", false, "short flag 2")
2622 f.StringP("short3", "f", "", "short flag 3")
2623 _ = rootCmd.RegisterFlagCompletionFunc("short3", func(*Command, []string, string) ([]string, ShellCompDirective) {
2624 return []string{"works"}, ShellCompDirectiveNoFileComp
2625 })
2626
2627
2628 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "")
2629 if err != nil {
2630 t.Errorf("Unexpected error: %v", err)
2631 }
2632
2633 expected := strings.Join([]string{
2634 "foo",
2635 "bar",
2636 ":4",
2637 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2638
2639 if output != expected {
2640 t.Errorf("expected: %q, got: %q", expected, output)
2641 }
2642
2643
2644 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sd", "")
2645 if err != nil {
2646 t.Errorf("Unexpected error: %v", err)
2647 }
2648
2649 expected = strings.Join([]string{
2650 "foo",
2651 "bar",
2652 ":4",
2653 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2654
2655 if output != expected {
2656 t.Errorf("expected: %q, got: %q", expected, output)
2657 }
2658
2659
2660 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf", "")
2661 if err != nil {
2662 t.Errorf("Unexpected error: %v", err)
2663 }
2664
2665 expected = strings.Join([]string{
2666 "works",
2667 ":4",
2668 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2669
2670 if output != expected {
2671 t.Errorf("expected: %q, got: %q", expected, output)
2672 }
2673
2674
2675 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf=")
2676 if err != nil {
2677 t.Errorf("Unexpected error: %v", err)
2678 }
2679
2680 expected = strings.Join([]string{
2681 "works",
2682 ":4",
2683 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2684
2685 if output != expected {
2686 t.Errorf("expected: %q, got: %q", expected, output)
2687 }
2688
2689
2690 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-sdf=abc", "")
2691 if err != nil {
2692 t.Errorf("Unexpected error: %v", err)
2693 }
2694
2695 expected = strings.Join([]string{
2696 "foo",
2697 "bar",
2698 ":4",
2699 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2700
2701 if output != expected {
2702 t.Errorf("expected: %q, got: %q", expected, output)
2703 }
2704 }
2705
2706 func TestCompleteWithDisableFlagParsing(t *testing.T) {
2707
2708 flagValidArgs := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2709 return []string{"--flag", "-f"}, ShellCompDirectiveNoFileComp
2710 }
2711
2712 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
2713 childCmd := &Command{
2714 Use: "child",
2715 Run: emptyRun,
2716 DisableFlagParsing: true,
2717 ValidArgsFunction: flagValidArgs,
2718 }
2719 rootCmd.AddCommand(childCmd)
2720
2721 rootCmd.PersistentFlags().StringP("persistent", "p", "", "persistent flag")
2722 childCmd.Flags().StringP("nonPersistent", "n", "", "non-persistent flag")
2723
2724
2725
2726 childCmd.DisableFlagParsing = true
2727 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-")
2728 if err != nil {
2729 t.Errorf("Unexpected error: %v", err)
2730 }
2731
2732 expected := strings.Join([]string{
2733 "--persistent",
2734 "-p",
2735 "--nonPersistent",
2736 "-n",
2737 "--flag",
2738 "-f",
2739 ":4",
2740 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2741
2742 if output != expected {
2743 t.Errorf("expected: %q, got: %q", expected, output)
2744 }
2745
2746
2747 childCmd.DisableFlagParsing = false
2748 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-")
2749 if err != nil {
2750 t.Errorf("Unexpected error: %v", err)
2751 }
2752
2753
2754 expected = strings.Join([]string{
2755 "--persistent",
2756 "-p",
2757 "--help",
2758 "-h",
2759 "--nonPersistent",
2760 "-n",
2761 ":4",
2762 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2763
2764 if output != expected {
2765 t.Errorf("expected: %q, got: %q", expected, output)
2766 }
2767 }
2768
2769 func TestCompleteWithRootAndLegacyArgs(t *testing.T) {
2770
2771
2772 rootCmd := &Command{
2773 Use: "root",
2774 Args: nil,
2775 Run: emptyRun,
2776 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2777 return []string{"arg1", "arg2"}, ShellCompDirectiveNoFileComp
2778 },
2779 }
2780
2781
2782 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
2783 if err != nil {
2784 t.Errorf("Unexpected error: %v", err)
2785 }
2786
2787 expected := strings.Join([]string{
2788 "arg1",
2789 "arg2",
2790 ":4",
2791 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2792
2793 if output != expected {
2794 t.Errorf("expected: %q, got: %q", expected, output)
2795 }
2796
2797
2798 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "arg1", "")
2799 if err != nil {
2800 t.Errorf("Unexpected error: %v", err)
2801 }
2802
2803 expected = strings.Join([]string{
2804 "arg1",
2805 "arg2",
2806 ":4",
2807 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2808
2809 if output != expected {
2810 t.Errorf("expected: %q, got: %q", expected, output)
2811 }
2812 }
2813
2814 func TestFixedCompletions(t *testing.T) {
2815 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
2816 choices := []string{"apple", "banana", "orange"}
2817 childCmd := &Command{
2818 Use: "child",
2819 ValidArgsFunction: FixedCompletions(choices, ShellCompDirectiveNoFileComp),
2820 Run: emptyRun,
2821 }
2822 rootCmd.AddCommand(childCmd)
2823
2824 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "a")
2825 if err != nil {
2826 t.Errorf("Unexpected error: %v", err)
2827 }
2828
2829 expected := strings.Join([]string{
2830 "apple",
2831 "banana",
2832 "orange",
2833 ":4",
2834 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
2835
2836 if output != expected {
2837 t.Errorf("expected: %q, got: %q", expected, output)
2838 }
2839 }
2840
2841 func TestCompletionForGroupedFlags(t *testing.T) {
2842 getCmd := func() *Command {
2843 rootCmd := &Command{
2844 Use: "root",
2845 Run: emptyRun,
2846 }
2847 childCmd := &Command{
2848 Use: "child",
2849 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2850 return []string{"subArg"}, ShellCompDirectiveNoFileComp
2851 },
2852 Run: emptyRun,
2853 }
2854 rootCmd.AddCommand(childCmd)
2855
2856 rootCmd.PersistentFlags().Int("ingroup1", -1, "ingroup1")
2857 rootCmd.PersistentFlags().String("ingroup2", "", "ingroup2")
2858
2859 childCmd.Flags().Bool("ingroup3", false, "ingroup3")
2860 childCmd.Flags().Bool("nogroup", false, "nogroup")
2861
2862
2863 childCmd.MarkFlagsRequiredTogether("ingroup1", "ingroup2", "ingroup3")
2864
2865 return rootCmd
2866 }
2867
2868
2869 testcases := []struct {
2870 desc string
2871 args []string
2872 expectedOutput string
2873 }{
2874 {
2875 desc: "flags in group not suggested without - prefix",
2876 args: []string{"child", ""},
2877 expectedOutput: strings.Join([]string{
2878 "subArg",
2879 ":4",
2880 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2881 },
2882 {
2883 desc: "flags in group suggested with - prefix",
2884 args: []string{"child", "-"},
2885 expectedOutput: strings.Join([]string{
2886 "--ingroup1",
2887 "--ingroup2",
2888 "--help",
2889 "-h",
2890 "--ingroup3",
2891 "--nogroup",
2892 ":4",
2893 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2894 },
2895 {
2896 desc: "when flag in group present, other flags in group suggested even without - prefix",
2897 args: []string{"child", "--ingroup2", "value", ""},
2898 expectedOutput: strings.Join([]string{
2899 "--ingroup1",
2900 "--ingroup3",
2901 "subArg",
2902 ":4",
2903 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2904 },
2905 {
2906 desc: "when all flags in group present, flags not suggested without - prefix",
2907 args: []string{"child", "--ingroup1", "8", "--ingroup2", "value2", "--ingroup3", ""},
2908 expectedOutput: strings.Join([]string{
2909 "subArg",
2910 ":4",
2911 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2912 },
2913 {
2914 desc: "group ignored if some flags not applicable",
2915 args: []string{"--ingroup2", "value", ""},
2916 expectedOutput: strings.Join([]string{
2917 "child",
2918 "completion",
2919 "help",
2920 ":4",
2921 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2922 },
2923 }
2924
2925 for _, tc := range testcases {
2926 t.Run(tc.desc, func(t *testing.T) {
2927 c := getCmd()
2928 args := []string{ShellCompNoDescRequestCmd}
2929 args = append(args, tc.args...)
2930 output, err := executeCommand(c, args...)
2931 switch {
2932 case err == nil && output != tc.expectedOutput:
2933 t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
2934 case err != nil:
2935 t.Errorf("Unexpected error %q", err)
2936 }
2937 })
2938 }
2939 }
2940
2941 func TestCompletionForOneRequiredGroupFlags(t *testing.T) {
2942 getCmd := func() *Command {
2943 rootCmd := &Command{
2944 Use: "root",
2945 Run: emptyRun,
2946 }
2947 childCmd := &Command{
2948 Use: "child",
2949 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
2950 return []string{"subArg"}, ShellCompDirectiveNoFileComp
2951 },
2952 Run: emptyRun,
2953 }
2954 rootCmd.AddCommand(childCmd)
2955
2956 rootCmd.PersistentFlags().Int("ingroup1", -1, "ingroup1")
2957 rootCmd.PersistentFlags().String("ingroup2", "", "ingroup2")
2958
2959 childCmd.Flags().Bool("ingroup3", false, "ingroup3")
2960 childCmd.Flags().Bool("nogroup", false, "nogroup")
2961
2962
2963 childCmd.MarkFlagsOneRequired("ingroup1", "ingroup2", "ingroup3")
2964
2965 return rootCmd
2966 }
2967
2968
2969 testcases := []struct {
2970 desc string
2971 args []string
2972 expectedOutput string
2973 }{
2974 {
2975 desc: "flags in group suggested without - prefix",
2976 args: []string{"child", ""},
2977 expectedOutput: strings.Join([]string{
2978 "--ingroup1",
2979 "--ingroup2",
2980 "--ingroup3",
2981 "subArg",
2982 ":4",
2983 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2984 },
2985 {
2986 desc: "flags in group suggested with - prefix",
2987 args: []string{"child", "-"},
2988 expectedOutput: strings.Join([]string{
2989 "--ingroup1",
2990 "--ingroup2",
2991 "--ingroup3",
2992 ":4",
2993 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
2994 },
2995 {
2996 desc: "when any flag in group present, other flags in group not suggested without - prefix",
2997 args: []string{"child", "--ingroup2", "value", ""},
2998 expectedOutput: strings.Join([]string{
2999 "subArg",
3000 ":4",
3001 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3002 },
3003 {
3004 desc: "when all flags in group present, flags not suggested without - prefix",
3005 args: []string{"child", "--ingroup1", "8", "--ingroup2", "value2", "--ingroup3", ""},
3006 expectedOutput: strings.Join([]string{
3007 "subArg",
3008 ":4",
3009 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3010 },
3011 {
3012 desc: "group ignored if some flags not applicable",
3013 args: []string{"--ingroup2", "value", ""},
3014 expectedOutput: strings.Join([]string{
3015 "child",
3016 "completion",
3017 "help",
3018 ":4",
3019 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3020 },
3021 }
3022
3023 for _, tc := range testcases {
3024 t.Run(tc.desc, func(t *testing.T) {
3025 c := getCmd()
3026 args := []string{ShellCompNoDescRequestCmd}
3027 args = append(args, tc.args...)
3028 output, err := executeCommand(c, args...)
3029 switch {
3030 case err == nil && output != tc.expectedOutput:
3031 t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
3032 case err != nil:
3033 t.Errorf("Unexpected error %q", err)
3034 }
3035 })
3036 }
3037 }
3038
3039 func TestCompletionForMutuallyExclusiveFlags(t *testing.T) {
3040 getCmd := func() *Command {
3041 rootCmd := &Command{
3042 Use: "root",
3043 Run: emptyRun,
3044 }
3045 childCmd := &Command{
3046 Use: "child",
3047 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3048 return []string{"subArg"}, ShellCompDirectiveNoFileComp
3049 },
3050 Run: emptyRun,
3051 }
3052 rootCmd.AddCommand(childCmd)
3053
3054 rootCmd.PersistentFlags().IntSlice("ingroup1", []int{1}, "ingroup1")
3055 rootCmd.PersistentFlags().String("ingroup2", "", "ingroup2")
3056
3057 childCmd.Flags().Bool("ingroup3", false, "ingroup3")
3058 childCmd.Flags().Bool("nogroup", false, "nogroup")
3059
3060
3061 childCmd.MarkFlagsMutuallyExclusive("ingroup1", "ingroup2", "ingroup3")
3062
3063 return rootCmd
3064 }
3065
3066
3067 testcases := []struct {
3068 desc string
3069 args []string
3070 expectedOutput string
3071 }{
3072 {
3073 desc: "flags in mutually exclusive group not suggested without the - prefix",
3074 args: []string{"child", ""},
3075 expectedOutput: strings.Join([]string{
3076 "subArg",
3077 ":4",
3078 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3079 },
3080 {
3081 desc: "flags in mutually exclusive group suggested with the - prefix",
3082 args: []string{"child", "-"},
3083 expectedOutput: strings.Join([]string{
3084 "--ingroup1",
3085 "--ingroup2",
3086 "--help",
3087 "-h",
3088 "--ingroup3",
3089 "--nogroup",
3090 ":4",
3091 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3092 },
3093 {
3094 desc: "when flag in mutually exclusive group present, other flags in group not suggested even with the - prefix",
3095 args: []string{"child", "--ingroup1", "8", "-"},
3096 expectedOutput: strings.Join([]string{
3097 "--ingroup1",
3098 "--help",
3099 "-h",
3100 "--nogroup",
3101 ":4",
3102 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3103 },
3104 {
3105 desc: "group ignored if some flags not applicable",
3106 args: []string{"--ingroup1", "8", "-"},
3107 expectedOutput: strings.Join([]string{
3108 "--help",
3109 "-h",
3110 "--ingroup1",
3111 "--ingroup2",
3112 ":4",
3113 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3114 },
3115 }
3116
3117 for _, tc := range testcases {
3118 t.Run(tc.desc, func(t *testing.T) {
3119 c := getCmd()
3120 args := []string{ShellCompNoDescRequestCmd}
3121 args = append(args, tc.args...)
3122 output, err := executeCommand(c, args...)
3123 switch {
3124 case err == nil && output != tc.expectedOutput:
3125 t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
3126 case err != nil:
3127 t.Errorf("Unexpected error %q", err)
3128 }
3129 })
3130 }
3131 }
3132
3133 func TestCompletionCobraFlags(t *testing.T) {
3134 getCmd := func() *Command {
3135 rootCmd := &Command{
3136 Use: "root",
3137 Version: "1.1.1",
3138 Run: emptyRun,
3139 }
3140 childCmd := &Command{
3141 Use: "child",
3142 Version: "1.1.1",
3143 Run: emptyRun,
3144 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3145 return []string{"extra"}, ShellCompDirectiveNoFileComp
3146 },
3147 }
3148 childCmd2 := &Command{
3149 Use: "child2",
3150 Version: "1.1.1",
3151 Run: emptyRun,
3152 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3153 return []string{"extra2"}, ShellCompDirectiveNoFileComp
3154 },
3155 }
3156 childCmd3 := &Command{
3157 Use: "child3",
3158 Version: "1.1.1",
3159 Run: emptyRun,
3160 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3161 return []string{"extra3"}, ShellCompDirectiveNoFileComp
3162 },
3163 }
3164 childCmd4 := &Command{
3165 Use: "child4",
3166 Version: "1.1.1",
3167 Run: emptyRun,
3168 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3169 return []string{"extra4"}, ShellCompDirectiveNoFileComp
3170 },
3171 DisableFlagParsing: true,
3172 }
3173 childCmd5 := &Command{
3174 Use: "child5",
3175 Version: "1.1.1",
3176 Run: emptyRun,
3177 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3178 return []string{"extra5"}, ShellCompDirectiveNoFileComp
3179 },
3180 DisableFlagParsing: true,
3181 }
3182
3183 rootCmd.AddCommand(childCmd, childCmd2, childCmd3, childCmd4, childCmd5)
3184
3185 _ = childCmd.Flags().Bool("bool", false, "A bool flag")
3186 _ = childCmd.MarkFlagRequired("bool")
3187
3188
3189 _ = childCmd2.Flags().BoolP("help", "h", false, "My own help")
3190 _ = childCmd2.Flags().BoolP("version", "v", false, "My own version")
3191
3192
3193 _ = childCmd3.Flags().BoolP("verbose", "v", false, "Not a version flag")
3194
3195
3196 _ = childCmd5.Flags().BoolP("help", "h", false, "My own help")
3197 _ = childCmd5.Flags().BoolP("version", "v", false, "My own version")
3198
3199 return rootCmd
3200 }
3201
3202
3203 testcases := []struct {
3204 desc string
3205 args []string
3206 expectedOutput string
3207 }{
3208 {
3209 desc: "completion of help and version flags",
3210 args: []string{"-"},
3211 expectedOutput: strings.Join([]string{
3212 "--help",
3213 "-h",
3214 "--version",
3215 "-v",
3216 ":4",
3217 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3218 },
3219 {
3220 desc: "no completion after --help flag",
3221 args: []string{"--help", ""},
3222 expectedOutput: strings.Join([]string{
3223 ":4",
3224 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3225 },
3226 {
3227 desc: "no completion after -h flag",
3228 args: []string{"-h", ""},
3229 expectedOutput: strings.Join([]string{
3230 ":4",
3231 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3232 },
3233 {
3234 desc: "no completion after --version flag",
3235 args: []string{"--version", ""},
3236 expectedOutput: strings.Join([]string{
3237 ":4",
3238 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3239 },
3240 {
3241 desc: "no completion after -v flag",
3242 args: []string{"-v", ""},
3243 expectedOutput: strings.Join([]string{
3244 ":4",
3245 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3246 },
3247 {
3248 desc: "no completion after --help flag even with other completions",
3249 args: []string{"child", "--help", ""},
3250 expectedOutput: strings.Join([]string{
3251 ":4",
3252 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3253 },
3254 {
3255 desc: "no completion after -h flag even with other completions",
3256 args: []string{"child", "-h", ""},
3257 expectedOutput: strings.Join([]string{
3258 ":4",
3259 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3260 },
3261 {
3262 desc: "no completion after --version flag even with other completions",
3263 args: []string{"child", "--version", ""},
3264 expectedOutput: strings.Join([]string{
3265 ":4",
3266 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3267 },
3268 {
3269 desc: "no completion after -v flag even with other completions",
3270 args: []string{"child", "-v", ""},
3271 expectedOutput: strings.Join([]string{
3272 ":4",
3273 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3274 },
3275 {
3276 desc: "no completion after -v flag even with other flag completions",
3277 args: []string{"child", "-v", "-"},
3278 expectedOutput: strings.Join([]string{
3279 ":4",
3280 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3281 },
3282 {
3283 desc: "completion after --help flag when created by program",
3284 args: []string{"child2", "--help", ""},
3285 expectedOutput: strings.Join([]string{
3286 "extra2",
3287 ":4",
3288 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3289 },
3290 {
3291 desc: "completion after -h flag when created by program",
3292 args: []string{"child2", "-h", ""},
3293 expectedOutput: strings.Join([]string{
3294 "extra2",
3295 ":4",
3296 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3297 },
3298 {
3299 desc: "completion after --version flag when created by program",
3300 args: []string{"child2", "--version", ""},
3301 expectedOutput: strings.Join([]string{
3302 "extra2",
3303 ":4",
3304 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3305 },
3306 {
3307 desc: "completion after -v flag when created by program",
3308 args: []string{"child2", "-v", ""},
3309 expectedOutput: strings.Join([]string{
3310 "extra2",
3311 ":4",
3312 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3313 },
3314 {
3315 desc: "completion after --version when only -v flag was created by program",
3316 args: []string{"child3", "--version", ""},
3317 expectedOutput: strings.Join([]string{
3318 ":4",
3319 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3320 },
3321 {
3322 desc: "completion after -v flag when only -v flag was created by program",
3323 args: []string{"child3", "-v", ""},
3324 expectedOutput: strings.Join([]string{
3325 "extra3",
3326 ":4",
3327 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3328 },
3329 {
3330 desc: "no completion for --help/-h and --version/-v flags when DisableFlagParsing=true",
3331 args: []string{"child4", "-"},
3332 expectedOutput: strings.Join([]string{
3333 "extra4",
3334 ":4",
3335 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3336 },
3337 {
3338 desc: "completions for program-defined --help/-h and --version/-v flags even when DisableFlagParsing=true",
3339 args: []string{"child5", "-"},
3340 expectedOutput: strings.Join([]string{
3341 "--help",
3342 "-h",
3343 "--version",
3344 "-v",
3345 "extra5",
3346 ":4",
3347 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3348 },
3349 }
3350
3351 for _, tc := range testcases {
3352 t.Run(tc.desc, func(t *testing.T) {
3353 c := getCmd()
3354 args := []string{ShellCompNoDescRequestCmd}
3355 args = append(args, tc.args...)
3356 output, err := executeCommand(c, args...)
3357 switch {
3358 case err == nil && output != tc.expectedOutput:
3359 t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
3360 case err != nil:
3361 t.Errorf("Unexpected error %q", err)
3362 }
3363 })
3364 }
3365 }
3366
3367 func TestArgsNotDetectedAsFlagsCompletionInGo(t *testing.T) {
3368
3369
3370
3371 root := Command{
3372 Use: "root",
3373 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3374 return []string{"service", "1-123", "11-123"}, ShellCompDirectiveNoFileComp
3375 },
3376 }
3377
3378 completion := `service
3379 1-123
3380 11-123
3381 :4
3382 Completion ended with directive: ShellCompDirectiveNoFileComp
3383 `
3384
3385 testcases := []struct {
3386 desc string
3387 args []string
3388 expectedOutput string
3389 }{
3390 {
3391 desc: "empty",
3392 args: []string{""},
3393 expectedOutput: completion,
3394 },
3395 {
3396 desc: "service only",
3397 args: []string{"service", ""},
3398 expectedOutput: completion,
3399 },
3400 {
3401 desc: "service last",
3402 args: []string{"1-123", "service", ""},
3403 expectedOutput: completion,
3404 },
3405 {
3406 desc: "two digit prefixed dash last",
3407 args: []string{"service", "11-123", ""},
3408 expectedOutput: completion,
3409 },
3410 {
3411 desc: "one digit prefixed dash last",
3412 args: []string{"service", "1-123", ""},
3413 expectedOutput: completion,
3414 },
3415 }
3416 for _, tc := range testcases {
3417 t.Run(tc.desc, func(t *testing.T) {
3418 args := []string{ShellCompNoDescRequestCmd}
3419 args = append(args, tc.args...)
3420 output, err := executeCommand(&root, args...)
3421 switch {
3422 case err == nil && output != tc.expectedOutput:
3423 t.Errorf("expected: %q, got: %q", tc.expectedOutput, output)
3424 case err != nil:
3425 t.Errorf("Unexpected error %q", err)
3426 }
3427 })
3428 }
3429 }
3430
3431 func TestGetFlagCompletion(t *testing.T) {
3432 rootCmd := &Command{Use: "root", Run: emptyRun}
3433
3434 rootCmd.Flags().String("rootflag", "", "root flag")
3435 _ = rootCmd.RegisterFlagCompletionFunc("rootflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3436 return []string{"rootvalue"}, ShellCompDirectiveKeepOrder
3437 })
3438
3439 rootCmd.PersistentFlags().String("persistentflag", "", "persistent flag")
3440 _ = rootCmd.RegisterFlagCompletionFunc("persistentflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3441 return []string{"persistentvalue"}, ShellCompDirectiveDefault
3442 })
3443
3444 childCmd := &Command{Use: "child", Run: emptyRun}
3445
3446 childCmd.Flags().String("childflag", "", "child flag")
3447 _ = childCmd.RegisterFlagCompletionFunc("childflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3448 return []string{"childvalue"}, ShellCompDirectiveNoFileComp | ShellCompDirectiveNoSpace
3449 })
3450
3451 rootCmd.AddCommand(childCmd)
3452
3453 testcases := []struct {
3454 desc string
3455 cmd *Command
3456 flagName string
3457 exists bool
3458 comps []string
3459 directive ShellCompDirective
3460 }{
3461 {
3462 desc: "get flag completion function for command",
3463 cmd: rootCmd,
3464 flagName: "rootflag",
3465 exists: true,
3466 comps: []string{"rootvalue"},
3467 directive: ShellCompDirectiveKeepOrder,
3468 },
3469 {
3470 desc: "get persistent flag completion function for command",
3471 cmd: rootCmd,
3472 flagName: "persistentflag",
3473 exists: true,
3474 comps: []string{"persistentvalue"},
3475 directive: ShellCompDirectiveDefault,
3476 },
3477 {
3478 desc: "get flag completion function for child command",
3479 cmd: childCmd,
3480 flagName: "childflag",
3481 exists: true,
3482 comps: []string{"childvalue"},
3483 directive: ShellCompDirectiveNoFileComp | ShellCompDirectiveNoSpace,
3484 },
3485 {
3486 desc: "get persistent flag completion function for child command",
3487 cmd: childCmd,
3488 flagName: "persistentflag",
3489 exists: true,
3490 comps: []string{"persistentvalue"},
3491 directive: ShellCompDirectiveDefault,
3492 },
3493 {
3494 desc: "cannot get flag completion function for local parent flag",
3495 cmd: childCmd,
3496 flagName: "rootflag",
3497 exists: false,
3498 },
3499 }
3500
3501 for _, tc := range testcases {
3502 t.Run(tc.desc, func(t *testing.T) {
3503 compFunc, exists := tc.cmd.GetFlagCompletionFunc(tc.flagName)
3504 if tc.exists != exists {
3505 t.Errorf("Unexpected result looking for flag completion function")
3506 }
3507
3508 if exists {
3509 comps, directive := compFunc(tc.cmd, []string{}, "")
3510 if strings.Join(tc.comps, " ") != strings.Join(comps, " ") {
3511 t.Errorf("Unexpected completions %q", comps)
3512 }
3513 if tc.directive != directive {
3514 t.Errorf("Unexpected directive %q", directive)
3515 }
3516 }
3517 })
3518 }
3519 }
3520
View as plain text