You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

185 lines
4.5 KiB

  1. package cli
  2. import (
  3. "errors"
  4. "flag"
  5. "fmt"
  6. "io/ioutil"
  7. "strings"
  8. "testing"
  9. )
  10. func TestCommandFlagParsing(t *testing.T) {
  11. cases := []struct {
  12. testArgs []string
  13. skipFlagParsing bool
  14. skipArgReorder bool
  15. expectedErr error
  16. }{
  17. // Test normal "not ignoring flags" flow
  18. {[]string{"test-cmd", "blah", "blah", "-break"}, false, false, errors.New("flag provided but not defined: -break")},
  19. // Test no arg reorder
  20. {[]string{"test-cmd", "blah", "blah", "-break"}, false, true, nil},
  21. {[]string{"test-cmd", "blah", "blah"}, true, false, nil}, // Test SkipFlagParsing without any args that look like flags
  22. {[]string{"test-cmd", "blah", "-break"}, true, false, nil}, // Test SkipFlagParsing with random flag arg
  23. {[]string{"test-cmd", "blah", "-help"}, true, false, nil}, // Test SkipFlagParsing with "special" help flag arg
  24. }
  25. for _, c := range cases {
  26. app := NewApp()
  27. app.Writer = ioutil.Discard
  28. set := flag.NewFlagSet("test", 0)
  29. set.Parse(c.testArgs)
  30. context := NewContext(app, set, nil)
  31. command := Command{
  32. Name: "test-cmd",
  33. Aliases: []string{"tc"},
  34. Usage: "this is for testing",
  35. Description: "testing",
  36. Action: func(_ *Context) error { return nil },
  37. SkipFlagParsing: c.skipFlagParsing,
  38. SkipArgReorder: c.skipArgReorder,
  39. }
  40. err := command.Run(context)
  41. expect(t, err, c.expectedErr)
  42. expect(t, []string(context.Args()), c.testArgs)
  43. }
  44. }
  45. func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
  46. app := NewApp()
  47. app.Commands = []Command{
  48. {
  49. Name: "bar",
  50. Before: func(c *Context) error {
  51. return fmt.Errorf("before error")
  52. },
  53. After: func(c *Context) error {
  54. return fmt.Errorf("after error")
  55. },
  56. },
  57. }
  58. err := app.Run([]string{"foo", "bar"})
  59. if err == nil {
  60. t.Fatalf("expected to receive error from Run, got none")
  61. }
  62. if !strings.Contains(err.Error(), "before error") {
  63. t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
  64. }
  65. if !strings.Contains(err.Error(), "after error") {
  66. t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
  67. }
  68. }
  69. func TestCommand_Run_BeforeSavesMetadata(t *testing.T) {
  70. var receivedMsgFromAction string
  71. var receivedMsgFromAfter string
  72. app := NewApp()
  73. app.Commands = []Command{
  74. {
  75. Name: "bar",
  76. Before: func(c *Context) error {
  77. c.App.Metadata["msg"] = "hello world"
  78. return nil
  79. },
  80. Action: func(c *Context) error {
  81. msg, ok := c.App.Metadata["msg"]
  82. if !ok {
  83. return errors.New("msg not found")
  84. }
  85. receivedMsgFromAction = msg.(string)
  86. return nil
  87. },
  88. After: func(c *Context) error {
  89. msg, ok := c.App.Metadata["msg"]
  90. if !ok {
  91. return errors.New("msg not found")
  92. }
  93. receivedMsgFromAfter = msg.(string)
  94. return nil
  95. },
  96. },
  97. }
  98. err := app.Run([]string{"foo", "bar"})
  99. if err != nil {
  100. t.Fatalf("expected no error from Run, got %s", err)
  101. }
  102. expectedMsg := "hello world"
  103. if receivedMsgFromAction != expectedMsg {
  104. t.Fatalf("expected msg from Action to match. Given: %q\nExpected: %q",
  105. receivedMsgFromAction, expectedMsg)
  106. }
  107. if receivedMsgFromAfter != expectedMsg {
  108. t.Fatalf("expected msg from After to match. Given: %q\nExpected: %q",
  109. receivedMsgFromAction, expectedMsg)
  110. }
  111. }
  112. func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
  113. app := NewApp()
  114. app.Commands = []Command{
  115. {
  116. Name: "bar",
  117. Flags: []Flag{
  118. IntFlag{Name: "flag"},
  119. },
  120. OnUsageError: func(c *Context, err error, _ bool) error {
  121. if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
  122. t.Errorf("Expect an invalid value error, but got \"%v\"", err)
  123. }
  124. return errors.New("intercepted: " + err.Error())
  125. },
  126. },
  127. }
  128. err := app.Run([]string{"foo", "bar", "--flag=wrong"})
  129. if err == nil {
  130. t.Fatalf("expected to receive error from Run, got none")
  131. }
  132. if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
  133. t.Errorf("Expect an intercepted error, but got \"%v\"", err)
  134. }
  135. }
  136. func TestCommand_Run_SubcommandsCanUseErrWriter(t *testing.T) {
  137. app := NewApp()
  138. app.ErrWriter = ioutil.Discard
  139. app.Commands = []Command{
  140. {
  141. Name: "bar",
  142. Usage: "this is for testing",
  143. Subcommands: []Command{
  144. {
  145. Name: "baz",
  146. Usage: "this is for testing",
  147. Action: func(c *Context) error {
  148. if c.App.ErrWriter != ioutil.Discard {
  149. return fmt.Errorf("ErrWriter not passed")
  150. }
  151. return nil
  152. },
  153. },
  154. },
  155. },
  156. }
  157. err := app.Run([]string{"foo", "bar", "baz"})
  158. if err != nil {
  159. t.Fatal(err)
  160. }
  161. }