1package cli 2 3import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "runtime" 10 "strings" 11 "testing" 12) 13 14func Test_ShowAppHelp_NoAuthor(t *testing.T) { 15 output := new(bytes.Buffer) 16 app := &App{Writer: output} 17 18 c := NewContext(app, nil, nil) 19 20 _ = ShowAppHelp(c) 21 22 if bytes.Contains(output.Bytes(), []byte("AUTHOR(S):")) { 23 t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):") 24 } 25} 26 27func Test_ShowAppHelp_NoVersion(t *testing.T) { 28 output := new(bytes.Buffer) 29 app := &App{Writer: output} 30 31 app.Version = "" 32 33 c := NewContext(app, nil, nil) 34 35 _ = ShowAppHelp(c) 36 37 if bytes.Contains(output.Bytes(), []byte("VERSION:")) { 38 t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:") 39 } 40} 41 42func Test_ShowAppHelp_HideVersion(t *testing.T) { 43 output := new(bytes.Buffer) 44 app := &App{Writer: output} 45 46 app.HideVersion = true 47 48 c := NewContext(app, nil, nil) 49 50 _ = ShowAppHelp(c) 51 52 if bytes.Contains(output.Bytes(), []byte("VERSION:")) { 53 t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:") 54 } 55} 56 57func Test_Help_Custom_Flags(t *testing.T) { 58 oldFlag := HelpFlag 59 defer func() { 60 HelpFlag = oldFlag 61 }() 62 63 HelpFlag = &BoolFlag{ 64 Name: "help", 65 Aliases: []string{"x"}, 66 Usage: "show help", 67 } 68 69 app := App{ 70 Flags: []Flag{ 71 &BoolFlag{Name: "foo", Aliases: []string{"h"}}, 72 }, 73 Action: func(ctx *Context) error { 74 if ctx.Bool("h") != true { 75 t.Errorf("custom help flag not set") 76 } 77 return nil 78 }, 79 } 80 output := new(bytes.Buffer) 81 app.Writer = output 82 _ = app.Run([]string{"test", "-h"}) 83 if output.Len() > 0 { 84 t.Errorf("unexpected output: %s", output.String()) 85 } 86} 87 88func Test_Version_Custom_Flags(t *testing.T) { 89 oldFlag := VersionFlag 90 defer func() { 91 VersionFlag = oldFlag 92 }() 93 94 VersionFlag = &BoolFlag{ 95 Name: "version", 96 Aliases: []string{"V"}, 97 Usage: "show version", 98 } 99 100 app := App{ 101 Flags: []Flag{ 102 &BoolFlag{Name: "foo", Aliases: []string{"v"}}, 103 }, 104 Action: func(ctx *Context) error { 105 if ctx.Bool("v") != true { 106 t.Errorf("custom version flag not set") 107 } 108 return nil 109 }, 110 } 111 output := new(bytes.Buffer) 112 app.Writer = output 113 _ = app.Run([]string{"test", "-v"}) 114 if output.Len() > 0 { 115 t.Errorf("unexpected output: %s", output.String()) 116 } 117} 118 119func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) { 120 app := &App{} 121 122 set := flag.NewFlagSet("test", 0) 123 _ = set.Parse([]string{"foo"}) 124 125 c := NewContext(app, set, nil) 126 127 err := helpCommand.Action(c) 128 129 if err == nil { 130 t.Fatalf("expected error from helpCommand.Action(), but got nil") 131 } 132 133 exitErr, ok := err.(*exitError) 134 if !ok { 135 t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error()) 136 } 137 138 if !strings.HasPrefix(exitErr.Error(), "No help topic for") { 139 t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error()) 140 } 141 142 if exitErr.exitCode != 3 { 143 t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode) 144 } 145} 146 147func Test_helpCommand_InHelpOutput(t *testing.T) { 148 app := &App{} 149 output := &bytes.Buffer{} 150 app.Writer = output 151 _ = app.Run([]string{"test", "--help"}) 152 153 s := output.String() 154 155 if strings.Contains(s, "\nCOMMANDS:\nGLOBAL OPTIONS:\n") { 156 t.Fatalf("empty COMMANDS section detected: %q", s) 157 } 158 159 if !strings.Contains(s, "help, h") { 160 t.Fatalf("missing \"help, h\": %q", s) 161 } 162} 163 164func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) { 165 app := &App{} 166 167 set := flag.NewFlagSet("test", 0) 168 _ = set.Parse([]string{"foo"}) 169 170 c := NewContext(app, set, nil) 171 172 err := helpSubcommand.Action(c) 173 174 if err == nil { 175 t.Fatalf("expected error from helpCommand.Action(), but got nil") 176 } 177 178 exitErr, ok := err.(*exitError) 179 if !ok { 180 t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error()) 181 } 182 183 if !strings.HasPrefix(exitErr.Error(), "No help topic for") { 184 t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error()) 185 } 186 187 if exitErr.exitCode != 3 { 188 t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode) 189 } 190} 191 192func TestShowAppHelp_CommandAliases(t *testing.T) { 193 app := &App{ 194 Commands: []*Command{ 195 { 196 Name: "frobbly", 197 Aliases: []string{"fr", "frob"}, 198 Action: func(ctx *Context) error { 199 return nil 200 }, 201 }, 202 }, 203 } 204 205 output := &bytes.Buffer{} 206 app.Writer = output 207 _ = app.Run([]string{"foo", "--help"}) 208 209 if !strings.Contains(output.String(), "frobbly, fr, frob") { 210 t.Errorf("expected output to include all command aliases; got: %q", output.String()) 211 } 212} 213 214func TestShowCommandHelp_HelpPrinter(t *testing.T) { 215 doublecho := func(text string) string { 216 return text + " " + text 217 } 218 219 tests := []struct { 220 name string 221 template string 222 printer helpPrinter 223 command string 224 wantTemplate string 225 wantOutput string 226 }{ 227 { 228 name: "no-command", 229 template: "", 230 printer: func(w io.Writer, templ string, data interface{}) { 231 fmt.Fprint(w, "yo") 232 }, 233 command: "", 234 wantTemplate: SubcommandHelpTemplate, 235 wantOutput: "yo", 236 }, 237 { 238 name: "standard-command", 239 template: "", 240 printer: func(w io.Writer, templ string, data interface{}) { 241 fmt.Fprint(w, "yo") 242 }, 243 command: "my-command", 244 wantTemplate: CommandHelpTemplate, 245 wantOutput: "yo", 246 }, 247 { 248 name: "custom-template-command", 249 template: "{{doublecho .Name}}", 250 printer: func(w io.Writer, templ string, data interface{}) { 251 // Pass a custom function to ensure it gets used 252 fm := map[string]interface{}{"doublecho": doublecho} 253 HelpPrinterCustom(w, templ, data, fm) 254 }, 255 command: "my-command", 256 wantTemplate: "{{doublecho .Name}}", 257 wantOutput: "my-command my-command", 258 }, 259 } 260 261 for _, tt := range tests { 262 t.Run(tt.name, func(t *testing.T) { 263 defer func(old helpPrinter) { 264 HelpPrinter = old 265 }(HelpPrinter) 266 HelpPrinter = func(w io.Writer, templ string, data interface{}) { 267 if templ != tt.wantTemplate { 268 t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ) 269 } 270 271 tt.printer(w, templ, data) 272 } 273 274 var buf bytes.Buffer 275 app := &App{ 276 Name: "my-app", 277 Writer: &buf, 278 Commands: []*Command{ 279 { 280 Name: "my-command", 281 CustomHelpTemplate: tt.template, 282 }, 283 }, 284 } 285 286 err := app.Run([]string{"my-app", "help", tt.command}) 287 if err != nil { 288 t.Fatal(err) 289 } 290 291 got := buf.String() 292 if got != tt.wantOutput { 293 t.Errorf("want output %q, got %q", tt.wantOutput, got) 294 } 295 }) 296 } 297} 298 299func TestShowCommandHelp_HelpPrinterCustom(t *testing.T) { 300 doublecho := func(text string) string { 301 return text + " " + text 302 } 303 304 tests := []struct { 305 name string 306 template string 307 printer helpPrinterCustom 308 command string 309 wantTemplate string 310 wantOutput string 311 }{ 312 { 313 name: "no-command", 314 template: "", 315 printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) { 316 fmt.Fprint(w, "yo") 317 }, 318 command: "", 319 wantTemplate: SubcommandHelpTemplate, 320 wantOutput: "yo", 321 }, 322 { 323 name: "standard-command", 324 template: "", 325 printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) { 326 fmt.Fprint(w, "yo") 327 }, 328 command: "my-command", 329 wantTemplate: CommandHelpTemplate, 330 wantOutput: "yo", 331 }, 332 { 333 name: "custom-template-command", 334 template: "{{doublecho .Name}}", 335 printer: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) { 336 // Pass a custom function to ensure it gets used 337 fm := map[string]interface{}{"doublecho": doublecho} 338 printHelpCustom(w, templ, data, fm) 339 }, 340 command: "my-command", 341 wantTemplate: "{{doublecho .Name}}", 342 wantOutput: "my-command my-command", 343 }, 344 } 345 346 for _, tt := range tests { 347 t.Run(tt.name, func(t *testing.T) { 348 defer func(old helpPrinterCustom) { 349 HelpPrinterCustom = old 350 }(HelpPrinterCustom) 351 HelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) { 352 if fm != nil { 353 t.Error("unexpected function map passed") 354 } 355 356 if templ != tt.wantTemplate { 357 t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ) 358 } 359 360 tt.printer(w, templ, data, fm) 361 } 362 363 var buf bytes.Buffer 364 app := &App{ 365 Name: "my-app", 366 Writer: &buf, 367 Commands: []*Command{ 368 { 369 Name: "my-command", 370 CustomHelpTemplate: tt.template, 371 }, 372 }, 373 } 374 375 err := app.Run([]string{"my-app", "help", tt.command}) 376 if err != nil { 377 t.Fatal(err) 378 } 379 380 got := buf.String() 381 if got != tt.wantOutput { 382 t.Errorf("want output %q, got %q", tt.wantOutput, got) 383 } 384 }) 385 } 386} 387 388func TestShowCommandHelp_CommandAliases(t *testing.T) { 389 app := &App{ 390 Commands: []*Command{ 391 { 392 Name: "frobbly", 393 Aliases: []string{"fr", "frob", "bork"}, 394 Action: func(ctx *Context) error { 395 return nil 396 }, 397 }, 398 }, 399 } 400 401 output := &bytes.Buffer{} 402 app.Writer = output 403 _ = app.Run([]string{"foo", "help", "fr"}) 404 405 if !strings.Contains(output.String(), "frobbly") { 406 t.Errorf("expected output to include command name; got: %q", output.String()) 407 } 408 409 if strings.Contains(output.String(), "bork") { 410 t.Errorf("expected output to exclude command aliases; got: %q", output.String()) 411 } 412} 413 414func TestShowSubcommandHelp_CommandAliases(t *testing.T) { 415 app := &App{ 416 Commands: []*Command{ 417 { 418 Name: "frobbly", 419 Aliases: []string{"fr", "frob", "bork"}, 420 Action: func(ctx *Context) error { 421 return nil 422 }, 423 }, 424 }, 425 } 426 427 output := &bytes.Buffer{} 428 app.Writer = output 429 _ = app.Run([]string{"foo", "help"}) 430 431 if !strings.Contains(output.String(), "frobbly, fr, frob, bork") { 432 t.Errorf("expected output to include all command aliases; got: %q", output.String()) 433 } 434} 435 436func TestShowCommandHelp_Customtemplate(t *testing.T) { 437 app := &App{ 438 Commands: []*Command{ 439 { 440 Name: "frobbly", 441 Action: func(ctx *Context) error { 442 return nil 443 }, 444 HelpName: "foo frobbly", 445 CustomHelpTemplate: `NAME: 446 {{.HelpName}} - {{.Usage}} 447 448USAGE: 449 {{.HelpName}} [FLAGS] TARGET [TARGET ...] 450 451FLAGS: 452 {{range .VisibleFlags}}{{.}} 453 {{end}} 454EXAMPLES: 455 1. Frobbly runs with this param locally. 456 $ {{.HelpName}} wobbly 457`, 458 }, 459 }, 460 } 461 output := &bytes.Buffer{} 462 app.Writer = output 463 _ = app.Run([]string{"foo", "help", "frobbly"}) 464 465 if strings.Contains(output.String(), "2. Frobbly runs without this param locally.") { 466 t.Errorf("expected output to exclude \"2. Frobbly runs without this param locally.\"; got: %q", output.String()) 467 } 468 469 if !strings.Contains(output.String(), "1. Frobbly runs with this param locally.") { 470 t.Errorf("expected output to include \"1. Frobbly runs with this param locally.\"; got: %q", output.String()) 471 } 472 473 if !strings.Contains(output.String(), "$ foo frobbly wobbly") { 474 t.Errorf("expected output to include \"$ foo frobbly wobbly\"; got: %q", output.String()) 475 } 476} 477 478func TestShowSubcommandHelp_CommandUsageText(t *testing.T) { 479 app := &App{ 480 Commands: []*Command{ 481 { 482 Name: "frobbly", 483 UsageText: "this is usage text", 484 }, 485 }, 486 } 487 488 output := &bytes.Buffer{} 489 app.Writer = output 490 491 _ = app.Run([]string{"foo", "frobbly", "--help"}) 492 493 if !strings.Contains(output.String(), "this is usage text") { 494 t.Errorf("expected output to include usage text; got: %q", output.String()) 495 } 496} 497 498func TestShowSubcommandHelp_SubcommandUsageText(t *testing.T) { 499 app := &App{ 500 Commands: []*Command{ 501 { 502 Name: "frobbly", 503 Subcommands: []*Command{ 504 { 505 Name: "bobbly", 506 UsageText: "this is usage text", 507 }, 508 }, 509 }, 510 }, 511 } 512 513 output := &bytes.Buffer{} 514 app.Writer = output 515 _ = app.Run([]string{"foo", "frobbly", "bobbly", "--help"}) 516 517 if !strings.Contains(output.String(), "this is usage text") { 518 t.Errorf("expected output to include usage text; got: %q", output.String()) 519 } 520} 521 522func TestShowAppHelp_HiddenCommand(t *testing.T) { 523 app := &App{ 524 Commands: []*Command{ 525 { 526 Name: "frobbly", 527 Action: func(ctx *Context) error { 528 return nil 529 }, 530 }, 531 { 532 Name: "secretfrob", 533 Hidden: true, 534 Action: func(ctx *Context) error { 535 return nil 536 }, 537 }, 538 }, 539 } 540 541 output := &bytes.Buffer{} 542 app.Writer = output 543 _ = app.Run([]string{"app", "--help"}) 544 545 if strings.Contains(output.String(), "secretfrob") { 546 t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String()) 547 } 548 549 if !strings.Contains(output.String(), "frobbly") { 550 t.Errorf("expected output to include \"frobbly\"; got: %q", output.String()) 551 } 552} 553 554func TestShowAppHelp_HelpPrinter(t *testing.T) { 555 doublecho := func(text string) string { 556 return text + " " + text 557 } 558 559 tests := []struct { 560 name string 561 template string 562 printer helpPrinter 563 wantTemplate string 564 wantOutput string 565 }{ 566 { 567 name: "standard-command", 568 template: "", 569 printer: func(w io.Writer, templ string, data interface{}) { 570 fmt.Fprint(w, "yo") 571 }, 572 wantTemplate: AppHelpTemplate, 573 wantOutput: "yo", 574 }, 575 { 576 name: "custom-template-command", 577 template: "{{doublecho .Name}}", 578 printer: func(w io.Writer, templ string, data interface{}) { 579 // Pass a custom function to ensure it gets used 580 fm := map[string]interface{}{"doublecho": doublecho} 581 printHelpCustom(w, templ, data, fm) 582 }, 583 wantTemplate: "{{doublecho .Name}}", 584 wantOutput: "my-app my-app", 585 }, 586 } 587 588 for _, tt := range tests { 589 t.Run(tt.name, func(t *testing.T) { 590 defer func(old helpPrinter) { 591 HelpPrinter = old 592 }(HelpPrinter) 593 HelpPrinter = func(w io.Writer, templ string, data interface{}) { 594 if templ != tt.wantTemplate { 595 t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ) 596 } 597 598 tt.printer(w, templ, data) 599 } 600 601 var buf bytes.Buffer 602 app := &App{ 603 Name: "my-app", 604 Writer: &buf, 605 CustomAppHelpTemplate: tt.template, 606 } 607 608 err := app.Run([]string{"my-app", "help"}) 609 if err != nil { 610 t.Fatal(err) 611 } 612 613 got := buf.String() 614 if got != tt.wantOutput { 615 t.Errorf("want output %q, got %q", tt.wantOutput, got) 616 } 617 }) 618 } 619} 620 621func TestShowAppHelp_HelpPrinterCustom(t *testing.T) { 622 doublecho := func(text string) string { 623 return text + " " + text 624 } 625 626 tests := []struct { 627 name string 628 template string 629 printer helpPrinterCustom 630 wantTemplate string 631 wantOutput string 632 }{ 633 { 634 name: "standard-command", 635 template: "", 636 printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) { 637 fmt.Fprint(w, "yo") 638 }, 639 wantTemplate: AppHelpTemplate, 640 wantOutput: "yo", 641 }, 642 { 643 name: "custom-template-command", 644 template: "{{doublecho .Name}}", 645 printer: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) { 646 // Pass a custom function to ensure it gets used 647 fm := map[string]interface{}{"doublecho": doublecho} 648 printHelpCustom(w, templ, data, fm) 649 }, 650 wantTemplate: "{{doublecho .Name}}", 651 wantOutput: "my-app my-app", 652 }, 653 } 654 655 for _, tt := range tests { 656 t.Run(tt.name, func(t *testing.T) { 657 defer func(old helpPrinterCustom) { 658 HelpPrinterCustom = old 659 }(HelpPrinterCustom) 660 HelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) { 661 if fm != nil { 662 t.Error("unexpected function map passed") 663 } 664 665 if templ != tt.wantTemplate { 666 t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ) 667 } 668 669 tt.printer(w, templ, data, fm) 670 } 671 672 var buf bytes.Buffer 673 app := &App{ 674 Name: "my-app", 675 Writer: &buf, 676 CustomAppHelpTemplate: tt.template, 677 } 678 679 err := app.Run([]string{"my-app", "help"}) 680 if err != nil { 681 t.Fatal(err) 682 } 683 684 got := buf.String() 685 if got != tt.wantOutput { 686 t.Errorf("want output %q, got %q", tt.wantOutput, got) 687 } 688 }) 689 } 690} 691 692func TestShowAppHelp_CustomAppTemplate(t *testing.T) { 693 app := &App{ 694 Commands: []*Command{ 695 { 696 Name: "frobbly", 697 Action: func(ctx *Context) error { 698 return nil 699 }, 700 }, 701 { 702 Name: "secretfrob", 703 Hidden: true, 704 Action: func(ctx *Context) error { 705 return nil 706 }, 707 }, 708 }, 709 ExtraInfo: func() map[string]string { 710 platform := fmt.Sprintf("OS: %s | Arch: %s", runtime.GOOS, runtime.GOARCH) 711 goruntime := fmt.Sprintf("Version: %s | CPUs: %d", runtime.Version(), runtime.NumCPU()) 712 return map[string]string{ 713 "PLATFORM": platform, 714 "RUNTIME": goruntime, 715 } 716 }, 717 CustomAppHelpTemplate: `NAME: 718 {{.Name}} - {{.Usage}} 719 720USAGE: 721 {{.Name}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}} [COMMAND FLAGS | -h]{{end}} [ARGUMENTS...] 722 723COMMANDS: 724 {{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} 725 {{end}}{{if .VisibleFlags}} 726GLOBAL FLAGS: 727 {{range .VisibleFlags}}{{.}} 728 {{end}}{{end}} 729VERSION: 730 2.0.0 731{{"\n"}}{{range $key, $value := ExtraInfo}} 732{{$key}}: 733 {{$value}} 734{{end}}`, 735 } 736 737 output := &bytes.Buffer{} 738 app.Writer = output 739 _ = app.Run([]string{"app", "--help"}) 740 741 if strings.Contains(output.String(), "secretfrob") { 742 t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String()) 743 } 744 745 if !strings.Contains(output.String(), "frobbly") { 746 t.Errorf("expected output to include \"frobbly\"; got: %q", output.String()) 747 } 748 749 if !strings.Contains(output.String(), "PLATFORM:") || 750 !strings.Contains(output.String(), "OS:") || 751 !strings.Contains(output.String(), "Arch:") { 752 t.Errorf("expected output to include \"PLATFORM:, OS: and Arch:\"; got: %q", output.String()) 753 } 754 755 if !strings.Contains(output.String(), "RUNTIME:") || 756 !strings.Contains(output.String(), "Version:") || 757 !strings.Contains(output.String(), "CPUs:") { 758 t.Errorf("expected output to include \"RUNTIME:, Version: and CPUs:\"; got: %q", output.String()) 759 } 760 761 if !strings.Contains(output.String(), "VERSION:") || 762 !strings.Contains(output.String(), "2.0.0") { 763 t.Errorf("expected output to include \"VERSION:, 2.0.0\"; got: %q", output.String()) 764 } 765} 766 767func TestHideHelpCommand(t *testing.T) { 768 app := &App{ 769 HideHelpCommand: true, 770 Writer: ioutil.Discard, 771 } 772 773 err := app.Run([]string{"foo", "help"}) 774 if err == nil { 775 t.Fatalf("expected a non-nil error") 776 } 777 if !strings.Contains(err.Error(), "No help topic for 'help'") { 778 t.Errorf("Run returned unexpected error: %v", err) 779 } 780 781 err = app.Run([]string{"foo", "--help"}) 782 if err != nil { 783 t.Errorf("Run returned unexpected error: %v", err) 784 } 785} 786 787func TestHideHelpCommand_False(t *testing.T) { 788 app := &App{ 789 HideHelpCommand: false, 790 Writer: ioutil.Discard, 791 } 792 793 err := app.Run([]string{"foo", "help"}) 794 if err != nil { 795 t.Errorf("Run returned unexpected error: %v", err) 796 } 797 798 err = app.Run([]string{"foo", "--help"}) 799 if err != nil { 800 t.Errorf("Run returned unexpected error: %v", err) 801 } 802} 803 804func TestHideHelpCommand_WithHideHelp(t *testing.T) { 805 app := &App{ 806 HideHelp: true, // effective (hides both command and flag) 807 HideHelpCommand: true, // ignored 808 Writer: ioutil.Discard, 809 } 810 811 err := app.Run([]string{"foo", "help"}) 812 if err == nil { 813 t.Fatalf("expected a non-nil error") 814 } 815 if !strings.Contains(err.Error(), "No help topic for 'help'") { 816 t.Errorf("Run returned unexpected error: %v", err) 817 } 818 819 err = app.Run([]string{"foo", "--help"}) 820 if err == nil { 821 t.Fatalf("expected a non-nil error") 822 } 823 if !strings.Contains(err.Error(), "flag: help requested") { 824 t.Errorf("Run returned unexpected error: %v", err) 825 } 826} 827 828func newContextFromStringSlice(ss []string) *Context { 829 set := flag.NewFlagSet("", flag.ContinueOnError) 830 _ = set.Parse(ss) 831 return &Context{flagSet: set} 832} 833 834func TestHideHelpCommand_RunAsSubcommand(t *testing.T) { 835 app := &App{ 836 HideHelpCommand: true, 837 Writer: ioutil.Discard, 838 Commands: []*Command{ 839 { 840 Name: "dummy", 841 }, 842 }, 843 } 844 845 err := app.RunAsSubcommand(newContextFromStringSlice([]string{"", "help"})) 846 if err == nil { 847 t.Fatalf("expected a non-nil error") 848 } 849 if !strings.Contains(err.Error(), "No help topic for 'help'") { 850 t.Errorf("Run returned unexpected error: %v", err) 851 } 852 853 err = app.RunAsSubcommand(newContextFromStringSlice([]string{"", "--help"})) 854 if err != nil { 855 t.Errorf("Run returned unexpected error: %v", err) 856 } 857} 858 859func TestHideHelpCommand_RunAsSubcommand_False(t *testing.T) { 860 app := &App{ 861 HideHelpCommand: false, 862 Writer: ioutil.Discard, 863 Commands: []*Command{ 864 { 865 Name: "dummy", 866 }, 867 }, 868 } 869 870 err := app.RunAsSubcommand(newContextFromStringSlice([]string{"", "help"})) 871 if err != nil { 872 t.Errorf("Run returned unexpected error: %v", err) 873 } 874 875 err = app.RunAsSubcommand(newContextFromStringSlice([]string{"", "--help"})) 876 if err != nil { 877 t.Errorf("Run returned unexpected error: %v", err) 878 } 879} 880 881func TestHideHelpCommand_WithSubcommands(t *testing.T) { 882 app := &App{ 883 Writer: ioutil.Discard, 884 Commands: []*Command{ 885 { 886 Name: "dummy", 887 Subcommands: []*Command{ 888 { 889 Name: "dummy2", 890 }, 891 }, 892 HideHelpCommand: true, 893 }, 894 }, 895 } 896 897 err := app.Run([]string{"foo", "dummy", "help"}) 898 if err == nil { 899 t.Fatalf("expected a non-nil error") 900 } 901 if !strings.Contains(err.Error(), "No help topic for 'help'") { 902 t.Errorf("Run returned unexpected error: %v", err) 903 } 904 905 err = app.Run([]string{"foo", "dummy", "--help"}) 906 if err != nil { 907 t.Errorf("Run returned unexpected error: %v", err) 908 } 909} 910