|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691 |
- package cli
-
- import (
- "bytes"
- "errors"
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "reflect"
- "strings"
- "testing"
- )
-
- var (
- lastExitCode = 0
- fakeOsExiter = func(rc int) {
- lastExitCode = rc
- }
- fakeErrWriter = &bytes.Buffer{}
- )
-
- func init() {
- OsExiter = fakeOsExiter
- ErrWriter = fakeErrWriter
- }
-
- type opCounts struct {
- Total, BashComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
- }
-
- func ExampleApp_Run() {
- // set args for examples sake
- os.Args = []string{"greet", "--name", "Jeremy"}
-
- app := NewApp()
- app.Name = "greet"
- app.Flags = []Flag{
- StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
- }
- app.Action = func(c *Context) error {
- fmt.Printf("Hello %v\n", c.String("name"))
- return nil
- }
- app.UsageText = "app [first_arg] [second_arg]"
- app.Author = "Harrison"
- app.Email = "harrison@lolwut.com"
- app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
- app.Run(os.Args)
- // Output:
- // Hello Jeremy
- }
-
- func ExampleApp_Run_subcommand() {
- // set args for examples sake
- os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
- app := NewApp()
- app.Name = "say"
- app.Commands = []Command{
- {
- Name: "hello",
- Aliases: []string{"hi"},
- Usage: "use it to see a description",
- Description: "This is how we describe hello the function",
- Subcommands: []Command{
- {
- Name: "english",
- Aliases: []string{"en"},
- Usage: "sends a greeting in english",
- Description: "greets someone in english",
- Flags: []Flag{
- StringFlag{
- Name: "name",
- Value: "Bob",
- Usage: "Name of the person to greet",
- },
- },
- Action: func(c *Context) error {
- fmt.Println("Hello,", c.String("name"))
- return nil
- },
- },
- },
- },
- }
-
- app.Run(os.Args)
- // Output:
- // Hello, Jeremy
- }
-
- func ExampleApp_Run_appHelp() {
- // set args for examples sake
- os.Args = []string{"greet", "help"}
-
- app := NewApp()
- app.Name = "greet"
- app.Version = "0.1.0"
- app.Description = "This is how we describe greet the app"
- app.Authors = []Author{
- {Name: "Harrison", Email: "harrison@lolwut.com"},
- {Name: "Oliver Allen", Email: "oliver@toyshop.com"},
- }
- app.Flags = []Flag{
- StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
- }
- app.Commands = []Command{
- {
- Name: "describeit",
- Aliases: []string{"d"},
- Usage: "use it to see a description",
- Description: "This is how we describe describeit the function",
- Action: func(c *Context) error {
- fmt.Printf("i like to describe things")
- return nil
- },
- },
- }
- app.Run(os.Args)
- // Output:
- // NAME:
- // greet - A new cli application
- //
- // USAGE:
- // greet [global options] command [command options] [arguments...]
- //
- // VERSION:
- // 0.1.0
- //
- // DESCRIPTION:
- // This is how we describe greet the app
- //
- // AUTHORS:
- // Harrison <harrison@lolwut.com>
- // Oliver Allen <oliver@toyshop.com>
- //
- // COMMANDS:
- // describeit, d use it to see a description
- // help, h Shows a list of commands or help for one command
- //
- // GLOBAL FLAGS:
- // --name value a name to say (default: "bob")
- // --help, -h show help
- // --version, -v print the version
- }
-
- func ExampleApp_Run_commandHelp() {
- // set args for examples sake
- os.Args = []string{"greet", "h", "describeit"}
-
- app := NewApp()
- app.Name = "greet"
- app.Flags = []Flag{
- StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
- }
- app.Commands = []Command{
- {
- Name: "describeit",
- Aliases: []string{"d"},
- Usage: "use it to see a description",
- Description: "This is how we describe describeit the function",
- Action: func(c *Context) error {
- fmt.Printf("i like to describe things")
- return nil
- },
- },
- }
- app.Run(os.Args)
- // Output:
- // NAME:
- // greet describeit - use it to see a description
- //
- // USAGE:
- // greet describeit [command options] [arguments...]
- //
- // DESCRIPTION:
- // This is how we describe describeit the function
- //
- // FLAGS:
- // --help, -h show help
- }
-
- func ExampleApp_Run_noAction() {
- app := App{}
- app.Name = "greet"
- app.Run([]string{"greet"})
- // Output:
- // NAME:
- // greet
- //
- // USAGE:
- // [global options] command [command options] [arguments...]
- //
- // COMMANDS:
- // help, h Shows a list of commands or help for one command
- //
- // GLOBAL FLAGS:
- // --help, -h show help
- // --version, -v print the version
- }
-
- func ExampleApp_Run_subcommandNoAction() {
- app := App{}
- app.Name = "greet"
- app.Commands = []Command{
- {
- Name: "describeit",
- Aliases: []string{"d"},
- Usage: "use it to see a description",
- Description: "This is how we describe describeit the function",
- },
- }
- app.Run([]string{"greet", "describeit"})
- // Output:
- // NAME:
- // describeit - use it to see a description
- //
- // USAGE:
- // describeit [command options] [arguments...]
- //
- // DESCRIPTION:
- // This is how we describe describeit the function
- //
- // FLAGS:
- // --help, -h show help
-
- }
-
- func ExampleApp_Run_bashComplete() {
- // set args for examples sake
- os.Args = []string{"greet", "--generate-bash-completion"}
-
- app := NewApp()
- app.Name = "greet"
- app.EnableBashCompletion = true
- app.Commands = []Command{
- {
- Name: "describeit",
- Aliases: []string{"d"},
- Usage: "use it to see a description",
- Description: "This is how we describe describeit the function",
- Action: func(c *Context) error {
- fmt.Printf("i like to describe things")
- return nil
- },
- }, {
- Name: "next",
- Usage: "next example",
- Description: "more stuff to see when generating bash completion",
- Action: func(c *Context) error {
- fmt.Printf("the next example")
- return nil
- },
- },
- }
-
- app.Run(os.Args)
- // Output:
- // describeit
- // d
- // next
- // help
- // h
- }
-
- func TestApp_Run(t *testing.T) {
- s := ""
-
- app := NewApp()
- app.Action = func(c *Context) error {
- s = s + c.Args().First()
- return nil
- }
-
- err := app.Run([]string{"command", "foo"})
- expect(t, err, nil)
- err = app.Run([]string{"command", "bar"})
- expect(t, err, nil)
- expect(t, s, "foobar")
- }
-
- var commandAppTests = []struct {
- name string
- expected bool
- }{
- {"foobar", true},
- {"batbaz", true},
- {"b", true},
- {"f", true},
- {"bat", false},
- {"nothing", false},
- }
-
- func TestApp_Command(t *testing.T) {
- app := NewApp()
- fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
- batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
- app.Commands = []Command{
- fooCommand,
- batCommand,
- }
-
- for _, test := range commandAppTests {
- expect(t, app.Command(test.name) != nil, test.expected)
- }
- }
-
- func TestApp_Setup_defaultsWriter(t *testing.T) {
- app := &App{}
- app.Setup()
- expect(t, app.Writer, os.Stdout)
- }
-
- func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
- var parsedOption, firstArg string
-
- app := NewApp()
- command := Command{
- Name: "cmd",
- Flags: []Flag{
- StringFlag{Name: "option", Value: "", Usage: "some option"},
- },
- Action: func(c *Context) error {
- parsedOption = c.String("option")
- firstArg = c.Args().First()
- return nil
- },
- }
- app.Commands = []Command{command}
-
- app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
-
- expect(t, parsedOption, "my-option")
- expect(t, firstArg, "my-arg")
- }
-
- func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
- var context *Context
-
- a := NewApp()
- a.Commands = []Command{
- {
- Name: "foo",
- Action: func(c *Context) error {
- context = c
- return nil
- },
- Flags: []Flag{
- StringFlag{
- Name: "lang",
- Value: "english",
- Usage: "language for the greeting",
- },
- },
- Before: func(_ *Context) error { return nil },
- },
- }
- a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
-
- expect(t, context.Args().Get(0), "abcd")
- expect(t, context.String("lang"), "spanish")
- }
-
- func TestApp_RunAsSubCommandIncorrectUsage(t *testing.T) {
- a := App{
- Flags: []Flag{
- StringFlag{Name: "--foo"},
- },
- Writer: bytes.NewBufferString(""),
- }
-
- set := flag.NewFlagSet("", flag.ContinueOnError)
- set.Parse([]string{"", "---foo"})
- c := &Context{flagSet: set}
-
- err := a.RunAsSubcommand(c)
-
- expect(t, err, errors.New("bad flag syntax: ---foo"))
- }
-
- func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
- var parsedOption string
- var args []string
-
- app := NewApp()
- command := Command{
- Name: "cmd",
- Flags: []Flag{
- StringFlag{Name: "option", Value: "", Usage: "some option"},
- },
- Action: func(c *Context) error {
- parsedOption = c.String("option")
- args = c.Args()
- return nil
- },
- }
- app.Commands = []Command{command}
-
- app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
-
- expect(t, parsedOption, "my-option")
- expect(t, args[0], "my-arg")
- expect(t, args[1], "--")
- expect(t, args[2], "--notARealFlag")
- }
-
- func TestApp_CommandWithDash(t *testing.T) {
- var args []string
-
- app := NewApp()
- command := Command{
- Name: "cmd",
- Action: func(c *Context) error {
- args = c.Args()
- return nil
- },
- }
- app.Commands = []Command{command}
-
- app.Run([]string{"", "cmd", "my-arg", "-"})
-
- expect(t, args[0], "my-arg")
- expect(t, args[1], "-")
- }
-
- func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
- var args []string
-
- app := NewApp()
- command := Command{
- Name: "cmd",
- Action: func(c *Context) error {
- args = c.Args()
- return nil
- },
- }
- app.Commands = []Command{command}
-
- app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
-
- expect(t, args[0], "my-arg")
- expect(t, args[1], "--")
- expect(t, args[2], "notAFlagAtAll")
- }
-
- func TestApp_VisibleCommands(t *testing.T) {
- app := NewApp()
- app.Commands = []Command{
- {
- Name: "frob",
- HelpName: "foo frob",
- Action: func(_ *Context) error { return nil },
- },
- {
- Name: "frib",
- HelpName: "foo frib",
- Hidden: true,
- Action: func(_ *Context) error { return nil },
- },
- }
-
- app.Setup()
- expected := []Command{
- app.Commands[0],
- app.Commands[2], // help
- }
- actual := app.VisibleCommands()
- expect(t, len(expected), len(actual))
- for i, actualCommand := range actual {
- expectedCommand := expected[i]
-
- if expectedCommand.Action != nil {
- // comparing func addresses is OK!
- expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
- }
-
- // nil out funcs, as they cannot be compared
- // (https://github.com/golang/go/issues/8554)
- expectedCommand.Action = nil
- actualCommand.Action = nil
-
- if !reflect.DeepEqual(expectedCommand, actualCommand) {
- t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand)
- }
- }
- }
-
- func TestApp_Float64Flag(t *testing.T) {
- var meters float64
-
- app := NewApp()
- app.Flags = []Flag{
- Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
- }
- app.Action = func(c *Context) error {
- meters = c.Float64("height")
- return nil
- }
-
- app.Run([]string{"", "--height", "1.93"})
- expect(t, meters, 1.93)
- }
-
- func TestApp_ParseSliceFlags(t *testing.T) {
- var parsedOption, firstArg string
- var parsedIntSlice []int
- var parsedStringSlice []string
-
- app := NewApp()
- command := Command{
- Name: "cmd",
- Flags: []Flag{
- IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"},
- StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"},
- },
- Action: func(c *Context) error {
- parsedIntSlice = c.IntSlice("p")
- parsedStringSlice = c.StringSlice("ip")
- parsedOption = c.String("option")
- firstArg = c.Args().First()
- return nil
- },
- }
- app.Commands = []Command{command}
-
- app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
-
- IntsEquals := func(a, b []int) bool {
- if len(a) != len(b) {
- return false
- }
- for i, v := range a {
- if v != b[i] {
- return false
- }
- }
- return true
- }
-
- StrsEquals := func(a, b []string) bool {
- if len(a) != len(b) {
- return false
- }
- for i, v := range a {
- if v != b[i] {
- return false
- }
- }
- return true
- }
- var expectedIntSlice = []int{22, 80}
- var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
-
- if !IntsEquals(parsedIntSlice, expectedIntSlice) {
- t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
- }
-
- if !StrsEquals(parsedStringSlice, expectedStringSlice) {
- t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
- }
- }
-
- func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
- var parsedIntSlice []int
- var parsedStringSlice []string
-
- app := NewApp()
- command := Command{
- Name: "cmd",
- Flags: []Flag{
- IntSliceFlag{Name: "a", Usage: "set numbers"},
- StringSliceFlag{Name: "str", Usage: "set strings"},
- },
- Action: func(c *Context) error {
- parsedIntSlice = c.IntSlice("a")
- parsedStringSlice = c.StringSlice("str")
- return nil
- },
- }
- app.Commands = []Command{command}
-
- app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"})
-
- var expectedIntSlice = []int{2}
- var expectedStringSlice = []string{"A"}
-
- if parsedIntSlice[0] != expectedIntSlice[0] {
- t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
- }
-
- if parsedStringSlice[0] != expectedStringSlice[0] {
- t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
- }
- }
-
- func TestApp_DefaultStdout(t *testing.T) {
- app := NewApp()
-
- if app.Writer != os.Stdout {
- t.Error("Default output writer not set.")
- }
- }
-
- type mockWriter struct {
- written []byte
- }
-
- func (fw *mockWriter) Write(p []byte) (n int, err error) {
- if fw.written == nil {
- fw.written = p
- } else {
- fw.written = append(fw.written, p...)
- }
-
- return len(p), nil
- }
-
- func (fw *mockWriter) GetWritten() (b []byte) {
- return fw.written
- }
-
- func TestApp_SetStdout(t *testing.T) {
- w := &mockWriter{}
-
- app := NewApp()
- app.Name = "test"
- app.Writer = w
-
- err := app.Run([]string{"help"})
-
- if err != nil {
- t.Fatalf("Run error: %s", err)
- }
-
- if len(w.written) == 0 {
- t.Error("App did not write output to desired writer.")
- }
- }
-
- func TestApp_BeforeFunc(t *testing.T) {
- counts := &opCounts{}
- beforeError := fmt.Errorf("fail")
- var err error
-
- app := NewApp()
-
- app.Before = func(c *Context) error {
- counts.Total++
- counts.Before = counts.Total
- s := c.String("opt")
- if s == "fail" {
- return beforeError
- }
-
- return nil
- }
-
- app.Commands = []Command{
- {
- Name: "sub",
- Action: func(c *Context) error {
- counts.Total++
- counts.SubCommand = counts.Total
- return nil
- },
- },
- }
-
- app.Flags = []Flag{
- StringFlag{Name: "opt"},
- }
-
- // run with the Before() func succeeding
- err = app.Run([]string{"command", "--opt", "succeed", "sub"})
-
- if err != nil {
- t.Fatalf("Run error: %s", err)
- }
-
- if counts.Before != 1 {
- t.Errorf("Before() not executed when expected")
- }
-
- if counts.SubCommand != 2 {
- t.Errorf("Subcommand not executed when expected")
- }
-
- // reset
- counts = &opCounts{}
-
- // run with the Before() func failing
- err = app.Run([]string{"command", "--opt", "fail", "sub"})
-
- // should be the same error produced by the Before func
- if err != beforeError {
- t.Errorf("Run error expected, but not received")
- }
-
- if counts.Before != 1 {
- t.Errorf("Before() not executed when expected")
- }
-
- if counts.SubCommand != 0 {
- t.Errorf("Subcommand executed when NOT expected")
- }
-
- // reset
- counts = &opCounts{}
-
- afterError := errors.New("fail again")
- app.After = func(_ *Context) error {
- return afterError
- }
-
- // run with the Before() func failing, wrapped by After()
- err = app.Run([]string{"command", "--opt", "fail", "sub"})
-
- // should be the same error produced by the Before func
- if _, ok := err.(MultiError); !ok {
- t.Errorf("MultiError expected, but not received")
- }
-
- if counts.Before != 1 {
- t.Errorf("Before() not executed when expected")
- }
-
- if counts.SubCommand != 0 {
- t.Errorf("Subcommand executed when NOT expected")
- }
- }
-
- func TestApp_AfterFunc(t *testing.T) {
- counts := &opCounts{}
- afterError := fmt.Errorf("fail")
- var err error
-
- app := NewApp()
-
- app.After = func(c *Context) error {
- counts.Total++
- counts.After = counts.Total
- s := c.String("opt")
- if s == "fail" {
- return afterError
- }
-
- return nil
- }
-
- app.Commands = []Command{
- {
- Name: "sub",
- Action: func(c *Context) error {
- counts.Total++
- counts.SubCommand = counts.Total
- return nil
- },
- },
- }
-
- app.Flags = []Flag{
- StringFlag{Name: "opt"},
- }
-
- // run with the After() func succeeding
- err = app.Run([]string{"command", "--opt", "succeed", "sub"})
-
- if err != nil {
- t.Fatalf("Run error: %s", err)
- }
-
- if counts.After != 2 {
- t.Errorf("After() not executed when expected")
- }
-
- if counts.SubCommand != 1 {
- t.Errorf("Subcommand not executed when expected")
- }
-
- // reset
- counts = &opCounts{}
-
- // run with the Before() func failing
- err = app.Run([]string{"command", "--opt", "fail", "sub"})
-
- // should be the same error produced by the Before func
- if err != afterError {
- t.Errorf("Run error expected, but not received")
- }
-
- if counts.After != 2 {
- t.Errorf("After() not executed when expected")
- }
-
- if counts.SubCommand != 1 {
- t.Errorf("Subcommand not executed when expected")
- }
- }
-
- func TestAppNoHelpFlag(t *testing.T) {
- oldFlag := HelpFlag
- defer func() {
- HelpFlag = oldFlag
- }()
-
- HelpFlag = BoolFlag{}
-
- app := NewApp()
- app.Writer = ioutil.Discard
- err := app.Run([]string{"test", "-h"})
-
- if err != flag.ErrHelp {
- t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
- }
- }
-
- func TestAppHelpPrinter(t *testing.T) {
- oldPrinter := HelpPrinter
- defer func() {
- HelpPrinter = oldPrinter
- }()
-
- var wasCalled = false
- HelpPrinter = func(w io.Writer, template string, data interface{}) {
- wasCalled = true
- }
-
- app := NewApp()
- app.Run([]string{"-h"})
-
- if wasCalled == false {
- t.Errorf("Help printer expected to be called, but was not")
- }
- }
-
- func TestApp_VersionPrinter(t *testing.T) {
- oldPrinter := VersionPrinter
- defer func() {
- VersionPrinter = oldPrinter
- }()
-
- var wasCalled = false
- VersionPrinter = func(c *Context) {
- wasCalled = true
- }
-
- app := NewApp()
- ctx := NewContext(app, nil, nil)
- ShowVersion(ctx)
-
- if wasCalled == false {
- t.Errorf("Version printer expected to be called, but was not")
- }
- }
-
- func TestApp_CommandNotFound(t *testing.T) {
- counts := &opCounts{}
- app := NewApp()
-
- app.CommandNotFound = func(c *Context, command string) {
- counts.Total++
- counts.CommandNotFound = counts.Total
- }
-
- app.Commands = []Command{
- {
- Name: "bar",
- Action: func(c *Context) error {
- counts.Total++
- counts.SubCommand = counts.Total
- return nil
- },
- },
- }
-
- app.Run([]string{"command", "foo"})
-
- expect(t, counts.CommandNotFound, 1)
- expect(t, counts.SubCommand, 0)
- expect(t, counts.Total, 1)
- }
-
- func TestApp_OrderOfOperations(t *testing.T) {
- counts := &opCounts{}
-
- resetCounts := func() { counts = &opCounts{} }
-
- app := NewApp()
- app.EnableBashCompletion = true
- app.BashComplete = func(c *Context) {
- counts.Total++
- counts.BashComplete = counts.Total
- }
-
- app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
- counts.Total++
- counts.OnUsageError = counts.Total
- return errors.New("hay OnUsageError")
- }
-
- beforeNoError := func(c *Context) error {
- counts.Total++
- counts.Before = counts.Total
- return nil
- }
-
- beforeError := func(c *Context) error {
- counts.Total++
- counts.Before = counts.Total
- return errors.New("hay Before")
- }
-
- app.Before = beforeNoError
- app.CommandNotFound = func(c *Context, command string) {
- counts.Total++
- counts.CommandNotFound = counts.Total
- }
-
- afterNoError := func(c *Context) error {
- counts.Total++
- counts.After = counts.Total
- return nil
- }
-
- afterError := func(c *Context) error {
- counts.Total++
- counts.After = counts.Total
- return errors.New("hay After")
- }
-
- app.After = afterNoError
- app.Commands = []Command{
- {
- Name: "bar",
- Action: func(c *Context) error {
- counts.Total++
- counts.SubCommand = counts.Total
- return nil
- },
- },
- }
-
- app.Action = func(c *Context) error {
- counts.Total++
- counts.Action = counts.Total
- return nil
- }
-
- _ = app.Run([]string{"command", "--nope"})
- expect(t, counts.OnUsageError, 1)
- expect(t, counts.Total, 1)
-
- resetCounts()
-
- _ = app.Run([]string{"command", "--generate-bash-completion"})
- expect(t, counts.BashComplete, 1)
- expect(t, counts.Total, 1)
-
- resetCounts()
-
- oldOnUsageError := app.OnUsageError
- app.OnUsageError = nil
- _ = app.Run([]string{"command", "--nope"})
- expect(t, counts.Total, 0)
- app.OnUsageError = oldOnUsageError
-
- resetCounts()
-
- _ = app.Run([]string{"command", "foo"})
- expect(t, counts.OnUsageError, 0)
- expect(t, counts.Before, 1)
- expect(t, counts.CommandNotFound, 0)
- expect(t, counts.Action, 2)
- expect(t, counts.After, 3)
- expect(t, counts.Total, 3)
-
- resetCounts()
-
- app.Before = beforeError
- _ = app.Run([]string{"command", "bar"})
- expect(t, counts.OnUsageError, 0)
- expect(t, counts.Before, 1)
- expect(t, counts.After, 2)
- expect(t, counts.Total, 2)
- app.Before = beforeNoError
-
- resetCounts()
-
- app.After = nil
- _ = app.Run([]string{"command", "bar"})
- expect(t, counts.OnUsageError, 0)
- expect(t, counts.Before, 1)
- expect(t, counts.SubCommand, 2)
- expect(t, counts.Total, 2)
- app.After = afterNoError
-
- resetCounts()
-
- app.After = afterError
- err := app.Run([]string{"command", "bar"})
- if err == nil {
- t.Fatalf("expected a non-nil error")
- }
- expect(t, counts.OnUsageError, 0)
- expect(t, counts.Before, 1)
- expect(t, counts.SubCommand, 2)
- expect(t, counts.After, 3)
- expect(t, counts.Total, 3)
- app.After = afterNoError
-
- resetCounts()
-
- oldCommands := app.Commands
- app.Commands = nil
- _ = app.Run([]string{"command"})
- expect(t, counts.OnUsageError, 0)
- expect(t, counts.Before, 1)
- expect(t, counts.Action, 2)
- expect(t, counts.After, 3)
- expect(t, counts.Total, 3)
- app.Commands = oldCommands
- }
-
- func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
- var subcommandHelpTopics = [][]string{
- {"command", "foo", "--help"},
- {"command", "foo", "-h"},
- {"command", "foo", "help"},
- }
-
- for _, flagSet := range subcommandHelpTopics {
- t.Logf("==> checking with flags %v", flagSet)
-
- app := NewApp()
- buf := new(bytes.Buffer)
- app.Writer = buf
-
- subCmdBar := Command{
- Name: "bar",
- Usage: "does bar things",
- }
- subCmdBaz := Command{
- Name: "baz",
- Usage: "does baz things",
- }
- cmd := Command{
- Name: "foo",
- Description: "descriptive wall of text about how it does foo things",
- Subcommands: []Command{subCmdBar, subCmdBaz},
- Action: func(c *Context) error { return nil },
- }
-
- app.Commands = []Command{cmd}
- err := app.Run(flagSet)
-
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- t.Logf("output: %q\n", buf.Bytes())
-
- if strings.Contains(output, "No help topic for") {
- t.Errorf("expect a help topic, got none: \n%q", output)
- }
-
- for _, shouldContain := range []string{
- cmd.Name, cmd.Description,
- subCmdBar.Name, subCmdBar.Usage,
- subCmdBaz.Name, subCmdBaz.Usage,
- } {
- if !strings.Contains(output, shouldContain) {
- t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
- }
- }
- }
- }
-
- func TestApp_Run_SubcommandFullPath(t *testing.T) {
- app := NewApp()
- buf := new(bytes.Buffer)
- app.Writer = buf
- app.Name = "command"
- subCmd := Command{
- Name: "bar",
- Usage: "does bar things",
- }
- cmd := Command{
- Name: "foo",
- Description: "foo commands",
- Subcommands: []Command{subCmd},
- }
- app.Commands = []Command{cmd}
-
- err := app.Run([]string{"command", "foo", "bar", "--help"})
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- if !strings.Contains(output, "command foo bar - does bar things") {
- t.Errorf("expected full path to subcommand: %s", output)
- }
- if !strings.Contains(output, "command foo bar [command options] [arguments...]") {
- t.Errorf("expected full path to subcommand: %s", output)
- }
- }
-
- func TestApp_Run_SubcommandHelpName(t *testing.T) {
- app := NewApp()
- buf := new(bytes.Buffer)
- app.Writer = buf
- app.Name = "command"
- subCmd := Command{
- Name: "bar",
- HelpName: "custom",
- Usage: "does bar things",
- }
- cmd := Command{
- Name: "foo",
- Description: "foo commands",
- Subcommands: []Command{subCmd},
- }
- app.Commands = []Command{cmd}
-
- err := app.Run([]string{"command", "foo", "bar", "--help"})
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- if !strings.Contains(output, "custom - does bar things") {
- t.Errorf("expected HelpName for subcommand: %s", output)
- }
- if !strings.Contains(output, "custom [command options] [arguments...]") {
- t.Errorf("expected HelpName to subcommand: %s", output)
- }
- }
-
- func TestApp_Run_CommandHelpName(t *testing.T) {
- app := NewApp()
- buf := new(bytes.Buffer)
- app.Writer = buf
- app.Name = "command"
- subCmd := Command{
- Name: "bar",
- Usage: "does bar things",
- }
- cmd := Command{
- Name: "foo",
- HelpName: "custom",
- Description: "foo commands",
- Subcommands: []Command{subCmd},
- }
- app.Commands = []Command{cmd}
-
- err := app.Run([]string{"command", "foo", "bar", "--help"})
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- if !strings.Contains(output, "command foo bar - does bar things") {
- t.Errorf("expected full path to subcommand: %s", output)
- }
- if !strings.Contains(output, "command foo bar [command options] [arguments...]") {
- t.Errorf("expected full path to subcommand: %s", output)
- }
- }
-
- func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
- app := NewApp()
- buf := new(bytes.Buffer)
- app.Writer = buf
- app.Name = "base"
- subCmd := Command{
- Name: "bar",
- HelpName: "custom",
- Usage: "does bar things",
- }
- cmd := Command{
- Name: "foo",
- Description: "foo commands",
- Subcommands: []Command{subCmd},
- }
- app.Commands = []Command{cmd}
-
- err := app.Run([]string{"command", "foo", "--help"})
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- if !strings.Contains(output, "base foo - foo commands") {
- t.Errorf("expected full path to subcommand: %s", output)
- }
- if !strings.Contains(output, "base foo COMMAND [COMMAND FLAGS | -h] [ARGUMENTS...]") {
- t.Errorf("expected full path to subcommand: %s", output)
- }
- }
-
- func TestApp_Run_Help(t *testing.T) {
- var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}
-
- for _, args := range helpArguments {
- buf := new(bytes.Buffer)
-
- t.Logf("==> checking with arguments %v", args)
-
- app := NewApp()
- app.Name = "boom"
- app.Usage = "make an explosive entrance"
- app.Writer = buf
- app.Action = func(c *Context) error {
- buf.WriteString("boom I say!")
- return nil
- }
-
- err := app.Run(args)
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- t.Logf("output: %q\n", buf.Bytes())
-
- if !strings.Contains(output, "boom - make an explosive entrance") {
- t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
- }
- }
- }
-
- func TestApp_Run_Version(t *testing.T) {
- var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}}
-
- for _, args := range versionArguments {
- buf := new(bytes.Buffer)
-
- t.Logf("==> checking with arguments %v", args)
-
- app := NewApp()
- app.Name = "boom"
- app.Usage = "make an explosive entrance"
- app.Version = "0.1.0"
- app.Writer = buf
- app.Action = func(c *Context) error {
- buf.WriteString("boom I say!")
- return nil
- }
-
- err := app.Run(args)
- if err != nil {
- t.Error(err)
- }
-
- output := buf.String()
- t.Logf("output: %q\n", buf.Bytes())
-
- if !strings.Contains(output, "0.1.0") {
- t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output)
- }
- }
- }
-
- func TestApp_Run_Categories(t *testing.T) {
- app := NewApp()
- app.Name = "categories"
- app.HideHelpCommand = true
- app.Commands = []Command{
- {
- Name: "command1",
- Category: "1",
- },
- {
- Name: "command2",
- Category: "1",
- },
- {
- Name: "command3",
- Category: "2",
- },
- }
- buf := new(bytes.Buffer)
- app.Writer = buf
-
- app.Run([]string{"categories"})
-
- expect := CommandCategories{
- &CommandCategory{
- Name: "1",
- Commands: []Command{
- app.Commands[0],
- app.Commands[1],
- },
- },
- &CommandCategory{
- Name: "2",
- Commands: []Command{
- app.Commands[2],
- },
- },
- }
- if !reflect.DeepEqual(app.Categories(), expect) {
- t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
- }
-
- output := buf.String()
- t.Logf("output: %q\n", buf.Bytes())
-
- if !strings.Contains(output, "1:\n command1") {
- t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output)
- }
- }
-
- func TestApp_VisibleCategories(t *testing.T) {
- app := NewApp()
- app.Name = "visible-categories"
- app.HideHelpCommand = true
- app.Commands = []Command{
- {
- Name: "command1",
- Category: "1",
- HelpName: "foo command1",
- Hidden: true,
- },
- {
- Name: "command2",
- Category: "2",
- HelpName: "foo command2",
- },
- {
- Name: "command3",
- Category: "3",
- HelpName: "foo command3",
- },
- }
-
- expected := []*CommandCategory{
- {
- Name: "2",
- Commands: []Command{
- app.Commands[1],
- },
- },
- {
- Name: "3",
- Commands: []Command{
- app.Commands[2],
- },
- },
- }
-
- app.Setup()
- expect(t, expected, app.VisibleCategories())
-
- app = NewApp()
- app.Name = "visible-categories"
- app.HideHelpCommand = true
- app.Commands = []Command{
- {
- Name: "command1",
- Category: "1",
- HelpName: "foo command1",
- Hidden: true,
- },
- {
- Name: "command2",
- Category: "2",
- HelpName: "foo command2",
- Hidden: true,
- },
- {
- Name: "command3",
- Category: "3",
- HelpName: "foo command3",
- },
- }
-
- expected = []*CommandCategory{
- {
- Name: "3",
- Commands: []Command{
- app.Commands[2],
- },
- },
- }
-
- app.Setup()
- expect(t, expected, app.VisibleCategories())
-
- app = NewApp()
- app.Name = "visible-categories"
- app.HideHelpCommand = true
- app.Commands = []Command{
- {
- Name: "command1",
- Category: "1",
- HelpName: "foo command1",
- Hidden: true,
- },
- {
- Name: "command2",
- Category: "2",
- HelpName: "foo command2",
- Hidden: true,
- },
- {
- Name: "command3",
- Category: "3",
- HelpName: "foo command3",
- Hidden: true,
- },
- }
-
- expected = []*CommandCategory{}
-
- app.Setup()
- expect(t, expected, app.VisibleCategories())
- }
-
- func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
- app := NewApp()
- app.Action = func(c *Context) error { return nil }
- app.Before = func(c *Context) error { return fmt.Errorf("before error") }
- app.After = func(c *Context) error { return fmt.Errorf("after error") }
-
- err := app.Run([]string{"foo"})
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- if !strings.Contains(err.Error(), "before error") {
- t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
- }
- if !strings.Contains(err.Error(), "after error") {
- t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
- }
- }
-
- func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
- app := NewApp()
- app.Commands = []Command{
- {
- Subcommands: []Command{
- {
- Name: "sub",
- },
- },
- Name: "bar",
- Before: func(c *Context) error { return fmt.Errorf("before error") },
- After: func(c *Context) error { return fmt.Errorf("after error") },
- },
- }
-
- err := app.Run([]string{"foo", "bar"})
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- if !strings.Contains(err.Error(), "before error") {
- t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
- }
- if !strings.Contains(err.Error(), "after error") {
- t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
- }
- }
-
- func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
- app := NewApp()
- app.Flags = []Flag{
- IntFlag{Name: "flag"},
- }
- app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
- if isSubcommand {
- t.Errorf("Expect no subcommand")
- }
- if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
- t.Errorf("Expect an invalid value error, but got \"%v\"", err)
- }
- return errors.New("intercepted: " + err.Error())
- }
- app.Commands = []Command{
- {
- Name: "bar",
- },
- }
-
- err := app.Run([]string{"foo", "--flag=wrong"})
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
- t.Errorf("Expect an intercepted error, but got \"%v\"", err)
- }
- }
-
- func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
- app := NewApp()
- app.Flags = []Flag{
- IntFlag{Name: "flag"},
- }
- app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
- if isSubcommand {
- t.Errorf("Expect subcommand")
- }
- if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
- t.Errorf("Expect an invalid value error, but got \"%v\"", err)
- }
- return errors.New("intercepted: " + err.Error())
- }
- app.Commands = []Command{
- {
- Name: "bar",
- },
- }
-
- err := app.Run([]string{"foo", "--flag=wrong", "bar"})
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
- t.Errorf("Expect an intercepted error, but got \"%v\"", err)
- }
- }
-
- func TestHandleAction_WithNonFuncAction(t *testing.T) {
- app := NewApp()
- app.Action = 42
- fs, err := flagSet(app.Name, app.Flags)
- if err != nil {
- t.Errorf("error creating FlagSet: %s", err)
- }
- err = HandleAction(app.Action, NewContext(app, fs, nil))
-
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- exitErr, ok := err.(*ExitError)
-
- if !ok {
- t.Fatalf("expected to receive a *ExitError")
- }
-
- if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type.") {
- t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error())
- }
-
- if exitErr.ExitCode() != 2 {
- t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
- }
- }
-
- func TestHandleAction_WithInvalidFuncSignature(t *testing.T) {
- app := NewApp()
- app.Action = func() string { return "" }
- fs, err := flagSet(app.Name, app.Flags)
- if err != nil {
- t.Errorf("error creating FlagSet: %s", err)
- }
- err = HandleAction(app.Action, NewContext(app, fs, nil))
-
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- exitErr, ok := err.(*ExitError)
-
- if !ok {
- t.Fatalf("expected to receive a *ExitError")
- }
-
- if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") {
- t.Fatalf("expected an unknown Action error, but got: %v", exitErr.Error())
- }
-
- if exitErr.ExitCode() != 2 {
- t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
- }
- }
-
- func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) {
- app := NewApp()
- app.Action = func(_ *Context) (int, error) { return 0, nil }
- fs, err := flagSet(app.Name, app.Flags)
- if err != nil {
- t.Errorf("error creating FlagSet: %s", err)
- }
- err = HandleAction(app.Action, NewContext(app, fs, nil))
-
- if err == nil {
- t.Fatalf("expected to receive error from Run, got none")
- }
-
- exitErr, ok := err.(*ExitError)
-
- if !ok {
- t.Fatalf("expected to receive a *ExitError")
- }
-
- if !strings.HasPrefix(exitErr.Error(), "ERROR invalid Action type") {
- t.Fatalf("expected an invalid Action signature error, but got: %v", exitErr.Error())
- }
-
- if exitErr.ExitCode() != 2 {
- t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode())
- }
- }
-
- func TestHandleAction_WithUnknownPanic(t *testing.T) {
- defer func() { refute(t, recover(), nil) }()
-
- var fn ActionFunc
-
- app := NewApp()
- app.Action = func(ctx *Context) error {
- fn(ctx)
- return nil
- }
- fs, err := flagSet(app.Name, app.Flags)
- if err != nil {
- t.Errorf("error creating FlagSet: %s", err)
- }
- HandleAction(app.Action, NewContext(app, fs, nil))
- }
-
- func TestShellCompletionForIncompleteFlags(t *testing.T) {
- app := NewApp()
- app.Flags = []Flag{
- IntFlag{
- Name: "test-completion",
- },
- }
- app.EnableBashCompletion = true
- app.BashComplete = func(ctx *Context) {
- for _, command := range ctx.App.Commands {
- if command.Hidden {
- continue
- }
-
- for _, name := range command.Names() {
- fmt.Fprintln(ctx.App.Writer, name)
- }
- }
-
- for _, flag := range ctx.App.Flags {
- for _, name := range strings.Split(flag.GetName(), ",") {
- if name == BashCompletionFlag.Name {
- continue
- }
-
- switch name = strings.TrimSpace(name); len(name) {
- case 0:
- case 1:
- fmt.Fprintln(ctx.App.Writer, "-"+name)
- default:
- fmt.Fprintln(ctx.App.Writer, "--"+name)
- }
- }
- }
- }
- app.Action = func(ctx *Context) error {
- return fmt.Errorf("should not get here")
- }
- err := app.Run([]string{"", "--test-completion", "--" + BashCompletionFlag.Name})
- if err != nil {
- t.Errorf("app should not return an error: %s", err)
- }
- }
-
- func TestHandleActionActuallyWorksWithActions(t *testing.T) {
- var f ActionFunc
- called := false
- f = func(c *Context) error {
- called = true
- return nil
- }
-
- err := HandleAction(f, nil)
-
- if err != nil {
- t.Errorf("Should not have errored: %v", err)
- }
-
- if !called {
- t.Errorf("Function was not called")
- }
- }
|