github.com/btwiuse/jiri@v0.0.0-20191125065820-53353bcfef54/cmdline/cmdline_test.go (about) 1 // Copyright 2015 The Vanadium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cmdline 6 7 import ( 8 "bytes" 9 "errors" 10 "flag" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "reflect" 17 "regexp" 18 "strconv" 19 "strings" 20 "testing" 21 22 "github.com/btwiuse/jiri/envvar" 23 ) 24 25 var ( 26 errEchoStr = "echo error" 27 flagExtra bool 28 optNoNewline bool 29 flagTopLevelExtra bool 30 31 errUsageStr = fmt.Sprint(ErrUsage) 32 ) 33 34 // runEcho is used to implement commands for our tests. 35 func runEcho(env *Env, args []string) error { 36 if len(args) == 1 { 37 if args[0] == "error" { 38 return errors.New(errEchoStr) 39 } else if args[0] == "bad_arg" { 40 return env.UsageErrorf("Invalid argument %v", args[0]) 41 } 42 } 43 if flagExtra { 44 args = append(args, "extra") 45 } 46 if flagTopLevelExtra { 47 args = append(args, "tlextra") 48 } 49 if optNoNewline { 50 fmt.Fprint(env.Stdout, args) 51 } else { 52 fmt.Fprintln(env.Stdout, args) 53 } 54 return nil 55 } 56 57 // runHello is another function for test commands. 58 func runHello(env *Env, args []string) error { 59 if flagTopLevelExtra { 60 args = append(args, "tlextra") 61 } 62 fmt.Fprintln(env.Stdout, strings.Join(append([]string{"Hello"}, args...), " ")) 63 return nil 64 } 65 66 func runDumpEnv(env *Env, args []string) error { 67 fmt.Fprintln(env.Stdout, envvar.MapToSlice(env.Vars)) 68 return nil 69 } 70 71 type testCase struct { 72 Args []string 73 Vars map[string]string 74 Err string 75 Stdout string 76 Stderr string 77 GlobalFlag1 string 78 GlobalFlag2 int64 79 } 80 81 func stripTestFlags(got string) string { 82 // The global flags include the flags from the testing package, so strip them 83 // out before the comparison. 84 re := regexp.MustCompile(" -test[^\n]+\n(?: [^\n]+\n)+") 85 return re.ReplaceAllLiteralString(got, "") 86 } 87 88 func errString(err error) string { 89 if err == nil { 90 return "" 91 } 92 return fmt.Sprint(err) 93 } 94 95 var baseVars = map[string]string{ 96 "CMDLINE_WIDTH": "80", // make sure formatting stays the same. 97 } 98 99 func runTestCases(t *testing.T, cmd *Command, tests []testCase) { 100 for _, test := range tests { 101 // Reset global variables before running each test case. 102 var stdout, stderr bytes.Buffer 103 flagExtra, flagTopLevelExtra, optNoNewline = false, false, false 104 105 // Start with a fresh flag.CommandLine for each run. 106 flag.CommandLine = flag.NewFlagSet("test", flag.ContinueOnError) 107 var globalFlag1 string 108 flag.StringVar(&globalFlag1, "global1", "", "global test flag 1") 109 globalFlag2 := flag.Int64("global2", 0, "global test flag 2") 110 if flag.CommandLine.Parsed() { 111 t.Errorf("flag.CommandLine should not be parsed yet") 112 } 113 114 // Parse and run the command and check against expected results. 115 parseOK := false 116 env := &Env{ 117 Stdout: &stdout, 118 Stderr: &stderr, 119 Vars: envvar.MergeMaps(baseVars, test.Vars), 120 } 121 runner, args, err := Parse(cmd, env, test.Args) 122 if err == nil { 123 err = runner.Run(env, args) 124 parseOK = true 125 } 126 if got, want := errString(err), test.Err; got != want { 127 t.Errorf("Ran with args %q vars %q\n GOT error:\n%q\nWANT error:\n%q", test.Args, test.Vars, got, want) 128 } 129 if got, want := stripTestFlags(stdout.String()), test.Stdout; got != want { 130 t.Errorf("Ran with args %q vars %q\n GOT stdout:\n%q\nWANT stdout:\n%q", test.Args, test.Vars, got, want) 131 } 132 if got, want := stripTestFlags(stderr.String()), test.Stderr; got != want { 133 t.Errorf("Ran with args %q vars %q\n GOT stderr:\n%q\nWANT stderr:\n%q", test.Args, test.Vars, got, want) 134 } 135 if got, want := globalFlag1, test.GlobalFlag1; got != want { 136 t.Errorf("global1 flag got %q, want %q", got, want) 137 } 138 if got, want := *globalFlag2, test.GlobalFlag2; got != want { 139 t.Errorf("global2 flag got %q, want %q", got, want) 140 } 141 142 if parseOK && !flag.CommandLine.Parsed() { 143 t.Errorf("flag.CommandLine should be parsed by now") 144 } 145 } 146 } 147 148 func TestEmptyRootName(t *testing.T) { 149 noname := &Command{ 150 Name: "", 151 Short: "Empty root name", 152 Long: "Empty root name.", 153 Runner: RunnerFunc(runHello), 154 } 155 wantErr := `CODE INVARIANT BROKEN; FIX YOUR CODE 156 157 Root command name cannot be empty.` 158 tests := []testCase{ 159 {Args: []string{}, Err: wantErr}, 160 {Args: []string{"foo"}, Err: wantErr}, 161 } 162 runTestCases(t, noname, tests) 163 } 164 165 func TestEmptyTopicName(t *testing.T) { 166 topic := Topic{ 167 Name: "", 168 Short: "noname", 169 Long: "noname", 170 } 171 parent := &Command{ 172 Name: "parent", 173 Short: "parent", 174 Long: "parent", 175 Topics: []Topic{topic}, 176 } 177 wantErr := `parent: CODE INVARIANT BROKEN; FIX YOUR CODE 178 179 Command and topic names cannot be empty.` 180 tests := []testCase{ 181 {Args: []string{}, Err: wantErr}, 182 {Args: []string{"foo"}, Err: wantErr}, 183 } 184 runTestCases(t, parent, tests) 185 grandparent := &Command{ 186 Name: "grandparent", 187 Short: "grandparent", 188 Long: "grandparent", 189 Children: []*Command{parent}, 190 } 191 wantErr = "grandparent " + wantErr 192 tests = []testCase{ 193 {Args: []string{}, Err: wantErr}, 194 {Args: []string{"foo"}, Err: wantErr}, 195 } 196 runTestCases(t, grandparent, tests) 197 } 198 199 func TestEmptyChildName(t *testing.T) { 200 child := &Command{ 201 Name: "", 202 Short: "Empty child name", 203 Long: "Empty child name.", 204 Runner: RunnerFunc(runHello), 205 } 206 parent := &Command{ 207 Name: "parent", 208 Short: "parent", 209 Long: "parent", 210 Children: []*Command{child}, 211 } 212 wantErr := `parent: CODE INVARIANT BROKEN; FIX YOUR CODE 213 214 Command and topic names cannot be empty.` 215 tests := []testCase{ 216 {Args: []string{}, Err: wantErr}, 217 {Args: []string{"foo"}, Err: wantErr}, 218 } 219 runTestCases(t, parent, tests) 220 grandparent := &Command{ 221 Name: "grandparent", 222 Short: "grandparent", 223 Long: "grandparent", 224 Children: []*Command{parent}, 225 } 226 wantErr = "grandparent " + wantErr 227 tests = []testCase{ 228 {Args: []string{}, Err: wantErr}, 229 {Args: []string{"foo"}, Err: wantErr}, 230 } 231 runTestCases(t, grandparent, tests) 232 } 233 234 func TestDuplicateNames(t *testing.T) { 235 child := &Command{ 236 Name: "duplicate", 237 Short: "Dup command name", 238 Long: "Dup command name.", 239 Runner: RunnerFunc(runHello), 240 } 241 topic := Topic{ 242 Name: "duplicate", 243 Short: "Dup topic name", 244 Long: "Dup topic name.", 245 } 246 parent := &Command{ 247 Name: "parent", 248 Short: "parent", 249 Long: "parent", 250 Children: []*Command{child}, 251 Topics: []Topic{topic}, 252 } 253 wantErr := `parent: CODE INVARIANT BROKEN; FIX YOUR CODE 254 255 Each command must have unique children and topic names. 256 Saw "duplicate" multiple times.` 257 tests := []testCase{ 258 {Args: []string{}, Err: wantErr}, 259 {Args: []string{"foo"}, Err: wantErr}, 260 } 261 runTestCases(t, parent, tests) 262 grandparent := &Command{ 263 Name: "grandparent", 264 Short: "grandparent", 265 Long: "grandparent", 266 Children: []*Command{parent}, 267 } 268 wantErr = "grandparent " + wantErr 269 tests = []testCase{ 270 {Args: []string{}, Err: wantErr}, 271 {Args: []string{"foo"}, Err: wantErr}, 272 } 273 runTestCases(t, grandparent, tests) 274 } 275 276 func TestNoChildrenOrRunner(t *testing.T) { 277 neither := &Command{ 278 Name: "neither", 279 Short: "Neither is invalid.", 280 Long: "Neither has no commands and no runner.", 281 } 282 wantErr := `neither: CODE INVARIANT BROKEN; FIX YOUR CODE 283 284 At least one of Children or Runner must be specified.` 285 tests := []testCase{ 286 {Args: []string{}, Err: wantErr}, 287 {Args: []string{"foo"}, Err: wantErr}, 288 } 289 runTestCases(t, neither, tests) 290 parent := &Command{ 291 Name: "parent", 292 Short: "parent", 293 Long: "parent", 294 Children: []*Command{neither}, 295 } 296 wantErr = "parent " + wantErr 297 tests = []testCase{ 298 {Args: []string{}, Err: wantErr}, 299 {Args: []string{"foo"}, Err: wantErr}, 300 } 301 runTestCases(t, parent, tests) 302 } 303 304 func TestBothChildrenAndRunnerWithArgs(t *testing.T) { 305 child := &Command{ 306 Name: "child", 307 Short: "Child command.", 308 Long: "Child command.", 309 Runner: RunnerFunc(runEcho), 310 } 311 both := &Command{ 312 Name: "both", 313 Short: "Both is invalid.", 314 Long: "Both has both commands and a runner with args.", 315 ArgsName: "[strings]", 316 ArgsLong: "[strings] are arbitrary strings that will be echoed.", 317 Children: []*Command{child}, 318 Runner: RunnerFunc(runEcho), 319 } 320 wantErr := `both: CODE INVARIANT BROKEN; FIX YOUR CODE 321 322 Since both Children and Runner are specified, the Runner cannot take args. 323 Otherwise a conflict between child names and runner args is possible.` 324 tests := []testCase{ 325 {Args: []string{}, Err: wantErr}, 326 {Args: []string{"foo"}, Err: wantErr}, 327 } 328 runTestCases(t, both, tests) 329 parent := &Command{ 330 Name: "parent", 331 Short: "parent", 332 Long: "parent", 333 Children: []*Command{both}, 334 } 335 wantErr = "parent " + wantErr 336 tests = []testCase{ 337 {Args: []string{}, Err: wantErr}, 338 {Args: []string{"foo"}, Err: wantErr}, 339 } 340 runTestCases(t, parent, tests) 341 } 342 343 func TestBothChildrenAndRunnerNoArgs(t *testing.T) { 344 cmdEcho := &Command{ 345 Name: "echo", 346 Short: "Print strings on stdout", 347 Long: "Echo prints any strings passed in to stdout.", 348 Runner: RunnerFunc(runEcho), 349 ArgsName: "[strings]", 350 ArgsLong: "[strings] are arbitrary strings that will be echoed.", 351 } 352 prog := &Command{ 353 Name: "cmdrun", 354 Short: "Cmdrun program.", 355 Long: "Cmdrun has the echo command and a Run function with no args.", 356 Children: []*Command{cmdEcho}, 357 Runner: RunnerFunc(runHello), 358 } 359 var tests = []testCase{ 360 { 361 Args: []string{}, 362 Stdout: "Hello\n", 363 }, 364 { 365 Args: []string{"foo"}, 366 Err: errUsageStr, 367 Stderr: `ERROR: cmdrun: unknown command "foo" 368 369 Cmdrun has the echo command and a Run function with no args. 370 371 Usage: 372 cmdrun [flags] 373 cmdrun [flags] <command> 374 375 The cmdrun commands are: 376 echo Print strings on stdout 377 help Display help for commands or topics 378 Run "cmdrun help [command]" for command usage. 379 380 The global flags are: 381 -global1= 382 global test flag 1 383 -global2=0 384 global test flag 2 385 `, 386 }, 387 { 388 Args: []string{"help"}, 389 Stdout: `Cmdrun has the echo command and a Run function with no args. 390 391 Usage: 392 cmdrun [flags] 393 cmdrun [flags] <command> 394 395 The cmdrun commands are: 396 echo Print strings on stdout 397 help Display help for commands or topics 398 Run "cmdrun help [command]" for command usage. 399 400 The global flags are: 401 -global1= 402 global test flag 1 403 -global2=0 404 global test flag 2 405 `, 406 }, 407 { 408 Args: []string{"help", "echo"}, 409 Stdout: `Echo prints any strings passed in to stdout. 410 411 Usage: 412 cmdrun echo [flags] [strings] 413 414 [strings] are arbitrary strings that will be echoed. 415 416 The global flags are: 417 -global1= 418 global test flag 1 419 -global2=0 420 global test flag 2 421 `, 422 }, 423 { 424 Args: []string{"help", "..."}, 425 Stdout: `Cmdrun has the echo command and a Run function with no args. 426 427 Usage: 428 cmdrun [flags] 429 cmdrun [flags] <command> 430 431 The cmdrun commands are: 432 echo Print strings on stdout 433 help Display help for commands or topics 434 Run "cmdrun help [command]" for command usage. 435 436 The global flags are: 437 -global1= 438 global test flag 1 439 -global2=0 440 global test flag 2 441 ================================================================================ 442 Cmdrun echo - Print strings on stdout 443 444 Echo prints any strings passed in to stdout. 445 446 Usage: 447 cmdrun echo [flags] [strings] 448 449 [strings] are arbitrary strings that will be echoed. 450 ================================================================================ 451 Cmdrun help - Display help for commands or topics 452 453 Help with no args displays the usage of the parent command. 454 455 Help with args displays the usage of the specified sub-command or help topic. 456 457 "help ..." recursively displays help for all commands and topics. 458 459 Usage: 460 cmdrun help [flags] [command/topic ...] 461 462 [command/topic ...] optionally identifies a specific sub-command or help topic. 463 464 The cmdrun help flags are: 465 -style=compact 466 The formatting style for help output: 467 compact - Good for compact cmdline output. 468 full - Good for cmdline output, shows all global flags. 469 godoc - Good for godoc processing. 470 shortonly - Only output short description. 471 Override the default by setting the CMDLINE_STYLE environment variable. 472 -width=80 473 Format output to this target width in runes, or unlimited if width < 0. 474 Defaults to the terminal width if available. Override the default by setting 475 the CMDLINE_WIDTH environment variable. 476 `, 477 }, 478 { 479 Args: []string{"help", "foo"}, 480 Err: errUsageStr, 481 Stderr: `ERROR: cmdrun: unknown command or topic "foo" 482 483 Cmdrun has the echo command and a Run function with no args. 484 485 Usage: 486 cmdrun [flags] 487 cmdrun [flags] <command> 488 489 The cmdrun commands are: 490 echo Print strings on stdout 491 help Display help for commands or topics 492 Run "cmdrun help [command]" for command usage. 493 494 The global flags are: 495 -global1= 496 global test flag 1 497 -global2=0 498 global test flag 2 499 `, 500 }, 501 { 502 Args: []string{"echo", "foo", "bar"}, 503 Stdout: "[foo bar]\n", 504 }, 505 { 506 Args: []string{"echo", "error"}, 507 Err: errEchoStr, 508 }, 509 { 510 Args: []string{"echo", "bad_arg"}, 511 Err: errUsageStr, 512 Stderr: `ERROR: Invalid argument bad_arg 513 514 Echo prints any strings passed in to stdout. 515 516 Usage: 517 cmdrun echo [flags] [strings] 518 519 [strings] are arbitrary strings that will be echoed. 520 521 The global flags are: 522 -global1= 523 global test flag 1 524 -global2=0 525 global test flag 2 526 `, 527 }, 528 } 529 runTestCases(t, prog, tests) 530 } 531 532 func TestOneCommand(t *testing.T) { 533 cmdEcho := &Command{ 534 Name: "echo", 535 Short: "Print strings on stdout", 536 Long: ` 537 Echo prints any strings passed in to stdout. 538 `, 539 Runner: RunnerFunc(runEcho), 540 ArgsName: "[strings]", 541 ArgsLong: "[strings] are arbitrary strings that will be echoed.", 542 } 543 prog := &Command{ 544 Name: "onecmd", 545 Short: "Onecmd program.", 546 Long: "Onecmd only has the echo command.", 547 Children: []*Command{cmdEcho}, 548 } 549 550 tests := []testCase{ 551 { 552 Args: []string{}, 553 Err: errUsageStr, 554 Stderr: `ERROR: onecmd: no command specified 555 556 Onecmd only has the echo command. 557 558 Usage: 559 onecmd [flags] <command> 560 561 The onecmd commands are: 562 echo Print strings on stdout 563 help Display help for commands or topics 564 Run "onecmd help [command]" for command usage. 565 566 The global flags are: 567 -global1= 568 global test flag 1 569 -global2=0 570 global test flag 2 571 `, 572 }, 573 { 574 Args: []string{"foo"}, 575 Err: errUsageStr, 576 Stderr: `ERROR: onecmd: unknown command "foo" 577 578 Onecmd only has the echo command. 579 580 Usage: 581 onecmd [flags] <command> 582 583 The onecmd commands are: 584 echo Print strings on stdout 585 help Display help for commands or topics 586 Run "onecmd help [command]" for command usage. 587 588 The global flags are: 589 -global1= 590 global test flag 1 591 -global2=0 592 global test flag 2 593 `, 594 }, 595 { 596 Args: []string{"help"}, 597 Stdout: `Onecmd only has the echo command. 598 599 Usage: 600 onecmd [flags] <command> 601 602 The onecmd commands are: 603 echo Print strings on stdout 604 help Display help for commands or topics 605 Run "onecmd help [command]" for command usage. 606 607 The global flags are: 608 -global1= 609 global test flag 1 610 -global2=0 611 global test flag 2 612 `, 613 }, 614 { 615 Args: []string{"help", "echo"}, 616 Stdout: `Echo prints any strings passed in to stdout. 617 618 Usage: 619 onecmd echo [flags] [strings] 620 621 [strings] are arbitrary strings that will be echoed. 622 623 The global flags are: 624 -global1= 625 global test flag 1 626 -global2=0 627 global test flag 2 628 `, 629 }, 630 { 631 Args: []string{"help", "help"}, 632 Stdout: `Help with no args displays the usage of the parent command. 633 634 Help with args displays the usage of the specified sub-command or help topic. 635 636 "help ..." recursively displays help for all commands and topics. 637 638 Usage: 639 onecmd help [flags] [command/topic ...] 640 641 [command/topic ...] optionally identifies a specific sub-command or help topic. 642 643 The onecmd help flags are: 644 -style=compact 645 The formatting style for help output: 646 compact - Good for compact cmdline output. 647 full - Good for cmdline output, shows all global flags. 648 godoc - Good for godoc processing. 649 shortonly - Only output short description. 650 Override the default by setting the CMDLINE_STYLE environment variable. 651 -width=80 652 Format output to this target width in runes, or unlimited if width < 0. 653 Defaults to the terminal width if available. Override the default by setting 654 the CMDLINE_WIDTH environment variable. 655 656 The global flags are: 657 -global1= 658 global test flag 1 659 -global2=0 660 global test flag 2 661 `, 662 }, 663 { 664 Args: []string{"help", "..."}, 665 Stdout: `Onecmd only has the echo command. 666 667 Usage: 668 onecmd [flags] <command> 669 670 The onecmd commands are: 671 echo Print strings on stdout 672 help Display help for commands or topics 673 Run "onecmd help [command]" for command usage. 674 675 The global flags are: 676 -global1= 677 global test flag 1 678 -global2=0 679 global test flag 2 680 ================================================================================ 681 Onecmd echo - Print strings on stdout 682 683 Echo prints any strings passed in to stdout. 684 685 Usage: 686 onecmd echo [flags] [strings] 687 688 [strings] are arbitrary strings that will be echoed. 689 ================================================================================ 690 Onecmd help - Display help for commands or topics 691 692 Help with no args displays the usage of the parent command. 693 694 Help with args displays the usage of the specified sub-command or help topic. 695 696 "help ..." recursively displays help for all commands and topics. 697 698 Usage: 699 onecmd help [flags] [command/topic ...] 700 701 [command/topic ...] optionally identifies a specific sub-command or help topic. 702 703 The onecmd help flags are: 704 -style=compact 705 The formatting style for help output: 706 compact - Good for compact cmdline output. 707 full - Good for cmdline output, shows all global flags. 708 godoc - Good for godoc processing. 709 shortonly - Only output short description. 710 Override the default by setting the CMDLINE_STYLE environment variable. 711 -width=80 712 Format output to this target width in runes, or unlimited if width < 0. 713 Defaults to the terminal width if available. Override the default by setting 714 the CMDLINE_WIDTH environment variable. 715 `, 716 }, 717 { 718 Args: []string{"help", "foo"}, 719 Err: errUsageStr, 720 Stderr: `ERROR: onecmd: unknown command or topic "foo" 721 722 Onecmd only has the echo command. 723 724 Usage: 725 onecmd [flags] <command> 726 727 The onecmd commands are: 728 echo Print strings on stdout 729 help Display help for commands or topics 730 Run "onecmd help [command]" for command usage. 731 732 The global flags are: 733 -global1= 734 global test flag 1 735 -global2=0 736 global test flag 2 737 `, 738 }, 739 { 740 Args: []string{"echo", "foo", "bar"}, 741 Stdout: "[foo bar]\n", 742 }, 743 { 744 Args: []string{"echo", "error"}, 745 Err: errEchoStr, 746 }, 747 { 748 Args: []string{"echo", "bad_arg"}, 749 Err: errUsageStr, 750 Stderr: `ERROR: Invalid argument bad_arg 751 752 Echo prints any strings passed in to stdout. 753 754 Usage: 755 onecmd echo [flags] [strings] 756 757 [strings] are arbitrary strings that will be echoed. 758 759 The global flags are: 760 -global1= 761 global test flag 1 762 -global2=0 763 global test flag 2 764 `, 765 }, 766 } 767 runTestCases(t, prog, tests) 768 } 769 770 func TestMultiCommands(t *testing.T) { 771 cmdEcho := &Command{ 772 Runner: RunnerFunc(runEcho), 773 Name: "echo", 774 Short: "Print strings on stdout", 775 Long: ` 776 Echo prints any strings passed in to stdout. 777 `, 778 ArgsName: "[strings]", 779 ArgsLong: "[strings] are arbitrary strings that will be echoed.", 780 } 781 var cmdEchoOpt = &Command{ 782 Runner: RunnerFunc(runEcho), 783 Name: "echoopt", 784 Short: "Print strings on stdout with opts", 785 // Try varying number of header/trailer newlines around the long description. 786 Long: `Echoopt prints any args passed in to stdout. 787 788 789 `, 790 ArgsName: "[args]", 791 ArgsLong: "[args] are arbitrary strings that will be echoed.", 792 } 793 cmdEchoOpt.Flags.BoolVar(&optNoNewline, "n", false, "Do not output trailing newline") 794 795 prog := &Command{ 796 Name: "multi", 797 Short: "Multi test command", 798 Long: "Multi has two variants of echo.", 799 Children: []*Command{cmdEcho, cmdEchoOpt}, 800 } 801 prog.Flags.BoolVar(&flagExtra, "extra", false, "Print an extra arg") 802 803 var tests = []testCase{ 804 { 805 Args: []string{}, 806 Err: errUsageStr, 807 Stderr: `ERROR: multi: no command specified 808 809 Multi has two variants of echo. 810 811 Usage: 812 multi [flags] <command> 813 814 The multi commands are: 815 echo Print strings on stdout 816 echoopt Print strings on stdout with opts 817 help Display help for commands or topics 818 Run "multi help [command]" for command usage. 819 820 The multi flags are: 821 -extra=false 822 Print an extra arg 823 824 The global flags are: 825 -global1= 826 global test flag 1 827 -global2=0 828 global test flag 2 829 `, 830 }, 831 { 832 Args: []string{"help"}, 833 Stdout: `Multi has two variants of echo. 834 835 Usage: 836 multi [flags] <command> 837 838 The multi commands are: 839 echo Print strings on stdout 840 echoopt Print strings on stdout with opts 841 help Display help for commands or topics 842 Run "multi help [command]" for command usage. 843 844 The multi flags are: 845 -extra=false 846 Print an extra arg 847 848 The global flags are: 849 -global1= 850 global test flag 1 851 -global2=0 852 global test flag 2 853 `, 854 }, 855 { 856 Args: []string{"help", "..."}, 857 Stdout: `Multi has two variants of echo. 858 859 Usage: 860 multi [flags] <command> 861 862 The multi commands are: 863 echo Print strings on stdout 864 echoopt Print strings on stdout with opts 865 help Display help for commands or topics 866 Run "multi help [command]" for command usage. 867 868 The multi flags are: 869 -extra=false 870 Print an extra arg 871 872 The global flags are: 873 -global1= 874 global test flag 1 875 -global2=0 876 global test flag 2 877 ================================================================================ 878 Multi echo - Print strings on stdout 879 880 Echo prints any strings passed in to stdout. 881 882 Usage: 883 multi echo [flags] [strings] 884 885 [strings] are arbitrary strings that will be echoed. 886 887 Run "multi help -style=full echo" to show all flags. 888 ================================================================================ 889 Multi echoopt - Print strings on stdout with opts 890 891 Echoopt prints any args passed in to stdout. 892 893 Usage: 894 multi echoopt [flags] [args] 895 896 [args] are arbitrary strings that will be echoed. 897 898 The multi echoopt flags are: 899 -n=false 900 Do not output trailing newline 901 902 Run "multi help -style=full echoopt" to show all flags. 903 ================================================================================ 904 Multi help - Display help for commands or topics 905 906 Help with no args displays the usage of the parent command. 907 908 Help with args displays the usage of the specified sub-command or help topic. 909 910 "help ..." recursively displays help for all commands and topics. 911 912 Usage: 913 multi help [flags] [command/topic ...] 914 915 [command/topic ...] optionally identifies a specific sub-command or help topic. 916 917 The multi help flags are: 918 -style=compact 919 The formatting style for help output: 920 compact - Good for compact cmdline output. 921 full - Good for cmdline output, shows all global flags. 922 godoc - Good for godoc processing. 923 shortonly - Only output short description. 924 Override the default by setting the CMDLINE_STYLE environment variable. 925 -width=80 926 Format output to this target width in runes, or unlimited if width < 0. 927 Defaults to the terminal width if available. Override the default by setting 928 the CMDLINE_WIDTH environment variable. 929 `, 930 }, 931 { 932 Args: []string{"help", "echo"}, 933 Stdout: `Echo prints any strings passed in to stdout. 934 935 Usage: 936 multi echo [flags] [strings] 937 938 [strings] are arbitrary strings that will be echoed. 939 940 The global flags are: 941 -global1= 942 global test flag 1 943 -global2=0 944 global test flag 2 945 946 Run "multi help -style=full echo" to show all flags. 947 `, 948 }, 949 { 950 Args: []string{"help", "echoopt"}, 951 Stdout: `Echoopt prints any args passed in to stdout. 952 953 Usage: 954 multi echoopt [flags] [args] 955 956 [args] are arbitrary strings that will be echoed. 957 958 The multi echoopt flags are: 959 -n=false 960 Do not output trailing newline 961 962 The global flags are: 963 -global1= 964 global test flag 1 965 -global2=0 966 global test flag 2 967 968 Run "multi help -style=full echoopt" to show all flags. 969 `, 970 }, 971 { 972 Args: []string{"help", "foo"}, 973 Err: errUsageStr, 974 Stderr: `ERROR: multi: unknown command or topic "foo" 975 976 Multi has two variants of echo. 977 978 Usage: 979 multi [flags] <command> 980 981 The multi commands are: 982 echo Print strings on stdout 983 echoopt Print strings on stdout with opts 984 help Display help for commands or topics 985 Run "multi help [command]" for command usage. 986 987 The multi flags are: 988 -extra=false 989 Print an extra arg 990 991 The global flags are: 992 -global1= 993 global test flag 1 994 -global2=0 995 global test flag 2 996 `, 997 }, 998 { 999 Args: []string{"echo", "foo", "bar"}, 1000 Stdout: "[foo bar]\n", 1001 }, 1002 { 1003 Args: []string{"-extra", "echo", "foo", "bar"}, 1004 Stdout: "[foo bar extra]\n", 1005 }, 1006 { 1007 Args: []string{"echo", "error"}, 1008 Err: errEchoStr, 1009 }, 1010 { 1011 Args: []string{"echoopt", "foo", "bar"}, 1012 Stdout: "[foo bar]\n", 1013 }, 1014 { 1015 Args: []string{"-extra", "echoopt", "foo", "bar"}, 1016 Stdout: "[foo bar extra]\n", 1017 }, 1018 { 1019 Args: []string{"echoopt", "-n", "foo", "bar"}, 1020 Stdout: "[foo bar]", 1021 }, 1022 { 1023 Args: []string{"-extra", "echoopt", "-n", "foo", "bar"}, 1024 Stdout: "[foo bar extra]", 1025 }, 1026 { 1027 Args: []string{"-global1=globalStringValue", "-extra", "echoopt", "-n", "foo", "bar"}, 1028 Stdout: "[foo bar extra]", 1029 GlobalFlag1: "globalStringValue", 1030 }, 1031 { 1032 Args: []string{"-global2=42", "echoopt", "-n", "foo", "bar"}, 1033 Stdout: "[foo bar]", 1034 GlobalFlag2: 42, 1035 }, 1036 { 1037 Args: []string{"-global1=globalStringOtherValue", "-global2=43", "-extra", "echoopt", "-n", "foo", "bar"}, 1038 Stdout: "[foo bar extra]", 1039 GlobalFlag1: "globalStringOtherValue", 1040 GlobalFlag2: 43, 1041 }, 1042 { 1043 Args: []string{"echoopt", "error"}, 1044 Err: errEchoStr, 1045 }, 1046 { 1047 Args: []string{"echo", "-n", "foo", "bar"}, 1048 Err: errUsageStr, 1049 Stderr: `ERROR: multi echo: flag provided but not defined: -n 1050 1051 Echo prints any strings passed in to stdout. 1052 1053 Usage: 1054 multi echo [flags] [strings] 1055 1056 [strings] are arbitrary strings that will be echoed. 1057 1058 The global flags are: 1059 -global1= 1060 global test flag 1 1061 -global2=0 1062 global test flag 2 1063 1064 Run "multi help -style=full echo" to show all flags. 1065 `, 1066 }, 1067 { 1068 Args: []string{"-nosuchflag", "echo", "foo", "bar"}, 1069 Err: errUsageStr, 1070 Stderr: `ERROR: multi: flag provided but not defined: -nosuchflag 1071 1072 Multi has two variants of echo. 1073 1074 Usage: 1075 multi [flags] <command> 1076 1077 The multi commands are: 1078 echo Print strings on stdout 1079 echoopt Print strings on stdout with opts 1080 help Display help for commands or topics 1081 Run "multi help [command]" for command usage. 1082 1083 The multi flags are: 1084 -extra=false 1085 Print an extra arg 1086 1087 The global flags are: 1088 -global1= 1089 global test flag 1 1090 -global2=0 1091 global test flag 2 1092 `, 1093 }, 1094 } 1095 runTestCases(t, prog, tests) 1096 } 1097 1098 func TestMultiLevelCommands(t *testing.T) { 1099 cmdEcho := &Command{ 1100 Runner: RunnerFunc(runEcho), 1101 Name: "echo", 1102 Short: "Print strings on stdout", 1103 Long: ` 1104 Echo prints any strings passed in to stdout. 1105 `, 1106 ArgsName: "[strings]", 1107 ArgsLong: "[strings] are arbitrary strings that will be echoed.", 1108 } 1109 cmdEchoOpt := &Command{ 1110 Runner: RunnerFunc(runEcho), 1111 Name: "echoopt", 1112 Short: "Print strings on stdout with opts", 1113 // Try varying number of header/trailer newlines around the long description. 1114 Long: `Echoopt prints any args passed in to stdout. 1115 1116 1117 `, 1118 ArgsName: "[args]", 1119 ArgsLong: "[args] are arbitrary strings that will be echoed.", 1120 } 1121 cmdEchoOpt.Flags.BoolVar(&optNoNewline, "n", false, "Do not output trailing newline") 1122 cmdHello := &Command{ 1123 Runner: RunnerFunc(runHello), 1124 Name: "hello", 1125 Short: "Print strings on stdout preceded by Hello", 1126 Long: ` 1127 Hello prints any strings passed in to stdout preceded by "Hello". 1128 `, 1129 ArgsName: "[strings]", 1130 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1131 } 1132 echoProg := &Command{ 1133 Name: "echoprog", 1134 Short: "Set of echo commands", 1135 Long: "Echoprog has two variants of echo.", 1136 Children: []*Command{cmdEcho, cmdEchoOpt}, 1137 Topics: []Topic{ 1138 {Name: "topic3", Short: "Help topic 3 short", Long: "Help topic 3 long."}, 1139 }, 1140 } 1141 echoProg.Flags.BoolVar(&flagExtra, "extra", false, "Print an extra arg") 1142 prog := &Command{ 1143 Name: "toplevelprog", 1144 Short: "Top level prog", 1145 Long: "Toplevelprog has the echo subprogram and the hello command.", 1146 Children: []*Command{echoProg, cmdHello}, 1147 Topics: []Topic{ 1148 {Name: "topic1", Short: "Help topic 1 short", Long: "Help topic 1 long."}, 1149 {Name: "topic2", Short: "Help topic 2 short", Long: "Help topic 2 long."}, 1150 }, 1151 } 1152 prog.Flags.BoolVar(&flagTopLevelExtra, "tlextra", false, "Print an extra arg for all commands") 1153 1154 var tests = []testCase{ 1155 { 1156 Args: []string{}, 1157 Err: errUsageStr, 1158 Stderr: `ERROR: toplevelprog: no command specified 1159 1160 Toplevelprog has the echo subprogram and the hello command. 1161 1162 Usage: 1163 toplevelprog [flags] <command> 1164 1165 The toplevelprog commands are: 1166 echoprog Set of echo commands 1167 hello Print strings on stdout preceded by Hello 1168 help Display help for commands or topics 1169 Run "toplevelprog help [command]" for command usage. 1170 1171 The toplevelprog additional help topics are: 1172 topic1 Help topic 1 short 1173 topic2 Help topic 2 short 1174 Run "toplevelprog help [topic]" for topic details. 1175 1176 The toplevelprog flags are: 1177 -tlextra=false 1178 Print an extra arg for all commands 1179 1180 The global flags are: 1181 -global1= 1182 global test flag 1 1183 -global2=0 1184 global test flag 2 1185 `, 1186 }, 1187 { 1188 Args: []string{"help"}, 1189 Stdout: `Toplevelprog has the echo subprogram and the hello command. 1190 1191 Usage: 1192 toplevelprog [flags] <command> 1193 1194 The toplevelprog commands are: 1195 echoprog Set of echo commands 1196 hello Print strings on stdout preceded by Hello 1197 help Display help for commands or topics 1198 Run "toplevelprog help [command]" for command usage. 1199 1200 The toplevelprog additional help topics are: 1201 topic1 Help topic 1 short 1202 topic2 Help topic 2 short 1203 Run "toplevelprog help [topic]" for topic details. 1204 1205 The toplevelprog flags are: 1206 -tlextra=false 1207 Print an extra arg for all commands 1208 1209 The global flags are: 1210 -global1= 1211 global test flag 1 1212 -global2=0 1213 global test flag 2 1214 `, 1215 }, 1216 { 1217 Args: []string{"help", "..."}, 1218 Stdout: `Toplevelprog has the echo subprogram and the hello command. 1219 1220 Usage: 1221 toplevelprog [flags] <command> 1222 1223 The toplevelprog commands are: 1224 echoprog Set of echo commands 1225 hello Print strings on stdout preceded by Hello 1226 help Display help for commands or topics 1227 Run "toplevelprog help [command]" for command usage. 1228 1229 The toplevelprog additional help topics are: 1230 topic1 Help topic 1 short 1231 topic2 Help topic 2 short 1232 Run "toplevelprog help [topic]" for topic details. 1233 1234 The toplevelprog flags are: 1235 -tlextra=false 1236 Print an extra arg for all commands 1237 1238 The global flags are: 1239 -global1= 1240 global test flag 1 1241 -global2=0 1242 global test flag 2 1243 ================================================================================ 1244 Toplevelprog echoprog - Set of echo commands 1245 1246 Echoprog has two variants of echo. 1247 1248 Usage: 1249 toplevelprog echoprog [flags] <command> 1250 1251 The toplevelprog echoprog commands are: 1252 echo Print strings on stdout 1253 echoopt Print strings on stdout with opts 1254 1255 The toplevelprog echoprog additional help topics are: 1256 topic3 Help topic 3 short 1257 1258 The toplevelprog echoprog flags are: 1259 -extra=false 1260 Print an extra arg 1261 1262 Run "toplevelprog echoprog help -style=full" to show all flags. 1263 ================================================================================ 1264 Toplevelprog echoprog echo - Print strings on stdout 1265 1266 Echo prints any strings passed in to stdout. 1267 1268 Usage: 1269 toplevelprog echoprog echo [flags] [strings] 1270 1271 [strings] are arbitrary strings that will be echoed. 1272 1273 Run "toplevelprog echoprog help -style=full echo" to show all flags. 1274 ================================================================================ 1275 Toplevelprog echoprog echoopt - Print strings on stdout with opts 1276 1277 Echoopt prints any args passed in to stdout. 1278 1279 Usage: 1280 toplevelprog echoprog echoopt [flags] [args] 1281 1282 [args] are arbitrary strings that will be echoed. 1283 1284 The toplevelprog echoprog echoopt flags are: 1285 -n=false 1286 Do not output trailing newline 1287 1288 Run "toplevelprog echoprog help -style=full echoopt" to show all flags. 1289 ================================================================================ 1290 Toplevelprog echoprog topic3 - Help topic 3 short 1291 1292 Help topic 3 long. 1293 ================================================================================ 1294 Toplevelprog hello - Print strings on stdout preceded by Hello 1295 1296 Hello prints any strings passed in to stdout preceded by "Hello". 1297 1298 Usage: 1299 toplevelprog hello [flags] [strings] 1300 1301 [strings] are arbitrary strings that will be printed. 1302 1303 Run "toplevelprog help -style=full hello" to show all flags. 1304 ================================================================================ 1305 Toplevelprog help - Display help for commands or topics 1306 1307 Help with no args displays the usage of the parent command. 1308 1309 Help with args displays the usage of the specified sub-command or help topic. 1310 1311 "help ..." recursively displays help for all commands and topics. 1312 1313 Usage: 1314 toplevelprog help [flags] [command/topic ...] 1315 1316 [command/topic ...] optionally identifies a specific sub-command or help topic. 1317 1318 The toplevelprog help flags are: 1319 -style=compact 1320 The formatting style for help output: 1321 compact - Good for compact cmdline output. 1322 full - Good for cmdline output, shows all global flags. 1323 godoc - Good for godoc processing. 1324 shortonly - Only output short description. 1325 Override the default by setting the CMDLINE_STYLE environment variable. 1326 -width=80 1327 Format output to this target width in runes, or unlimited if width < 0. 1328 Defaults to the terminal width if available. Override the default by setting 1329 the CMDLINE_WIDTH environment variable. 1330 ================================================================================ 1331 Toplevelprog topic1 - Help topic 1 short 1332 1333 Help topic 1 long. 1334 ================================================================================ 1335 Toplevelprog topic2 - Help topic 2 short 1336 1337 Help topic 2 long. 1338 `, 1339 }, 1340 { 1341 Args: []string{"help", "echoprog"}, 1342 Stdout: `Echoprog has two variants of echo. 1343 1344 Usage: 1345 toplevelprog echoprog [flags] <command> 1346 1347 The toplevelprog echoprog commands are: 1348 echo Print strings on stdout 1349 echoopt Print strings on stdout with opts 1350 help Display help for commands or topics 1351 Run "toplevelprog echoprog help [command]" for command usage. 1352 1353 The toplevelprog echoprog additional help topics are: 1354 topic3 Help topic 3 short 1355 Run "toplevelprog echoprog help [topic]" for topic details. 1356 1357 The toplevelprog echoprog flags are: 1358 -extra=false 1359 Print an extra arg 1360 1361 The global flags are: 1362 -global1= 1363 global test flag 1 1364 -global2=0 1365 global test flag 2 1366 1367 Run "toplevelprog echoprog help -style=full" to show all flags. 1368 `, 1369 }, 1370 { 1371 Args: []string{"help", "topic1"}, 1372 Stdout: `Help topic 1 long. 1373 `, 1374 }, 1375 { 1376 Args: []string{"help", "topic2"}, 1377 Stdout: `Help topic 2 long. 1378 `, 1379 }, 1380 { 1381 Args: []string{"echoprog", "help", "..."}, 1382 Stdout: `Echoprog has two variants of echo. 1383 1384 Usage: 1385 toplevelprog echoprog [flags] <command> 1386 1387 The toplevelprog echoprog commands are: 1388 echo Print strings on stdout 1389 echoopt Print strings on stdout with opts 1390 help Display help for commands or topics 1391 Run "toplevelprog echoprog help [command]" for command usage. 1392 1393 The toplevelprog echoprog additional help topics are: 1394 topic3 Help topic 3 short 1395 Run "toplevelprog echoprog help [topic]" for topic details. 1396 1397 The toplevelprog echoprog flags are: 1398 -extra=false 1399 Print an extra arg 1400 1401 The global flags are: 1402 -global1= 1403 global test flag 1 1404 -global2=0 1405 global test flag 2 1406 1407 Run "toplevelprog echoprog help -style=full" to show all flags. 1408 ================================================================================ 1409 Toplevelprog echoprog echo - Print strings on stdout 1410 1411 Echo prints any strings passed in to stdout. 1412 1413 Usage: 1414 toplevelprog echoprog echo [flags] [strings] 1415 1416 [strings] are arbitrary strings that will be echoed. 1417 1418 Run "toplevelprog echoprog help -style=full echo" to show all flags. 1419 ================================================================================ 1420 Toplevelprog echoprog echoopt - Print strings on stdout with opts 1421 1422 Echoopt prints any args passed in to stdout. 1423 1424 Usage: 1425 toplevelprog echoprog echoopt [flags] [args] 1426 1427 [args] are arbitrary strings that will be echoed. 1428 1429 The toplevelprog echoprog echoopt flags are: 1430 -n=false 1431 Do not output trailing newline 1432 1433 Run "toplevelprog echoprog help -style=full echoopt" to show all flags. 1434 ================================================================================ 1435 Toplevelprog echoprog help - Display help for commands or topics 1436 1437 Help with no args displays the usage of the parent command. 1438 1439 Help with args displays the usage of the specified sub-command or help topic. 1440 1441 "help ..." recursively displays help for all commands and topics. 1442 1443 Usage: 1444 toplevelprog echoprog help [flags] [command/topic ...] 1445 1446 [command/topic ...] optionally identifies a specific sub-command or help topic. 1447 1448 The toplevelprog echoprog help flags are: 1449 -style=compact 1450 The formatting style for help output: 1451 compact - Good for compact cmdline output. 1452 full - Good for cmdline output, shows all global flags. 1453 godoc - Good for godoc processing. 1454 shortonly - Only output short description. 1455 Override the default by setting the CMDLINE_STYLE environment variable. 1456 -width=80 1457 Format output to this target width in runes, or unlimited if width < 0. 1458 Defaults to the terminal width if available. Override the default by setting 1459 the CMDLINE_WIDTH environment variable. 1460 ================================================================================ 1461 Toplevelprog echoprog topic3 - Help topic 3 short 1462 1463 Help topic 3 long. 1464 `, 1465 }, 1466 { 1467 Args: []string{"echoprog", "help", "echoopt"}, 1468 Stdout: `Echoopt prints any args passed in to stdout. 1469 1470 Usage: 1471 toplevelprog echoprog echoopt [flags] [args] 1472 1473 [args] are arbitrary strings that will be echoed. 1474 1475 The toplevelprog echoprog echoopt flags are: 1476 -n=false 1477 Do not output trailing newline 1478 1479 The global flags are: 1480 -global1= 1481 global test flag 1 1482 -global2=0 1483 global test flag 2 1484 1485 Run "toplevelprog echoprog help -style=full echoopt" to show all flags. 1486 `, 1487 }, 1488 { 1489 Args: []string{"help", "echoprog", "topic3"}, 1490 Stdout: `Help topic 3 long. 1491 `, 1492 }, 1493 { 1494 Args: []string{"echoprog", "help", "topic3"}, 1495 Stdout: `Help topic 3 long. 1496 `, 1497 }, 1498 { 1499 Args: []string{"help", "hello"}, 1500 Stdout: `Hello prints any strings passed in to stdout preceded by "Hello". 1501 1502 Usage: 1503 toplevelprog hello [flags] [strings] 1504 1505 [strings] are arbitrary strings that will be printed. 1506 1507 The global flags are: 1508 -global1= 1509 global test flag 1 1510 -global2=0 1511 global test flag 2 1512 1513 Run "toplevelprog help -style=full hello" to show all flags. 1514 `, 1515 }, 1516 { 1517 Args: []string{"help", "foo"}, 1518 Err: errUsageStr, 1519 Stderr: `ERROR: toplevelprog: unknown command or topic "foo" 1520 1521 Toplevelprog has the echo subprogram and the hello command. 1522 1523 Usage: 1524 toplevelprog [flags] <command> 1525 1526 The toplevelprog commands are: 1527 echoprog Set of echo commands 1528 hello Print strings on stdout preceded by Hello 1529 help Display help for commands or topics 1530 Run "toplevelprog help [command]" for command usage. 1531 1532 The toplevelprog additional help topics are: 1533 topic1 Help topic 1 short 1534 topic2 Help topic 2 short 1535 Run "toplevelprog help [topic]" for topic details. 1536 1537 The toplevelprog flags are: 1538 -tlextra=false 1539 Print an extra arg for all commands 1540 1541 The global flags are: 1542 -global1= 1543 global test flag 1 1544 -global2=0 1545 global test flag 2 1546 `, 1547 }, 1548 { 1549 Args: []string{"echoprog", "echo", "foo", "bar"}, 1550 Stdout: "[foo bar]\n", 1551 }, 1552 { 1553 Args: []string{"echoprog", "-extra", "echo", "foo", "bar"}, 1554 Stdout: "[foo bar extra]\n", 1555 }, 1556 { 1557 Args: []string{"echoprog", "echo", "error"}, 1558 Err: errEchoStr, 1559 }, 1560 { 1561 Args: []string{"echoprog", "echoopt", "foo", "bar"}, 1562 Stdout: "[foo bar]\n", 1563 }, 1564 { 1565 Args: []string{"echoprog", "-extra", "echoopt", "foo", "bar"}, 1566 Stdout: "[foo bar extra]\n", 1567 }, 1568 { 1569 Args: []string{"echoprog", "echoopt", "-n", "foo", "bar"}, 1570 Stdout: "[foo bar]", 1571 }, 1572 { 1573 Args: []string{"echoprog", "-extra", "echoopt", "-n", "foo", "bar"}, 1574 Stdout: "[foo bar extra]", 1575 }, 1576 { 1577 Args: []string{"echoprog", "echoopt", "error"}, 1578 Err: errEchoStr, 1579 }, 1580 { 1581 Args: []string{"--tlextra", "echoprog", "-extra", "echoopt", "foo", "bar"}, 1582 Stdout: "[foo bar extra tlextra]\n", 1583 }, 1584 { 1585 Args: []string{"hello", "foo", "bar"}, 1586 Stdout: "Hello foo bar\n", 1587 }, 1588 { 1589 Args: []string{"--tlextra", "hello", "foo", "bar"}, 1590 Stdout: "Hello foo bar tlextra\n", 1591 }, 1592 { 1593 Args: []string{"hello", "--extra", "foo", "bar"}, 1594 Err: errUsageStr, 1595 Stderr: `ERROR: toplevelprog hello: flag provided but not defined: -extra 1596 1597 Hello prints any strings passed in to stdout preceded by "Hello". 1598 1599 Usage: 1600 toplevelprog hello [flags] [strings] 1601 1602 [strings] are arbitrary strings that will be printed. 1603 1604 The global flags are: 1605 -global1= 1606 global test flag 1 1607 -global2=0 1608 global test flag 2 1609 1610 Run "toplevelprog help -style=full hello" to show all flags. 1611 `, 1612 }, 1613 { 1614 Args: []string{"-extra", "echoprog", "echoopt", "foo", "bar"}, 1615 Err: errUsageStr, 1616 Stderr: `ERROR: toplevelprog: flag provided but not defined: -extra 1617 1618 Toplevelprog has the echo subprogram and the hello command. 1619 1620 Usage: 1621 toplevelprog [flags] <command> 1622 1623 The toplevelprog commands are: 1624 echoprog Set of echo commands 1625 hello Print strings on stdout preceded by Hello 1626 help Display help for commands or topics 1627 Run "toplevelprog help [command]" for command usage. 1628 1629 The toplevelprog additional help topics are: 1630 topic1 Help topic 1 short 1631 topic2 Help topic 2 short 1632 Run "toplevelprog help [topic]" for topic details. 1633 1634 The toplevelprog flags are: 1635 -tlextra=false 1636 Print an extra arg for all commands 1637 1638 The global flags are: 1639 -global1= 1640 global test flag 1 1641 -global2=0 1642 global test flag 2 1643 `, 1644 }, 1645 } 1646 runTestCases(t, prog, tests) 1647 } 1648 1649 func TestMultiLevelCommandsOrdering(t *testing.T) { 1650 cmdHello11 := &Command{ 1651 Name: "hello11", 1652 Short: "Print strings on stdout preceded by Hello", 1653 Long: ` 1654 Hello prints any strings passed in to stdout preceded by "Hello". 1655 `, 1656 ArgsName: "[strings]", 1657 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1658 Runner: RunnerFunc(runHello), 1659 } 1660 cmdHello12 := &Command{ 1661 Name: "hello12", 1662 Short: "Print strings on stdout preceded by Hello", 1663 Long: ` 1664 Hello prints any strings passed in to stdout preceded by "Hello". 1665 `, 1666 ArgsName: "[strings]", 1667 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1668 Runner: RunnerFunc(runHello), 1669 } 1670 cmdHello21 := &Command{ 1671 Name: "hello21", 1672 Short: "Print strings on stdout preceded by Hello", 1673 Long: ` 1674 Hello prints any strings passed in to stdout preceded by "Hello". 1675 `, 1676 ArgsName: "[strings]", 1677 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1678 Runner: RunnerFunc(runHello), 1679 } 1680 cmdHello22 := &Command{ 1681 Name: "hello22", 1682 Short: "Print strings on stdout preceded by Hello", 1683 Long: ` 1684 Hello prints any strings passed in to stdout preceded by "Hello". 1685 `, 1686 ArgsName: "[strings]", 1687 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1688 Runner: RunnerFunc(runHello), 1689 } 1690 cmdHello31 := &Command{ 1691 Name: "hello31", 1692 Short: "Print strings on stdout preceded by Hello", 1693 Long: ` 1694 Hello prints any strings passed in to stdout preceded by "Hello". 1695 `, 1696 ArgsName: "[strings]", 1697 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1698 Runner: RunnerFunc(runHello), 1699 } 1700 cmdHello32 := &Command{ 1701 Name: "hello32", 1702 Short: "Print strings on stdout preceded by Hello", 1703 Long: ` 1704 Hello prints any strings passed in to stdout preceded by "Hello". 1705 `, 1706 ArgsName: "[strings]", 1707 ArgsLong: "[strings] are arbitrary strings that will be printed.", 1708 Runner: RunnerFunc(runHello), 1709 } 1710 progHello3 := &Command{ 1711 Name: "prog3", 1712 Short: "Set of hello commands", 1713 Long: "Prog3 has two variants of hello.", 1714 Children: []*Command{cmdHello31, cmdHello32}, 1715 } 1716 progHello2 := &Command{ 1717 Name: "prog2", 1718 Short: "Set of hello commands", 1719 Long: "Prog2 has two variants of hello and a subprogram prog3.", 1720 Children: []*Command{cmdHello21, progHello3, cmdHello22}, 1721 } 1722 progHello1 := &Command{ 1723 Name: "prog1", 1724 Short: "Set of hello commands", 1725 Long: "Prog1 has two variants of hello and a subprogram prog2.", 1726 Children: []*Command{cmdHello11, cmdHello12, progHello2}, 1727 } 1728 1729 var tests = []testCase{ 1730 { 1731 Args: []string{}, 1732 Err: errUsageStr, 1733 Stderr: `ERROR: prog1: no command specified 1734 1735 Prog1 has two variants of hello and a subprogram prog2. 1736 1737 Usage: 1738 prog1 [flags] <command> 1739 1740 The prog1 commands are: 1741 hello11 Print strings on stdout preceded by Hello 1742 hello12 Print strings on stdout preceded by Hello 1743 prog2 Set of hello commands 1744 help Display help for commands or topics 1745 Run "prog1 help [command]" for command usage. 1746 1747 The global flags are: 1748 -global1= 1749 global test flag 1 1750 -global2=0 1751 global test flag 2 1752 `, 1753 }, 1754 { 1755 Args: []string{"help"}, 1756 Stdout: `Prog1 has two variants of hello and a subprogram prog2. 1757 1758 Usage: 1759 prog1 [flags] <command> 1760 1761 The prog1 commands are: 1762 hello11 Print strings on stdout preceded by Hello 1763 hello12 Print strings on stdout preceded by Hello 1764 prog2 Set of hello commands 1765 help Display help for commands or topics 1766 Run "prog1 help [command]" for command usage. 1767 1768 The global flags are: 1769 -global1= 1770 global test flag 1 1771 -global2=0 1772 global test flag 2 1773 `, 1774 }, 1775 { 1776 Args: []string{"help", "..."}, 1777 Stdout: `Prog1 has two variants of hello and a subprogram prog2. 1778 1779 Usage: 1780 prog1 [flags] <command> 1781 1782 The prog1 commands are: 1783 hello11 Print strings on stdout preceded by Hello 1784 hello12 Print strings on stdout preceded by Hello 1785 prog2 Set of hello commands 1786 help Display help for commands or topics 1787 Run "prog1 help [command]" for command usage. 1788 1789 The global flags are: 1790 -global1= 1791 global test flag 1 1792 -global2=0 1793 global test flag 2 1794 ================================================================================ 1795 Prog1 hello11 - Print strings on stdout preceded by Hello 1796 1797 Hello prints any strings passed in to stdout preceded by "Hello". 1798 1799 Usage: 1800 prog1 hello11 [flags] [strings] 1801 1802 [strings] are arbitrary strings that will be printed. 1803 ================================================================================ 1804 Prog1 hello12 - Print strings on stdout preceded by Hello 1805 1806 Hello prints any strings passed in to stdout preceded by "Hello". 1807 1808 Usage: 1809 prog1 hello12 [flags] [strings] 1810 1811 [strings] are arbitrary strings that will be printed. 1812 ================================================================================ 1813 Prog1 prog2 - Set of hello commands 1814 1815 Prog2 has two variants of hello and a subprogram prog3. 1816 1817 Usage: 1818 prog1 prog2 [flags] <command> 1819 1820 The prog1 prog2 commands are: 1821 hello21 Print strings on stdout preceded by Hello 1822 prog3 Set of hello commands 1823 hello22 Print strings on stdout preceded by Hello 1824 ================================================================================ 1825 Prog1 prog2 hello21 - Print strings on stdout preceded by Hello 1826 1827 Hello prints any strings passed in to stdout preceded by "Hello". 1828 1829 Usage: 1830 prog1 prog2 hello21 [flags] [strings] 1831 1832 [strings] are arbitrary strings that will be printed. 1833 ================================================================================ 1834 Prog1 prog2 prog3 - Set of hello commands 1835 1836 Prog3 has two variants of hello. 1837 1838 Usage: 1839 prog1 prog2 prog3 [flags] <command> 1840 1841 The prog1 prog2 prog3 commands are: 1842 hello31 Print strings on stdout preceded by Hello 1843 hello32 Print strings on stdout preceded by Hello 1844 ================================================================================ 1845 Prog1 prog2 prog3 hello31 - Print strings on stdout preceded by Hello 1846 1847 Hello prints any strings passed in to stdout preceded by "Hello". 1848 1849 Usage: 1850 prog1 prog2 prog3 hello31 [flags] [strings] 1851 1852 [strings] are arbitrary strings that will be printed. 1853 ================================================================================ 1854 Prog1 prog2 prog3 hello32 - Print strings on stdout preceded by Hello 1855 1856 Hello prints any strings passed in to stdout preceded by "Hello". 1857 1858 Usage: 1859 prog1 prog2 prog3 hello32 [flags] [strings] 1860 1861 [strings] are arbitrary strings that will be printed. 1862 ================================================================================ 1863 Prog1 prog2 hello22 - Print strings on stdout preceded by Hello 1864 1865 Hello prints any strings passed in to stdout preceded by "Hello". 1866 1867 Usage: 1868 prog1 prog2 hello22 [flags] [strings] 1869 1870 [strings] are arbitrary strings that will be printed. 1871 ================================================================================ 1872 Prog1 help - Display help for commands or topics 1873 1874 Help with no args displays the usage of the parent command. 1875 1876 Help with args displays the usage of the specified sub-command or help topic. 1877 1878 "help ..." recursively displays help for all commands and topics. 1879 1880 Usage: 1881 prog1 help [flags] [command/topic ...] 1882 1883 [command/topic ...] optionally identifies a specific sub-command or help topic. 1884 1885 The prog1 help flags are: 1886 -style=compact 1887 The formatting style for help output: 1888 compact - Good for compact cmdline output. 1889 full - Good for cmdline output, shows all global flags. 1890 godoc - Good for godoc processing. 1891 shortonly - Only output short description. 1892 Override the default by setting the CMDLINE_STYLE environment variable. 1893 -width=80 1894 Format output to this target width in runes, or unlimited if width < 0. 1895 Defaults to the terminal width if available. Override the default by setting 1896 the CMDLINE_WIDTH environment variable. 1897 `, 1898 }, 1899 { 1900 Args: []string{"prog2", "help", "..."}, 1901 Stdout: `Prog2 has two variants of hello and a subprogram prog3. 1902 1903 Usage: 1904 prog1 prog2 [flags] <command> 1905 1906 The prog1 prog2 commands are: 1907 hello21 Print strings on stdout preceded by Hello 1908 prog3 Set of hello commands 1909 hello22 Print strings on stdout preceded by Hello 1910 help Display help for commands or topics 1911 Run "prog1 prog2 help [command]" for command usage. 1912 1913 The global flags are: 1914 -global1= 1915 global test flag 1 1916 -global2=0 1917 global test flag 2 1918 ================================================================================ 1919 Prog1 prog2 hello21 - Print strings on stdout preceded by Hello 1920 1921 Hello prints any strings passed in to stdout preceded by "Hello". 1922 1923 Usage: 1924 prog1 prog2 hello21 [flags] [strings] 1925 1926 [strings] are arbitrary strings that will be printed. 1927 ================================================================================ 1928 Prog1 prog2 prog3 - Set of hello commands 1929 1930 Prog3 has two variants of hello. 1931 1932 Usage: 1933 prog1 prog2 prog3 [flags] <command> 1934 1935 The prog1 prog2 prog3 commands are: 1936 hello31 Print strings on stdout preceded by Hello 1937 hello32 Print strings on stdout preceded by Hello 1938 ================================================================================ 1939 Prog1 prog2 prog3 hello31 - Print strings on stdout preceded by Hello 1940 1941 Hello prints any strings passed in to stdout preceded by "Hello". 1942 1943 Usage: 1944 prog1 prog2 prog3 hello31 [flags] [strings] 1945 1946 [strings] are arbitrary strings that will be printed. 1947 ================================================================================ 1948 Prog1 prog2 prog3 hello32 - Print strings on stdout preceded by Hello 1949 1950 Hello prints any strings passed in to stdout preceded by "Hello". 1951 1952 Usage: 1953 prog1 prog2 prog3 hello32 [flags] [strings] 1954 1955 [strings] are arbitrary strings that will be printed. 1956 ================================================================================ 1957 Prog1 prog2 hello22 - Print strings on stdout preceded by Hello 1958 1959 Hello prints any strings passed in to stdout preceded by "Hello". 1960 1961 Usage: 1962 prog1 prog2 hello22 [flags] [strings] 1963 1964 [strings] are arbitrary strings that will be printed. 1965 ================================================================================ 1966 Prog1 prog2 help - Display help for commands or topics 1967 1968 Help with no args displays the usage of the parent command. 1969 1970 Help with args displays the usage of the specified sub-command or help topic. 1971 1972 "help ..." recursively displays help for all commands and topics. 1973 1974 Usage: 1975 prog1 prog2 help [flags] [command/topic ...] 1976 1977 [command/topic ...] optionally identifies a specific sub-command or help topic. 1978 1979 The prog1 prog2 help flags are: 1980 -style=compact 1981 The formatting style for help output: 1982 compact - Good for compact cmdline output. 1983 full - Good for cmdline output, shows all global flags. 1984 godoc - Good for godoc processing. 1985 shortonly - Only output short description. 1986 Override the default by setting the CMDLINE_STYLE environment variable. 1987 -width=80 1988 Format output to this target width in runes, or unlimited if width < 0. 1989 Defaults to the terminal width if available. Override the default by setting 1990 the CMDLINE_WIDTH environment variable. 1991 `, 1992 }, 1993 { 1994 Args: []string{"prog2", "prog3", "help", "..."}, 1995 Stdout: `Prog3 has two variants of hello. 1996 1997 Usage: 1998 prog1 prog2 prog3 [flags] <command> 1999 2000 The prog1 prog2 prog3 commands are: 2001 hello31 Print strings on stdout preceded by Hello 2002 hello32 Print strings on stdout preceded by Hello 2003 help Display help for commands or topics 2004 Run "prog1 prog2 prog3 help [command]" for command usage. 2005 2006 The global flags are: 2007 -global1= 2008 global test flag 1 2009 -global2=0 2010 global test flag 2 2011 ================================================================================ 2012 Prog1 prog2 prog3 hello31 - Print strings on stdout preceded by Hello 2013 2014 Hello prints any strings passed in to stdout preceded by "Hello". 2015 2016 Usage: 2017 prog1 prog2 prog3 hello31 [flags] [strings] 2018 2019 [strings] are arbitrary strings that will be printed. 2020 ================================================================================ 2021 Prog1 prog2 prog3 hello32 - Print strings on stdout preceded by Hello 2022 2023 Hello prints any strings passed in to stdout preceded by "Hello". 2024 2025 Usage: 2026 prog1 prog2 prog3 hello32 [flags] [strings] 2027 2028 [strings] are arbitrary strings that will be printed. 2029 ================================================================================ 2030 Prog1 prog2 prog3 help - Display help for commands or topics 2031 2032 Help with no args displays the usage of the parent command. 2033 2034 Help with args displays the usage of the specified sub-command or help topic. 2035 2036 "help ..." recursively displays help for all commands and topics. 2037 2038 Usage: 2039 prog1 prog2 prog3 help [flags] [command/topic ...] 2040 2041 [command/topic ...] optionally identifies a specific sub-command or help topic. 2042 2043 The prog1 prog2 prog3 help flags are: 2044 -style=compact 2045 The formatting style for help output: 2046 compact - Good for compact cmdline output. 2047 full - Good for cmdline output, shows all global flags. 2048 godoc - Good for godoc processing. 2049 shortonly - Only output short description. 2050 Override the default by setting the CMDLINE_STYLE environment variable. 2051 -width=80 2052 Format output to this target width in runes, or unlimited if width < 0. 2053 Defaults to the terminal width if available. Override the default by setting 2054 the CMDLINE_WIDTH environment variable. 2055 `, 2056 }, 2057 { 2058 Args: []string{"help", "prog2", "prog3", "..."}, 2059 Stdout: `Prog3 has two variants of hello. 2060 2061 Usage: 2062 prog1 prog2 prog3 [flags] <command> 2063 2064 The prog1 prog2 prog3 commands are: 2065 hello31 Print strings on stdout preceded by Hello 2066 hello32 Print strings on stdout preceded by Hello 2067 help Display help for commands or topics 2068 Run "prog1 prog2 prog3 help [command]" for command usage. 2069 2070 The global flags are: 2071 -global1= 2072 global test flag 1 2073 -global2=0 2074 global test flag 2 2075 ================================================================================ 2076 Prog1 prog2 prog3 hello31 - Print strings on stdout preceded by Hello 2077 2078 Hello prints any strings passed in to stdout preceded by "Hello". 2079 2080 Usage: 2081 prog1 prog2 prog3 hello31 [flags] [strings] 2082 2083 [strings] are arbitrary strings that will be printed. 2084 ================================================================================ 2085 Prog1 prog2 prog3 hello32 - Print strings on stdout preceded by Hello 2086 2087 Hello prints any strings passed in to stdout preceded by "Hello". 2088 2089 Usage: 2090 prog1 prog2 prog3 hello32 [flags] [strings] 2091 2092 [strings] are arbitrary strings that will be printed. 2093 ================================================================================ 2094 Prog1 prog2 prog3 help - Display help for commands or topics 2095 2096 Help with no args displays the usage of the parent command. 2097 2098 Help with args displays the usage of the specified sub-command or help topic. 2099 2100 "help ..." recursively displays help for all commands and topics. 2101 2102 Usage: 2103 prog1 prog2 prog3 help [flags] [command/topic ...] 2104 2105 [command/topic ...] optionally identifies a specific sub-command or help topic. 2106 2107 The prog1 prog2 prog3 help flags are: 2108 -style=compact 2109 The formatting style for help output: 2110 compact - Good for compact cmdline output. 2111 full - Good for cmdline output, shows all global flags. 2112 godoc - Good for godoc processing. 2113 shortonly - Only output short description. 2114 Override the default by setting the CMDLINE_STYLE environment variable. 2115 -width=80 2116 Format output to this target width in runes, or unlimited if width < 0. 2117 Defaults to the terminal width if available. Override the default by setting 2118 the CMDLINE_WIDTH environment variable. 2119 `, 2120 }, 2121 { 2122 Args: []string{"help", "-style=godoc", "..."}, 2123 Stdout: `Prog1 has two variants of hello and a subprogram prog2. 2124 2125 Usage: 2126 prog1 [flags] <command> 2127 2128 The prog1 commands are: 2129 hello11 Print strings on stdout preceded by Hello 2130 hello12 Print strings on stdout preceded by Hello 2131 prog2 Set of hello commands 2132 help Display help for commands or topics 2133 2134 The global flags are: 2135 -global1= 2136 global test flag 1 2137 -global2=0 2138 global test flag 2 2139 2140 Prog1 hello11 - Print strings on stdout preceded by Hello 2141 2142 Hello prints any strings passed in to stdout preceded by "Hello". 2143 2144 Usage: 2145 prog1 hello11 [flags] [strings] 2146 2147 [strings] are arbitrary strings that will be printed. 2148 2149 Prog1 hello12 - Print strings on stdout preceded by Hello 2150 2151 Hello prints any strings passed in to stdout preceded by "Hello". 2152 2153 Usage: 2154 prog1 hello12 [flags] [strings] 2155 2156 [strings] are arbitrary strings that will be printed. 2157 2158 Prog1 prog2 - Set of hello commands 2159 2160 Prog2 has two variants of hello and a subprogram prog3. 2161 2162 Usage: 2163 prog1 prog2 [flags] <command> 2164 2165 The prog1 prog2 commands are: 2166 hello21 Print strings on stdout preceded by Hello 2167 prog3 Set of hello commands 2168 hello22 Print strings on stdout preceded by Hello 2169 2170 Prog1 prog2 hello21 - Print strings on stdout preceded by Hello 2171 2172 Hello prints any strings passed in to stdout preceded by "Hello". 2173 2174 Usage: 2175 prog1 prog2 hello21 [flags] [strings] 2176 2177 [strings] are arbitrary strings that will be printed. 2178 2179 Prog1 prog2 prog3 - Set of hello commands 2180 2181 Prog3 has two variants of hello. 2182 2183 Usage: 2184 prog1 prog2 prog3 [flags] <command> 2185 2186 The prog1 prog2 prog3 commands are: 2187 hello31 Print strings on stdout preceded by Hello 2188 hello32 Print strings on stdout preceded by Hello 2189 2190 Prog1 prog2 prog3 hello31 - Print strings on stdout preceded by Hello 2191 2192 Hello prints any strings passed in to stdout preceded by "Hello". 2193 2194 Usage: 2195 prog1 prog2 prog3 hello31 [flags] [strings] 2196 2197 [strings] are arbitrary strings that will be printed. 2198 2199 Prog1 prog2 prog3 hello32 - Print strings on stdout preceded by Hello 2200 2201 Hello prints any strings passed in to stdout preceded by "Hello". 2202 2203 Usage: 2204 prog1 prog2 prog3 hello32 [flags] [strings] 2205 2206 [strings] are arbitrary strings that will be printed. 2207 2208 Prog1 prog2 hello22 - Print strings on stdout preceded by Hello 2209 2210 Hello prints any strings passed in to stdout preceded by "Hello". 2211 2212 Usage: 2213 prog1 prog2 hello22 [flags] [strings] 2214 2215 [strings] are arbitrary strings that will be printed. 2216 2217 Prog1 help - Display help for commands or topics 2218 2219 Help with no args displays the usage of the parent command. 2220 2221 Help with args displays the usage of the specified sub-command or help topic. 2222 2223 "help ..." recursively displays help for all commands and topics. 2224 2225 Usage: 2226 prog1 help [flags] [command/topic ...] 2227 2228 [command/topic ...] optionally identifies a specific sub-command or help topic. 2229 2230 The prog1 help flags are: 2231 -style=compact 2232 The formatting style for help output: 2233 compact - Good for compact cmdline output. 2234 full - Good for cmdline output, shows all global flags. 2235 godoc - Good for godoc processing. 2236 shortonly - Only output short description. 2237 Override the default by setting the CMDLINE_STYLE environment variable. 2238 -width=<terminal width> 2239 Format output to this target width in runes, or unlimited if width < 0. 2240 Defaults to the terminal width if available. Override the default by setting 2241 the CMDLINE_WIDTH environment variable. 2242 `, 2243 }, 2244 } 2245 runTestCases(t, progHello1, tests) 2246 } 2247 2248 func TestLongCommands(t *testing.T) { 2249 cmdLong := &Command{ 2250 Name: "thisisaverylongcommand", 2251 Short: "the short description of the very long command is very long, and will have to be wrapped", 2252 Long: "The long description of the very long command is also very long, and will similarly have to be wrapped", 2253 Runner: RunnerFunc(runEcho), 2254 } 2255 cmdShort := &Command{ 2256 Name: "x", 2257 Short: "description of short command.", 2258 Long: "blah blah blah", 2259 Runner: RunnerFunc(runEcho), 2260 } 2261 prog := &Command{ 2262 Name: "program", 2263 Short: "Test help strings when there are long commands.", 2264 Long: "Test help strings when there are long commands.", 2265 Children: []*Command{cmdShort, cmdLong}, 2266 } 2267 var tests = []testCase{ 2268 { 2269 Args: []string{"help"}, 2270 Stdout: `Test help strings when there are long commands. 2271 2272 Usage: 2273 program [flags] <command> 2274 2275 The program commands are: 2276 x description of short command. 2277 thisisaverylongcommand the short description of the very long command is very 2278 long, and will have to be wrapped 2279 help Display help for commands or topics 2280 Run "program help [command]" for command usage. 2281 2282 The global flags are: 2283 -global1= 2284 global test flag 1 2285 -global2=0 2286 global test flag 2 2287 `, 2288 }, 2289 { 2290 Args: []string{"help", "thisisaverylongcommand"}, 2291 Stdout: `The long description of the very long command is also very long, and will 2292 similarly have to be wrapped 2293 2294 Usage: 2295 program thisisaverylongcommand [flags] 2296 2297 The global flags are: 2298 -global1= 2299 global test flag 1 2300 -global2=0 2301 global test flag 2 2302 `, 2303 }, 2304 } 2305 runTestCases(t, prog, tests) 2306 } 2307 2308 func TestHideGlobalFlags(t *testing.T) { 2309 HideGlobalFlags(regexp.MustCompile(`^global1$`)) 2310 cmdChild := &Command{ 2311 Name: "child", 2312 Short: "description of child command.", 2313 Long: "blah blah blah", 2314 Runner: RunnerFunc(runEcho), 2315 } 2316 prog := &Command{ 2317 Name: "program", 2318 Short: "Test hiding global flags.", 2319 Long: "Test hiding global flags.", 2320 Children: []*Command{cmdChild}, 2321 } 2322 var tests = []testCase{ 2323 { 2324 Args: []string{"help"}, 2325 Stdout: `Test hiding global flags. 2326 2327 Usage: 2328 program [flags] <command> 2329 2330 The program commands are: 2331 child description of child command. 2332 help Display help for commands or topics 2333 Run "program help [command]" for command usage. 2334 2335 The global flags are: 2336 -global2=0 2337 global test flag 2 2338 2339 Run "program help -style=full" to show all flags. 2340 `, 2341 }, 2342 { 2343 Args: []string{"help", "child"}, 2344 Stdout: `blah blah blah 2345 2346 Usage: 2347 program child [flags] 2348 2349 The global flags are: 2350 -global2=0 2351 global test flag 2 2352 2353 Run "program help -style=full child" to show all flags. 2354 `, 2355 }, 2356 { 2357 Args: []string{"help", "-style=full"}, 2358 Stdout: `Test hiding global flags. 2359 2360 Usage: 2361 program [flags] <command> 2362 2363 The program commands are: 2364 child description of child command. 2365 help Display help for commands or topics 2366 Run "program help [command]" for command usage. 2367 2368 The global flags are: 2369 -global2=0 2370 global test flag 2 2371 2372 -global1= 2373 global test flag 1 2374 `, 2375 }, 2376 { 2377 Args: []string{"help", "-style=full", "child"}, 2378 Stdout: `blah blah blah 2379 2380 Usage: 2381 program child [flags] 2382 2383 The global flags are: 2384 -global2=0 2385 global test flag 2 2386 2387 -global1= 2388 global test flag 1 2389 `, 2390 }, 2391 } 2392 runTestCases(t, prog, tests) 2393 hiddenGlobalFlags = nil 2394 } 2395 2396 func TestHideGlobalFlagsRootNoChildren(t *testing.T) { 2397 HideGlobalFlags(regexp.MustCompile(`^global1$`)) 2398 prog := &Command{ 2399 Name: "program", 2400 Short: "Test hiding global flags, root no children.", 2401 Long: "Test hiding global flags, root no children.", 2402 Runner: RunnerFunc(runEcho), 2403 } 2404 var tests = []testCase{ 2405 { 2406 Args: []string{"-help"}, 2407 Stdout: `Test hiding global flags, root no children. 2408 2409 Usage: 2410 program [flags] 2411 2412 The global flags are: 2413 -global2=0 2414 global test flag 2 2415 2416 Run "CMDLINE_STYLE=full program -help" to show all flags. 2417 `, 2418 }, 2419 { 2420 Args: []string{"-help"}, 2421 Vars: map[string]string{"CMDLINE_STYLE": "full"}, 2422 Stdout: `Test hiding global flags, root no children. 2423 2424 Usage: 2425 program [flags] 2426 2427 The global flags are: 2428 -global2=0 2429 global test flag 2 2430 2431 -global1= 2432 global test flag 1 2433 `, 2434 }, 2435 } 2436 runTestCases(t, prog, tests) 2437 hiddenGlobalFlags = nil 2438 } 2439 2440 func TestRootCommandFlags(t *testing.T) { 2441 root := &Command{ 2442 Name: "root", 2443 Short: "Test root command flags.", 2444 Long: "Test root command flags.", 2445 Runner: RunnerFunc(runHello), 2446 } 2447 rb := root.Flags.Bool("rbool", false, "rbool desc") 2448 rs := root.Flags.String("rstring", "abc", "rstring desc") 2449 origFlags := flag.CommandLine 2450 // Parse and make sure the flags get set appropriately. 2451 _, _, err := Parse(root, EnvFromOS(), []string{"-rbool=true", "-rstring=XYZ"}) 2452 if err != nil { 2453 t.Fatalf("Parse failed: %v", err) 2454 } 2455 if got, want := *rb, true; got != want { 2456 t.Errorf("rbool got %v want %v", got, want) 2457 } 2458 if got, want := *rs, "XYZ"; got != want { 2459 t.Errorf("rstring got %v want %v", got, want) 2460 } 2461 // Make sure we haven't changed the flag.CommandLine pointer, and that it's 2462 // parsed, and it contains our root command flags. These properties are 2463 // important to ensure so that users can check whether the flags are already 2464 // parsed to avoid double-parsing. Even if they do call flag.Parse it'll 2465 // succeed, as long as cmdline.Parse succeeded. 2466 if got, want := flag.CommandLine, origFlags; got != want { 2467 t.Errorf("flag.CommandLine pointer changed, got %p want %p", got, want) 2468 } 2469 if got, want := flag.CommandLine.Parsed(), true; got != want { 2470 t.Errorf("flag.CommandLine.Parsed() got %v, want %v", got, want) 2471 } 2472 if name := "rbool"; flag.CommandLine.Lookup(name) == nil { 2473 t.Errorf("flag.CommandLine.Lookup(%q) failed", name) 2474 } 2475 if name := "rstring"; flag.CommandLine.Lookup(name) == nil { 2476 t.Errorf("flag.CommandLine.Lookup(%q) failed", name) 2477 } 2478 // Actually try double-parsing flag.CommandLine. 2479 if err := flag.CommandLine.Parse([]string{"-rbool=false", "-rstring=123"}); err != nil { 2480 t.Errorf("flag.CommandLine.Parse() failed: %v", err) 2481 } 2482 if got, want := *rb, false; got != want { 2483 t.Errorf("rbool got %v want %v", got, want) 2484 } 2485 if got, want := *rs, "123"; got != want { 2486 t.Errorf("rstring got %v want %v", got, want) 2487 } 2488 } 2489 2490 func TestExternalSubcommand(t *testing.T) { 2491 // Create a temporary directory for the external subcommands. 2492 tmpDir, err := ioutil.TempDir("", "cmdline-test") 2493 if err != nil { 2494 t.Fatalf("%v", err) 2495 } 2496 defer os.RemoveAll(tmpDir) 2497 2498 // Add the temporary directory to PATH. We add it twice to ensure dups are 2499 // filtered in the resulting output. 2500 oldPath := os.Getenv("PATH") 2501 defer os.Setenv("PATH", oldPath) 2502 tokens := strings.Split(oldPath, string(os.PathListSeparator)) 2503 tokens = append([]string{tmpDir, tmpDir}, tokens...) 2504 os.Setenv("PATH", strings.Join(tokens, string(os.PathListSeparator))) 2505 2506 // Build the external subcommands. 2507 for _, subCmd := range []string{"exitcode", "flags", "flat", "foreign", "nested", "repeated"} { 2508 cmd := exec.Command("go", "build", "-o", filepath.Join(tmpDir, "unlikely-"+subCmd), filepath.Join(".", "testdata", subCmd+".go")) 2509 if out, err := cmd.CombinedOutput(); err != nil { 2510 t.Fatalf("%v, %v", string(out), err) 2511 } 2512 } 2513 2514 // Create a command that uses these. 2515 cmd := &Command{ 2516 Name: "unlikely", 2517 Short: "Short description of command unlikely", 2518 Long: "Long description of command unlikely.", 2519 LookPath: true, 2520 Children: []*Command{ 2521 &Command{ 2522 Runner: RunnerFunc(runDumpEnv), 2523 Name: "dumpenv", 2524 Short: "Short description of command dumpenv", 2525 Long: "Long description of command dumpenv.", 2526 }, 2527 &Command{ 2528 Runner: RunnerFunc(runHello), 2529 Name: "repeated", 2530 Short: "Repeated appears as both a child and as a binary", 2531 Long: "Long description of command repeated.", 2532 }, 2533 }, 2534 } 2535 cmd.Flags.StringVar(new(string), "shared", "", "description of shared") 2536 2537 var tests = []testCase{ 2538 { 2539 Args: []string{"-help"}, 2540 Vars: map[string]string{ 2541 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2542 }, 2543 Stdout: `Long description of command unlikely. 2544 2545 Usage: 2546 unlikely [flags] <command> 2547 2548 The unlikely commands are: 2549 dumpenv Short description of command dumpenv 2550 repeated Repeated appears as both a child and as a binary 2551 help Display help for commands or topics 2552 The unlikely external commands are: 2553 exitcode Short description of command exitcode 2554 flags Short description of command flags 2555 flat Short description of command flat 2556 foreign No description available 2557 nested Short description of command nested 2558 Run "unlikely help [command]" for command usage. 2559 2560 The unlikely flags are: 2561 -shared= 2562 description of shared 2563 2564 The global flags are: 2565 -global1= 2566 global test flag 1 2567 -global2=0 2568 global test flag 2 2569 `, 2570 }, 2571 { 2572 Args: []string{"help"}, 2573 Vars: map[string]string{ 2574 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2575 }, 2576 Stdout: `Long description of command unlikely. 2577 2578 Usage: 2579 unlikely [flags] <command> 2580 2581 The unlikely commands are: 2582 dumpenv Short description of command dumpenv 2583 repeated Repeated appears as both a child and as a binary 2584 help Display help for commands or topics 2585 The unlikely external commands are: 2586 exitcode Short description of command exitcode 2587 flags Short description of command flags 2588 flat Short description of command flat 2589 foreign No description available 2590 nested Short description of command nested 2591 Run "unlikely help [command]" for command usage. 2592 2593 The unlikely flags are: 2594 -shared= 2595 description of shared 2596 2597 The global flags are: 2598 -global1= 2599 global test flag 1 2600 -global2=0 2601 global test flag 2 2602 `, 2603 }, 2604 { 2605 Args: []string{"help", "..."}, 2606 Vars: map[string]string{ 2607 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2608 }, 2609 Stdout: `Long description of command unlikely. 2610 2611 Usage: 2612 unlikely [flags] <command> 2613 2614 The unlikely commands are: 2615 dumpenv Short description of command dumpenv 2616 repeated Repeated appears as both a child and as a binary 2617 help Display help for commands or topics 2618 The unlikely external commands are: 2619 exitcode Short description of command exitcode 2620 flags Short description of command flags 2621 flat Short description of command flat 2622 foreign No description available 2623 nested Short description of command nested 2624 Run "unlikely help [command]" for command usage. 2625 2626 The unlikely flags are: 2627 -shared= 2628 description of shared 2629 2630 The global flags are: 2631 -global1= 2632 global test flag 1 2633 -global2=0 2634 global test flag 2 2635 ================================================================================ 2636 Unlikely dumpenv - Short description of command dumpenv 2637 2638 Long description of command dumpenv. 2639 2640 Usage: 2641 unlikely dumpenv [flags] 2642 2643 Run "unlikely help -style=full dumpenv" to show all flags. 2644 ================================================================================ 2645 Unlikely repeated - Repeated appears as both a child and as a binary 2646 2647 Long description of command repeated. 2648 2649 Usage: 2650 unlikely repeated [flags] 2651 2652 Run "unlikely help -style=full repeated" to show all flags. 2653 ================================================================================ 2654 Unlikely help - Display help for commands or topics 2655 2656 Help with no args displays the usage of the parent command. 2657 2658 Help with args displays the usage of the specified sub-command or help topic. 2659 2660 "help ..." recursively displays help for all commands and topics. 2661 2662 Usage: 2663 unlikely help [flags] [command/topic ...] 2664 2665 [command/topic ...] optionally identifies a specific sub-command or help topic. 2666 2667 The unlikely help flags are: 2668 -style=compact 2669 The formatting style for help output: 2670 compact - Good for compact cmdline output. 2671 full - Good for cmdline output, shows all global flags. 2672 godoc - Good for godoc processing. 2673 shortonly - Only output short description. 2674 Override the default by setting the CMDLINE_STYLE environment variable. 2675 -width=80 2676 Format output to this target width in runes, or unlimited if width < 0. 2677 Defaults to the terminal width if available. Override the default by setting 2678 the CMDLINE_WIDTH environment variable. 2679 ================================================================================ 2680 Unlikely exitcode - Short description of command exitcode 2681 2682 Long description of command exitcode. 2683 2684 Usage: 2685 unlikely exitcode [flags] [args] 2686 2687 [args] are ignored 2688 ================================================================================ 2689 Unlikely flags - Short description of command flags 2690 2691 Long description of command flags. 2692 2693 Usage: 2694 unlikely flags [flags] [args] 2695 2696 [args] are ignored 2697 2698 The unlikely flags flags are: 2699 -global1= 2700 description of global1 2701 -local= 2702 description of local 2703 -shared= 2704 description of shared 2705 ================================================================================ 2706 Unlikely flat - Short description of command flat 2707 2708 Long description of command flat. 2709 2710 Usage: 2711 unlikely flat [flags] [args] 2712 2713 [args] are ignored 2714 ================================================================================ 2715 Unlikely foreign - No description available 2716 ================================================================================ 2717 Unlikely nested - Short description of command nested 2718 2719 Long description of command nested. 2720 2721 Usage: 2722 unlikely nested [flags] <command> 2723 2724 The unlikely nested commands are: 2725 child Short description of command child 2726 ================================================================================ 2727 Unlikely nested child - Short description of command child 2728 2729 Long description of command child. 2730 2731 Usage: 2732 unlikely nested child [flags] 2733 `, 2734 }, 2735 { 2736 Args: []string{"help", "-style=godoc", "..."}, 2737 Vars: map[string]string{ 2738 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2739 }, 2740 Stdout: `Long description of command unlikely. 2741 2742 Usage: 2743 unlikely [flags] <command> 2744 2745 The unlikely commands are: 2746 dumpenv Short description of command dumpenv 2747 repeated Repeated appears as both a child and as a binary 2748 help Display help for commands or topics 2749 The unlikely external commands are: 2750 exitcode Short description of command exitcode 2751 flags Short description of command flags 2752 flat Short description of command flat 2753 foreign No description available 2754 nested Short description of command nested 2755 2756 The unlikely flags are: 2757 -shared= 2758 description of shared 2759 2760 The global flags are: 2761 -global1= 2762 global test flag 1 2763 -global2=0 2764 global test flag 2 2765 2766 Unlikely dumpenv - Short description of command dumpenv 2767 2768 Long description of command dumpenv. 2769 2770 Usage: 2771 unlikely dumpenv [flags] 2772 2773 The unlikely dumpenv flags are: 2774 -shared= 2775 description of shared 2776 2777 Unlikely repeated - Repeated appears as both a child and as a binary 2778 2779 Long description of command repeated. 2780 2781 Usage: 2782 unlikely repeated [flags] 2783 2784 The unlikely repeated flags are: 2785 -shared= 2786 description of shared 2787 2788 Unlikely help - Display help for commands or topics 2789 2790 Help with no args displays the usage of the parent command. 2791 2792 Help with args displays the usage of the specified sub-command or help topic. 2793 2794 "help ..." recursively displays help for all commands and topics. 2795 2796 Usage: 2797 unlikely help [flags] [command/topic ...] 2798 2799 [command/topic ...] optionally identifies a specific sub-command or help topic. 2800 2801 The unlikely help flags are: 2802 -style=compact 2803 The formatting style for help output: 2804 compact - Good for compact cmdline output. 2805 full - Good for cmdline output, shows all global flags. 2806 godoc - Good for godoc processing. 2807 shortonly - Only output short description. 2808 Override the default by setting the CMDLINE_STYLE environment variable. 2809 -width=<terminal width> 2810 Format output to this target width in runes, or unlimited if width < 0. 2811 Defaults to the terminal width if available. Override the default by setting 2812 the CMDLINE_WIDTH environment variable. 2813 2814 Unlikely exitcode - Short description of command exitcode 2815 2816 Long description of command exitcode. 2817 2818 Usage: 2819 unlikely exitcode [flags] [args] 2820 2821 [args] are ignored 2822 2823 Unlikely flags - Short description of command flags 2824 2825 Long description of command flags. 2826 2827 Usage: 2828 unlikely flags [flags] [args] 2829 2830 [args] are ignored 2831 2832 The unlikely flags flags are: 2833 -global1= 2834 description of global1 2835 -local= 2836 description of local 2837 -shared= 2838 description of shared 2839 2840 Unlikely flat - Short description of command flat 2841 2842 Long description of command flat. 2843 2844 Usage: 2845 unlikely flat [flags] [args] 2846 2847 [args] are ignored 2848 2849 Unlikely foreign - No description available 2850 2851 Unlikely nested - Short description of command nested 2852 2853 Long description of command nested. 2854 2855 Usage: 2856 unlikely nested [flags] <command> 2857 2858 The unlikely nested commands are: 2859 child Short description of command child 2860 2861 Unlikely nested child - Short description of command child 2862 2863 Long description of command child. 2864 2865 Usage: 2866 unlikely nested child [flags] 2867 `, 2868 }, 2869 { 2870 Args: []string{"flat", "help", "..."}, 2871 Vars: map[string]string{ 2872 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2873 }, 2874 Err: errUsageStr, 2875 Stderr: `ERROR: unlikely flat: unsupported help invocation 2876 2877 Long description of command flat. 2878 2879 Usage: 2880 unlikely flat [flags] [args] 2881 2882 [args] are ignored 2883 2884 The global flags are: 2885 -metadata=<just specify -metadata to activate> 2886 Displays metadata for the program and exits. 2887 -time=false 2888 Dump timing information to stderr before exiting the program. 2889 `, 2890 }, 2891 { 2892 Args: []string{"nested", "child"}, 2893 Vars: map[string]string{ 2894 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2895 }, 2896 Err: errUsageStr, 2897 Stderr: `ERROR: wombats! 2898 2899 Long description of command child. 2900 2901 Usage: 2902 unlikely nested child [flags] 2903 2904 The global flags are: 2905 -metadata=<just specify -metadata to activate> 2906 Displays metadata for the program and exits. 2907 -time=false 2908 Dump timing information to stderr before exiting the program. 2909 `, 2910 }, 2911 { 2912 Args: []string{"dumpenv"}, 2913 Vars: map[string]string{"A": "a", "B": "b", "CMDLINE_PREFIX": "abc"}, 2914 Stdout: "[A=a B=b]\n", 2915 }, 2916 { 2917 Args: []string{"repeated"}, 2918 Vars: map[string]string{ 2919 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2920 }, 2921 Stdout: "Hello\n", 2922 }, 2923 { 2924 Args: []string{"exitcode"}, 2925 Vars: map[string]string{ 2926 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2927 }, 2928 Err: "exit code 42", 2929 }, 2930 { 2931 Args: []string{"flags"}, 2932 Vars: map[string]string{ 2933 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2934 }, 2935 Stdout: `global1="" shared="" local="" []` + "\n", 2936 }, 2937 { 2938 Args: []string{"-global1=A B", "-shared=C D", "flags"}, 2939 Vars: map[string]string{ 2940 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2941 }, 2942 Stdout: `global1="A B" shared="C D" local="" []` + "\n", 2943 GlobalFlag1: "A B", 2944 }, 2945 { 2946 Args: []string{"flags", "-global1=A B", "-shared=C D"}, 2947 Vars: map[string]string{ 2948 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2949 }, 2950 Stdout: `global1="A B" shared="C D" local="" []` + "\n", 2951 }, 2952 { 2953 Args: []string{"flags", "-global1=A B", "-shared=C D", "-local=E F"}, 2954 Vars: map[string]string{ 2955 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2956 }, 2957 Stdout: `global1="A B" shared="C D" local="E F" []` + "\n", 2958 }, 2959 { 2960 Args: []string{"flags", "x", "y", "z"}, 2961 Vars: map[string]string{ 2962 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2963 }, 2964 Stdout: `global1="" shared="" local="" ["x" "y" "z"]` + "\n", 2965 }, 2966 { 2967 Args: []string{"flags", "-global1=A B", "-shared=C D", "-local=E F", "x", "y", "z"}, 2968 Vars: map[string]string{ 2969 "PATH": strings.Join(tokens, string(os.PathListSeparator)), 2970 }, 2971 Stdout: `global1="A B" shared="C D" local="E F" ["x" "y" "z"]` + "\n", 2972 }, 2973 } 2974 runTestCases(t, cmd, tests) 2975 } 2976 2977 func TestParsedFlags(t *testing.T) { 2978 root := &Command{ 2979 Name: "root", 2980 Short: "short", 2981 Long: "long.", 2982 Runner: RunnerFunc(runHello), 2983 } 2984 var v1, v2 bool 2985 env := EnvFromOS() 2986 root.Flags.BoolVar(&v1, "a", false, "bool") 2987 root.Flags.BoolVar(&v2, "b", false, "bool") 2988 2989 // ParsedFlags should be nil if Parse fails. 2990 _, _, err := Parse(root, env, []string{"-xx"}) 2991 if err == nil { 2992 t.Errorf("expected an error") 2993 } 2994 var nilFlagSet *flag.FlagSet 2995 if got, want := root.ParsedFlags, nilFlagSet; got != want { 2996 t.Errorf("got %v, want %v", got, want) 2997 } 2998 2999 // ParsedFlags should be set and Parsed returns true if 3000 // the command line is successfully parsed. 3001 _, _, err = Parse(root, env, nil) 3002 if err != nil { 3003 t.Fatal(err) 3004 } 3005 if got, want := root.Flags.Parsed(), false; got != want { 3006 t.Errorf("got %v, want %v", got, want) 3007 } 3008 if got, want := root.ParsedFlags.Parsed(), true; got != want { 3009 t.Errorf("got %v, want %v", got, want) 3010 } 3011 if got, want := v1, false; got != want { 3012 t.Errorf("got %v, want %v", got, want) 3013 } 3014 if got, want := v2, false; got != want { 3015 t.Errorf("got %v, want %v", got, want) 3016 } 3017 3018 _, _, err = Parse(root, env, []string{"-a"}) 3019 if err != nil { 3020 t.Fatal(err) 3021 } 3022 if got, want := root.Flags.Parsed(), false; got != want { 3023 t.Errorf("got %v, want %v", got, want) 3024 } 3025 if got, want := root.ParsedFlags.Parsed(), true; got != want { 3026 t.Errorf("got %v, want %v", got, want) 3027 } 3028 if got, want := v1, true; got != want { 3029 t.Errorf("got %v, want %v", got, want) 3030 } 3031 if got, want := v2, false; got != want { 3032 t.Errorf("got %v, want %v", got, want) 3033 } 3034 } 3035 3036 type fc struct { 3037 DontPropagateFlags bool 3038 DontInheritFlags bool 3039 } 3040 3041 func TestFlagPropagation(t *testing.T) { 3042 var err error 3043 env := EnvFromOS() 3044 3045 tests := []struct { 3046 flagConfigs []fc 3047 args []string 3048 want []string 3049 }{ 3050 { 3051 []fc{fc{false, false}, fc{false, false}, fc{false, false}}, 3052 []string{"cmd1", "cmd2"}, 3053 []string{"flag0", "flag1", "flag2"}, 3054 }, 3055 { 3056 []fc{fc{true, false}, fc{false, false}, fc{false, false}}, 3057 []string{"cmd1", "cmd2"}, 3058 []string{"flag1", "flag2"}, 3059 }, 3060 { 3061 []fc{fc{false, false}, fc{true, false}, fc{false, false}}, 3062 []string{"cmd1", "cmd2"}, 3063 []string{"flag2"}, 3064 }, 3065 { 3066 []fc{fc{false, false}, fc{false, true}, fc{false, false}}, 3067 []string{"cmd1", "cmd2"}, 3068 []string{"flag1", "flag2"}, 3069 }, 3070 { 3071 []fc{fc{false, false}, fc{true, true}, fc{false, false}}, 3072 []string{"cmd1", "cmd2"}, 3073 []string{"flag2"}, 3074 }, 3075 { 3076 []fc{fc{false, false}, fc{false, false}, fc{true, false}}, 3077 []string{"cmd1", "cmd2"}, 3078 []string{"flag0", "flag1", "flag2"}, 3079 }, 3080 { 3081 []fc{fc{false, false}, fc{false, false}, fc{false, true}}, 3082 []string{"cmd1", "cmd2"}, 3083 []string{"flag2"}, 3084 }, 3085 { 3086 []fc{fc{false, false}, fc{false, false}, fc{true, true}}, 3087 []string{"cmd1", "cmd2"}, 3088 []string{"flag2"}, 3089 }, 3090 } 3091 3092 for _, test := range tests { 3093 commands := createCommandTree(test.flagConfigs) 3094 root := commands[0] 3095 leaf := commands[len(commands)-1] 3096 3097 _, _, err = Parse(root, env, test.args) 3098 if err != nil { 3099 t.Fatal(err) 3100 } 3101 3102 want := map[string]bool{} 3103 globalFlags.VisitAll(func(f *flag.Flag) { want[f.Name] = true }) 3104 for _, flagName := range test.want { 3105 want[flagName] = true 3106 } 3107 3108 got := map[string]bool{} 3109 leaf.ParsedFlags.VisitAll(func(f *flag.Flag) { got[f.Name] = true }) 3110 3111 if !reflect.DeepEqual(got, want) { 3112 t.Fatalf("got %v, want %v", got, want) 3113 } 3114 } 3115 } 3116 3117 func createCommandTree(flagConfigs []fc) []*Command { 3118 size := len(flagConfigs) 3119 result := make([]*Command, size) 3120 3121 result[size-1] = &Command{Runner: RunnerFunc(runHello)} 3122 for i := size - 2; i >= 0; i-- { 3123 result[i] = &Command{Children: []*Command{result[i+1]}} 3124 } 3125 3126 for i, cmd := range result { 3127 cmd.Name = "cmd" + strconv.Itoa(i) 3128 cmd.Short = "short" 3129 cmd.Long = "long." 3130 cmd.Flags.Bool("flag"+strconv.Itoa(i), false, "bool") 3131 cmd.DontPropagateFlags = flagConfigs[i].DontPropagateFlags 3132 cmd.DontInheritFlags = flagConfigs[i].DontInheritFlags 3133 } 3134 3135 return result 3136 }