diff --git a/app_test.go b/app_test.go index ebf26c7..417bf98 100644 --- a/app_test.go +++ b/app_test.go @@ -13,6 +13,10 @@ import ( "testing" ) +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"} @@ -439,14 +443,15 @@ func TestApp_SetStdout(t *testing.T) { } func TestApp_BeforeFunc(t *testing.T) { - beforeRun, subcommandRun := false, false + counts := &opCounts{} beforeError := fmt.Errorf("fail") var err error app := NewApp() app.Before = func(c *Context) error { - beforeRun = true + counts.Total++ + counts.Before = counts.Total s := c.String("opt") if s == "fail" { return beforeError @@ -459,7 +464,8 @@ func TestApp_BeforeFunc(t *testing.T) { Command{ Name: "sub", Action: func(c *Context) { - subcommandRun = true + counts.Total++ + counts.SubCommand = counts.Total }, }, } @@ -475,16 +481,16 @@ func TestApp_BeforeFunc(t *testing.T) { t.Fatalf("Run error: %s", err) } - if beforeRun == false { + if counts.Before != 1 { t.Errorf("Before() not executed when expected") } - if subcommandRun == false { + if counts.SubCommand != 2 { t.Errorf("Subcommand not executed when expected") } // reset - beforeRun, subcommandRun = false, false + counts = &opCounts{} // run with the Before() func failing err = app.Run([]string{"command", "--opt", "fail", "sub"}) @@ -494,25 +500,26 @@ func TestApp_BeforeFunc(t *testing.T) { t.Errorf("Run error expected, but not received") } - if beforeRun == false { + if counts.Before != 1 { t.Errorf("Before() not executed when expected") } - if subcommandRun == true { + if counts.SubCommand != 0 { t.Errorf("Subcommand executed when NOT expected") } } func TestApp_AfterFunc(t *testing.T) { - afterRun, subcommandRun := false, false + counts := &opCounts{} afterError := fmt.Errorf("fail") var err error app := NewApp() app.After = func(c *Context) error { - afterRun = true + counts.Total++ + counts.After = counts.Total s := c.String("opt") if s == "fail" { return afterError @@ -525,7 +532,8 @@ func TestApp_AfterFunc(t *testing.T) { Command{ Name: "sub", Action: func(c *Context) { - subcommandRun = true + counts.Total++ + counts.SubCommand = counts.Total }, }, } @@ -541,16 +549,16 @@ func TestApp_AfterFunc(t *testing.T) { t.Fatalf("Run error: %s", err) } - if afterRun == false { + if counts.After != 2 { t.Errorf("After() not executed when expected") } - if subcommandRun == false { + if counts.SubCommand != 1 { t.Errorf("Subcommand not executed when expected") } // reset - afterRun, subcommandRun = false, false + counts = &opCounts{} // run with the Before() func failing err = app.Run([]string{"command", "--opt", "fail", "sub"}) @@ -560,11 +568,11 @@ func TestApp_AfterFunc(t *testing.T) { t.Errorf("Run error expected, but not received") } - if afterRun == false { + if counts.After != 2 { t.Errorf("After() not executed when expected") } - if subcommandRun == false { + if counts.SubCommand != 1 { t.Errorf("Subcommand not executed when expected") } } @@ -605,7 +613,7 @@ func TestAppHelpPrinter(t *testing.T) { } } -func TestAppVersionPrinter(t *testing.T) { +func TestApp_VersionPrinter(t *testing.T) { oldPrinter := VersionPrinter defer func() { VersionPrinter = oldPrinter @@ -625,81 +633,168 @@ func TestAppVersionPrinter(t *testing.T) { } } -func TestAppCommandNotFound(t *testing.T) { - beforeRun, subcommandRun := false, false +func TestApp_CommandNotFound(t *testing.T) { + counts := &opCounts{} app := NewApp() app.CommandNotFound = func(c *Context, command string) { - beforeRun = true + counts.Total++ + counts.CommandNotFound = counts.Total } app.Commands = []Command{ Command{ Name: "bar", Action: func(c *Context) { - subcommandRun = true + counts.Total++ + counts.SubCommand = counts.Total }, }, } app.Run([]string{"command", "foo"}) - expect(t, beforeRun, true) - expect(t, subcommandRun, false) + expect(t, counts.CommandNotFound, 1) + expect(t, counts.SubCommand, 0) + expect(t, counts.Total, 1) } -func TestGlobalFlag(t *testing.T) { - var globalFlag string - var globalFlagSet bool +func TestApp_OrderOfOperations(t *testing.T) { + counts := &opCounts{} + + resetCounts := func() { counts = &opCounts{} } + app := NewApp() - app.Flags = []Flag{ - StringFlag{Name: "global, g", Usage: "global"}, + app.EnableBashCompletion = true + app.BashComplete = func(c *Context) { + counts.Total++ + counts.BashComplete = counts.Total } - app.Action = func(c *Context) { - globalFlag = c.GlobalString("global") - globalFlagSet = c.GlobalIsSet("global") + app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { + counts.Total++ + counts.OnUsageError = counts.Total + return errors.New("hay OnUsageError") } - app.Run([]string{"command", "-g", "foo"}) - expect(t, globalFlag, "foo") - expect(t, globalFlagSet, true) -} + beforeNoError := func(c *Context) error { + counts.Total++ + counts.Before = counts.Total + return nil + } -func TestGlobalFlagsInSubcommands(t *testing.T) { - subcommandRun := false - parentFlag := false - app := NewApp() + beforeError := func(c *Context) error { + counts.Total++ + counts.Before = counts.Total + return errors.New("hay Before") + } - app.Flags = []Flag{ - BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, + 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{ Command{ - Name: "foo", - Flags: []Flag{ - BoolFlag{Name: "parent, p", Usage: "Parent flag"}, - }, - Subcommands: []Command{ - { - Name: "bar", - Action: func(c *Context) { - if c.GlobalBool("debug") { - subcommandRun = true - } - if c.GlobalBool("parent") { - parentFlag = true - } - }, - }, + Name: "bar", + Action: func(c *Context) { + counts.Total++ + counts.SubCommand = counts.Total }, }, } - app.Run([]string{"command", "-d", "foo", "-p", "bar"}) + app.Action = func(c *Context) { + counts.Total++ + counts.Action = counts.Total + } + + _ = app.Run([]string{"command", "--nope"}) + expect(t, counts.OnUsageError, 1) + expect(t, counts.Total, 1) + + resetCounts() - expect(t, subcommandRun, true) - expect(t, parentFlag, true) + _ = 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) { diff --git a/context_test.go b/context_test.go index e821235..20647b8 100644 --- a/context_test.go +++ b/context_test.go @@ -146,3 +146,57 @@ func TestContext_NumFlags(t *testing.T) { globalSet.Parse([]string{"--myflagGlobal"}) expect(t, c.NumFlags(), 2) } + +func TestContext_GlobalFlag(t *testing.T) { + var globalFlag string + var globalFlagSet bool + app := NewApp() + app.Flags = []Flag{ + StringFlag{Name: "global, g", Usage: "global"}, + } + app.Action = func(c *Context) { + globalFlag = c.GlobalString("global") + globalFlagSet = c.GlobalIsSet("global") + } + app.Run([]string{"command", "-g", "foo"}) + expect(t, globalFlag, "foo") + expect(t, globalFlagSet, true) + +} + +func TestContext_GlobalFlagsInSubcommands(t *testing.T) { + subcommandRun := false + parentFlag := false + app := NewApp() + + app.Flags = []Flag{ + BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, + } + + app.Commands = []Command{ + Command{ + Name: "foo", + Flags: []Flag{ + BoolFlag{Name: "parent, p", Usage: "Parent flag"}, + }, + Subcommands: []Command{ + { + Name: "bar", + Action: func(c *Context) { + if c.GlobalBool("debug") { + subcommandRun = true + } + if c.GlobalBool("parent") { + parentFlag = true + } + }, + }, + }, + }, + } + + app.Run([]string{"command", "-d", "foo", "-p", "bar"}) + + expect(t, subcommandRun, true) + expect(t, parentFlag, true) +} diff --git a/helpers_test.go b/helpers_test.go index b1b7339..109ea7a 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -1,14 +1,23 @@ package cli import ( + "os" "reflect" + "runtime" + "strings" "testing" ) -/* Test Helpers */ +var ( + wd, _ = os.Getwd() +) + func expect(t *testing.T, a interface{}, b interface{}) { + _, fn, line, _ := runtime.Caller(1) + fn = strings.Replace(fn, wd+"/", "", -1) + if !reflect.DeepEqual(a, b) { - t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a)) } }