1package cobra 2 3import ( 4 "bytes" 5 "strings" 6 "testing" 7) 8 9func validArgsFunc(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 10 if len(args) != 0 { 11 return nil, ShellCompDirectiveNoFileComp 12 } 13 14 var completions []string 15 for _, comp := range []string{"one\tThe first", "two\tThe second"} { 16 if strings.HasPrefix(comp, toComplete) { 17 completions = append(completions, comp) 18 } 19 } 20 return completions, ShellCompDirectiveDefault 21} 22 23func validArgsFunc2(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 24 if len(args) != 0 { 25 return nil, ShellCompDirectiveNoFileComp 26 } 27 28 var completions []string 29 for _, comp := range []string{"three\tThe third", "four\tThe fourth"} { 30 if strings.HasPrefix(comp, toComplete) { 31 completions = append(completions, comp) 32 } 33 } 34 return completions, ShellCompDirectiveDefault 35} 36 37func TestCmdNameCompletionInGo(t *testing.T) { 38 rootCmd := &Command{ 39 Use: "root", 40 Run: emptyRun, 41 } 42 childCmd1 := &Command{ 43 Use: "firstChild", 44 Short: "First command", 45 Run: emptyRun, 46 } 47 childCmd2 := &Command{ 48 Use: "secondChild", 49 Run: emptyRun, 50 } 51 hiddenCmd := &Command{ 52 Use: "testHidden", 53 Hidden: true, // Not completed 54 Run: emptyRun, 55 } 56 deprecatedCmd := &Command{ 57 Use: "testDeprecated", 58 Deprecated: "deprecated", // Not completed 59 Run: emptyRun, 60 } 61 aliasedCmd := &Command{ 62 Use: "aliased", 63 Short: "A command with aliases", 64 Aliases: []string{"testAlias", "testSynonym"}, // Not completed 65 Run: emptyRun, 66 } 67 68 rootCmd.AddCommand(childCmd1, childCmd2, hiddenCmd, deprecatedCmd, aliasedCmd) 69 70 // Test that sub-command names are completed 71 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 72 if err != nil { 73 t.Errorf("Unexpected error: %v", err) 74 } 75 76 expected := strings.Join([]string{ 77 "aliased", 78 "firstChild", 79 "help", 80 "secondChild", 81 ":4", 82 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 83 84 if output != expected { 85 t.Errorf("expected: %q, got: %q", expected, output) 86 } 87 88 // Test that sub-command names are completed with prefix 89 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "s") 90 if err != nil { 91 t.Errorf("Unexpected error: %v", err) 92 } 93 94 expected = strings.Join([]string{ 95 "secondChild", 96 ":4", 97 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 98 99 if output != expected { 100 t.Errorf("expected: %q, got: %q", expected, output) 101 } 102 103 // Test that even with no valid sub-command matches, hidden, deprecated and 104 // aliases are not completed 105 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "test") 106 if err != nil { 107 t.Errorf("Unexpected error: %v", err) 108 } 109 110 expected = strings.Join([]string{ 111 ":4", 112 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 113 114 if output != expected { 115 t.Errorf("expected: %q, got: %q", expected, output) 116 } 117 118 // Test that sub-command names are completed with description 119 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "") 120 if err != nil { 121 t.Errorf("Unexpected error: %v", err) 122 } 123 124 expected = strings.Join([]string{ 125 "aliased\tA command with aliases", 126 "firstChild\tFirst command", 127 "help\tHelp about any command", 128 "secondChild", 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 137func TestNoCmdNameCompletionInGo(t *testing.T) { 138 rootCmd := &Command{ 139 Use: "root", 140 Run: emptyRun, 141 } 142 rootCmd.Flags().String("localroot", "", "local root flag") 143 144 childCmd1 := &Command{ 145 Use: "childCmd1", 146 Short: "First command", 147 Args: MinimumNArgs(0), 148 Run: emptyRun, 149 } 150 rootCmd.AddCommand(childCmd1) 151 childCmd1.PersistentFlags().StringP("persistent", "p", "", "persistent flag") 152 persistentFlag := childCmd1.PersistentFlags().Lookup("persistent") 153 childCmd1.Flags().StringP("nonPersistent", "n", "", "non-persistent flag") 154 nonPersistentFlag := childCmd1.Flags().Lookup("nonPersistent") 155 156 childCmd2 := &Command{ 157 Use: "childCmd2", 158 Run: emptyRun, 159 } 160 childCmd1.AddCommand(childCmd2) 161 162 // Test that sub-command names are not completed if there is an argument already 163 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "arg1", "") 164 if err != nil { 165 t.Errorf("Unexpected error: %v", err) 166 } 167 168 expected := strings.Join([]string{ 169 ":0", 170 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 171 172 if output != expected { 173 t.Errorf("expected: %q, got: %q", expected, output) 174 } 175 176 // Test that sub-command names are not completed if a local non-persistent flag is present 177 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--nonPersistent", "value", "") 178 if err != nil { 179 t.Errorf("Unexpected error: %v", err) 180 } 181 // Reset the flag for the next command 182 nonPersistentFlag.Changed = false 183 184 expected = strings.Join([]string{ 185 ":0", 186 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 187 188 if output != expected { 189 t.Errorf("expected: %q, got: %q", expected, output) 190 } 191 192 // Test that sub-command names are completed if a local non-persistent flag is present and TraverseChildren is set to true 193 // set TraverseChildren to true on the root cmd 194 rootCmd.TraverseChildren = true 195 196 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "") 197 if err != nil { 198 t.Errorf("Unexpected error: %v", err) 199 } 200 // Reset TraverseChildren for next command 201 rootCmd.TraverseChildren = false 202 203 expected = strings.Join([]string{ 204 "childCmd1", 205 "help", 206 ":4", 207 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 208 209 if output != expected { 210 t.Errorf("expected: %q, got: %q", expected, output) 211 } 212 213 // Test that sub-command names from a child cmd are completed if a local non-persistent flag is present 214 // and TraverseChildren is set to true on the root cmd 215 rootCmd.TraverseChildren = true 216 217 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "--nonPersistent", "value", "") 218 if err != nil { 219 t.Errorf("Unexpected error: %v", err) 220 } 221 // Reset TraverseChildren for next command 222 rootCmd.TraverseChildren = false 223 // Reset the flag for the next command 224 nonPersistentFlag.Changed = false 225 226 expected = strings.Join([]string{ 227 "childCmd2", 228 ":4", 229 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 230 231 if output != expected { 232 t.Errorf("expected: %q, got: %q", expected, output) 233 } 234 235 // Test that we don't use Traverse when we shouldn't. 236 // This command should not return a completion since the command line is invalid without TraverseChildren. 237 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--localroot", "value", "childCmd1", "") 238 if err != nil { 239 t.Errorf("Unexpected error: %v", err) 240 } 241 242 expected = strings.Join([]string{ 243 ":0", 244 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 245 246 if output != expected { 247 t.Errorf("expected: %q, got: %q", expected, output) 248 } 249 250 // Test that sub-command names are not completed if a local non-persistent short flag is present 251 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-n", "value", "") 252 if err != nil { 253 t.Errorf("Unexpected error: %v", err) 254 } 255 // Reset the flag for the next command 256 nonPersistentFlag.Changed = false 257 258 expected = strings.Join([]string{ 259 ":0", 260 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 261 262 if output != expected { 263 t.Errorf("expected: %q, got: %q", expected, output) 264 } 265 266 // Test that sub-command names are completed with a persistent flag 267 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "--persistent", "value", "") 268 if err != nil { 269 t.Errorf("Unexpected error: %v", err) 270 } 271 // Reset the flag for the next command 272 persistentFlag.Changed = false 273 274 expected = strings.Join([]string{ 275 "childCmd2", 276 ":4", 277 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 278 279 if output != expected { 280 t.Errorf("expected: %q, got: %q", expected, output) 281 } 282 283 // Test that sub-command names are completed with a persistent short flag 284 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd1", "-p", "value", "") 285 if err != nil { 286 t.Errorf("Unexpected error: %v", err) 287 } 288 // Reset the flag for the next command 289 persistentFlag.Changed = false 290 291 expected = strings.Join([]string{ 292 "childCmd2", 293 ":4", 294 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 295 296 if output != expected { 297 t.Errorf("expected: %q, got: %q", expected, output) 298 } 299} 300 301func TestValidArgsCompletionInGo(t *testing.T) { 302 rootCmd := &Command{ 303 Use: "root", 304 ValidArgs: []string{"one", "two", "three"}, 305 Args: MinimumNArgs(1), 306 } 307 308 // Test that validArgs are completed 309 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 310 if err != nil { 311 t.Errorf("Unexpected error: %v", err) 312 } 313 314 expected := strings.Join([]string{ 315 "one", 316 "two", 317 "three", 318 ":4", 319 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 320 321 if output != expected { 322 t.Errorf("expected: %q, got: %q", expected, output) 323 } 324 325 // Test that validArgs are completed with prefix 326 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "o") 327 if err != nil { 328 t.Errorf("Unexpected error: %v", err) 329 } 330 331 expected = strings.Join([]string{ 332 "one", 333 ":4", 334 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 335 336 if output != expected { 337 t.Errorf("expected: %q, got: %q", expected, output) 338 } 339 340 // Test that validArgs don't repeat 341 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "one", "") 342 if err != nil { 343 t.Errorf("Unexpected error: %v", err) 344 } 345 346 expected = strings.Join([]string{ 347 ":0", 348 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 349 350 if output != expected { 351 t.Errorf("expected: %q, got: %q", expected, output) 352 } 353} 354 355func TestValidArgsAndCmdCompletionInGo(t *testing.T) { 356 rootCmd := &Command{ 357 Use: "root", 358 ValidArgs: []string{"one", "two"}, 359 Run: emptyRun, 360 } 361 362 childCmd := &Command{ 363 Use: "thechild", 364 Run: emptyRun, 365 } 366 367 rootCmd.AddCommand(childCmd) 368 369 // Test that both sub-commands and validArgs are completed 370 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 371 if err != nil { 372 t.Errorf("Unexpected error: %v", err) 373 } 374 375 expected := strings.Join([]string{ 376 "help", 377 "thechild", 378 "one", 379 "two", 380 ":4", 381 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 382 383 if output != expected { 384 t.Errorf("expected: %q, got: %q", expected, output) 385 } 386 387 // Test that both sub-commands and validArgs are completed with prefix 388 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") 389 if err != nil { 390 t.Errorf("Unexpected error: %v", err) 391 } 392 393 expected = strings.Join([]string{ 394 "thechild", 395 "two", 396 ":4", 397 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 398 399 if output != expected { 400 t.Errorf("expected: %q, got: %q", expected, output) 401 } 402} 403 404func TestValidArgsFuncAndCmdCompletionInGo(t *testing.T) { 405 rootCmd := &Command{ 406 Use: "root", 407 ValidArgsFunction: validArgsFunc, 408 Run: emptyRun, 409 } 410 411 childCmd := &Command{ 412 Use: "thechild", 413 Short: "The child command", 414 Run: emptyRun, 415 } 416 417 rootCmd.AddCommand(childCmd) 418 419 // Test that both sub-commands and validArgsFunction are completed 420 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 421 if err != nil { 422 t.Errorf("Unexpected error: %v", err) 423 } 424 425 expected := strings.Join([]string{ 426 "help", 427 "thechild", 428 "one", 429 "two", 430 ":0", 431 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 432 433 if output != expected { 434 t.Errorf("expected: %q, got: %q", expected, output) 435 } 436 437 // Test that both sub-commands and validArgs are completed with prefix 438 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") 439 if err != nil { 440 t.Errorf("Unexpected error: %v", err) 441 } 442 443 expected = strings.Join([]string{ 444 "thechild", 445 "two", 446 ":0", 447 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 448 449 if output != expected { 450 t.Errorf("expected: %q, got: %q", expected, output) 451 } 452 453 // Test that both sub-commands and validArgs are completed with description 454 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "t") 455 if err != nil { 456 t.Errorf("Unexpected error: %v", err) 457 } 458 459 expected = strings.Join([]string{ 460 "thechild\tThe child command", 461 "two\tThe second", 462 ":0", 463 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 464 465 if output != expected { 466 t.Errorf("expected: %q, got: %q", expected, output) 467 } 468} 469 470func TestFlagNameCompletionInGo(t *testing.T) { 471 rootCmd := &Command{ 472 Use: "root", 473 Run: emptyRun, 474 } 475 childCmd := &Command{ 476 Use: "childCmd", 477 Run: emptyRun, 478 } 479 rootCmd.AddCommand(childCmd) 480 481 rootCmd.Flags().IntP("first", "f", -1, "first flag") 482 rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag") 483 childCmd.Flags().String("subFlag", "", "sub flag") 484 485 // Test that flag names are not shown if the user has not given the '-' prefix 486 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 487 if err != nil { 488 t.Errorf("Unexpected error: %v", err) 489 } 490 491 expected := strings.Join([]string{ 492 "childCmd", 493 "help", 494 ":4", 495 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 496 497 if output != expected { 498 t.Errorf("expected: %q, got: %q", expected, output) 499 } 500 501 // Test that flag names are completed 502 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-") 503 if err != nil { 504 t.Errorf("Unexpected error: %v", err) 505 } 506 507 expected = strings.Join([]string{ 508 "--first", 509 "-f", 510 "--second", 511 "-s", 512 ":4", 513 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 514 515 if output != expected { 516 t.Errorf("expected: %q, got: %q", expected, output) 517 } 518 519 // Test that flag names are completed when a prefix is given 520 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--f") 521 if err != nil { 522 t.Errorf("Unexpected error: %v", err) 523 } 524 525 expected = strings.Join([]string{ 526 "--first", 527 ":4", 528 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 529 530 if output != expected { 531 t.Errorf("expected: %q, got: %q", expected, output) 532 } 533 534 // Test that flag names are completed in a sub-cmd 535 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-") 536 if err != nil { 537 t.Errorf("Unexpected error: %v", err) 538 } 539 540 expected = strings.Join([]string{ 541 "--second", 542 "-s", 543 "--subFlag", 544 ":4", 545 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 546 547 if output != expected { 548 t.Errorf("expected: %q, got: %q", expected, output) 549 } 550} 551 552func TestFlagNameCompletionInGoWithDesc(t *testing.T) { 553 rootCmd := &Command{ 554 Use: "root", 555 Run: emptyRun, 556 } 557 childCmd := &Command{ 558 Use: "childCmd", 559 Short: "first command", 560 Run: emptyRun, 561 } 562 rootCmd.AddCommand(childCmd) 563 564 rootCmd.Flags().IntP("first", "f", -1, "first flag\nlonger description for flag") 565 rootCmd.PersistentFlags().BoolP("second", "s", false, "second flag") 566 childCmd.Flags().String("subFlag", "", "sub flag") 567 568 // Test that flag names are not shown if the user has not given the '-' prefix 569 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "") 570 if err != nil { 571 t.Errorf("Unexpected error: %v", err) 572 } 573 574 expected := strings.Join([]string{ 575 "childCmd\tfirst command", 576 "help\tHelp about any command", 577 ":4", 578 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 579 580 if output != expected { 581 t.Errorf("expected: %q, got: %q", expected, output) 582 } 583 584 // Test that flag names are completed 585 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "-") 586 if err != nil { 587 t.Errorf("Unexpected error: %v", err) 588 } 589 590 expected = strings.Join([]string{ 591 "--first\tfirst flag", 592 "-f\tfirst flag", 593 "--second\tsecond flag", 594 "-s\tsecond flag", 595 ":4", 596 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 597 598 if output != expected { 599 t.Errorf("expected: %q, got: %q", expected, output) 600 } 601 602 // Test that flag names are completed when a prefix is given 603 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--f") 604 if err != nil { 605 t.Errorf("Unexpected error: %v", err) 606 } 607 608 expected = strings.Join([]string{ 609 "--first\tfirst flag", 610 ":4", 611 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 612 613 if output != expected { 614 t.Errorf("expected: %q, got: %q", expected, output) 615 } 616 617 // Test that flag names are completed in a sub-cmd 618 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "childCmd", "-") 619 if err != nil { 620 t.Errorf("Unexpected error: %v", err) 621 } 622 623 expected = strings.Join([]string{ 624 "--second\tsecond flag", 625 "-s\tsecond flag", 626 "--subFlag\tsub flag", 627 ":4", 628 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 629 630 if output != expected { 631 t.Errorf("expected: %q, got: %q", expected, output) 632 } 633} 634 635func TestFlagNameCompletionRepeat(t *testing.T) { 636 rootCmd := &Command{ 637 Use: "root", 638 Run: emptyRun, 639 } 640 childCmd := &Command{ 641 Use: "childCmd", 642 Short: "first command", 643 Run: emptyRun, 644 } 645 rootCmd.AddCommand(childCmd) 646 647 rootCmd.Flags().IntP("first", "f", -1, "first flag") 648 firstFlag := rootCmd.Flags().Lookup("first") 649 rootCmd.Flags().BoolP("second", "s", false, "second flag") 650 secondFlag := rootCmd.Flags().Lookup("second") 651 rootCmd.Flags().StringArrayP("array", "a", nil, "array flag") 652 arrayFlag := rootCmd.Flags().Lookup("array") 653 rootCmd.Flags().IntSliceP("slice", "l", nil, "slice flag") 654 sliceFlag := rootCmd.Flags().Lookup("slice") 655 rootCmd.Flags().BoolSliceP("bslice", "b", nil, "bool slice flag") 656 bsliceFlag := rootCmd.Flags().Lookup("bslice") 657 658 // Test that flag names are not repeated unless they are an array or slice 659 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--") 660 if err != nil { 661 t.Errorf("Unexpected error: %v", err) 662 } 663 // Reset the flag for the next command 664 firstFlag.Changed = false 665 666 expected := strings.Join([]string{ 667 "--array", 668 "--bslice", 669 "--second", 670 "--slice", 671 ":4", 672 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 673 674 if output != expected { 675 t.Errorf("expected: %q, got: %q", expected, output) 676 } 677 678 // Test that flag names are not repeated unless they are an array or slice 679 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--first", "1", "--second=false", "--") 680 if err != nil { 681 t.Errorf("Unexpected error: %v", err) 682 } 683 // Reset the flag for the next command 684 firstFlag.Changed = false 685 secondFlag.Changed = false 686 687 expected = strings.Join([]string{ 688 "--array", 689 "--bslice", 690 "--slice", 691 ":4", 692 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 693 694 if output != expected { 695 t.Errorf("expected: %q, got: %q", expected, output) 696 } 697 698 // Test that flag names are not repeated unless they are an array or slice 699 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--slice", "1", "--slice=2", "--array", "val", "--bslice", "true", "--") 700 if err != nil { 701 t.Errorf("Unexpected error: %v", err) 702 } 703 // Reset the flag for the next command 704 sliceFlag.Changed = false 705 arrayFlag.Changed = false 706 bsliceFlag.Changed = false 707 708 expected = strings.Join([]string{ 709 "--array", 710 "--bslice", 711 "--first", 712 "--second", 713 "--slice", 714 ":4", 715 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 716 717 if output != expected { 718 t.Errorf("expected: %q, got: %q", expected, output) 719 } 720 721 // Test that flag names are not repeated unless they are an array or slice, using shortname 722 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-") 723 if err != nil { 724 t.Errorf("Unexpected error: %v", err) 725 } 726 // Reset the flag for the next command 727 sliceFlag.Changed = false 728 arrayFlag.Changed = false 729 730 expected = strings.Join([]string{ 731 "--array", 732 "-a", 733 "--bslice", 734 "-b", 735 "--first", 736 "-f", 737 "--second", 738 "-s", 739 "--slice", 740 "-l", 741 ":4", 742 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 743 744 if output != expected { 745 t.Errorf("expected: %q, got: %q", expected, output) 746 } 747 748 // Test that flag names are not repeated unless they are an array or slice, using shortname with prefix 749 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-l", "1", "-l=2", "-a", "val", "-a") 750 if err != nil { 751 t.Errorf("Unexpected error: %v", err) 752 } 753 // Reset the flag for the next command 754 sliceFlag.Changed = false 755 arrayFlag.Changed = false 756 757 expected = strings.Join([]string{ 758 "-a", 759 ":4", 760 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 761 762 if output != expected { 763 t.Errorf("expected: %q, got: %q", expected, output) 764 } 765} 766 767func TestRequiredFlagNameCompletionInGo(t *testing.T) { 768 rootCmd := &Command{ 769 Use: "root", 770 ValidArgs: []string{"realArg"}, 771 Run: emptyRun, 772 } 773 childCmd := &Command{ 774 Use: "childCmd", 775 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 776 return []string{"subArg"}, ShellCompDirectiveNoFileComp 777 }, 778 Run: emptyRun, 779 } 780 rootCmd.AddCommand(childCmd) 781 782 rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag") 783 rootCmd.MarkFlagRequired("requiredFlag") 784 requiredFlag := rootCmd.Flags().Lookup("requiredFlag") 785 786 rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent") 787 rootCmd.MarkPersistentFlagRequired("requiredPersistent") 788 requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent") 789 790 rootCmd.Flags().StringP("release", "R", "", "Release name") 791 792 childCmd.Flags().BoolP("subRequired", "s", false, "sub required flag") 793 childCmd.MarkFlagRequired("subRequired") 794 childCmd.Flags().BoolP("subNotRequired", "n", false, "sub not required flag") 795 796 // Test that a required flag is suggested even without the - prefix 797 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 798 if err != nil { 799 t.Errorf("Unexpected error: %v", err) 800 } 801 802 expected := strings.Join([]string{ 803 "childCmd", 804 "help", 805 "--requiredFlag", 806 "-r", 807 "--requiredPersistent", 808 "-p", 809 "realArg", 810 ":4", 811 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 812 813 if output != expected { 814 t.Errorf("expected: %q, got: %q", expected, output) 815 } 816 817 // Test that a required flag is suggested without other flags when using the '-' prefix 818 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-") 819 if err != nil { 820 t.Errorf("Unexpected error: %v", err) 821 } 822 823 expected = strings.Join([]string{ 824 "--requiredFlag", 825 "-r", 826 "--requiredPersistent", 827 "-p", 828 ":4", 829 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 830 831 if output != expected { 832 t.Errorf("expected: %q, got: %q", expected, output) 833 } 834 835 // Test that if no required flag matches, the normal flags are suggested 836 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--relea") 837 if err != nil { 838 t.Errorf("Unexpected error: %v", err) 839 } 840 841 expected = strings.Join([]string{ 842 "--release", 843 ":4", 844 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 845 846 if output != expected { 847 t.Errorf("expected: %q, got: %q", expected, output) 848 } 849 850 // Test required flags for sub-commands 851 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "") 852 if err != nil { 853 t.Errorf("Unexpected error: %v", err) 854 } 855 856 expected = strings.Join([]string{ 857 "--requiredPersistent", 858 "-p", 859 "--subRequired", 860 "-s", 861 "subArg", 862 ":4", 863 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 864 865 if output != expected { 866 t.Errorf("expected: %q, got: %q", expected, output) 867 } 868 869 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "-") 870 if err != nil { 871 t.Errorf("Unexpected error: %v", err) 872 } 873 874 expected = strings.Join([]string{ 875 "--requiredPersistent", 876 "-p", 877 "--subRequired", 878 "-s", 879 ":4", 880 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 881 882 if output != expected { 883 t.Errorf("expected: %q, got: %q", expected, output) 884 } 885 886 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "childCmd", "--subNot") 887 if err != nil { 888 t.Errorf("Unexpected error: %v", err) 889 } 890 891 expected = strings.Join([]string{ 892 "--subNotRequired", 893 ":4", 894 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 895 896 if output != expected { 897 t.Errorf("expected: %q, got: %q", expected, output) 898 } 899 900 // Test that when a required flag is present, it is not suggested anymore 901 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "") 902 if err != nil { 903 t.Errorf("Unexpected error: %v", err) 904 } 905 // Reset the flag for the next command 906 requiredFlag.Changed = false 907 908 expected = strings.Join([]string{ 909 "--requiredPersistent", 910 "-p", 911 "realArg", 912 ":4", 913 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 914 915 if output != expected { 916 t.Errorf("expected: %q, got: %q", expected, output) 917 } 918 919 // Test that when a persistent required flag is present, it is not suggested anymore 920 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredPersistent", "1", "") 921 if err != nil { 922 t.Errorf("Unexpected error: %v", err) 923 } 924 // Reset the flag for the next command 925 requiredPersistent.Changed = false 926 927 expected = strings.Join([]string{ 928 "childCmd", 929 "help", 930 "--requiredFlag", 931 "-r", 932 "realArg", 933 ":4", 934 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 935 936 if output != expected { 937 t.Errorf("expected: %q, got: %q", expected, output) 938 } 939 940 // Test that when all required flags are present, normal completion is done 941 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--requiredFlag", "1", "--requiredPersistent", "1", "") 942 if err != nil { 943 t.Errorf("Unexpected error: %v", err) 944 } 945 // Reset the flags for the next command 946 requiredFlag.Changed = false 947 requiredPersistent.Changed = false 948 949 expected = strings.Join([]string{ 950 "realArg", 951 ":4", 952 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 953 954 if output != expected { 955 t.Errorf("expected: %q, got: %q", expected, output) 956 } 957} 958 959func TestFlagFileExtFilterCompletionInGo(t *testing.T) { 960 rootCmd := &Command{ 961 Use: "root", 962 Run: emptyRun, 963 } 964 965 // No extensions. Should be ignored. 966 rootCmd.Flags().StringP("file", "f", "", "file flag") 967 rootCmd.MarkFlagFilename("file") 968 969 // Single extension 970 rootCmd.Flags().StringP("log", "l", "", "log flag") 971 rootCmd.MarkFlagFilename("log", "log") 972 973 // Multiple extensions 974 rootCmd.Flags().StringP("yaml", "y", "", "yaml flag") 975 rootCmd.MarkFlagFilename("yaml", "yaml", "yml") 976 977 // Directly using annotation 978 rootCmd.Flags().StringP("text", "t", "", "text flag") 979 rootCmd.Flags().SetAnnotation("text", BashCompFilenameExt, []string{"txt"}) 980 981 // Test that the completion logic returns the proper info for the completion 982 // script to handle the file filtering 983 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--file", "") 984 if err != nil { 985 t.Errorf("Unexpected error: %v", err) 986 } 987 988 expected := strings.Join([]string{ 989 ":0", 990 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 991 992 if output != expected { 993 t.Errorf("expected: %q, got: %q", expected, output) 994 } 995 996 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--log", "") 997 if err != nil { 998 t.Errorf("Unexpected error: %v", err) 999 } 1000 1001 expected = strings.Join([]string{ 1002 "log", 1003 ":8", 1004 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") 1005 1006 if output != expected { 1007 t.Errorf("expected: %q, got: %q", expected, output) 1008 } 1009 1010 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml", "") 1011 if err != nil { 1012 t.Errorf("Unexpected error: %v", err) 1013 } 1014 1015 expected = strings.Join([]string{ 1016 "yaml", "yml", 1017 ":8", 1018 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") 1019 1020 if output != expected { 1021 t.Errorf("expected: %q, got: %q", expected, output) 1022 } 1023 1024 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--yaml=") 1025 if err != nil { 1026 t.Errorf("Unexpected error: %v", err) 1027 } 1028 1029 expected = strings.Join([]string{ 1030 "yaml", "yml", 1031 ":8", 1032 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") 1033 1034 if output != expected { 1035 t.Errorf("expected: %q, got: %q", expected, output) 1036 } 1037 1038 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y", "") 1039 if err != nil { 1040 t.Errorf("Unexpected error: %v", err) 1041 } 1042 1043 expected = strings.Join([]string{ 1044 "yaml", "yml", 1045 ":8", 1046 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") 1047 1048 if output != expected { 1049 t.Errorf("expected: %q, got: %q", expected, output) 1050 } 1051 1052 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-y=") 1053 if err != nil { 1054 t.Errorf("Unexpected error: %v", err) 1055 } 1056 1057 expected = strings.Join([]string{ 1058 "yaml", "yml", 1059 ":8", 1060 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") 1061 1062 if output != expected { 1063 t.Errorf("expected: %q, got: %q", expected, output) 1064 } 1065 1066 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--text", "") 1067 if err != nil { 1068 t.Errorf("Unexpected error: %v", err) 1069 } 1070 1071 expected = strings.Join([]string{ 1072 "txt", 1073 ":8", 1074 "Completion ended with directive: ShellCompDirectiveFilterFileExt", ""}, "\n") 1075 1076 if output != expected { 1077 t.Errorf("expected: %q, got: %q", expected, output) 1078 } 1079} 1080 1081func TestFlagDirFilterCompletionInGo(t *testing.T) { 1082 rootCmd := &Command{ 1083 Use: "root", 1084 Run: emptyRun, 1085 } 1086 1087 // Filter directories 1088 rootCmd.Flags().StringP("dir", "d", "", "dir flag") 1089 rootCmd.MarkFlagDirname("dir") 1090 1091 // Filter directories within a directory 1092 rootCmd.Flags().StringP("subdir", "s", "", "subdir") 1093 rootCmd.Flags().SetAnnotation("subdir", BashCompSubdirsInDir, []string{"themes"}) 1094 1095 // Multiple directory specification get ignored 1096 rootCmd.Flags().StringP("manydir", "m", "", "manydir") 1097 rootCmd.Flags().SetAnnotation("manydir", BashCompSubdirsInDir, []string{"themes", "colors"}) 1098 1099 // Test that the completion logic returns the proper info for the completion 1100 // script to handle the directory filtering 1101 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--dir", "") 1102 if err != nil { 1103 t.Errorf("Unexpected error: %v", err) 1104 } 1105 1106 expected := strings.Join([]string{ 1107 ":16", 1108 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1109 1110 if output != expected { 1111 t.Errorf("expected: %q, got: %q", expected, output) 1112 } 1113 1114 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-d", "") 1115 if err != nil { 1116 t.Errorf("Unexpected error: %v", err) 1117 } 1118 1119 expected = strings.Join([]string{ 1120 ":16", 1121 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1122 1123 if output != expected { 1124 t.Errorf("expected: %q, got: %q", expected, output) 1125 } 1126 1127 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir", "") 1128 if err != nil { 1129 t.Errorf("Unexpected error: %v", err) 1130 } 1131 1132 expected = strings.Join([]string{ 1133 "themes", 1134 ":16", 1135 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1136 1137 if output != expected { 1138 t.Errorf("expected: %q, got: %q", expected, output) 1139 } 1140 1141 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--subdir=") 1142 if err != nil { 1143 t.Errorf("Unexpected error: %v", err) 1144 } 1145 1146 expected = strings.Join([]string{ 1147 "themes", 1148 ":16", 1149 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1150 1151 if output != expected { 1152 t.Errorf("expected: %q, got: %q", expected, output) 1153 } 1154 1155 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s", "") 1156 if err != nil { 1157 t.Errorf("Unexpected error: %v", err) 1158 } 1159 1160 expected = strings.Join([]string{ 1161 "themes", 1162 ":16", 1163 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1164 1165 if output != expected { 1166 t.Errorf("expected: %q, got: %q", expected, output) 1167 } 1168 1169 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "-s=") 1170 if err != nil { 1171 t.Errorf("Unexpected error: %v", err) 1172 } 1173 1174 expected = strings.Join([]string{ 1175 "themes", 1176 ":16", 1177 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1178 1179 if output != expected { 1180 t.Errorf("expected: %q, got: %q", expected, output) 1181 } 1182 1183 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--manydir", "") 1184 if err != nil { 1185 t.Errorf("Unexpected error: %v", err) 1186 } 1187 1188 expected = strings.Join([]string{ 1189 ":16", 1190 "Completion ended with directive: ShellCompDirectiveFilterDirs", ""}, "\n") 1191 1192 if output != expected { 1193 t.Errorf("expected: %q, got: %q", expected, output) 1194 } 1195} 1196 1197func TestValidArgsFuncSingleCmd(t *testing.T) { 1198 rootCmd := &Command{ 1199 Use: "root", 1200 ValidArgsFunction: validArgsFunc, 1201 Run: emptyRun, 1202 } 1203 1204 // Test completing an empty string 1205 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 1206 if err != nil { 1207 t.Errorf("Unexpected error: %v", err) 1208 } 1209 1210 expected := strings.Join([]string{ 1211 "one", 1212 "two", 1213 ":0", 1214 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1215 1216 if output != expected { 1217 t.Errorf("expected: %q, got: %q", expected, output) 1218 } 1219 1220 // Check completing with a prefix 1221 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") 1222 if err != nil { 1223 t.Errorf("Unexpected error: %v", err) 1224 } 1225 1226 expected = strings.Join([]string{ 1227 "two", 1228 ":0", 1229 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1230 1231 if output != expected { 1232 t.Errorf("expected: %q, got: %q", expected, output) 1233 } 1234} 1235 1236func TestValidArgsFuncSingleCmdInvalidArg(t *testing.T) { 1237 rootCmd := &Command{ 1238 Use: "root", 1239 // If we don't specify a value for Args, this test fails. 1240 // This is only true for a root command without any subcommands, and is caused 1241 // by the fact that the __complete command becomes a subcommand when there should not be one. 1242 // The problem is in the implementation of legacyArgs(). 1243 Args: MinimumNArgs(1), 1244 ValidArgsFunction: validArgsFunc, 1245 Run: emptyRun, 1246 } 1247 1248 // Check completing with wrong number of args 1249 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "unexpectedArg", "t") 1250 if err != nil { 1251 t.Errorf("Unexpected error: %v", err) 1252 } 1253 1254 expected := strings.Join([]string{ 1255 ":4", 1256 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1257 1258 if output != expected { 1259 t.Errorf("expected: %q, got: %q", expected, output) 1260 } 1261} 1262 1263func TestValidArgsFuncChildCmds(t *testing.T) { 1264 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1265 child1Cmd := &Command{ 1266 Use: "child1", 1267 ValidArgsFunction: validArgsFunc, 1268 Run: emptyRun, 1269 } 1270 child2Cmd := &Command{ 1271 Use: "child2", 1272 ValidArgsFunction: validArgsFunc2, 1273 Run: emptyRun, 1274 } 1275 rootCmd.AddCommand(child1Cmd, child2Cmd) 1276 1277 // Test completion of first sub-command with empty argument 1278 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "") 1279 if err != nil { 1280 t.Errorf("Unexpected error: %v", err) 1281 } 1282 1283 expected := strings.Join([]string{ 1284 "one", 1285 "two", 1286 ":0", 1287 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1288 1289 if output != expected { 1290 t.Errorf("expected: %q, got: %q", expected, output) 1291 } 1292 1293 // Test completion of first sub-command with a prefix to complete 1294 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "t") 1295 if err != nil { 1296 t.Errorf("Unexpected error: %v", err) 1297 } 1298 1299 expected = strings.Join([]string{ 1300 "two", 1301 ":0", 1302 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1303 1304 if output != expected { 1305 t.Errorf("expected: %q, got: %q", expected, output) 1306 } 1307 1308 // Check completing with wrong number of args 1309 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child1", "unexpectedArg", "t") 1310 if err != nil { 1311 t.Errorf("Unexpected error: %v", err) 1312 } 1313 1314 expected = strings.Join([]string{ 1315 ":4", 1316 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1317 1318 if output != expected { 1319 t.Errorf("expected: %q, got: %q", expected, output) 1320 } 1321 1322 // Test completion of second sub-command with empty argument 1323 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "") 1324 if err != nil { 1325 t.Errorf("Unexpected error: %v", err) 1326 } 1327 1328 expected = strings.Join([]string{ 1329 "three", 1330 "four", 1331 ":0", 1332 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1333 1334 if output != expected { 1335 t.Errorf("expected: %q, got: %q", expected, output) 1336 } 1337 1338 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "t") 1339 if err != nil { 1340 t.Errorf("Unexpected error: %v", err) 1341 } 1342 1343 expected = strings.Join([]string{ 1344 "three", 1345 ":0", 1346 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1347 1348 if output != expected { 1349 t.Errorf("expected: %q, got: %q", expected, output) 1350 } 1351 1352 // Check completing with wrong number of args 1353 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child2", "unexpectedArg", "t") 1354 if err != nil { 1355 t.Errorf("Unexpected error: %v", err) 1356 } 1357 1358 expected = strings.Join([]string{ 1359 ":4", 1360 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1361 1362 if output != expected { 1363 t.Errorf("expected: %q, got: %q", expected, output) 1364 } 1365} 1366 1367func TestValidArgsFuncAliases(t *testing.T) { 1368 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1369 child := &Command{ 1370 Use: "child", 1371 Aliases: []string{"son", "daughter"}, 1372 ValidArgsFunction: validArgsFunc, 1373 Run: emptyRun, 1374 } 1375 rootCmd.AddCommand(child) 1376 1377 // Test completion of first sub-command with empty argument 1378 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "") 1379 if err != nil { 1380 t.Errorf("Unexpected error: %v", err) 1381 } 1382 1383 expected := strings.Join([]string{ 1384 "one", 1385 "two", 1386 ":0", 1387 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1388 1389 if output != expected { 1390 t.Errorf("expected: %q, got: %q", expected, output) 1391 } 1392 1393 // Test completion of first sub-command with a prefix to complete 1394 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "daughter", "t") 1395 if err != nil { 1396 t.Errorf("Unexpected error: %v", err) 1397 } 1398 1399 expected = strings.Join([]string{ 1400 "two", 1401 ":0", 1402 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1403 1404 if output != expected { 1405 t.Errorf("expected: %q, got: %q", expected, output) 1406 } 1407 1408 // Check completing with wrong number of args 1409 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "son", "unexpectedArg", "t") 1410 if err != nil { 1411 t.Errorf("Unexpected error: %v", err) 1412 } 1413 1414 expected = strings.Join([]string{ 1415 ":4", 1416 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1417 1418 if output != expected { 1419 t.Errorf("expected: %q, got: %q", expected, output) 1420 } 1421} 1422 1423func TestValidArgsFuncInBashScript(t *testing.T) { 1424 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1425 child := &Command{ 1426 Use: "child", 1427 ValidArgsFunction: validArgsFunc, 1428 Run: emptyRun, 1429 } 1430 rootCmd.AddCommand(child) 1431 1432 buf := new(bytes.Buffer) 1433 rootCmd.GenBashCompletion(buf) 1434 output := buf.String() 1435 1436 check(t, output, "has_completion_function=1") 1437} 1438 1439func TestNoValidArgsFuncInBashScript(t *testing.T) { 1440 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1441 child := &Command{ 1442 Use: "child", 1443 Run: emptyRun, 1444 } 1445 rootCmd.AddCommand(child) 1446 1447 buf := new(bytes.Buffer) 1448 rootCmd.GenBashCompletion(buf) 1449 output := buf.String() 1450 1451 checkOmit(t, output, "has_completion_function=1") 1452} 1453 1454func TestCompleteCmdInBashScript(t *testing.T) { 1455 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1456 child := &Command{ 1457 Use: "child", 1458 ValidArgsFunction: validArgsFunc, 1459 Run: emptyRun, 1460 } 1461 rootCmd.AddCommand(child) 1462 1463 buf := new(bytes.Buffer) 1464 rootCmd.GenBashCompletion(buf) 1465 output := buf.String() 1466 1467 check(t, output, ShellCompNoDescRequestCmd) 1468} 1469 1470func TestCompleteNoDesCmdInZshScript(t *testing.T) { 1471 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1472 child := &Command{ 1473 Use: "child", 1474 ValidArgsFunction: validArgsFunc, 1475 Run: emptyRun, 1476 } 1477 rootCmd.AddCommand(child) 1478 1479 buf := new(bytes.Buffer) 1480 rootCmd.GenZshCompletionNoDesc(buf) 1481 output := buf.String() 1482 1483 check(t, output, ShellCompNoDescRequestCmd) 1484} 1485 1486func TestCompleteCmdInZshScript(t *testing.T) { 1487 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1488 child := &Command{ 1489 Use: "child", 1490 ValidArgsFunction: validArgsFunc, 1491 Run: emptyRun, 1492 } 1493 rootCmd.AddCommand(child) 1494 1495 buf := new(bytes.Buffer) 1496 rootCmd.GenZshCompletion(buf) 1497 output := buf.String() 1498 1499 check(t, output, ShellCompRequestCmd) 1500 checkOmit(t, output, ShellCompNoDescRequestCmd) 1501} 1502 1503func TestFlagCompletionInGo(t *testing.T) { 1504 rootCmd := &Command{ 1505 Use: "root", 1506 Run: emptyRun, 1507 } 1508 rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") 1509 rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 1510 completions := []string{} 1511 for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} { 1512 if strings.HasPrefix(comp, toComplete) { 1513 completions = append(completions, comp) 1514 } 1515 } 1516 return completions, ShellCompDirectiveDefault 1517 }) 1518 rootCmd.Flags().String("filename", "", "Enter a filename") 1519 rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 1520 completions := []string{} 1521 for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} { 1522 if strings.HasPrefix(comp, toComplete) { 1523 completions = append(completions, comp) 1524 } 1525 } 1526 return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp 1527 }) 1528 1529 // Test completing an empty string 1530 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "") 1531 if err != nil { 1532 t.Errorf("Unexpected error: %v", err) 1533 } 1534 1535 expected := strings.Join([]string{ 1536 "1", 1537 "2", 1538 "10", 1539 ":0", 1540 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1541 1542 if output != expected { 1543 t.Errorf("expected: %q, got: %q", expected, output) 1544 } 1545 1546 // Check completing with a prefix 1547 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "1") 1548 if err != nil { 1549 t.Errorf("Unexpected error: %v", err) 1550 } 1551 1552 expected = strings.Join([]string{ 1553 "1", 1554 "10", 1555 ":0", 1556 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1557 1558 if output != expected { 1559 t.Errorf("expected: %q, got: %q", expected, output) 1560 } 1561 1562 // Test completing an empty string 1563 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "") 1564 if err != nil { 1565 t.Errorf("Unexpected error: %v", err) 1566 } 1567 1568 expected = strings.Join([]string{ 1569 "file.yaml", 1570 "myfile.json", 1571 "file.xml", 1572 ":6", 1573 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") 1574 1575 if output != expected { 1576 t.Errorf("expected: %q, got: %q", expected, output) 1577 } 1578 1579 // Check completing with a prefix 1580 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--filename", "f") 1581 if err != nil { 1582 t.Errorf("Unexpected error: %v", err) 1583 } 1584 1585 expected = strings.Join([]string{ 1586 "file.yaml", 1587 "file.xml", 1588 ":6", 1589 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") 1590 1591 if output != expected { 1592 t.Errorf("expected: %q, got: %q", expected, output) 1593 } 1594} 1595 1596func TestValidArgsFuncChildCmdsWithDesc(t *testing.T) { 1597 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1598 child1Cmd := &Command{ 1599 Use: "child1", 1600 ValidArgsFunction: validArgsFunc, 1601 Run: emptyRun, 1602 } 1603 child2Cmd := &Command{ 1604 Use: "child2", 1605 ValidArgsFunction: validArgsFunc2, 1606 Run: emptyRun, 1607 } 1608 rootCmd.AddCommand(child1Cmd, child2Cmd) 1609 1610 // Test completion of first sub-command with empty argument 1611 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "child1", "") 1612 if err != nil { 1613 t.Errorf("Unexpected error: %v", err) 1614 } 1615 1616 expected := strings.Join([]string{ 1617 "one\tThe first", 1618 "two\tThe second", 1619 ":0", 1620 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1621 1622 if output != expected { 1623 t.Errorf("expected: %q, got: %q", expected, output) 1624 } 1625 1626 // Test completion of first sub-command with a prefix to complete 1627 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "t") 1628 if err != nil { 1629 t.Errorf("Unexpected error: %v", err) 1630 } 1631 1632 expected = strings.Join([]string{ 1633 "two\tThe second", 1634 ":0", 1635 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1636 1637 if output != expected { 1638 t.Errorf("expected: %q, got: %q", expected, output) 1639 } 1640 1641 // Check completing with wrong number of args 1642 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child1", "unexpectedArg", "t") 1643 if err != nil { 1644 t.Errorf("Unexpected error: %v", err) 1645 } 1646 1647 expected = strings.Join([]string{ 1648 ":4", 1649 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1650 1651 if output != expected { 1652 t.Errorf("expected: %q, got: %q", expected, output) 1653 } 1654 1655 // Test completion of second sub-command with empty argument 1656 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "") 1657 if err != nil { 1658 t.Errorf("Unexpected error: %v", err) 1659 } 1660 1661 expected = strings.Join([]string{ 1662 "three\tThe third", 1663 "four\tThe fourth", 1664 ":0", 1665 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1666 1667 if output != expected { 1668 t.Errorf("expected: %q, got: %q", expected, output) 1669 } 1670 1671 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "t") 1672 if err != nil { 1673 t.Errorf("Unexpected error: %v", err) 1674 } 1675 1676 expected = strings.Join([]string{ 1677 "three\tThe third", 1678 ":0", 1679 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1680 1681 if output != expected { 1682 t.Errorf("expected: %q, got: %q", expected, output) 1683 } 1684 1685 // Check completing with wrong number of args 1686 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "child2", "unexpectedArg", "t") 1687 if err != nil { 1688 t.Errorf("Unexpected error: %v", err) 1689 } 1690 1691 expected = strings.Join([]string{ 1692 ":4", 1693 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1694 1695 if output != expected { 1696 t.Errorf("expected: %q, got: %q", expected, output) 1697 } 1698} 1699 1700func TestFlagCompletionInGoWithDesc(t *testing.T) { 1701 rootCmd := &Command{ 1702 Use: "root", 1703 Run: emptyRun, 1704 } 1705 rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") 1706 rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 1707 completions := []string{} 1708 for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} { 1709 if strings.HasPrefix(comp, toComplete) { 1710 completions = append(completions, comp) 1711 } 1712 } 1713 return completions, ShellCompDirectiveDefault 1714 }) 1715 rootCmd.Flags().String("filename", "", "Enter a filename") 1716 rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 1717 completions := []string{} 1718 for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} { 1719 if strings.HasPrefix(comp, toComplete) { 1720 completions = append(completions, comp) 1721 } 1722 } 1723 return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp 1724 }) 1725 1726 // Test completing an empty string 1727 output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "") 1728 if err != nil { 1729 t.Errorf("Unexpected error: %v", err) 1730 } 1731 1732 expected := strings.Join([]string{ 1733 "1\tThe first", 1734 "2\tThe second", 1735 "10\tThe tenth", 1736 ":0", 1737 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1738 1739 if output != expected { 1740 t.Errorf("expected: %q, got: %q", expected, output) 1741 } 1742 1743 // Check completing with a prefix 1744 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "1") 1745 if err != nil { 1746 t.Errorf("Unexpected error: %v", err) 1747 } 1748 1749 expected = strings.Join([]string{ 1750 "1\tThe first", 1751 "10\tThe tenth", 1752 ":0", 1753 "Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n") 1754 1755 if output != expected { 1756 t.Errorf("expected: %q, got: %q", expected, output) 1757 } 1758 1759 // Test completing an empty string 1760 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "") 1761 if err != nil { 1762 t.Errorf("Unexpected error: %v", err) 1763 } 1764 1765 expected = strings.Join([]string{ 1766 "file.yaml\tYAML format", 1767 "myfile.json\tJSON format", 1768 "file.xml\tXML format", 1769 ":6", 1770 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") 1771 1772 if output != expected { 1773 t.Errorf("expected: %q, got: %q", expected, output) 1774 } 1775 1776 // Check completing with a prefix 1777 output, err = executeCommand(rootCmd, ShellCompRequestCmd, "--filename", "f") 1778 if err != nil { 1779 t.Errorf("Unexpected error: %v", err) 1780 } 1781 1782 expected = strings.Join([]string{ 1783 "file.yaml\tYAML format", 1784 "file.xml\tXML format", 1785 ":6", 1786 "Completion ended with directive: ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp", ""}, "\n") 1787 1788 if output != expected { 1789 t.Errorf("expected: %q, got: %q", expected, output) 1790 } 1791} 1792 1793func TestValidArgsNotValidArgsFunc(t *testing.T) { 1794 rootCmd := &Command{ 1795 Use: "root", 1796 ValidArgs: []string{"one", "two"}, 1797 ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { 1798 return []string{"three", "four"}, ShellCompDirectiveNoFileComp 1799 }, 1800 Run: emptyRun, 1801 } 1802 1803 // Test that if both ValidArgs and ValidArgsFunction are present 1804 // only ValidArgs is considered 1805 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 1806 if err != nil { 1807 t.Errorf("Unexpected error: %v", err) 1808 } 1809 1810 expected := strings.Join([]string{ 1811 "one", 1812 "two", 1813 ":4", 1814 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1815 1816 if output != expected { 1817 t.Errorf("expected: %q, got: %q", expected, output) 1818 } 1819 1820 // Check completing with a prefix 1821 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") 1822 if err != nil { 1823 t.Errorf("Unexpected error: %v", err) 1824 } 1825 1826 expected = strings.Join([]string{ 1827 "two", 1828 ":4", 1829 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1830 1831 if output != expected { 1832 t.Errorf("expected: %q, got: %q", expected, output) 1833 } 1834} 1835 1836func TestArgAliasesCompletionInGo(t *testing.T) { 1837 rootCmd := &Command{ 1838 Use: "root", 1839 Args: OnlyValidArgs, 1840 ValidArgs: []string{"one", "two", "three"}, 1841 ArgAliases: []string{"un", "deux", "trois"}, 1842 Run: emptyRun, 1843 } 1844 1845 // Test that argaliases are not completed when there are validargs that match 1846 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 1847 if err != nil { 1848 t.Errorf("Unexpected error: %v", err) 1849 } 1850 1851 expected := strings.Join([]string{ 1852 "one", 1853 "two", 1854 "three", 1855 ":4", 1856 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1857 1858 if output != expected { 1859 t.Errorf("expected: %q, got: %q", expected, output) 1860 } 1861 1862 // Test that argaliases are not completed when there are validargs that match using a prefix 1863 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "t") 1864 if err != nil { 1865 t.Errorf("Unexpected error: %v", err) 1866 } 1867 1868 expected = strings.Join([]string{ 1869 "two", 1870 "three", 1871 ":4", 1872 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1873 1874 if output != expected { 1875 t.Errorf("expected: %q, got: %q", expected, output) 1876 } 1877 1878 // Test that argaliases are completed when there are no validargs that match 1879 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "tr") 1880 if err != nil { 1881 t.Errorf("Unexpected error: %v", err) 1882 } 1883 1884 expected = strings.Join([]string{ 1885 "trois", 1886 ":4", 1887 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1888 1889 if output != expected { 1890 t.Errorf("expected: %q, got: %q", expected, output) 1891 } 1892} 1893 1894func TestCompleteHelp(t *testing.T) { 1895 rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} 1896 child1Cmd := &Command{ 1897 Use: "child1", 1898 Run: emptyRun, 1899 } 1900 child2Cmd := &Command{ 1901 Use: "child2", 1902 Run: emptyRun, 1903 } 1904 rootCmd.AddCommand(child1Cmd, child2Cmd) 1905 1906 child3Cmd := &Command{ 1907 Use: "child3", 1908 Run: emptyRun, 1909 } 1910 child1Cmd.AddCommand(child3Cmd) 1911 1912 // Test that completion includes the help command 1913 output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "") 1914 if err != nil { 1915 t.Errorf("Unexpected error: %v", err) 1916 } 1917 1918 expected := strings.Join([]string{ 1919 "child1", 1920 "child2", 1921 "help", 1922 ":4", 1923 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1924 1925 if output != expected { 1926 t.Errorf("expected: %q, got: %q", expected, output) 1927 } 1928 1929 // Test sub-commands are completed on first level of help command 1930 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "") 1931 if err != nil { 1932 t.Errorf("Unexpected error: %v", err) 1933 } 1934 1935 expected = strings.Join([]string{ 1936 "child1", 1937 "child2", 1938 "help", // "<program> help help" is a valid command, so should be completed 1939 ":4", 1940 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1941 1942 if output != expected { 1943 t.Errorf("expected: %q, got: %q", expected, output) 1944 } 1945 1946 // Test sub-commands are completed on first level of help command 1947 output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "child1", "") 1948 if err != nil { 1949 t.Errorf("Unexpected error: %v", err) 1950 } 1951 1952 expected = strings.Join([]string{ 1953 "child3", 1954 ":4", 1955 "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") 1956 1957 if output != expected { 1958 t.Errorf("expected: %q, got: %q", expected, output) 1959 } 1960} 1961