github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/cli/app_test.go (about) 1 package cli 2 3 import ( 4 "bytes" 5 "errors" 6 "flag" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "reflect" 12 "strings" 13 "testing" 14 ) 15 16 func ExampleApp_Run() { 17 // set args for examples sake 18 os.Args = []string{"greet", "--name", "Jeremy"} 19 20 app := NewApp() 21 app.Name = "greet" 22 app.Flags = []Flag{ 23 StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, 24 } 25 app.Action = func(c *Context) { 26 fmt.Printf("Hello %v\n", c.String("name")) 27 } 28 app.UsageText = "app [first_arg] [second_arg]" 29 app.Author = "Harrison" 30 app.Email = "harrison@lolwut.com" 31 app.Authors = []Author{Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}} 32 app.Run(os.Args) 33 // Output: 34 // Hello Jeremy 35 } 36 37 func ExampleApp_Run_subcommand() { 38 // set args for examples sake 39 os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} 40 app := NewApp() 41 app.Name = "say" 42 app.Commands = []Command{ 43 { 44 Name: "hello", 45 Aliases: []string{"hi"}, 46 Usage: "use it to see a description", 47 Description: "This is how we describe hello the function", 48 Subcommands: []Command{ 49 { 50 Name: "english", 51 Aliases: []string{"en"}, 52 Usage: "sends a greeting in english", 53 Description: "greets someone in english", 54 Flags: []Flag{ 55 StringFlag{ 56 Name: "name", 57 Value: "Bob", 58 Usage: "Name of the person to greet", 59 }, 60 }, 61 Action: func(c *Context) { 62 fmt.Println("Hello,", c.String("name")) 63 }, 64 }, 65 }, 66 }, 67 } 68 69 app.Run(os.Args) 70 // Output: 71 // Hello, Jeremy 72 } 73 74 func ExampleApp_Run_help() { 75 // set args for examples sake 76 os.Args = []string{"greet", "h", "describeit"} 77 78 app := NewApp() 79 app.Name = "greet" 80 app.Flags = []Flag{ 81 StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, 82 } 83 app.Commands = []Command{ 84 { 85 Name: "describeit", 86 Aliases: []string{"d"}, 87 Usage: "use it to see a description", 88 Description: "This is how we describe describeit the function", 89 Action: func(c *Context) { 90 fmt.Printf("i like to describe things") 91 }, 92 }, 93 } 94 app.Run(os.Args) 95 // Output: 96 // NAME: 97 // greet describeit - use it to see a description 98 // 99 // USAGE: 100 // greet describeit [arguments...] 101 // 102 // DESCRIPTION: 103 // This is how we describe describeit the function 104 } 105 106 func ExampleApp_Run_bashComplete() { 107 // set args for examples sake 108 os.Args = []string{"greet", "--generate-bash-completion"} 109 110 app := NewApp() 111 app.Name = "greet" 112 app.EnableBashCompletion = true 113 app.Commands = []Command{ 114 { 115 Name: "describeit", 116 Aliases: []string{"d"}, 117 Usage: "use it to see a description", 118 Description: "This is how we describe describeit the function", 119 Action: func(c *Context) { 120 fmt.Printf("i like to describe things") 121 }, 122 }, { 123 Name: "next", 124 Usage: "next example", 125 Description: "more stuff to see when generating bash completion", 126 Action: func(c *Context) { 127 fmt.Printf("the next example") 128 }, 129 }, 130 } 131 132 app.Run(os.Args) 133 // Output: 134 // describeit 135 // d 136 // next 137 // help 138 // h 139 } 140 141 func TestApp_Run(t *testing.T) { 142 s := "" 143 144 app := NewApp() 145 app.Action = func(c *Context) { 146 s = s + c.Args().First() 147 } 148 149 err := app.Run([]string{"command", "foo"}) 150 expect(t, err, nil) 151 err = app.Run([]string{"command", "bar"}) 152 expect(t, err, nil) 153 expect(t, s, "foobar") 154 } 155 156 var commandAppTests = []struct { 157 name string 158 expected bool 159 }{ 160 {"foobar", true}, 161 {"batbaz", true}, 162 {"b", true}, 163 {"f", true}, 164 {"bat", false}, 165 {"nothing", false}, 166 } 167 168 func TestApp_Command(t *testing.T) { 169 app := NewApp() 170 fooCommand := Command{Name: "foobar", Aliases: []string{"f"}} 171 batCommand := Command{Name: "batbaz", Aliases: []string{"b"}} 172 app.Commands = []Command{ 173 fooCommand, 174 batCommand, 175 } 176 177 for _, test := range commandAppTests { 178 expect(t, app.Command(test.name) != nil, test.expected) 179 } 180 } 181 182 func TestApp_CommandWithArgBeforeFlags(t *testing.T) { 183 var parsedOption, firstArg string 184 185 app := NewApp() 186 command := Command{ 187 Name: "cmd", 188 Flags: []Flag{ 189 StringFlag{Name: "option", Value: "", Usage: "some option"}, 190 }, 191 Action: func(c *Context) { 192 parsedOption = c.String("option") 193 firstArg = c.Args().First() 194 }, 195 } 196 app.Commands = []Command{command} 197 198 app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"}) 199 200 expect(t, parsedOption, "my-option") 201 expect(t, firstArg, "my-arg") 202 } 203 204 func TestApp_RunAsSubcommandParseFlags(t *testing.T) { 205 var context *Context 206 207 a := NewApp() 208 a.Commands = []Command{ 209 { 210 Name: "foo", 211 Action: func(c *Context) { 212 context = c 213 }, 214 Flags: []Flag{ 215 StringFlag{ 216 Name: "lang", 217 Value: "english", 218 Usage: "language for the greeting", 219 }, 220 }, 221 Before: func(_ *Context) error { return nil }, 222 }, 223 } 224 a.Run([]string{"", "foo", "--lang", "spanish", "abcd"}) 225 226 expect(t, context.Args().Get(0), "abcd") 227 expect(t, context.String("lang"), "spanish") 228 } 229 230 func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { 231 var parsedOption string 232 var args []string 233 234 app := NewApp() 235 command := Command{ 236 Name: "cmd", 237 Flags: []Flag{ 238 StringFlag{Name: "option", Value: "", Usage: "some option"}, 239 }, 240 Action: func(c *Context) { 241 parsedOption = c.String("option") 242 args = c.Args() 243 }, 244 } 245 app.Commands = []Command{command} 246 247 app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"}) 248 249 expect(t, parsedOption, "my-option") 250 expect(t, args[0], "my-arg") 251 expect(t, args[1], "--") 252 expect(t, args[2], "--notARealFlag") 253 } 254 255 func TestApp_CommandWithDash(t *testing.T) { 256 var args []string 257 258 app := NewApp() 259 command := Command{ 260 Name: "cmd", 261 Action: func(c *Context) { 262 args = c.Args() 263 }, 264 } 265 app.Commands = []Command{command} 266 267 app.Run([]string{"", "cmd", "my-arg", "-"}) 268 269 expect(t, args[0], "my-arg") 270 expect(t, args[1], "-") 271 } 272 273 func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { 274 var args []string 275 276 app := NewApp() 277 command := Command{ 278 Name: "cmd", 279 Action: func(c *Context) { 280 args = c.Args() 281 }, 282 } 283 app.Commands = []Command{command} 284 285 app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}) 286 287 expect(t, args[0], "my-arg") 288 expect(t, args[1], "--") 289 expect(t, args[2], "notAFlagAtAll") 290 } 291 292 func TestApp_Float64Flag(t *testing.T) { 293 var meters float64 294 295 app := NewApp() 296 app.Flags = []Flag{ 297 Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, 298 } 299 app.Action = func(c *Context) { 300 meters = c.Float64("height") 301 } 302 303 app.Run([]string{"", "--height", "1.93"}) 304 expect(t, meters, 1.93) 305 } 306 307 func TestApp_ParseSliceFlags(t *testing.T) { 308 var parsedOption, firstArg string 309 var parsedIntSlice []int 310 var parsedStringSlice []string 311 312 app := NewApp() 313 command := Command{ 314 Name: "cmd", 315 Flags: []Flag{ 316 IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"}, 317 StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"}, 318 }, 319 Action: func(c *Context) { 320 parsedIntSlice = c.IntSlice("p") 321 parsedStringSlice = c.StringSlice("ip") 322 parsedOption = c.String("option") 323 firstArg = c.Args().First() 324 }, 325 } 326 app.Commands = []Command{command} 327 328 app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"}) 329 330 IntsEquals := func(a, b []int) bool { 331 if len(a) != len(b) { 332 return false 333 } 334 for i, v := range a { 335 if v != b[i] { 336 return false 337 } 338 } 339 return true 340 } 341 342 StrsEquals := func(a, b []string) bool { 343 if len(a) != len(b) { 344 return false 345 } 346 for i, v := range a { 347 if v != b[i] { 348 return false 349 } 350 } 351 return true 352 } 353 var expectedIntSlice = []int{22, 80} 354 var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"} 355 356 if !IntsEquals(parsedIntSlice, expectedIntSlice) { 357 t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice) 358 } 359 360 if !StrsEquals(parsedStringSlice, expectedStringSlice) { 361 t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice) 362 } 363 } 364 365 func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) { 366 var parsedIntSlice []int 367 var parsedStringSlice []string 368 369 app := NewApp() 370 command := Command{ 371 Name: "cmd", 372 Flags: []Flag{ 373 IntSliceFlag{Name: "a", Usage: "set numbers"}, 374 StringSliceFlag{Name: "str", Usage: "set strings"}, 375 }, 376 Action: func(c *Context) { 377 parsedIntSlice = c.IntSlice("a") 378 parsedStringSlice = c.StringSlice("str") 379 }, 380 } 381 app.Commands = []Command{command} 382 383 app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"}) 384 385 var expectedIntSlice = []int{2} 386 var expectedStringSlice = []string{"A"} 387 388 if parsedIntSlice[0] != expectedIntSlice[0] { 389 t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0]) 390 } 391 392 if parsedStringSlice[0] != expectedStringSlice[0] { 393 t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0]) 394 } 395 } 396 397 func TestApp_DefaultStdout(t *testing.T) { 398 app := NewApp() 399 400 if app.Writer != os.Stdout { 401 t.Error("Default output writer not set.") 402 } 403 } 404 405 type mockWriter struct { 406 written []byte 407 } 408 409 func (fw *mockWriter) Write(p []byte) (n int, err error) { 410 if fw.written == nil { 411 fw.written = p 412 } else { 413 fw.written = append(fw.written, p...) 414 } 415 416 return len(p), nil 417 } 418 419 func (fw *mockWriter) GetWritten() (b []byte) { 420 return fw.written 421 } 422 423 func TestApp_SetStdout(t *testing.T) { 424 w := &mockWriter{} 425 426 app := NewApp() 427 app.Name = "test" 428 app.Writer = w 429 430 err := app.Run([]string{"help"}) 431 432 if err != nil { 433 t.Fatalf("Run error: %s", err) 434 } 435 436 if len(w.written) == 0 { 437 t.Error("App did not write output to desired writer.") 438 } 439 } 440 441 func TestApp_BeforeFunc(t *testing.T) { 442 beforeRun, subcommandRun := false, false 443 beforeError := fmt.Errorf("fail") 444 var err error 445 446 app := NewApp() 447 448 app.Before = func(c *Context) error { 449 beforeRun = true 450 s := c.String("opt") 451 if s == "fail" { 452 return beforeError 453 } 454 455 return nil 456 } 457 458 app.Commands = []Command{ 459 Command{ 460 Name: "sub", 461 Action: func(c *Context) { 462 subcommandRun = true 463 }, 464 }, 465 } 466 467 app.Flags = []Flag{ 468 StringFlag{Name: "opt"}, 469 } 470 471 // run with the Before() func succeeding 472 err = app.Run([]string{"command", "--opt", "succeed", "sub"}) 473 474 if err != nil { 475 t.Fatalf("Run error: %s", err) 476 } 477 478 if beforeRun == false { 479 t.Errorf("Before() not executed when expected") 480 } 481 482 if subcommandRun == false { 483 t.Errorf("Subcommand not executed when expected") 484 } 485 486 // reset 487 beforeRun, subcommandRun = false, false 488 489 // run with the Before() func failing 490 err = app.Run([]string{"command", "--opt", "fail", "sub"}) 491 492 // should be the same error produced by the Before func 493 if err != beforeError { 494 t.Errorf("Run error expected, but not received") 495 } 496 497 if beforeRun == false { 498 t.Errorf("Before() not executed when expected") 499 } 500 501 if subcommandRun == true { 502 t.Errorf("Subcommand executed when NOT expected") 503 } 504 505 } 506 507 func TestApp_AfterFunc(t *testing.T) { 508 afterRun, subcommandRun := false, false 509 afterError := fmt.Errorf("fail") 510 var err error 511 512 app := NewApp() 513 514 app.After = func(c *Context) error { 515 afterRun = true 516 s := c.String("opt") 517 if s == "fail" { 518 return afterError 519 } 520 521 return nil 522 } 523 524 app.Commands = []Command{ 525 Command{ 526 Name: "sub", 527 Action: func(c *Context) { 528 subcommandRun = true 529 }, 530 }, 531 } 532 533 app.Flags = []Flag{ 534 StringFlag{Name: "opt"}, 535 } 536 537 // run with the After() func succeeding 538 err = app.Run([]string{"command", "--opt", "succeed", "sub"}) 539 540 if err != nil { 541 t.Fatalf("Run error: %s", err) 542 } 543 544 if afterRun == false { 545 t.Errorf("After() not executed when expected") 546 } 547 548 if subcommandRun == false { 549 t.Errorf("Subcommand not executed when expected") 550 } 551 552 // reset 553 afterRun, subcommandRun = false, false 554 555 // run with the Before() func failing 556 err = app.Run([]string{"command", "--opt", "fail", "sub"}) 557 558 // should be the same error produced by the Before func 559 if err != afterError { 560 t.Errorf("Run error expected, but not received") 561 } 562 563 if afterRun == false { 564 t.Errorf("After() not executed when expected") 565 } 566 567 if subcommandRun == false { 568 t.Errorf("Subcommand not executed when expected") 569 } 570 } 571 572 func TestAppNoHelpFlag(t *testing.T) { 573 oldFlag := HelpFlag 574 defer func() { 575 HelpFlag = oldFlag 576 }() 577 578 HelpFlag = BoolFlag{} 579 580 app := NewApp() 581 app.Writer = ioutil.Discard 582 err := app.Run([]string{"test", "-h"}) 583 584 if err != flag.ErrHelp { 585 t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err) 586 } 587 } 588 589 func TestAppHelpPrinter(t *testing.T) { 590 oldPrinter := HelpPrinter 591 defer func() { 592 HelpPrinter = oldPrinter 593 }() 594 595 var wasCalled = false 596 HelpPrinter = func(w io.Writer, template string, data interface{}) { 597 wasCalled = true 598 } 599 600 app := NewApp() 601 app.Run([]string{"-h"}) 602 603 if wasCalled == false { 604 t.Errorf("Help printer expected to be called, but was not") 605 } 606 } 607 608 func TestAppVersionPrinter(t *testing.T) { 609 oldPrinter := VersionPrinter 610 defer func() { 611 VersionPrinter = oldPrinter 612 }() 613 614 var wasCalled = false 615 VersionPrinter = func(c *Context) { 616 wasCalled = true 617 } 618 619 app := NewApp() 620 ctx := NewContext(app, nil, nil) 621 ShowVersion(ctx) 622 623 if wasCalled == false { 624 t.Errorf("Version printer expected to be called, but was not") 625 } 626 } 627 628 func TestAppCommandNotFound(t *testing.T) { 629 beforeRun, subcommandRun := false, false 630 app := NewApp() 631 632 app.CommandNotFound = func(c *Context, command string) { 633 beforeRun = true 634 } 635 636 app.Commands = []Command{ 637 Command{ 638 Name: "bar", 639 Action: func(c *Context) { 640 subcommandRun = true 641 }, 642 }, 643 } 644 645 app.Run([]string{"command", "foo"}) 646 647 expect(t, beforeRun, true) 648 expect(t, subcommandRun, false) 649 } 650 651 func TestGlobalFlag(t *testing.T) { 652 var globalFlag string 653 var globalFlagSet bool 654 app := NewApp() 655 app.Flags = []Flag{ 656 StringFlag{Name: "global, g", Usage: "global"}, 657 } 658 app.Action = func(c *Context) { 659 globalFlag = c.GlobalString("global") 660 globalFlagSet = c.GlobalIsSet("global") 661 } 662 app.Run([]string{"command", "-g", "foo"}) 663 expect(t, globalFlag, "foo") 664 expect(t, globalFlagSet, true) 665 666 } 667 668 func TestGlobalFlagsInSubcommands(t *testing.T) { 669 subcommandRun := false 670 parentFlag := false 671 app := NewApp() 672 673 app.Flags = []Flag{ 674 BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, 675 } 676 677 app.Commands = []Command{ 678 Command{ 679 Name: "foo", 680 Flags: []Flag{ 681 BoolFlag{Name: "parent, p", Usage: "Parent flag"}, 682 }, 683 Subcommands: []Command{ 684 { 685 Name: "bar", 686 Action: func(c *Context) { 687 if c.GlobalBool("debug") { 688 subcommandRun = true 689 } 690 if c.GlobalBool("parent") { 691 parentFlag = true 692 } 693 }, 694 }, 695 }, 696 }, 697 } 698 699 app.Run([]string{"command", "-d", "foo", "-p", "bar"}) 700 701 expect(t, subcommandRun, true) 702 expect(t, parentFlag, true) 703 } 704 705 func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) { 706 var subcommandHelpTopics = [][]string{ 707 {"command", "foo", "--help"}, 708 {"command", "foo", "-h"}, 709 {"command", "foo", "help"}, 710 } 711 712 for _, flagSet := range subcommandHelpTopics { 713 t.Logf("==> checking with flags %v", flagSet) 714 715 app := NewApp() 716 buf := new(bytes.Buffer) 717 app.Writer = buf 718 719 subCmdBar := Command{ 720 Name: "bar", 721 Usage: "does bar things", 722 } 723 subCmdBaz := Command{ 724 Name: "baz", 725 Usage: "does baz things", 726 } 727 cmd := Command{ 728 Name: "foo", 729 Description: "descriptive wall of text about how it does foo things", 730 Subcommands: []Command{subCmdBar, subCmdBaz}, 731 } 732 733 app.Commands = []Command{cmd} 734 err := app.Run(flagSet) 735 736 if err != nil { 737 t.Error(err) 738 } 739 740 output := buf.String() 741 t.Logf("output: %q\n", buf.Bytes()) 742 743 if strings.Contains(output, "No help topic for") { 744 t.Errorf("expect a help topic, got none: \n%q", output) 745 } 746 747 for _, shouldContain := range []string{ 748 cmd.Name, cmd.Description, 749 subCmdBar.Name, subCmdBar.Usage, 750 subCmdBaz.Name, subCmdBaz.Usage, 751 } { 752 if !strings.Contains(output, shouldContain) { 753 t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output) 754 } 755 } 756 } 757 } 758 759 func TestApp_Run_SubcommandFullPath(t *testing.T) { 760 app := NewApp() 761 buf := new(bytes.Buffer) 762 app.Writer = buf 763 app.Name = "command" 764 subCmd := Command{ 765 Name: "bar", 766 Usage: "does bar things", 767 } 768 cmd := Command{ 769 Name: "foo", 770 Description: "foo commands", 771 Subcommands: []Command{subCmd}, 772 } 773 app.Commands = []Command{cmd} 774 775 err := app.Run([]string{"command", "foo", "bar", "--help"}) 776 if err != nil { 777 t.Error(err) 778 } 779 780 output := buf.String() 781 if !strings.Contains(output, "command foo bar - does bar things") { 782 t.Errorf("expected full path to subcommand: %s", output) 783 } 784 if !strings.Contains(output, "command foo bar [arguments...]") { 785 t.Errorf("expected full path to subcommand: %s", output) 786 } 787 } 788 789 func TestApp_Run_SubcommandHelpName(t *testing.T) { 790 app := NewApp() 791 buf := new(bytes.Buffer) 792 app.Writer = buf 793 app.Name = "command" 794 subCmd := Command{ 795 Name: "bar", 796 HelpName: "custom", 797 Usage: "does bar things", 798 } 799 cmd := Command{ 800 Name: "foo", 801 Description: "foo commands", 802 Subcommands: []Command{subCmd}, 803 } 804 app.Commands = []Command{cmd} 805 806 err := app.Run([]string{"command", "foo", "bar", "--help"}) 807 if err != nil { 808 t.Error(err) 809 } 810 811 output := buf.String() 812 if !strings.Contains(output, "custom - does bar things") { 813 t.Errorf("expected HelpName for subcommand: %s", output) 814 } 815 if !strings.Contains(output, "custom [arguments...]") { 816 t.Errorf("expected HelpName to subcommand: %s", output) 817 } 818 } 819 820 func TestApp_Run_CommandHelpName(t *testing.T) { 821 app := NewApp() 822 buf := new(bytes.Buffer) 823 app.Writer = buf 824 app.Name = "command" 825 subCmd := Command{ 826 Name: "bar", 827 Usage: "does bar things", 828 } 829 cmd := Command{ 830 Name: "foo", 831 HelpName: "custom", 832 Description: "foo commands", 833 Subcommands: []Command{subCmd}, 834 } 835 app.Commands = []Command{cmd} 836 837 err := app.Run([]string{"command", "foo", "bar", "--help"}) 838 if err != nil { 839 t.Error(err) 840 } 841 842 output := buf.String() 843 if !strings.Contains(output, "command foo bar - does bar things") { 844 t.Errorf("expected full path to subcommand: %s", output) 845 } 846 if !strings.Contains(output, "command foo bar [arguments...]") { 847 t.Errorf("expected full path to subcommand: %s", output) 848 } 849 } 850 851 func TestApp_Run_CommandSubcommandHelpName(t *testing.T) { 852 app := NewApp() 853 buf := new(bytes.Buffer) 854 app.Writer = buf 855 app.Name = "base" 856 subCmd := Command{ 857 Name: "bar", 858 HelpName: "custom", 859 Usage: "does bar things", 860 } 861 cmd := Command{ 862 Name: "foo", 863 Description: "foo commands", 864 Subcommands: []Command{subCmd}, 865 } 866 app.Commands = []Command{cmd} 867 868 err := app.Run([]string{"command", "foo", "--help"}) 869 if err != nil { 870 t.Error(err) 871 } 872 873 output := buf.String() 874 if !strings.Contains(output, "base foo - foo commands") { 875 t.Errorf("expected full path to subcommand: %s", output) 876 } 877 if !strings.Contains(output, "base foo command [command options] [arguments...]") { 878 t.Errorf("expected full path to subcommand: %s", output) 879 } 880 } 881 882 func TestApp_Run_Help(t *testing.T) { 883 var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}} 884 885 for _, args := range helpArguments { 886 buf := new(bytes.Buffer) 887 888 t.Logf("==> checking with arguments %v", args) 889 890 app := NewApp() 891 app.Name = "boom" 892 app.Usage = "make an explosive entrance" 893 app.Writer = buf 894 app.Action = func(c *Context) { 895 buf.WriteString("boom I say!") 896 } 897 898 err := app.Run(args) 899 if err != nil { 900 t.Error(err) 901 } 902 903 output := buf.String() 904 t.Logf("output: %q\n", buf.Bytes()) 905 906 if !strings.Contains(output, "boom - make an explosive entrance") { 907 t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output) 908 } 909 } 910 } 911 912 func TestApp_Run_Version(t *testing.T) { 913 var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}} 914 915 for _, args := range versionArguments { 916 buf := new(bytes.Buffer) 917 918 t.Logf("==> checking with arguments %v", args) 919 920 app := NewApp() 921 app.Name = "boom" 922 app.Usage = "make an explosive entrance" 923 app.Version = "0.1.0" 924 app.Writer = buf 925 app.Action = func(c *Context) { 926 buf.WriteString("boom I say!") 927 } 928 929 err := app.Run(args) 930 if err != nil { 931 t.Error(err) 932 } 933 934 output := buf.String() 935 t.Logf("output: %q\n", buf.Bytes()) 936 937 if !strings.Contains(output, "0.1.0") { 938 t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output) 939 } 940 } 941 } 942 943 func TestApp_Run_Categories(t *testing.T) { 944 app := NewApp() 945 app.Name = "categories" 946 app.Commands = []Command{ 947 Command{ 948 Name: "command1", 949 Category: "1", 950 }, 951 Command{ 952 Name: "command2", 953 Category: "1", 954 }, 955 Command{ 956 Name: "command3", 957 Category: "2", 958 }, 959 } 960 buf := new(bytes.Buffer) 961 app.Writer = buf 962 963 app.Run([]string{"categories"}) 964 965 expect := CommandCategories{ 966 &CommandCategory{ 967 Name: "1", 968 Commands: []Command{ 969 app.Commands[0], 970 app.Commands[1], 971 }, 972 }, 973 &CommandCategory{ 974 Name: "2", 975 Commands: []Command{ 976 app.Commands[2], 977 }, 978 }, 979 } 980 if !reflect.DeepEqual(app.Categories(), expect) { 981 t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect) 982 } 983 984 output := buf.String() 985 t.Logf("output: %q\n", buf.Bytes()) 986 987 if !strings.Contains(output, "1:\n command1") { 988 t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output) 989 } 990 } 991 992 func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { 993 app := NewApp() 994 app.Action = func(c *Context) {} 995 app.Before = func(c *Context) error { return fmt.Errorf("before error") } 996 app.After = func(c *Context) error { return fmt.Errorf("after error") } 997 998 err := app.Run([]string{"foo"}) 999 if err == nil { 1000 t.Fatalf("expected to receive error from Run, got none") 1001 } 1002 1003 if !strings.Contains(err.Error(), "before error") { 1004 t.Errorf("expected text of error from Before method, but got none in \"%v\"", err) 1005 } 1006 if !strings.Contains(err.Error(), "after error") { 1007 t.Errorf("expected text of error from After method, but got none in \"%v\"", err) 1008 } 1009 } 1010 1011 func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { 1012 app := NewApp() 1013 app.Commands = []Command{ 1014 Command{ 1015 Subcommands: []Command{ 1016 Command{ 1017 Name: "sub", 1018 }, 1019 }, 1020 Name: "bar", 1021 Before: func(c *Context) error { return fmt.Errorf("before error") }, 1022 After: func(c *Context) error { return fmt.Errorf("after error") }, 1023 }, 1024 } 1025 1026 err := app.Run([]string{"foo", "bar"}) 1027 if err == nil { 1028 t.Fatalf("expected to receive error from Run, got none") 1029 } 1030 1031 if !strings.Contains(err.Error(), "before error") { 1032 t.Errorf("expected text of error from Before method, but got none in \"%v\"", err) 1033 } 1034 if !strings.Contains(err.Error(), "after error") { 1035 t.Errorf("expected text of error from After method, but got none in \"%v\"", err) 1036 } 1037 } 1038 1039 func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) { 1040 app := NewApp() 1041 app.Flags = []Flag{ 1042 IntFlag{Name: "flag"}, 1043 } 1044 app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { 1045 if isSubcommand { 1046 t.Errorf("Expect no subcommand") 1047 } 1048 if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { 1049 t.Errorf("Expect an invalid value error, but got \"%v\"", err) 1050 } 1051 return errors.New("intercepted: " + err.Error()) 1052 } 1053 app.Commands = []Command{ 1054 Command{ 1055 Name: "bar", 1056 }, 1057 } 1058 1059 err := app.Run([]string{"foo", "--flag=wrong"}) 1060 if err == nil { 1061 t.Fatalf("expected to receive error from Run, got none") 1062 } 1063 1064 if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { 1065 t.Errorf("Expect an intercepted error, but got \"%v\"", err) 1066 } 1067 } 1068 1069 func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) { 1070 app := NewApp() 1071 app.Flags = []Flag{ 1072 IntFlag{Name: "flag"}, 1073 } 1074 app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { 1075 if isSubcommand { 1076 t.Errorf("Expect subcommand") 1077 } 1078 if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { 1079 t.Errorf("Expect an invalid value error, but got \"%v\"", err) 1080 } 1081 return errors.New("intercepted: " + err.Error()) 1082 } 1083 app.Commands = []Command{ 1084 Command{ 1085 Name: "bar", 1086 }, 1087 } 1088 1089 err := app.Run([]string{"foo", "--flag=wrong", "bar"}) 1090 if err == nil { 1091 t.Fatalf("expected to receive error from Run, got none") 1092 } 1093 1094 if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { 1095 t.Errorf("Expect an intercepted error, but got \"%v\"", err) 1096 } 1097 }