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.
 
 
 

1692 lines
36 KiB

  1. package cli
  2. import (
  3. "bytes"
  4. "errors"
  5. "flag"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "os"
  10. "reflect"
  11. "strings"
  12. "testing"
  13. )
  14. var (
  15. lastExitCode = 0
  16. fakeOsExiter = func(rc int) {
  17. lastExitCode = rc
  18. }
  19. fakeErrWriter = &bytes.Buffer{}
  20. )
  21. func init() {
  22. OsExiter = fakeOsExiter
  23. ErrWriter = fakeErrWriter
  24. }
  25. type opCounts struct {
  26. Total, BashComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
  27. }
  28. func ExampleApp_Run() {
  29. // set args for examples sake
  30. os.Args = []string{"greet", "--name", "Jeremy"}
  31. app := NewApp()
  32. app.Name = "greet"
  33. app.Flags = []Flag{
  34. StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
  35. }
  36. app.Action = func(c *Context) error {
  37. fmt.Printf("Hello %v\n", c.String("name"))
  38. return nil
  39. }
  40. app.UsageText = "app [first_arg] [second_arg]"
  41. app.Author = "Harrison"
  42. app.Email = "harrison@lolwut.com"
  43. app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
  44. app.Run(os.Args)
  45. // Output:
  46. // Hello Jeremy
  47. }
  48. func ExampleApp_Run_subcommand() {
  49. // set args for examples sake
  50. os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
  51. app := NewApp()
  52. app.Name = "say"
  53. app.Commands = []Command{
  54. {
  55. Name: "hello",
  56. Aliases: []string{"hi"},
  57. Usage: "use it to see a description",
  58. Description: "This is how we describe hello the function",
  59. Subcommands: []Command{
  60. {
  61. Name: "english",
  62. Aliases: []string{"en"},
  63. Usage: "sends a greeting in english",
  64. Description: "greets someone in english",
  65. Flags: []Flag{
  66. StringFlag{
  67. Name: "name",
  68. Value: "Bob",
  69. Usage: "Name of the person to greet",
  70. },
  71. },
  72. Action: func(c *Context) error {
  73. fmt.Println("Hello,", c.String("name"))
  74. return nil
  75. },
  76. },
  77. },
  78. },
  79. }
  80. app.Run(os.Args)
  81. // Output:
  82. // Hello, Jeremy
  83. }
  84. func ExampleApp_Run_appHelp() {
  85. // set args for examples sake
  86. os.Args = []string{"greet", "help"}
  87. app := NewApp()
  88. app.Name = "greet"
  89. app.Version = "0.1.0"
  90. app.Description = "This is how we describe greet the app"
  91. app.Authors = []Author{
  92. {Name: "Harrison", Email: "harrison@lolwut.com"},
  93. {Name: "Oliver Allen", Email: "oliver@toyshop.com"},
  94. }
  95. app.Flags = []Flag{
  96. StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
  97. }
  98. app.Commands = []Command{
  99. {
  100. Name: "describeit",
  101. Aliases: []string{"d"},
  102. Usage: "use it to see a description",
  103. Description: "This is how we describe describeit the function",
  104. Action: func(c *Context) error {
  105. fmt.Printf("i like to describe things")
  106. return nil
  107. },
  108. },
  109. }
  110. app.Run(os.Args)
  111. // Output:
  112. // NAME:
  113. // greet - A new cli application
  114. //
  115. // USAGE:
  116. // greet [global options] command [command options] [arguments...]
  117. //
  118. // VERSION:
  119. // 0.1.0
  120. //
  121. // DESCRIPTION:
  122. // This is how we describe greet the app
  123. //
  124. // AUTHORS:
  125. // Harrison <harrison@lolwut.com>
  126. // Oliver Allen <oliver@toyshop.com>
  127. //
  128. // COMMANDS:
  129. // describeit, d use it to see a description
  130. // help, h Shows a list of commands or help for one command
  131. //
  132. // GLOBAL FLAGS:
  133. // --name value a name to say (default: "bob")
  134. // --help, -h show help
  135. // --version, -v print the version
  136. }
  137. func ExampleApp_Run_commandHelp() {
  138. // set args for examples sake
  139. os.Args = []string{"greet", "h", "describeit"}
  140. app := NewApp()
  141. app.Name = "greet"
  142. app.Flags = []Flag{
  143. StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
  144. }
  145. app.Commands = []Command{
  146. {
  147. Name: "describeit",
  148. Aliases: []string{"d"},
  149. Usage: "use it to see a description",
  150. Description: "This is how we describe describeit the function",
  151. Action: func(c *Context) error {
  152. fmt.Printf("i like to describe things")
  153. return nil
  154. },
  155. },
  156. }
  157. app.Run(os.Args)
  158. // Output:
  159. // NAME:
  160. // greet describeit - use it to see a description
  161. //
  162. // USAGE:
  163. // greet describeit [command options] [arguments...]
  164. //
  165. // DESCRIPTION:
  166. // This is how we describe describeit the function
  167. //
  168. // FLAGS:
  169. // --help, -h show help
  170. }
  171. func ExampleApp_Run_noAction() {
  172. app := App{}
  173. app.Name = "greet"
  174. app.Run([]string{"greet"})
  175. // Output:
  176. // NAME:
  177. // greet
  178. //
  179. // USAGE:
  180. // [global options] command [command options] [arguments...]
  181. //
  182. // COMMANDS:
  183. // help, h Shows a list of commands or help for one command
  184. //
  185. // GLOBAL FLAGS:
  186. // --help, -h show help
  187. // --version, -v print the version
  188. }
  189. func ExampleApp_Run_subcommandNoAction() {
  190. app := App{}
  191. app.Name = "greet"
  192. app.Commands = []Command{
  193. {
  194. Name: "describeit",
  195. Aliases: []string{"d"},
  196. Usage: "use it to see a description",
  197. Description: "This is how we describe describeit the function",
  198. },
  199. }
  200. app.Run([]string{"greet", "describeit"})
  201. // Output:
  202. // NAME:
  203. // describeit - use it to see a description
  204. //
  205. // USAGE:
  206. // describeit [command options] [arguments...]
  207. //
  208. // DESCRIPTION:
  209. // This is how we describe describeit the function
  210. //
  211. // FLAGS:
  212. // --help, -h show help
  213. }
  214. func ExampleApp_Run_bashComplete() {
  215. // set args for examples sake
  216. os.Args = []string{"greet", "--generate-bash-completion"}
  217. app := NewApp()
  218. app.Name = "greet"
  219. app.EnableBashCompletion = true
  220. app.Commands = []Command{
  221. {
  222. Name: "describeit",
  223. Aliases: []string{"d"},
  224. Usage: "use it to see a description",
  225. Description: "This is how we describe describeit the function",
  226. Action: func(c *Context) error {
  227. fmt.Printf("i like to describe things")
  228. return nil
  229. },
  230. }, {
  231. Name: "next",
  232. Usage: "next example",
  233. Description: "more stuff to see when generating bash completion",
  234. Action: func(c *Context) error {
  235. fmt.Printf("the next example")
  236. return nil
  237. },
  238. },
  239. }
  240. app.Run(os.Args)
  241. // Output:
  242. // describeit
  243. // d
  244. // next
  245. // help
  246. // h
  247. }
  248. func TestApp_Run(t *testing.T) {
  249. s := ""
  250. app := NewApp()
  251. app.Action = func(c *Context) error {
  252. s = s + c.Args().First()
  253. return nil
  254. }
  255. err := app.Run([]string{"command", "foo"})
  256. expect(t, err, nil)
  257. err = app.Run([]string{"command", "bar"})
  258. expect(t, err, nil)
  259. expect(t, s, "foobar")
  260. }
  261. var commandAppTests = []struct {
  262. name string
  263. expected bool
  264. }{
  265. {"foobar", true},
  266. {"batbaz", true},
  267. {"b", true},
  268. {"f", true},
  269. {"bat", false},
  270. {"nothing", false},
  271. }
  272. func TestApp_Command(t *testing.T) {
  273. app := NewApp()
  274. fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
  275. batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
  276. app.Commands = []Command{
  277. fooCommand,
  278. batCommand,
  279. }
  280. for _, test := range commandAppTests {
  281. expect(t, app.Command(test.name) != nil, test.expected)
  282. }
  283. }
  284. func TestApp_Setup_defaultsWriter(t *testing.T) {
  285. app := &App{}
  286. app.Setup()
  287. expect(t, app.Writer, os.Stdout)
  288. }
  289. func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
  290. var parsedOption, firstArg string
  291. app := NewApp()
  292. command := Command{
  293. Name: "cmd",
  294. Flags: []Flag{
  295. StringFlag{Name: "option", Value: "", Usage: "some option"},
  296. },
  297. Action: func(c *Context) error {
  298. parsedOption = c.String("option")
  299. firstArg = c.Args().First()
  300. return nil
  301. },
  302. }
  303. app.Commands = []Command{command}
  304. app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
  305. expect(t, parsedOption, "my-option")
  306. expect(t, firstArg, "my-arg")
  307. }
  308. func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
  309. var context *Context
  310. a := NewApp()
  311. a.Commands = []Command{
  312. {
  313. Name: "foo",
  314. Action: func(c *Context) error {
  315. context = c
  316. return nil
  317. },
  318. Flags: []Flag{
  319. StringFlag{
  320. Name: "lang",
  321. Value: "english",
  322. Usage: "language for the greeting",
  323. },
  324. },
  325. Before: func(_ *Context) error { return nil },
  326. },
  327. }
  328. a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
  329. expect(t, context.Args().Get(0), "abcd")
  330. expect(t, context.String("lang"), "spanish")
  331. }
  332. func TestApp_RunAsSubCommandIncorrectUsage(t *testing.T) {
  333. a := App{
  334. Flags: []Flag{
  335. StringFlag{Name: "--foo"},
  336. },
  337. Writer: bytes.NewBufferString(""),
  338. }
  339. set := flag.NewFlagSet("", flag.ContinueOnError)
  340. set.Parse([]string{"", "---foo"})
  341. c := &Context{flagSet: set}
  342. err := a.RunAsSubcommand(c)
  343. expect(t, err, errors.New("bad flag syntax: ---foo"))
  344. }
  345. func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
  346. var parsedOption string
  347. var args []string
  348. app := NewApp()
  349. command := Command{
  350. Name: "cmd",
  351. Flags: []Flag{
  352. StringFlag{Name: "option", Value: "", Usage: "some option"},
  353. },
  354. Action: func(c *Context) error {
  355. parsedOption = c.String("option")
  356. args = c.Args()
  357. return nil
  358. },
  359. }
  360. app.Commands = []Command{command}
  361. app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
  362. expect(t, parsedOption, "my-option")
  363. expect(t, args[0], "my-arg")
  364. expect(t, args[1], "--")
  365. expect(t, args[2], "--notARealFlag")
  366. }
  367. func TestApp_CommandWithDash(t *testing.T) {
  368. var args []string
  369. app := NewApp()
  370. command := Command{
  371. Name: "cmd",
  372. Action: func(c *Context) error {
  373. args = c.Args()
  374. return nil
  375. },
  376. }
  377. app.Commands = []Command{command}
  378. app.Run([]string{"", "cmd", "my-arg", "-"})
  379. expect(t, args[0], "my-arg")
  380. expect(t, args[1], "-")
  381. }
  382. func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
  383. var args []string
  384. app := NewApp()
  385. command := Command{
  386. Name: "cmd",
  387. Action: func(c *Context) error {
  388. args = c.Args()
  389. return nil
  390. },
  391. }
  392. app.Commands = []Command{command}
  393. app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
  394. expect(t, args[0], "my-arg")
  395. expect(t, args[1], "--")
  396. expect(t, args[2], "notAFlagAtAll")
  397. }
  398. func TestApp_VisibleCommands(t *testing.T) {
  399. app := NewApp()
  400. app.Commands = []Command{
  401. {
  402. Name: "frob",
  403. HelpName: "foo frob",
  404. Action: func(_ *Context) error { return nil },
  405. },
  406. {
  407. Name: "frib",
  408. HelpName: "foo frib",
  409. Hidden: true,
  410. Action: func(_ *Context) error { return nil },
  411. },
  412. }
  413. app.Setup()
  414. expected := []Command{
  415. app.Commands[0],
  416. app.Commands[2], // help
  417. }
  418. actual := app.VisibleCommands()
  419. expect(t, len(expected), len(actual))
  420. for i, actualCommand := range actual {
  421. expectedCommand := expected[i]
  422. if expectedCommand.Action != nil {
  423. // comparing func addresses is OK!
  424. expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
  425. }
  426. // nil out funcs, as they cannot be compared
  427. // (https://github.com/golang/go/issues/8554)
  428. expectedCommand.Action = nil
  429. actualCommand.Action = nil
  430. if !reflect.DeepEqual(expectedCommand, actualCommand) {
  431. t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand)
  432. }
  433. }
  434. }
  435. func TestApp_Float64Flag(t *testing.T) {
  436. var meters float64
  437. app := NewApp()
  438. app.Flags = []Flag{
  439. Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
  440. }
  441. app.Action = func(c *Context) error {
  442. meters = c.Float64("height")
  443. return nil
  444. }
  445. app.Run([]string{"", "--height", "1.93"})
  446. expect(t, meters, 1.93)
  447. }
  448. func TestApp_ParseSliceFlags(t *testing.T) {
  449. var parsedOption, firstArg string
  450. var parsedIntSlice []int
  451. var parsedStringSlice []string
  452. app := NewApp()
  453. command := Command{
  454. Name: "cmd",
  455. Flags: []Flag{
  456. IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"},
  457. StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"},
  458. },
  459. Action: func(c *Context) error {
  460. parsedIntSlice = c.IntSlice("p")
  461. parsedStringSlice = c.StringSlice("ip")
  462. parsedOption = c.String("option")
  463. firstArg = c.Args().First()
  464. return nil
  465. },
  466. }
  467. app.Commands = []Command{command}
  468. app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
  469. IntsEquals := func(a, b []int) bool {
  470. if len(a) != len(b) {
  471. return false
  472. }
  473. for i, v := range a {
  474. if v != b[i] {
  475. return false
  476. }
  477. }
  478. return true
  479. }
  480. StrsEquals := func(a, b []string) bool {
  481. if len(a) != len(b) {
  482. return false
  483. }
  484. for i, v := range a {
  485. if v != b[i] {
  486. return false
  487. }
  488. }
  489. return true
  490. }
  491. var expectedIntSlice = []int{22, 80}
  492. var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
  493. if !IntsEquals(parsedIntSlice, expectedIntSlice) {
  494. t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
  495. }
  496. if !StrsEquals(parsedStringSlice, expectedStringSlice) {
  497. t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
  498. }
  499. }
  500. func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
  501. var parsedIntSlice []int
  502. var parsedStringSlice []string
  503. app := NewApp()
  504. command := Command{
  505. Name: "cmd",
  506. Flags: []Flag{
  507. IntSliceFlag{Name: "a", Usage: "set numbers"},
  508. StringSliceFlag{Name: "str", Usage: "set strings"},
  509. },
  510. Action: func(c *Context) error {
  511. parsedIntSlice = c.IntSlice("a")
  512. parsedStringSlice = c.StringSlice("str")
  513. return nil
  514. },
  515. }
  516. app.Commands = []Command{command}
  517. app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"})
  518. var expectedIntSlice = []int{2}
  519. var expectedStringSlice = []string{"A"}
  520. if parsedIntSlice[0] != expectedIntSlice[0] {
  521. t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
  522. }
  523. if parsedStringSlice[0] != expectedStringSlice[0] {
  524. t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
  525. }
  526. }
  527. func TestApp_DefaultStdout(t *testing.T) {
  528. app := NewApp()
  529. if app.Writer != os.Stdout {
  530. t.Error("Default output writer not set.")
  531. }
  532. }
  533. type mockWriter struct {
  534. written []byte
  535. }
  536. func (fw *mockWriter) Write(p []byte) (n int, err error) {
  537. if fw.written == nil {
  538. fw.written = p
  539. } else {
  540. fw.written = append(fw.written, p...)
  541. }
  542. return len(p), nil
  543. }
  544. func (fw *mockWriter) GetWritten() (b []byte) {
  545. return fw.written
  546. }
  547. func TestApp_SetStdout(t *testing.T) {
  548. w := &mockWriter{}
  549. app := NewApp()
  550. app.Name = "test"
  551. app.Writer = w
  552. err := app.Run([]string{"help"})
  553. if err != nil {
  554. t.Fatalf("Run error: %s", err)
  555. }
  556. if len(w.written) == 0 {
  557. t.Error("App did not write output to desired writer.")
  558. }
  559. }
  560. func TestApp_BeforeFunc(t *testing.T) {
  561. counts := &opCounts{}
  562. beforeError := fmt.Errorf("fail")
  563. var err error
  564. app := NewApp()
  565. app.Before = func(c *Context) error {
  566. counts.Total++
  567. counts.Before = counts.Total
  568. s := c.String("opt")
  569. if s == "fail" {
  570. return beforeError
  571. }
  572. return nil
  573. }
  574. app.Commands = []Command{
  575. {
  576. Name: "sub",
  577. Action: func(c *Context) error {
  578. counts.Total++
  579. counts.SubCommand = counts.Total
  580. return nil
  581. },
  582. },
  583. }
  584. app.Flags = []Flag{
  585. StringFlag{Name: "opt"},
  586. }
  587. // run with the Before() func succeeding
  588. err = app.Run([]string{"command", "--opt", "succeed", "sub"})
  589. if err != nil {
  590. t.Fatalf("Run error: %s", err)
  591. }
  592. if counts.Before != 1 {
  593. t.Errorf("Before() not executed when expected")
  594. }
  595. if counts.SubCommand != 2 {
  596. t.Errorf("Subcommand not executed when expected")
  597. }
  598. // reset
  599. counts = &opCounts{}
  600. // run with the Before() func failing
  601. err = app.Run([]string{"command", "--opt", "fail", "sub"})
  602. // should be the same error produced by the Before func
  603. if err != beforeError {
  604. t.Errorf("Run error expected, but not received")
  605. }
  606. if counts.Before != 1 {
  607. t.Errorf("Before() not executed when expected")
  608. }
  609. if counts.SubCommand != 0 {
  610. t.Errorf("Subcommand executed when NOT expected")
  611. }
  612. // reset
  613. counts = &opCounts{}
  614. afterError := errors.New("fail again")
  615. app.After = func(_ *Context) error {
  616. return afterError
  617. }
  618. // run with the Before() func failing, wrapped by After()
  619. err = app.Run([]string{"command", "--opt", "fail", "sub"})
  620. // should be the same error produced by the Before func
  621. if _, ok := err.(MultiError); !ok {
  622. t.Errorf("MultiError expected, but not received")
  623. }
  624. if counts.Before != 1 {
  625. t.Errorf("Before() not executed when expected")
  626. }
  627. if counts.SubCommand != 0 {
  628. t.Errorf("Subcommand executed when NOT expected")
  629. }
  630. }
  631. func TestApp_AfterFunc(t *testing.T) {
  632. counts := &opCounts{}
  633. afterError := fmt.Errorf("fail")
  634. var err error
  635. app := NewApp()
  636. app.After = func(c *Context) error {
  637. counts.Total++
  638. counts.After = counts.Total
  639. s := c.String("opt")
  640. if s == "fail" {
  641. return afterError
  642. }
  643. return nil
  644. }
  645. app.Commands = []Command{
  646. {
  647. Name: "sub",
  648. Action: func(c *Context) error {
  649. counts.Total++
  650. counts.SubCommand = counts.Total
  651. return nil
  652. },
  653. },
  654. }
  655. app.Flags = []Flag{
  656. StringFlag{Name: "opt"},
  657. }
  658. // run with the After() func succeeding
  659. err = app.Run([]string{"command", "--opt", "succeed", "sub"})
  660. if err != nil {
  661. t.Fatalf("Run error: %s", err)
  662. }
  663. if counts.After != 2 {
  664. t.Errorf("After() not executed when expected")
  665. }
  666. if counts.SubCommand != 1 {
  667. t.Errorf("Subcommand not executed when expected")
  668. }
  669. // reset
  670. counts = &opCounts{}
  671. // run with the Before() func failing
  672. err = app.Run([]string{"command", "--opt", "fail", "sub"})
  673. // should be the same error produced by the Before func
  674. if err != afterError {
  675. t.Errorf("Run error expected, but not received")
  676. }
  677. if counts.After != 2 {
  678. t.Errorf("After() not executed when expected")
  679. }
  680. if counts.SubCommand != 1 {
  681. t.Errorf("Subcommand not executed when expected")
  682. }
  683. }
  684. func TestAppNoHelpFlag(t *testing.T) {
  685. oldFlag := HelpFlag
  686. defer func() {
  687. HelpFlag = oldFlag
  688. }()
  689. HelpFlag = BoolFlag{}
  690. app := NewApp()
  691. app.Writer = ioutil.Discard
  692. err := app.Run([]string{"test", "-h"})
  693. if err != flag.ErrHelp {
  694. t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
  695. }
  696. }
  697. func TestAppHelpPrinter(t *testing.T) {
  698. oldPrinter := HelpPrinter
  699. defer func() {
  700. HelpPrinter = oldPrinter
  701. }()
  702. var wasCalled = false
  703. HelpPrinter = func(w io.Writer, template string, data interface{}) {
  704. wasCalled = true
  705. }
  706. app := NewApp()
  707. app.Run([]string{"-h"})
  708. if wasCalled == false {
  709. t.Errorf("Help printer expected to be called, but was not")
  710. }
  711. }
  712. func TestApp_VersionPrinter(t *testing.T) {
  713. oldPrinter := VersionPrinter
  714. defer func() {
  715. VersionPrinter = oldPrinter
  716. }()
  717. var wasCalled = false
  718. VersionPrinter = func(c *Context) {
  719. wasCalled = true
  720. }
  721. app := NewApp()
  722. ctx := NewContext(app, nil, nil)
  723. ShowVersion(ctx)
  724. if wasCalled == false {
  725. t.Errorf("Version printer expected to be called, but was not")
  726. }
  727. }
  728. func TestApp_CommandNotFound(t *testing.T) {
  729. counts := &opCounts{}
  730. app := NewApp()
  731. app.CommandNotFound = func(c *Context, command string) {
  732. counts.Total++
  733. counts.CommandNotFound = counts.Total
  734. }
  735. app.Commands = []Command{
  736. {
  737. Name: "bar",
  738. Action: func(c *Context) error {
  739. counts.Total++
  740. counts.SubCommand = counts.Total
  741. return nil
  742. },
  743. },
  744. }
  745. app.Run([]string{"command", "foo"})
  746. expect(t, counts.CommandNotFound, 1)
  747. expect(t, counts.SubCommand, 0)
  748. expect(t, counts.Total, 1)
  749. }
  750. func TestApp_OrderOfOperations(t *testing.T) {
  751. counts := &opCounts{}
  752. resetCounts := func() { counts = &opCounts{} }
  753. app := NewApp()
  754. app.EnableBashCompletion = true
  755. app.BashComplete = func(c *Context) {
  756. counts.Total++
  757. counts.BashComplete = counts.Total
  758. }
  759. app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
  760. counts.Total++
  761. counts.OnUsageError = counts.Total
  762. return errors.New("hay OnUsageError")
  763. }
  764. beforeNoError := func(c *Context) error {
  765. counts.Total++
  766. counts.Before = counts.Total
  767. return nil
  768. }
  769. beforeError := func(c *Context) error {
  770. counts.Total++
  771. counts.Before = counts.Total
  772. return errors.New("hay Before")
  773. }
  774. app.Before = beforeNoError
  775. app.CommandNotFound = func(c *Context, command string) {
  776. counts.Total++
  777. counts.CommandNotFound = counts.Total
  778. }
  779. afterNoError := func(c *Context) error {
  780. counts.Total++
  781. counts.After = counts.Total
  782. return nil
  783. }
  784. afterError := func(c *Context) error {
  785. counts.Total++
  786. counts.After = counts.Total
  787. return errors.New("hay After")
  788. }
  789. app.After = afterNoError
  790. app.Commands = []Command{
  791. {
  792. Name: "bar",
  793. Action: func(c *Context) error {
  794. counts.Total++
  795. counts.SubCommand = counts.Total
  796. return nil
  797. },
  798. },
  799. }
  800. app.Action = func(c *Context) error {
  801. counts.Total++
  802. counts.Action = counts.Total
  803. return nil
  804. }
  805. _ = app.Run([]string{"command", "--nope"})
  806. expect(t, counts.OnUsageError, 1)
  807. expect(t, counts.Total, 1)
  808. resetCounts()
  809. _ = app.Run([]string{"command", "--generate-bash-completion"})
  810. expect(t, counts.BashComplete, 1)
  811. expect(t, counts.Total, 1)
  812. resetCounts()
  813. oldOnUsageError := app.OnUsageError
  814. app.OnUsageError = nil
  815. _ = app.Run([]string{"command", "--nope"})
  816. expect(t, counts.Total, 0)
  817. app.OnUsageError = oldOnUsageError
  818. resetCounts()
  819. _ = app.Run([]string{"command", "foo"})
  820. expect(t, counts.OnUsageError, 0)
  821. expect(t, counts.Before, 1)
  822. expect(t, counts.CommandNotFound, 0)
  823. expect(t, counts.Action, 2)
  824. expect(t, counts.After, 3)
  825. expect(t, counts.Total, 3)
  826. resetCounts()
  827. app.Before = beforeError
  828. _ = app.Run([]string{"command", "bar"})
  829. expect(t, counts.OnUsageError, 0)
  830. expect(t, counts.Before, 1)
  831. expect(t, counts.After, 2)
  832. expect(t, counts.Total, 2)
  833. app.Before = beforeNoError
  834. resetCounts()
  835. app.After = nil
  836. _ = app.Run([]string{"command", "bar"})
  837. expect(t, counts.OnUsageError, 0)
  838. expect(t, counts.Before, 1)
  839. expect(t, counts.SubCommand, 2)
  840. expect(t, counts.Total, 2)
  841. app.After = afterNoError
  842. resetCounts()
  843. app.After = afterError
  844. err := app.Run([]string{"command", "bar"})
  845. if err == nil {
  846. t.Fatalf("expected a non-nil error")
  847. }
  848. expect(t, counts.OnUsageError, 0)
  849. expect(t, counts.Before, 1)
  850. expect(t, counts.SubCommand, 2)
  851. expect(t, counts.After, 3)
  852. expect(t, counts.Total, 3)
  853. app.After = afterNoError
  854. resetCounts()
  855. oldCommands := app.Commands
  856. app.Commands = nil
  857. _ = app.Run([]string{"command"})
  858. expect(t, counts.OnUsageError, 0)
  859. expect(t, counts.Before, 1)
  860. expect(t, counts.Action, 2)
  861. expect(t, counts.After, 3)
  862. expect(t, counts.Total, 3)
  863. app.Commands = oldCommands
  864. }
  865. func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
  866. var subcommandHelpTopics = [][]string{
  867. {"command", "foo", "--help"},
  868. {"command", "foo", "-h"},
  869. {"command", "foo", "help"},
  870. }
  871. for _, flagSet := range subcommandHelpTopics {
  872. t.Logf("==> checking with flags %v", flagSet)
  873. app := NewApp()
  874. buf := new(bytes.Buffer)
  875. app.Writer = buf
  876. subCmdBar := Command{
  877. Name: "bar",
  878. Usage: "does bar things",
  879. }
  880. subCmdBaz := Command{
  881. Name: "baz",
  882. Usage: "does baz things",
  883. }
  884. cmd := Command{
  885. Name: "foo",
  886. Description: "descriptive wall of text about how it does foo things",
  887. Subcommands: []Command{subCmdBar, subCmdBaz},
  888. Action: func(c *Context) error { return nil },
  889. }
  890. app.Commands = []Command{cmd}
  891. err := app.Run(flagSet)
  892. if err != nil {
  893. t.Error(err)
  894. }
  895. output := buf.String()
  896. t.Logf("output: %q\n", buf.Bytes())
  897. if strings.Contains(output, "No help topic for") {
  898. t.Errorf("expect a help topic, got none: \n%q", output)
  899. }
  900. for _, shouldContain := range []string{
  901. cmd.Name, cmd.Description,
  902. subCmdBar.Name, subCmdBar.Usage,
  903. subCmdBaz.Name, subCmdBaz.Usage,
  904. } {
  905. if !strings.Contains(output, shouldContain) {
  906. t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
  907. }
  908. }
  909. }
  910. }
  911. func TestApp_Run_SubcommandFullPath(t *testing.T) {
  912. app := NewApp()
  913. buf := new(bytes.Buffer)
  914. app.Writer = buf
  915. app.Name = "command"
  916. subCmd := Command{
  917. Name: "bar",
  918. Usage: "does bar things",
  919. }
  920. cmd := Command{
  921. Name: "foo",
  922. Description: "foo commands",
  923. Subcommands: []Command{subCmd},
  924. }
  925. app.Commands = []Command{cmd}
  926. err := app.Run([]string{"command", "foo", "bar", "--help"})
  927. if err != nil {
  928. t.Error(err)
  929. }
  930. output := buf.String()
  931. if !strings.Contains(output, "command foo bar - does bar things") {
  932. t.Errorf("expected full path to subcommand: %s", output)
  933. }
  934. if !strings.Contains(output, "command foo bar [command options] [arguments...]") {
  935. t.Errorf("expected full path to subcommand: %s", output)
  936. }
  937. }
  938. func TestApp_Run_SubcommandHelpName(t *testing.T) {
  939. app := NewApp()
  940. buf := new(bytes.Buffer)
  941. app.Writer = buf
  942. app.Name = "command"
  943. subCmd := Command{
  944. Name: "bar",
  945. HelpName: "custom",
  946. Usage: "does bar things",
  947. }
  948. cmd := Command{
  949. Name: "foo",
  950. Description: "foo commands",
  951. Subcommands: []Command{subCmd},
  952. }
  953. app.Commands = []Command{cmd}
  954. err := app.Run([]string{"command", "foo", "bar", "--help"})
  955. if err != nil {
  956. t.Error(err)
  957. }
  958. output := buf.String()
  959. if !strings.Contains(output, "custom - does bar things") {
  960. t.Errorf("expected HelpName for subcommand: %s", output)
  961. }
  962. if !strings.Contains(output, "custom [command options] [arguments...]") {
  963. t.Errorf("expected HelpName to subcommand: %s", output)
  964. }
  965. }
  966. func TestApp_Run_CommandHelpName(t *testing.T) {
  967. app := NewApp()
  968. buf := new(bytes.Buffer)
  969. app.Writer = buf
  970. app.Name = "command"
  971. subCmd := Command{
  972. Name: "bar",
  973. Usage: "does bar things",
  974. }
  975. cmd := Command{
  976. Name: "foo",
  977. HelpName: "custom",
  978. Description: "foo commands",
  979. Subcommands: []Command{subCmd},
  980. }
  981. app.Commands = []Command{cmd}
  982. err := app.Run([]string{"command", "foo", "bar", "--help"})
  983. if err != nil {
  984. t.Error(err)
  985. }
  986. output := buf.String()
  987. if !strings.Contains(output, "command foo bar - does bar things") {
  988. t.Errorf("expected full path to subcommand: %s", output)
  989. }
  990. if !strings.Contains(output, "command foo bar [command options] [arguments...]") {
  991. t.Errorf("expected full path to subcommand: %s", output)
  992. }
  993. }
  994. func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
  995. app := NewApp()
  996. buf := new(bytes.Buffer)
  997. app.Writer = buf
  998. app.Name = "base"
  999. subCmd := Command{
  1000. Name: "bar",
  1001. HelpName: "custom",
  1002. Usage: "does bar things",
  1003. }
  1004. cmd := Command{
  1005. Name: "foo",
  1006. Description: "foo commands",
  1007. Subcommands: []Command{subCmd},
  1008. }
  1009. app.Commands = []Command{cmd}
  1010. err := app.Run([]string{"command", "foo", "--help"})
  1011. if err != nil {
  1012. t.Error(err)
  1013. }
  1014. output := buf.String()
  1015. if !strings.Contains(output, "base foo - foo commands") {
  1016. t.Errorf("expected full path to subcommand: %s", output)
  1017. }
  1018. if !strings.Contains(output, "base foo COMMAND [COMMAND FLAGS | -h] [ARGUMENTS...]") {
  1019. t.Errorf("expected full path to subcommand: %s", output)
  1020. }
  1021. }
  1022. func TestApp_Run_Help(t *testing.T) {
  1023. var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}
  1024. for _, args := range helpArguments {
  1025. buf := new(bytes.Buffer)
  1026. t.Logf("==> checking with arguments %v", args)
  1027. app := NewApp()
  1028. app.Name = "boom"
  1029. app.Usage = "make an explosive entrance"
  1030. app.Writer = buf
  1031. app.Action = func(c *Context) error {
  1032. buf.WriteString("boom I say!")
  1033. return nil
  1034. }
  1035. err := app.Run(args)
  1036. if err != nil {
  1037. t.Error(err)
  1038. }
  1039. output := buf.String()
  1040. t.Logf("output: %q\n", buf.Bytes())
  1041. if !strings.Contains(output, "boom - make an explosive entrance") {
  1042. t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
  1043. }
  1044. }
  1045. }
  1046. func TestApp_Run_Version(t *testing.T) {
  1047. var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}}
  1048. for _, args := range versionArguments {
  1049. buf := new(bytes.Buffer)
  1050. t.Logf("==> checking with arguments %v", args)
  1051. app := NewApp()
  1052. app.Name = "boom"
  1053. app.Usage = "make an explosive entrance"
  1054. app.Version = "0.1.0"
  1055. app.Writer = buf
  1056. app.Action = func(c *Context) error {
  1057. buf.WriteString("boom I say!")
  1058. return nil
  1059. }
  1060. err := app.Run(args)
  1061. if err != nil {
  1062. t.Error(err)
  1063. }
  1064. output := buf.String()
  1065. t.Logf("output: %q\n", buf.Bytes())
  1066. if !strings.Contains(output, "0.1.0") {
  1067. t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output)
  1068. }
  1069. }
  1070. }
  1071. func TestApp_Run_Categories(t *testing.T) {
  1072. app := NewApp()
  1073. app.Name = "categories"
  1074. app.HideHelpCommand = true
  1075. app.Commands = []Command{
  1076. {
  1077. Name: "command1",
  1078. Category: "1",
  1079. },
  1080. {
  1081. Name: "command2",
  1082. Category: "1",
  1083. },
  1084. {
  1085. Name: "command3",
  1086. Category: "2",
  1087. },
  1088. }
  1089. buf := new(bytes.Buffer)
  1090. app.Writer = buf
  1091. app.Run([]string{"categories"})
  1092. expect := CommandCategories{
  1093. &CommandCategory{
  1094. Name: "1",
  1095. Commands: []Command{
  1096. app.Commands[0],
  1097. app.Commands[1],
  1098. },
  1099. },
  1100. &CommandCategory{
  1101. Name: "2",
  1102. Commands: []Command{
  1103. app.Commands[2],
  1104. },
  1105. },
  1106. }
  1107. if !reflect.DeepEqual(app.Categories(), expect) {
  1108. t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
  1109. }
  1110. output := buf.String()
  1111. t.Logf("output: %q\n", buf.Bytes())
  1112. if !strings.Contains(output, "1:\n command1") {
  1113. t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output)
  1114. }
  1115. }
  1116. func TestApp_VisibleCategories(t *testing.T) {
  1117. app := NewApp()
  1118. app.Name = "visible-categories"
  1119. app.HideHelpCommand = true
  1120. app.Commands = []Command{
  1121. {
  1122. Name: "command1",
  1123. Category: "1",
  1124. HelpName: "foo command1",
  1125. Hidden: true,
  1126. },
  1127. {
  1128. Name: "command2",
  1129. Category: "2",
  1130. HelpName: "foo command2",
  1131. },
  1132. {
  1133. Name: "command3",
  1134. Category: "3",
  1135. HelpName: "foo command3",
  1136. },
  1137. }
  1138. expected := []*CommandCategory{
  1139. {
  1140. Name: "2",
  1141. Commands: []Command{
  1142. app.Commands[1],
  1143. },
  1144. },
  1145. {
  1146. Name: "3",
  1147. Commands: []Command{
  1148. app.Commands[2],
  1149. },
  1150. },
  1151. }
  1152. app.Setup()
  1153. expect(t, expected, app.VisibleCategories())
  1154. app = NewApp()
  1155. app.Name = "visible-categories"
  1156. app.HideHelpCommand = true
  1157. app.Commands = []Command{
  1158. {
  1159. Name: "command1",
  1160. Category: "1",
  1161. HelpName: "foo command1",
  1162. Hidden: true,
  1163. },
  1164. {
  1165. Name: "command2",
  1166. Category: "2",
  1167. HelpName: "foo command2",
  1168. Hidden: true,
  1169. },
  1170. {
  1171. Name: "command3",
  1172. Category: "3",
  1173. HelpName: "foo command3",
  1174. },
  1175. }
  1176. expected = []*CommandCategory{
  1177. {
  1178. Name: "3",
  1179. Commands: []Command{
  1180. app.Commands[2],
  1181. },
  1182. },
  1183. }
  1184. app.Setup()
  1185. expect(t, expected, app.VisibleCategories())
  1186. app = NewApp()
  1187. app.Name = "visible-categories"
  1188. app.HideHelpCommand = true
  1189. app.Commands = []Command{
  1190. {
  1191. Name: "command1",
  1192. Category: "1",
  1193. HelpName: "foo command1",
  1194. Hidden: true,
  1195. },
  1196. {
  1197. Name: "command2",
  1198. Category: "2",
  1199. HelpName: "foo command2",
  1200. Hidden: true,
  1201. },
  1202. {
  1203. Name: "command3",
  1204. Category: "3",
  1205. HelpName: "foo command3",
  1206. Hidden: true,
  1207. },
  1208. }
  1209. expected = []*CommandCategory{}
  1210. app.Setup()
  1211. expect(t, expected, app.VisibleCategories())
  1212. }
  1213. func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
  1214. app := NewApp()
  1215. app.Action = func(c *Context) error { return nil }
  1216. app.Before = func(c *Context) error { return fmt.Errorf("before error") }
  1217. app.After = func(c *Context) error { return fmt.Errorf("after error") }
  1218. err := app.Run([]string{"foo"})
  1219. if err == nil {
  1220. t.Fatalf("expected to receive error from Run, got none")
  1221. }
  1222. if !strings.Contains(err.Error(), "before error") {
  1223. t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
  1224. }
  1225. if !strings.Contains(err.Error(), "after error") {
  1226. t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
  1227. }
  1228. }
  1229. func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
  1230. app := NewApp()
  1231. app.Commands = []Command{
  1232. {
  1233. Subcommands: []Command{
  1234. {
  1235. Name: "sub",
  1236. },
  1237. },
  1238. Name: "bar",
  1239. Before: func(c *Context) error { return fmt.Errorf("before error") },
  1240. After: func(c *Context) error { return fmt.Errorf("after error") },
  1241. },
  1242. }
  1243. err := app.Run([]string{"foo", "bar"})
  1244. if err == nil {
  1245. t.Fatalf("expected to receive error from Run, got none")
  1246. }
  1247. if !strings.Contains(err.Error(), "before error") {
  1248. t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
  1249. }
  1250. if !strings.Contains(err.Error(), "after error") {
  1251. t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
  1252. }
  1253. }
  1254. func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
  1255. app := NewApp()
  1256. app.Flags = []Flag{
  1257. IntFlag{Name: "flag"},
  1258. }
  1259. app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
  1260. if isSubcommand {
  1261. t.Errorf("Expect no subcommand")
  1262. }
  1263. if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
  1264. t.Errorf("Expect an invalid value error, but got \"%v\"", err)
  1265. }
  1266. return errors.New("intercepted: " + err.Error())
  1267. }
  1268. app.Commands = []Command{
  1269. {
  1270. Name: "bar",
  1271. },
  1272. }
  1273. err := app.Run([]string{"foo", "--flag=wrong"})
  1274. if err == nil {
  1275. t.Fatalf("expected to receive error from Run, got none")
  1276. }
  1277. if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
  1278. t.Errorf("Expect an intercepted error, but got \"%v\"", err)
  1279. }
  1280. }
  1281. func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
  1282. app := NewApp()
  1283. app.Flags = []Flag{
  1284. IntFlag{Name: "flag"},
  1285. }
  1286. app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
  1287. if isSubcommand {
  1288. t.Errorf("Expect subcommand")
  1289. }
  1290. if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
  1291. t.Errorf("Expect an invalid value error, but got \"%v\"", err)
  1292. }
  1293. return errors.New("intercepted: " + err.Error())
  1294. }
  1295. app.Commands = []Command{
  1296. {
  1297. Name: "bar",
  1298. },
  1299. }
  1300. err := app.Run([]string{"foo", "--flag=wrong", "bar"})
  1301. if err == nil {
  1302. t.Fatalf("expected to receive error from Run, got none")
  1303. }
  1304. if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
  1305. t.Errorf("Expect an intercepted error, but got \"%v\"", err)
  1306. }
  1307. }
  1308. func TestHandleAction_WithNonFuncAction(t *testing.T) {
  1309. app := NewApp()
  1310. app.Action = 42
  1311. fs, err := flagSet(app.Name, app.Flags)
  1312. if err != nil {
  1313. t.Errorf("error creating FlagSet: %s", err)
  1314. }
  1315. err = HandleAction(app.Action, NewContext(app, fs, nil))
  1316. if err == nil {
  1317. t.Fatalf("expected to receive error from Run, got none")
  1318. }
  1319. exitErr, ok := err.(*ExitError)
  1320. if !ok {
  1321. t.Fatalf("expected to receive a *ExitError")
  1322. }
  1323. if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type.") {
  1324. t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error())
  1325. }
  1326. if exitErr.ExitCode() != 2 {
  1327. t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
  1328. }
  1329. }
  1330. func TestHandleAction_WithInvalidFuncSignature(t *testing.T) {
  1331. app := NewApp()
  1332. app.Action = func() string { return "" }
  1333. fs, err := flagSet(app.Name, app.Flags)
  1334. if err != nil {
  1335. t.Errorf("error creating FlagSet: %s", err)
  1336. }
  1337. err = HandleAction(app.Action, NewContext(app, fs, nil))
  1338. if err == nil {
  1339. t.Fatalf("expected to receive error from Run, got none")
  1340. }
  1341. exitErr, ok := err.(*ExitError)
  1342. if !ok {
  1343. t.Fatalf("expected to receive a *ExitError")
  1344. }
  1345. if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") {
  1346. t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error())
  1347. }
  1348. if exitErr.ExitCode() != 2 {
  1349. t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
  1350. }
  1351. }
  1352. func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) {
  1353. app := NewApp()
  1354. app.Action = func(_ *Context) (int, error) { return 0, nil }
  1355. fs, err := flagSet(app.Name, app.Flags)
  1356. if err != nil {
  1357. t.Errorf("error creating FlagSet: %s", err)
  1358. }
  1359. err = HandleAction(app.Action, NewContext(app, fs, nil))
  1360. if err == nil {
  1361. t.Fatalf("expected to receive error from Run, got none")
  1362. }
  1363. exitErr, ok := err.(*ExitError)
  1364. if !ok {
  1365. t.Fatalf("expected to receive a *ExitError")
  1366. }
  1367. if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") {
  1368. t.Fatalf("expected an invalid Action signature error, but got: %v", exitErr.Error())
  1369. }
  1370. if exitErr.ExitCode() != 2 {
  1371. t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
  1372. }
  1373. }
  1374. func TestHandleAction_WithUnknownPanic(t *testing.T) {
  1375. defer func() { refute(t, recover(), nil) }()
  1376. var fn ActionFunc
  1377. app := NewApp()
  1378. app.Action = func(ctx *Context) error {
  1379. fn(ctx)
  1380. return nil
  1381. }
  1382. fs, err := flagSet(app.Name, app.Flags)
  1383. if err != nil {
  1384. t.Errorf("error creating FlagSet: %s", err)
  1385. }
  1386. HandleAction(app.Action, NewContext(app, fs, nil))
  1387. }
  1388. func TestShellCompletionForIncompleteFlags(t *testing.T) {
  1389. app := NewApp()
  1390. app.Flags = []Flag{
  1391. IntFlag{
  1392. Name: "test-completion",
  1393. },
  1394. }
  1395. app.EnableBashCompletion = true
  1396. app.BashComplete = func(ctx *Context) {
  1397. for _, command := range ctx.App.Commands {
  1398. if command.Hidden {
  1399. continue
  1400. }
  1401. for _, name := range command.Names() {
  1402. fmt.Fprintln(ctx.App.Writer, name)
  1403. }
  1404. }
  1405. for _, flag := range ctx.App.Flags {
  1406. for _, name := range strings.Split(flag.GetName(), ",") {
  1407. if name == BashCompletionFlag.Name {
  1408. continue
  1409. }
  1410. switch name = strings.TrimSpace(name); len(name) {
  1411. case 0:
  1412. case 1:
  1413. fmt.Fprintln(ctx.App.Writer, "-"+name)
  1414. default:
  1415. fmt.Fprintln(ctx.App.Writer, "--"+name)
  1416. }
  1417. }
  1418. }
  1419. }
  1420. app.Action = func(ctx *Context) error {
  1421. return fmt.Errorf("should not get here")
  1422. }
  1423. err := app.Run([]string{"", "--test-completion", "--" + BashCompletionFlag.Name})
  1424. if err != nil {
  1425. t.Errorf("app should not return an error: %s", err)
  1426. }
  1427. }
  1428. func TestHandleActionActuallyWorksWithActions(t *testing.T) {
  1429. var f ActionFunc
  1430. called := false
  1431. f = func(c *Context) error {
  1432. called = true
  1433. return nil
  1434. }
  1435. err := HandleAction(f, nil)
  1436. if err != nil {
  1437. t.Errorf("Should not have errored: %v", err)
  1438. }
  1439. if !called {
  1440. t.Errorf("Function was not called")
  1441. }
  1442. }