1package cobra 2 3import ( 4 "bytes" 5 "fmt" 6 "os" 7 "reflect" 8 "runtime" 9 "strings" 10 "testing" 11 "text/template" 12 13 "github.com/spf13/pflag" 14) 15 16var tp, te, tt, t1, tr []string 17var rootPersPre, echoPre, echoPersPre, timesPersPre []string 18var flagb1, flagb2, flagb3, flagbr, flagbp bool 19var flags1, flags2a, flags2b, flags3, outs string 20var flagi1, flagi2, flagi3, flagi4, flagir int 21var globalFlag1 bool 22var flagEcho, rootcalled bool 23var versionUsed int 24 25const strtwoParentHelp = "help message for parent flag strtwo" 26const strtwoChildHelp = "help message for child flag strtwo" 27 28var cmdHidden = &Command{ 29 Use: "hide [secret string to print]", 30 Short: "Print anything to screen (if command is known)", 31 Long: `an absolutely utterly useless command for testing.`, 32 Run: func(cmd *Command, args []string) { 33 outs = "hidden" 34 }, 35 Hidden: true, 36} 37 38var cmdPrint = &Command{ 39 Use: "print [string to print]", 40 Short: "Print anything to the screen", 41 Long: `an absolutely utterly useless command for testing.`, 42 Run: func(cmd *Command, args []string) { 43 tp = args 44 }, 45} 46 47var cmdEcho = &Command{ 48 Use: "echo [string to echo]", 49 Aliases: []string{"say"}, 50 Short: "Echo anything to the screen", 51 Long: `an utterly useless command for testing.`, 52 Example: "Just run cobra-test echo", 53 PersistentPreRun: func(cmd *Command, args []string) { 54 echoPersPre = args 55 }, 56 PreRun: func(cmd *Command, args []string) { 57 echoPre = args 58 }, 59 Run: func(cmd *Command, args []string) { 60 te = args 61 }, 62} 63 64var cmdEchoSub = &Command{ 65 Use: "echosub [string to print]", 66 Short: "second sub command for echo", 67 Long: `an absolutely utterly useless command for testing gendocs!.`, 68 Run: func(cmd *Command, args []string) { 69 }, 70} 71 72var cmdDeprecated = &Command{ 73 Use: "deprecated [can't do anything here]", 74 Short: "A command which is deprecated", 75 Long: `an absolutely utterly useless command for testing deprecation!.`, 76 Deprecated: "Please use echo instead", 77 Run: func(cmd *Command, args []string) { 78 }, 79} 80 81var cmdTimes = &Command{ 82 Use: "times [# times] [string to echo]", 83 SuggestFor: []string{"counts"}, 84 Short: "Echo anything to the screen more times", 85 Long: `a slightly useless command for testing.`, 86 PersistentPreRun: func(cmd *Command, args []string) { 87 timesPersPre = args 88 }, 89 Run: func(cmd *Command, args []string) { 90 tt = args 91 }, 92} 93 94var cmdRootNoRun = &Command{ 95 Use: "cobra-test", 96 Short: "The root can run its own function", 97 Long: "The root description for help", 98 PersistentPreRun: func(cmd *Command, args []string) { 99 rootPersPre = args 100 }, 101} 102 103var cmdRootSameName = &Command{ 104 Use: "print", 105 Short: "Root with the same name as a subcommand", 106 Long: "The root description for help", 107} 108 109var cmdRootWithRun = &Command{ 110 Use: "cobra-test", 111 Short: "The root can run its own function", 112 Long: "The root description for help", 113 Run: func(cmd *Command, args []string) { 114 tr = args 115 rootcalled = true 116 }, 117} 118 119var cmdSubNoRun = &Command{ 120 Use: "subnorun", 121 Short: "A subcommand without a Run function", 122 Long: "A long output about a subcommand without a Run function", 123} 124 125var cmdCustomFlags = &Command{ 126 Use: "customflags [flags] -- REMOTE_COMMAND", 127 Short: "A command that expects flags in a custom location", 128 Long: "A long output about a command that expects flags in a custom location", 129 Run: func(cmd *Command, args []string) { 130 }, 131} 132 133var cmdVersion1 = &Command{ 134 Use: "version", 135 Short: "Print the version number", 136 Long: `First version of the version command`, 137 Run: func(cmd *Command, args []string) { 138 versionUsed = 1 139 }, 140} 141 142var cmdVersion2 = &Command{ 143 Use: "version", 144 Short: "Print the version number", 145 Long: `Second version of the version command`, 146 Run: func(cmd *Command, args []string) { 147 versionUsed = 2 148 }, 149} 150 151var cmdColon = &Command{ 152 Use: "cmd:colon", 153 Run: func(cmd *Command, args []string) { 154 }, 155} 156 157func flagInit() { 158 cmdEcho.ResetFlags() 159 cmdPrint.ResetFlags() 160 cmdTimes.ResetFlags() 161 cmdRootNoRun.ResetFlags() 162 cmdRootSameName.ResetFlags() 163 cmdRootWithRun.ResetFlags() 164 cmdSubNoRun.ResetFlags() 165 cmdCustomFlags.ResetFlags() 166 cmdVersion1.ResetFlags() 167 cmdVersion2.ResetFlags() 168 169 cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp) 170 cmdCustomFlags.Flags().IntVar(&flagi4, "intfour", 456, "help message for flag intfour") 171 cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone") 172 cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone") 173 cmdEcho.PersistentFlags().BoolVarP(&flagbp, "persistentbool", "p", false, "help message for flag persistentbool") 174 cmdEcho.PersistentFlags().StringVarP(&flags1, "strone", "s", "one", "help message for flag strone") 175 cmdPrint.Flags().IntVarP(&flagi3, "intthree", "i", 345, "help message for flag intthree") 176 cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo") 177 cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo") 178 cmdTimes.Flags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp) 179 cmdTimes.PersistentFlags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp) 180 cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree") 181 cmdPrint.PersistentFlags().StringVarP(&flags3, "strthree", "s", "three", "help message for flag strthree") 182} 183 184func commandInit() { 185 cmdEcho.ResetCommands() 186 cmdPrint.ResetCommands() 187 cmdTimes.ResetCommands() 188 cmdRootNoRun.ResetCommands() 189 cmdRootSameName.ResetCommands() 190 cmdRootWithRun.ResetCommands() 191 cmdSubNoRun.ResetCommands() 192 cmdCustomFlags.ResetCommands() 193} 194 195func initialize() *Command { 196 tt, tp, te = nil, nil, nil 197 rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil 198 199 var c = cmdRootNoRun 200 flagInit() 201 commandInit() 202 return c 203} 204 205func initializeWithSameName() *Command { 206 tt, tp, te = nil, nil, nil 207 rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil 208 var c = cmdRootSameName 209 flagInit() 210 commandInit() 211 return c 212} 213 214func initializeWithRootCmd() *Command { 215 cmdRootWithRun.ResetCommands() 216 tt, tp, te, tr, rootcalled = nil, nil, nil, nil, false 217 flagInit() 218 cmdRootWithRun.Flags().BoolVarP(&flagbr, "boolroot", "b", false, "help message for flag boolroot") 219 cmdRootWithRun.Flags().IntVarP(&flagir, "introot", "i", 321, "help message for flag introot") 220 commandInit() 221 return cmdRootWithRun 222} 223 224type resulter struct { 225 Error error 226 Output string 227 Command *Command 228} 229 230func fullSetupTest(input string) resulter { 231 c := initializeWithRootCmd() 232 233 return fullTester(c, input) 234} 235 236func noRRSetupTestSilenced(input string) resulter { 237 c := initialize() 238 c.SilenceErrors = true 239 c.SilenceUsage = true 240 return fullTester(c, input) 241} 242 243func noRRSetupTest(input string) resulter { 244 c := initialize() 245 246 return fullTester(c, input) 247} 248 249func rootOnlySetupTest(input string) resulter { 250 c := initializeWithRootCmd() 251 252 return simpleTester(c, input) 253} 254 255func simpleTester(c *Command, input string) resulter { 256 buf := new(bytes.Buffer) 257 // Testing flag with invalid input 258 c.SetOutput(buf) 259 c.SetArgs(strings.Split(input, " ")) 260 261 err := c.Execute() 262 output := buf.String() 263 264 return resulter{err, output, c} 265} 266 267func simpleTesterC(c *Command, input string) resulter { 268 buf := new(bytes.Buffer) 269 // Testing flag with invalid input 270 c.SetOutput(buf) 271 c.SetArgs(strings.Split(input, " ")) 272 273 cmd, err := c.ExecuteC() 274 output := buf.String() 275 276 return resulter{err, output, cmd} 277} 278 279func fullTester(c *Command, input string) resulter { 280 buf := new(bytes.Buffer) 281 // Testing flag with invalid input 282 c.SetOutput(buf) 283 cmdEcho.AddCommand(cmdTimes) 284 c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun, cmdCustomFlags, cmdDeprecated) 285 c.SetArgs(strings.Split(input, " ")) 286 287 err := c.Execute() 288 output := buf.String() 289 290 return resulter{err, output, c} 291} 292 293func logErr(t *testing.T, found, expected string) { 294 out := new(bytes.Buffer) 295 296 _, _, line, ok := runtime.Caller(2) 297 if ok { 298 fmt.Fprintf(out, "Line: %d ", line) 299 } 300 fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) 301 t.Errorf(out.String()) 302} 303 304func checkStringContains(t *testing.T, found, expected string) { 305 if !strings.Contains(found, expected) { 306 logErr(t, found, expected) 307 } 308} 309 310func checkResultContains(t *testing.T, x resulter, check string) { 311 checkStringContains(t, x.Output, check) 312} 313 314func checkStringOmits(t *testing.T, found, expected string) { 315 if strings.Contains(found, expected) { 316 logErr(t, found, expected) 317 } 318} 319 320func checkResultOmits(t *testing.T, x resulter, check string) { 321 checkStringOmits(t, x.Output, check) 322} 323 324func checkOutputContains(t *testing.T, c *Command, check string) { 325 buf := new(bytes.Buffer) 326 c.SetOutput(buf) 327 c.Execute() 328 329 if !strings.Contains(buf.String(), check) { 330 logErr(t, buf.String(), check) 331 } 332} 333 334func TestSingleCommand(t *testing.T) { 335 noRRSetupTest("print one two") 336 337 if te != nil || tt != nil { 338 t.Error("Wrong command called") 339 } 340 if tp == nil { 341 t.Error("Wrong command called") 342 } 343 if strings.Join(tp, " ") != "one two" { 344 t.Error("Command didn't parse correctly") 345 } 346} 347 348func TestChildCommand(t *testing.T) { 349 noRRSetupTest("echo times one two") 350 351 if te != nil || tp != nil { 352 t.Error("Wrong command called") 353 } 354 if tt == nil { 355 t.Error("Wrong command called") 356 } 357 if strings.Join(tt, " ") != "one two" { 358 t.Error("Command didn't parse correctly") 359 } 360} 361 362func TestCommandAlias(t *testing.T) { 363 noRRSetupTest("say times one two") 364 365 if te != nil || tp != nil { 366 t.Error("Wrong command called") 367 } 368 if tt == nil { 369 t.Error("Wrong command called") 370 } 371 if strings.Join(tt, " ") != "one two" { 372 t.Error("Command didn't parse correctly") 373 } 374} 375 376func TestPrefixMatching(t *testing.T) { 377 EnablePrefixMatching = true 378 noRRSetupTest("ech times one two") 379 380 if te != nil || tp != nil { 381 t.Error("Wrong command called") 382 } 383 if tt == nil { 384 t.Error("Wrong command called") 385 } 386 if strings.Join(tt, " ") != "one two" { 387 t.Error("Command didn't parse correctly") 388 } 389 390 EnablePrefixMatching = false 391} 392 393func TestNoPrefixMatching(t *testing.T) { 394 EnablePrefixMatching = false 395 396 noRRSetupTest("ech times one two") 397 398 if !(tt == nil && te == nil && tp == nil) { 399 t.Error("Wrong command called") 400 } 401} 402 403func TestAliasPrefixMatching(t *testing.T) { 404 EnablePrefixMatching = true 405 noRRSetupTest("sa times one two") 406 407 if te != nil || tp != nil { 408 t.Error("Wrong command called") 409 } 410 if tt == nil { 411 t.Error("Wrong command called") 412 } 413 if strings.Join(tt, " ") != "one two" { 414 t.Error("Command didn't parse correctly") 415 } 416 EnablePrefixMatching = false 417} 418 419func TestChildSameName(t *testing.T) { 420 c := initializeWithSameName() 421 c.AddCommand(cmdPrint, cmdEcho) 422 c.SetArgs(strings.Split("print one two", " ")) 423 c.Execute() 424 425 if te != nil || tt != nil { 426 t.Error("Wrong command called") 427 } 428 if tp == nil { 429 t.Error("Wrong command called") 430 } 431 if strings.Join(tp, " ") != "one two" { 432 t.Error("Command didn't parse correctly") 433 } 434} 435 436func TestGrandChildSameName(t *testing.T) { 437 c := initializeWithSameName() 438 cmdTimes.AddCommand(cmdPrint) 439 c.AddCommand(cmdTimes) 440 c.SetArgs(strings.Split("times print one two", " ")) 441 c.Execute() 442 443 if te != nil || tt != nil { 444 t.Error("Wrong command called") 445 } 446 if tp == nil { 447 t.Error("Wrong command called") 448 } 449 if strings.Join(tp, " ") != "one two" { 450 t.Error("Command didn't parse correctly") 451 } 452} 453 454func TestUsage(t *testing.T) { 455 x := fullSetupTest("help") 456 checkResultContains(t, x, cmdRootWithRun.Use+" [flags]") 457 x = fullSetupTest("help customflags") 458 checkResultContains(t, x, cmdCustomFlags.Use) 459 checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]") 460} 461 462func TestFlagLong(t *testing.T) { 463 noRRSetupTest("echo --intone=13 something -- here") 464 465 if cmdEcho.ArgsLenAtDash() != 1 { 466 t.Errorf("expected argsLenAtDash: %d but got %d", 1, cmdRootNoRun.ArgsLenAtDash()) 467 } 468 if strings.Join(te, " ") != "something here" { 469 t.Errorf("flags didn't leave proper args remaining..%s given", te) 470 } 471 if flagi1 != 13 { 472 t.Errorf("int flag didn't get correct value, had %d", flagi1) 473 } 474 if flagi2 != 234 { 475 t.Errorf("default flag value changed, 234 expected, %d given", flagi2) 476 } 477} 478 479func TestFlagShort(t *testing.T) { 480 noRRSetupTest("echo -i13 -- something here") 481 482 if cmdEcho.ArgsLenAtDash() != 0 { 483 t.Errorf("expected argsLenAtDash: %d but got %d", 0, cmdRootNoRun.ArgsLenAtDash()) 484 } 485 if strings.Join(te, " ") != "something here" { 486 t.Errorf("flags didn't leave proper args remaining..%s given", te) 487 } 488 if flagi1 != 13 { 489 t.Errorf("int flag didn't get correct value, had %d", flagi1) 490 } 491 if flagi2 != 234 { 492 t.Errorf("default flag value changed, 234 expected, %d given", flagi2) 493 } 494 495 noRRSetupTest("echo -i 13 something here") 496 497 if strings.Join(te, " ") != "something here" { 498 t.Errorf("flags didn't leave proper args remaining..%s given", te) 499 } 500 if flagi1 != 13 { 501 t.Errorf("int flag didn't get correct value, had %d", flagi1) 502 } 503 if flagi2 != 234 { 504 t.Errorf("default flag value changed, 234 expected, %d given", flagi2) 505 } 506 507 noRRSetupTest("print -i99 one two") 508 509 if strings.Join(tp, " ") != "one two" { 510 t.Errorf("flags didn't leave proper args remaining..%s given", tp) 511 } 512 if flagi3 != 99 { 513 t.Errorf("int flag didn't get correct value, had %d", flagi3) 514 } 515 if flagi1 != 123 { 516 t.Errorf("default flag value changed on different command with same shortname, 234 expected, %d given", flagi2) 517 } 518} 519 520func TestChildCommandFlags(t *testing.T) { 521 noRRSetupTest("echo times -j 99 one two") 522 523 if strings.Join(tt, " ") != "one two" { 524 t.Errorf("flags didn't leave proper args remaining..%s given", tt) 525 } 526 527 // Testing with flag that shouldn't be persistent 528 r := noRRSetupTest("echo times -j 99 -i77 one two") 529 530 if r.Error == nil { 531 t.Errorf("invalid flag should generate error") 532 } 533 534 if !strings.Contains(r.Error.Error(), "unknown shorthand") { 535 t.Errorf("Wrong error message displayed, \n %s", r.Error) 536 } 537 538 if flagi2 != 99 { 539 t.Errorf("flag value should be 99, %d given", flagi2) 540 } 541 542 if flagi1 != 123 { 543 t.Errorf("unset flag should have default value, expecting 123, given %d", flagi1) 544 } 545 546 // Testing with flag only existing on child 547 r = noRRSetupTest("echo -j 99 -i77 one two") 548 549 if r.Error == nil { 550 t.Errorf("invalid flag should generate error") 551 } 552 if !strings.Contains(r.Error.Error(), "unknown shorthand flag") { 553 t.Errorf("Wrong error message displayed, \n %s", r.Error) 554 } 555 556 // Testing with persistent flag overwritten by child 557 noRRSetupTest("echo times --strtwo=child one two") 558 559 if flags2b != "child" { 560 t.Errorf("flag value should be child, %s given", flags2b) 561 } 562 563 if flags2a != "two" { 564 t.Errorf("unset flag should have default value, expecting two, given %s", flags2a) 565 } 566 567 // Testing flag with invalid input 568 r = noRRSetupTest("echo -i10E") 569 570 if r.Error == nil { 571 t.Errorf("invalid input should generate error") 572 } 573 if !strings.Contains(r.Error.Error(), "invalid syntax") { 574 t.Errorf("Wrong error message displayed, \n %s", r.Error) 575 } 576} 577 578func TestTrailingCommandFlags(t *testing.T) { 579 x := fullSetupTest("echo two -x") 580 581 if x.Error == nil { 582 t.Errorf("invalid flag should generate error") 583 } 584} 585 586func TestInvalidSubcommandFlags(t *testing.T) { 587 cmd := initializeWithRootCmd() 588 cmd.AddCommand(cmdTimes) 589 590 result := simpleTester(cmd, "times --inttwo=2 --badflag=bar") 591 // given that we are not checking here result.Error we check for 592 // stock usage message 593 checkResultContains(t, result, "cobra-test times [# times]") 594 if strings.Contains(result.Error.Error(), "unknown flag: --inttwo") { 595 t.Errorf("invalid --badflag flag shouldn't fail on 'unknown' --inttwo flag") 596 } 597 598} 599 600func TestSubcommandExecuteC(t *testing.T) { 601 cmd := initializeWithRootCmd() 602 double := &Command{ 603 Use: "double message", 604 Run: func(c *Command, args []string) { 605 msg := strings.Join(args, " ") 606 c.Println(msg, msg) 607 }, 608 } 609 610 echo := &Command{ 611 Use: "echo message", 612 Run: func(c *Command, args []string) { 613 msg := strings.Join(args, " ") 614 c.Println(msg) 615 }, 616 } 617 618 cmd.AddCommand(double, echo) 619 620 result := simpleTesterC(cmd, "double hello world") 621 checkResultContains(t, result, "hello world hello world") 622 623 if result.Command.Name() != "double" { 624 t.Errorf("invalid cmd returned from ExecuteC: should be 'double' but got %s", result.Command.Name()) 625 } 626 627 result = simpleTesterC(cmd, "echo msg to be echoed") 628 checkResultContains(t, result, "msg to be echoed") 629 630 if result.Command.Name() != "echo" { 631 t.Errorf("invalid cmd returned from ExecuteC: should be 'echo' but got %s", result.Command.Name()) 632 } 633} 634 635func TestSubcommandArgEvaluation(t *testing.T) { 636 cmd := initializeWithRootCmd() 637 638 first := &Command{ 639 Use: "first", 640 Run: func(cmd *Command, args []string) { 641 }, 642 } 643 cmd.AddCommand(first) 644 645 second := &Command{ 646 Use: "second", 647 Run: func(cmd *Command, args []string) { 648 fmt.Fprintf(cmd.OutOrStdout(), "%v", args) 649 }, 650 } 651 first.AddCommand(second) 652 653 result := simpleTester(cmd, "first second first third") 654 655 expectedOutput := fmt.Sprintf("%v", []string{"first third"}) 656 if result.Output != expectedOutput { 657 t.Errorf("exptected %v, got %v", expectedOutput, result.Output) 658 } 659} 660 661func TestPersistentFlags(t *testing.T) { 662 fullSetupTest("echo -s something -p more here") 663 664 // persistentFlag should act like normal flag on its own command 665 if strings.Join(te, " ") != "more here" { 666 t.Errorf("flags didn't leave proper args remaining..%s given", te) 667 } 668 if flags1 != "something" { 669 t.Errorf("string flag didn't get correct value, had %v", flags1) 670 } 671 if !flagbp { 672 t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp) 673 } 674 675 // persistentFlag should act like normal flag on its own command 676 fullSetupTest("echo times -s again -c -p test here") 677 678 if strings.Join(tt, " ") != "test here" { 679 t.Errorf("flags didn't leave proper args remaining. %s given", tt) 680 } 681 682 if flags1 != "again" { 683 t.Errorf("string flag didn't get correct value, had %v", flags1) 684 } 685 686 if !flagb2 { 687 t.Errorf("local flag not parsed correctly. Expected true, had %v", flagb2) 688 } 689 if !flagbp { 690 t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp) 691 } 692} 693 694func TestHelpCommand(t *testing.T) { 695 x := fullSetupTest("help") 696 checkResultContains(t, x, cmdRootWithRun.Long) 697 698 x = fullSetupTest("help echo") 699 checkResultContains(t, x, cmdEcho.Long) 700 701 x = fullSetupTest("help echo times") 702 checkResultContains(t, x, cmdTimes.Long) 703} 704 705func TestChildCommandHelp(t *testing.T) { 706 c := noRRSetupTest("print --help") 707 checkResultContains(t, c, strtwoParentHelp) 708 r := noRRSetupTest("echo times --help") 709 checkResultContains(t, r, strtwoChildHelp) 710} 711 712func TestNonRunChildHelp(t *testing.T) { 713 x := noRRSetupTest("subnorun") 714 checkResultContains(t, x, cmdSubNoRun.Long) 715} 716 717func TestRunnableRootCommand(t *testing.T) { 718 x := fullSetupTest("") 719 720 if rootcalled != true { 721 t.Errorf("Root Function was not called\n out:%v", x.Error) 722 } 723} 724 725func TestVisitParents(t *testing.T) { 726 c := &Command{Use: "app"} 727 sub := &Command{Use: "sub"} 728 dsub := &Command{Use: "dsub"} 729 sub.AddCommand(dsub) 730 c.AddCommand(sub) 731 total := 0 732 add := func(x *Command) { 733 total++ 734 } 735 sub.VisitParents(add) 736 if total != 1 { 737 t.Errorf("Should have visited 1 parent but visited %d", total) 738 } 739 740 total = 0 741 dsub.VisitParents(add) 742 if total != 2 { 743 t.Errorf("Should have visited 2 parent but visited %d", total) 744 } 745 746 total = 0 747 c.VisitParents(add) 748 if total != 0 { 749 t.Errorf("Should have not visited any parent but visited %d", total) 750 } 751} 752 753func TestRunnableRootCommandNilInput(t *testing.T) { 754 var emptyArg []string 755 c := initializeWithRootCmd() 756 757 buf := new(bytes.Buffer) 758 // Testing flag with invalid input 759 c.SetOutput(buf) 760 cmdEcho.AddCommand(cmdTimes) 761 c.AddCommand(cmdPrint, cmdEcho) 762 c.SetArgs(emptyArg) 763 764 err := c.Execute() 765 if err != nil { 766 t.Errorf("Execute() failed with %v", err) 767 } 768 769 if rootcalled != true { 770 t.Errorf("Root Function was not called") 771 } 772} 773 774func TestRunnableRootCommandEmptyInput(t *testing.T) { 775 args := make([]string, 3) 776 args[0] = "" 777 args[1] = "--introot=12" 778 args[2] = "" 779 c := initializeWithRootCmd() 780 781 buf := new(bytes.Buffer) 782 // Testing flag with invalid input 783 c.SetOutput(buf) 784 cmdEcho.AddCommand(cmdTimes) 785 c.AddCommand(cmdPrint, cmdEcho) 786 c.SetArgs(args) 787 788 c.Execute() 789 790 if rootcalled != true { 791 t.Errorf("Root Function was not called.\n\nOutput was:\n\n%s\n", buf) 792 } 793} 794 795func TestInvalidSubcommandWhenArgsAllowed(t *testing.T) { 796 fullSetupTest("echo invalid-sub") 797 798 if te[0] != "invalid-sub" { 799 t.Errorf("Subcommand didn't work...") 800 } 801} 802 803func TestRootFlags(t *testing.T) { 804 fullSetupTest("-i 17 -b") 805 806 if flagbr != true { 807 t.Errorf("flag value should be true, %v given", flagbr) 808 } 809 810 if flagir != 17 { 811 t.Errorf("flag value should be 17, %d given", flagir) 812 } 813} 814 815func TestRootHelp(t *testing.T) { 816 x := fullSetupTest("--help") 817 818 checkResultContains(t, x, "Available Commands:") 819 checkResultContains(t, x, "for more information about a command") 820 821 if strings.Contains(x.Output, "unknown flag: --help") { 822 t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) 823 } 824 825 if strings.Contains(x.Output, cmdEcho.Use) { 826 t.Errorf("--help shouldn't display subcommand's usage, Got: \n %s", x.Output) 827 } 828 829 x = fullSetupTest("echo --help") 830 831 if strings.Contains(x.Output, cmdTimes.Use) { 832 t.Errorf("--help shouldn't display subsubcommand's usage, Got: \n %s", x.Output) 833 } 834 835 checkResultContains(t, x, "Available Commands:") 836 checkResultContains(t, x, "for more information about a command") 837 838 if strings.Contains(x.Output, "unknown flag: --help") { 839 t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) 840 } 841 842} 843 844func TestFlagAccess(t *testing.T) { 845 initialize() 846 847 local := cmdTimes.LocalFlags() 848 inherited := cmdTimes.InheritedFlags() 849 850 for _, f := range []string{"inttwo", "strtwo", "booltwo"} { 851 if local.Lookup(f) == nil { 852 t.Errorf("LocalFlags expected to contain %s, Got: nil", f) 853 } 854 } 855 if inherited.Lookup("strone") == nil { 856 t.Errorf("InheritedFlags expected to contain strone, Got: nil") 857 } 858 if inherited.Lookup("strtwo") != nil { 859 t.Errorf("InheritedFlags shouldn not contain overwritten flag strtwo") 860 } 861} 862 863func TestNoNRunnableRootCommandNilInput(t *testing.T) { 864 var args []string 865 c := initialize() 866 867 buf := new(bytes.Buffer) 868 // Testing flag with invalid input 869 c.SetOutput(buf) 870 cmdEcho.AddCommand(cmdTimes) 871 c.AddCommand(cmdPrint, cmdEcho) 872 c.SetArgs(args) 873 874 c.Execute() 875 876 if !strings.Contains(buf.String(), cmdRootNoRun.Long) { 877 t.Errorf("Expected to get help output, Got: \n %s", buf) 878 } 879} 880 881func TestRootNoCommandHelp(t *testing.T) { 882 x := rootOnlySetupTest("--help") 883 884 checkResultOmits(t, x, "Available Commands:") 885 checkResultOmits(t, x, "for more information about a command") 886 887 if strings.Contains(x.Output, "unknown flag: --help") { 888 t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) 889 } 890 891 x = rootOnlySetupTest("echo --help") 892 893 checkResultOmits(t, x, "Available Commands:") 894 checkResultOmits(t, x, "for more information about a command") 895 896 if strings.Contains(x.Output, "unknown flag: --help") { 897 t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output) 898 } 899} 900 901func TestRootUnknownCommand(t *testing.T) { 902 r := noRRSetupTest("bogus") 903 s := "Error: unknown command \"bogus\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n" 904 905 if r.Output != s { 906 t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output) 907 } 908 909 r = noRRSetupTest("--strtwo=a bogus") 910 if r.Output != s { 911 t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output) 912 } 913} 914 915func TestRootUnknownCommandSilenced(t *testing.T) { 916 r := noRRSetupTestSilenced("bogus") 917 918 if r.Output != "" { 919 t.Errorf("Unexpected response.\nExpecting to be: \n\"\"\n Got:\n %q\n", r.Output) 920 } 921 922 r = noRRSetupTestSilenced("--strtwo=a bogus") 923 if r.Output != "" { 924 t.Errorf("Unexpected response.\nExpecting to be:\n\"\"\nGot:\n %q\n", r.Output) 925 } 926} 927 928func TestRootSuggestions(t *testing.T) { 929 outputWithSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\n\nDid you mean this?\n\t%s\n\nRun 'cobra-test --help' for usage.\n" 930 outputWithoutSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n" 931 932 cmd := initializeWithRootCmd() 933 cmd.AddCommand(cmdTimes) 934 935 tests := map[string]string{ 936 "time": "times", 937 "tiems": "times", 938 "tims": "times", 939 "timeS": "times", 940 "rimes": "times", 941 "ti": "times", 942 "t": "times", 943 "timely": "times", 944 "ri": "", 945 "timezone": "", 946 "foo": "", 947 "counts": "times", 948 } 949 950 for typo, suggestion := range tests { 951 for _, suggestionsDisabled := range []bool{false, true} { 952 cmd.DisableSuggestions = suggestionsDisabled 953 result := simpleTester(cmd, typo) 954 expected := "" 955 if len(suggestion) == 0 || suggestionsDisabled { 956 expected = fmt.Sprintf(outputWithoutSuggestions, typo) 957 } else { 958 expected = fmt.Sprintf(outputWithSuggestions, typo, suggestion) 959 } 960 if result.Output != expected { 961 t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output) 962 } 963 } 964 } 965} 966 967func TestFlagsBeforeCommand(t *testing.T) { 968 // short without space 969 x := fullSetupTest("-i10 echo") 970 if x.Error != nil { 971 t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) 972 } 973 974 // short (int) with equals 975 // It appears that pflags doesn't support this... 976 // Commenting out until support can be added 977 978 //x = noRRSetupTest("echo -i=10") 979 //if x.Error != nil { 980 //t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error) 981 //} 982 983 // long with equals 984 x = noRRSetupTest("--intone=123 echo one two") 985 if x.Error != nil { 986 t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error) 987 } 988 989 // With parsing error properly reported 990 x = fullSetupTest("-i10E echo") 991 if !strings.Contains(x.Error.Error(), "invalid syntax") { 992 t.Errorf("Wrong error message displayed, \n %s", x.Error) 993 } 994 995 //With quotes 996 x = fullSetupTest("-s=\"walking\" echo") 997 if x.Error != nil { 998 t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) 999 } 1000 1001 //With quotes and space 1002 x = fullSetupTest("-s=\"walking fast\" echo") 1003 if x.Error != nil { 1004 t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) 1005 } 1006 1007 //With inner quote 1008 x = fullSetupTest("-s=\"walking \\\"Inner Quote\\\" fast\" echo") 1009 if x.Error != nil { 1010 t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) 1011 } 1012 1013 //With quotes and space 1014 x = fullSetupTest("-s=\"walking \\\"Inner Quote\\\" fast\" echo") 1015 if x.Error != nil { 1016 t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) 1017 } 1018 1019} 1020 1021func TestRemoveCommand(t *testing.T) { 1022 versionUsed = 0 1023 c := initializeWithRootCmd() 1024 c.AddCommand(cmdVersion1) 1025 c.RemoveCommand(cmdVersion1) 1026 x := fullTester(c, "version") 1027 if x.Error == nil { 1028 t.Errorf("Removed command should not have been called\n") 1029 return 1030 } 1031} 1032 1033func TestCommandWithoutSubcommands(t *testing.T) { 1034 c := initializeWithRootCmd() 1035 1036 x := simpleTester(c, "") 1037 if x.Error != nil { 1038 t.Errorf("Calling command without subcommands should not have error: %v", x.Error) 1039 return 1040 } 1041} 1042 1043func TestCommandWithoutSubcommandsWithArg(t *testing.T) { 1044 c := initializeWithRootCmd() 1045 expectedArgs := []string{"arg"} 1046 1047 x := simpleTester(c, "arg") 1048 if x.Error != nil { 1049 t.Errorf("Calling command without subcommands but with arg should not have error: %v", x.Error) 1050 return 1051 } 1052 if !reflect.DeepEqual(expectedArgs, tr) { 1053 t.Errorf("Calling command without subcommands but with arg has wrong args: expected: %v, actual: %v", expectedArgs, tr) 1054 return 1055 } 1056} 1057 1058func TestReplaceCommandWithRemove(t *testing.T) { 1059 versionUsed = 0 1060 c := initializeWithRootCmd() 1061 c.AddCommand(cmdVersion1) 1062 c.RemoveCommand(cmdVersion1) 1063 c.AddCommand(cmdVersion2) 1064 x := fullTester(c, "version") 1065 if x.Error != nil { 1066 t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error) 1067 return 1068 } 1069 if versionUsed == 1 { 1070 t.Errorf("Removed command shouldn't be called\n") 1071 } 1072 if versionUsed != 2 { 1073 t.Errorf("Replacing command should have been called but didn't\n") 1074 } 1075} 1076 1077func TestDeprecatedSub(t *testing.T) { 1078 c := fullSetupTest("deprecated") 1079 1080 checkResultContains(t, c, cmdDeprecated.Deprecated) 1081} 1082 1083func TestPreRun(t *testing.T) { 1084 noRRSetupTest("echo one two") 1085 if echoPre == nil || echoPersPre == nil { 1086 t.Error("PreRun or PersistentPreRun not called") 1087 } 1088 if rootPersPre != nil || timesPersPre != nil { 1089 t.Error("Wrong *Pre functions called!") 1090 } 1091 1092 noRRSetupTest("echo times one two") 1093 if timesPersPre == nil { 1094 t.Error("PreRun or PersistentPreRun not called") 1095 } 1096 if echoPre != nil || echoPersPre != nil || rootPersPre != nil { 1097 t.Error("Wrong *Pre functions called!") 1098 } 1099 1100 noRRSetupTest("print one two") 1101 if rootPersPre == nil { 1102 t.Error("Parent PersistentPreRun not called but should not have been") 1103 } 1104 if echoPre != nil || echoPersPre != nil || timesPersPre != nil { 1105 t.Error("Wrong *Pre functions called!") 1106 } 1107} 1108 1109// Check if cmdEchoSub gets PersistentPreRun from rootCmd even if is added last 1110func TestPeristentPreRunPropagation(t *testing.T) { 1111 rootCmd := initialize() 1112 1113 // First add the cmdEchoSub to cmdPrint 1114 cmdPrint.AddCommand(cmdEchoSub) 1115 // Now add cmdPrint to rootCmd 1116 rootCmd.AddCommand(cmdPrint) 1117 1118 rootCmd.SetArgs(strings.Split("print echosub lala", " ")) 1119 rootCmd.Execute() 1120 1121 if rootPersPre == nil || len(rootPersPre) == 0 || rootPersPre[0] != "lala" { 1122 t.Error("RootCmd PersistentPreRun not called but should have been") 1123 } 1124} 1125 1126func TestGlobalNormFuncPropagation(t *testing.T) { 1127 normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName { 1128 return pflag.NormalizedName(name) 1129 } 1130 1131 rootCmd := initialize() 1132 rootCmd.SetGlobalNormalizationFunc(normFunc) 1133 if reflect.ValueOf(normFunc) != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()) { 1134 t.Error("rootCmd seems to have a wrong normalization function") 1135 } 1136 1137 // First add the cmdEchoSub to cmdPrint 1138 cmdPrint.AddCommand(cmdEchoSub) 1139 if cmdPrint.GlobalNormalizationFunc() != nil && cmdEchoSub.GlobalNormalizationFunc() != nil { 1140 t.Error("cmdPrint and cmdEchoSub should had no normalization functions") 1141 } 1142 1143 // Now add cmdPrint to rootCmd 1144 rootCmd.AddCommand(cmdPrint) 1145 if reflect.ValueOf(cmdPrint.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() || 1146 reflect.ValueOf(cmdEchoSub.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() { 1147 t.Error("cmdPrint and cmdEchoSub should had the normalization function of rootCmd") 1148 } 1149} 1150 1151func TestFlagOnPflagCommandLine(t *testing.T) { 1152 flagName := "flagOnCommandLine" 1153 pflag.CommandLine.String(flagName, "", "about my flag") 1154 r := fullSetupTest("--help") 1155 1156 checkResultContains(t, r, flagName) 1157 1158 // reset CommandLine flagset 1159 pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) 1160} 1161 1162func TestAddTemplateFunctions(t *testing.T) { 1163 AddTemplateFunc("t", func() bool { return true }) 1164 AddTemplateFuncs(template.FuncMap{ 1165 "f": func() bool { return false }, 1166 "h": func() string { return "Hello," }, 1167 "w": func() string { return "world." }}) 1168 1169 const usage = "Hello, world." 1170 1171 c := &Command{} 1172 c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`) 1173 1174 if us := c.UsageString(); us != usage { 1175 t.Errorf("c.UsageString() != \"%s\", is \"%s\"", usage, us) 1176 } 1177} 1178 1179func TestUsageIsNotPrintedTwice(t *testing.T) { 1180 var cmd = &Command{Use: "root"} 1181 var sub = &Command{Use: "sub"} 1182 cmd.AddCommand(sub) 1183 1184 r := simpleTester(cmd, "") 1185 if strings.Count(r.Output, "Usage:") != 1 { 1186 t.Error("Usage output is not printed exactly once") 1187 } 1188} 1189 1190func BenchmarkInheritedFlags(b *testing.B) { 1191 initialize() 1192 cmdEcho.AddCommand(cmdTimes) 1193 b.ResetTimer() 1194 1195 for i := 0; i < b.N; i++ { 1196 cmdTimes.InheritedFlags() 1197 } 1198} 1199 1200func BenchmarkLocalFlags(b *testing.B) { 1201 initialize() 1202 cmdEcho.AddCommand(cmdTimes) 1203 b.ResetTimer() 1204 1205 for i := 0; i < b.N; i++ { 1206 cmdTimes.LocalFlags() 1207 } 1208} 1209