github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/cli/app_test.go (about)

     1  package cli
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func ExampleApp_Run() {
    17  	// set args for examples sake
    18  	os.Args = []string{"greet", "--name", "Jeremy"}
    19  
    20  	app := NewApp()
    21  	app.Name = "greet"
    22  	app.Flags = []Flag{
    23  		StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
    24  	}
    25  	app.Action = func(c *Context) {
    26  		fmt.Printf("Hello %v\n", c.String("name"))
    27  	}
    28  	app.UsageText = "app [first_arg] [second_arg]"
    29  	app.Author = "Harrison"
    30  	app.Email = "harrison@lolwut.com"
    31  	app.Authors = []Author{Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
    32  	app.Run(os.Args)
    33  	// Output:
    34  	// Hello Jeremy
    35  }
    36  
    37  func ExampleApp_Run_subcommand() {
    38  	// set args for examples sake
    39  	os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
    40  	app := NewApp()
    41  	app.Name = "say"
    42  	app.Commands = []Command{
    43  		{
    44  			Name:        "hello",
    45  			Aliases:     []string{"hi"},
    46  			Usage:       "use it to see a description",
    47  			Description: "This is how we describe hello the function",
    48  			Subcommands: []Command{
    49  				{
    50  					Name:        "english",
    51  					Aliases:     []string{"en"},
    52  					Usage:       "sends a greeting in english",
    53  					Description: "greets someone in english",
    54  					Flags: []Flag{
    55  						StringFlag{
    56  							Name:  "name",
    57  							Value: "Bob",
    58  							Usage: "Name of the person to greet",
    59  						},
    60  					},
    61  					Action: func(c *Context) {
    62  						fmt.Println("Hello,", c.String("name"))
    63  					},
    64  				},
    65  			},
    66  		},
    67  	}
    68  
    69  	app.Run(os.Args)
    70  	// Output:
    71  	// Hello, Jeremy
    72  }
    73  
    74  func ExampleApp_Run_help() {
    75  	// set args for examples sake
    76  	os.Args = []string{"greet", "h", "describeit"}
    77  
    78  	app := NewApp()
    79  	app.Name = "greet"
    80  	app.Flags = []Flag{
    81  		StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
    82  	}
    83  	app.Commands = []Command{
    84  		{
    85  			Name:        "describeit",
    86  			Aliases:     []string{"d"},
    87  			Usage:       "use it to see a description",
    88  			Description: "This is how we describe describeit the function",
    89  			Action: func(c *Context) {
    90  				fmt.Printf("i like to describe things")
    91  			},
    92  		},
    93  	}
    94  	app.Run(os.Args)
    95  	// Output:
    96  	// NAME:
    97  	//    greet describeit - use it to see a description
    98  	//
    99  	// USAGE:
   100  	//    greet describeit [arguments...]
   101  	//
   102  	// DESCRIPTION:
   103  	//    This is how we describe describeit the function
   104  }
   105  
   106  func ExampleApp_Run_bashComplete() {
   107  	// set args for examples sake
   108  	os.Args = []string{"greet", "--generate-bash-completion"}
   109  
   110  	app := NewApp()
   111  	app.Name = "greet"
   112  	app.EnableBashCompletion = true
   113  	app.Commands = []Command{
   114  		{
   115  			Name:        "describeit",
   116  			Aliases:     []string{"d"},
   117  			Usage:       "use it to see a description",
   118  			Description: "This is how we describe describeit the function",
   119  			Action: func(c *Context) {
   120  				fmt.Printf("i like to describe things")
   121  			},
   122  		}, {
   123  			Name:        "next",
   124  			Usage:       "next example",
   125  			Description: "more stuff to see when generating bash completion",
   126  			Action: func(c *Context) {
   127  				fmt.Printf("the next example")
   128  			},
   129  		},
   130  	}
   131  
   132  	app.Run(os.Args)
   133  	// Output:
   134  	// describeit
   135  	// d
   136  	// next
   137  	// help
   138  	// h
   139  }
   140  
   141  func TestApp_Run(t *testing.T) {
   142  	s := ""
   143  
   144  	app := NewApp()
   145  	app.Action = func(c *Context) {
   146  		s = s + c.Args().First()
   147  	}
   148  
   149  	err := app.Run([]string{"command", "foo"})
   150  	expect(t, err, nil)
   151  	err = app.Run([]string{"command", "bar"})
   152  	expect(t, err, nil)
   153  	expect(t, s, "foobar")
   154  }
   155  
   156  var commandAppTests = []struct {
   157  	name     string
   158  	expected bool
   159  }{
   160  	{"foobar", true},
   161  	{"batbaz", true},
   162  	{"b", true},
   163  	{"f", true},
   164  	{"bat", false},
   165  	{"nothing", false},
   166  }
   167  
   168  func TestApp_Command(t *testing.T) {
   169  	app := NewApp()
   170  	fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
   171  	batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
   172  	app.Commands = []Command{
   173  		fooCommand,
   174  		batCommand,
   175  	}
   176  
   177  	for _, test := range commandAppTests {
   178  		expect(t, app.Command(test.name) != nil, test.expected)
   179  	}
   180  }
   181  
   182  func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
   183  	var parsedOption, firstArg string
   184  
   185  	app := NewApp()
   186  	command := Command{
   187  		Name: "cmd",
   188  		Flags: []Flag{
   189  			StringFlag{Name: "option", Value: "", Usage: "some option"},
   190  		},
   191  		Action: func(c *Context) {
   192  			parsedOption = c.String("option")
   193  			firstArg = c.Args().First()
   194  		},
   195  	}
   196  	app.Commands = []Command{command}
   197  
   198  	app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
   199  
   200  	expect(t, parsedOption, "my-option")
   201  	expect(t, firstArg, "my-arg")
   202  }
   203  
   204  func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
   205  	var context *Context
   206  
   207  	a := NewApp()
   208  	a.Commands = []Command{
   209  		{
   210  			Name: "foo",
   211  			Action: func(c *Context) {
   212  				context = c
   213  			},
   214  			Flags: []Flag{
   215  				StringFlag{
   216  					Name:  "lang",
   217  					Value: "english",
   218  					Usage: "language for the greeting",
   219  				},
   220  			},
   221  			Before: func(_ *Context) error { return nil },
   222  		},
   223  	}
   224  	a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
   225  
   226  	expect(t, context.Args().Get(0), "abcd")
   227  	expect(t, context.String("lang"), "spanish")
   228  }
   229  
   230  func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
   231  	var parsedOption string
   232  	var args []string
   233  
   234  	app := NewApp()
   235  	command := Command{
   236  		Name: "cmd",
   237  		Flags: []Flag{
   238  			StringFlag{Name: "option", Value: "", Usage: "some option"},
   239  		},
   240  		Action: func(c *Context) {
   241  			parsedOption = c.String("option")
   242  			args = c.Args()
   243  		},
   244  	}
   245  	app.Commands = []Command{command}
   246  
   247  	app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
   248  
   249  	expect(t, parsedOption, "my-option")
   250  	expect(t, args[0], "my-arg")
   251  	expect(t, args[1], "--")
   252  	expect(t, args[2], "--notARealFlag")
   253  }
   254  
   255  func TestApp_CommandWithDash(t *testing.T) {
   256  	var args []string
   257  
   258  	app := NewApp()
   259  	command := Command{
   260  		Name: "cmd",
   261  		Action: func(c *Context) {
   262  			args = c.Args()
   263  		},
   264  	}
   265  	app.Commands = []Command{command}
   266  
   267  	app.Run([]string{"", "cmd", "my-arg", "-"})
   268  
   269  	expect(t, args[0], "my-arg")
   270  	expect(t, args[1], "-")
   271  }
   272  
   273  func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
   274  	var args []string
   275  
   276  	app := NewApp()
   277  	command := Command{
   278  		Name: "cmd",
   279  		Action: func(c *Context) {
   280  			args = c.Args()
   281  		},
   282  	}
   283  	app.Commands = []Command{command}
   284  
   285  	app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
   286  
   287  	expect(t, args[0], "my-arg")
   288  	expect(t, args[1], "--")
   289  	expect(t, args[2], "notAFlagAtAll")
   290  }
   291  
   292  func TestApp_Float64Flag(t *testing.T) {
   293  	var meters float64
   294  
   295  	app := NewApp()
   296  	app.Flags = []Flag{
   297  		Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
   298  	}
   299  	app.Action = func(c *Context) {
   300  		meters = c.Float64("height")
   301  	}
   302  
   303  	app.Run([]string{"", "--height", "1.93"})
   304  	expect(t, meters, 1.93)
   305  }
   306  
   307  func TestApp_ParseSliceFlags(t *testing.T) {
   308  	var parsedOption, firstArg string
   309  	var parsedIntSlice []int
   310  	var parsedStringSlice []string
   311  
   312  	app := NewApp()
   313  	command := Command{
   314  		Name: "cmd",
   315  		Flags: []Flag{
   316  			IntSliceFlag{Name: "p", Value: &IntSlice{}, Usage: "set one or more ip addr"},
   317  			StringSliceFlag{Name: "ip", Value: &StringSlice{}, Usage: "set one or more ports to open"},
   318  		},
   319  		Action: func(c *Context) {
   320  			parsedIntSlice = c.IntSlice("p")
   321  			parsedStringSlice = c.StringSlice("ip")
   322  			parsedOption = c.String("option")
   323  			firstArg = c.Args().First()
   324  		},
   325  	}
   326  	app.Commands = []Command{command}
   327  
   328  	app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
   329  
   330  	IntsEquals := func(a, b []int) bool {
   331  		if len(a) != len(b) {
   332  			return false
   333  		}
   334  		for i, v := range a {
   335  			if v != b[i] {
   336  				return false
   337  			}
   338  		}
   339  		return true
   340  	}
   341  
   342  	StrsEquals := func(a, b []string) bool {
   343  		if len(a) != len(b) {
   344  			return false
   345  		}
   346  		for i, v := range a {
   347  			if v != b[i] {
   348  				return false
   349  			}
   350  		}
   351  		return true
   352  	}
   353  	var expectedIntSlice = []int{22, 80}
   354  	var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
   355  
   356  	if !IntsEquals(parsedIntSlice, expectedIntSlice) {
   357  		t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
   358  	}
   359  
   360  	if !StrsEquals(parsedStringSlice, expectedStringSlice) {
   361  		t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
   362  	}
   363  }
   364  
   365  func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
   366  	var parsedIntSlice []int
   367  	var parsedStringSlice []string
   368  
   369  	app := NewApp()
   370  	command := Command{
   371  		Name: "cmd",
   372  		Flags: []Flag{
   373  			IntSliceFlag{Name: "a", Usage: "set numbers"},
   374  			StringSliceFlag{Name: "str", Usage: "set strings"},
   375  		},
   376  		Action: func(c *Context) {
   377  			parsedIntSlice = c.IntSlice("a")
   378  			parsedStringSlice = c.StringSlice("str")
   379  		},
   380  	}
   381  	app.Commands = []Command{command}
   382  
   383  	app.Run([]string{"", "cmd", "my-arg", "-a", "2", "-str", "A"})
   384  
   385  	var expectedIntSlice = []int{2}
   386  	var expectedStringSlice = []string{"A"}
   387  
   388  	if parsedIntSlice[0] != expectedIntSlice[0] {
   389  		t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
   390  	}
   391  
   392  	if parsedStringSlice[0] != expectedStringSlice[0] {
   393  		t.Errorf("%v does not match %v", parsedIntSlice[0], expectedIntSlice[0])
   394  	}
   395  }
   396  
   397  func TestApp_DefaultStdout(t *testing.T) {
   398  	app := NewApp()
   399  
   400  	if app.Writer != os.Stdout {
   401  		t.Error("Default output writer not set.")
   402  	}
   403  }
   404  
   405  type mockWriter struct {
   406  	written []byte
   407  }
   408  
   409  func (fw *mockWriter) Write(p []byte) (n int, err error) {
   410  	if fw.written == nil {
   411  		fw.written = p
   412  	} else {
   413  		fw.written = append(fw.written, p...)
   414  	}
   415  
   416  	return len(p), nil
   417  }
   418  
   419  func (fw *mockWriter) GetWritten() (b []byte) {
   420  	return fw.written
   421  }
   422  
   423  func TestApp_SetStdout(t *testing.T) {
   424  	w := &mockWriter{}
   425  
   426  	app := NewApp()
   427  	app.Name = "test"
   428  	app.Writer = w
   429  
   430  	err := app.Run([]string{"help"})
   431  
   432  	if err != nil {
   433  		t.Fatalf("Run error: %s", err)
   434  	}
   435  
   436  	if len(w.written) == 0 {
   437  		t.Error("App did not write output to desired writer.")
   438  	}
   439  }
   440  
   441  func TestApp_BeforeFunc(t *testing.T) {
   442  	beforeRun, subcommandRun := false, false
   443  	beforeError := fmt.Errorf("fail")
   444  	var err error
   445  
   446  	app := NewApp()
   447  
   448  	app.Before = func(c *Context) error {
   449  		beforeRun = true
   450  		s := c.String("opt")
   451  		if s == "fail" {
   452  			return beforeError
   453  		}
   454  
   455  		return nil
   456  	}
   457  
   458  	app.Commands = []Command{
   459  		Command{
   460  			Name: "sub",
   461  			Action: func(c *Context) {
   462  				subcommandRun = true
   463  			},
   464  		},
   465  	}
   466  
   467  	app.Flags = []Flag{
   468  		StringFlag{Name: "opt"},
   469  	}
   470  
   471  	// run with the Before() func succeeding
   472  	err = app.Run([]string{"command", "--opt", "succeed", "sub"})
   473  
   474  	if err != nil {
   475  		t.Fatalf("Run error: %s", err)
   476  	}
   477  
   478  	if beforeRun == false {
   479  		t.Errorf("Before() not executed when expected")
   480  	}
   481  
   482  	if subcommandRun == false {
   483  		t.Errorf("Subcommand not executed when expected")
   484  	}
   485  
   486  	// reset
   487  	beforeRun, subcommandRun = false, false
   488  
   489  	// run with the Before() func failing
   490  	err = app.Run([]string{"command", "--opt", "fail", "sub"})
   491  
   492  	// should be the same error produced by the Before func
   493  	if err != beforeError {
   494  		t.Errorf("Run error expected, but not received")
   495  	}
   496  
   497  	if beforeRun == false {
   498  		t.Errorf("Before() not executed when expected")
   499  	}
   500  
   501  	if subcommandRun == true {
   502  		t.Errorf("Subcommand executed when NOT expected")
   503  	}
   504  
   505  }
   506  
   507  func TestApp_AfterFunc(t *testing.T) {
   508  	afterRun, subcommandRun := false, false
   509  	afterError := fmt.Errorf("fail")
   510  	var err error
   511  
   512  	app := NewApp()
   513  
   514  	app.After = func(c *Context) error {
   515  		afterRun = true
   516  		s := c.String("opt")
   517  		if s == "fail" {
   518  			return afterError
   519  		}
   520  
   521  		return nil
   522  	}
   523  
   524  	app.Commands = []Command{
   525  		Command{
   526  			Name: "sub",
   527  			Action: func(c *Context) {
   528  				subcommandRun = true
   529  			},
   530  		},
   531  	}
   532  
   533  	app.Flags = []Flag{
   534  		StringFlag{Name: "opt"},
   535  	}
   536  
   537  	// run with the After() func succeeding
   538  	err = app.Run([]string{"command", "--opt", "succeed", "sub"})
   539  
   540  	if err != nil {
   541  		t.Fatalf("Run error: %s", err)
   542  	}
   543  
   544  	if afterRun == false {
   545  		t.Errorf("After() not executed when expected")
   546  	}
   547  
   548  	if subcommandRun == false {
   549  		t.Errorf("Subcommand not executed when expected")
   550  	}
   551  
   552  	// reset
   553  	afterRun, subcommandRun = false, false
   554  
   555  	// run with the Before() func failing
   556  	err = app.Run([]string{"command", "--opt", "fail", "sub"})
   557  
   558  	// should be the same error produced by the Before func
   559  	if err != afterError {
   560  		t.Errorf("Run error expected, but not received")
   561  	}
   562  
   563  	if afterRun == false {
   564  		t.Errorf("After() not executed when expected")
   565  	}
   566  
   567  	if subcommandRun == false {
   568  		t.Errorf("Subcommand not executed when expected")
   569  	}
   570  }
   571  
   572  func TestAppNoHelpFlag(t *testing.T) {
   573  	oldFlag := HelpFlag
   574  	defer func() {
   575  		HelpFlag = oldFlag
   576  	}()
   577  
   578  	HelpFlag = BoolFlag{}
   579  
   580  	app := NewApp()
   581  	app.Writer = ioutil.Discard
   582  	err := app.Run([]string{"test", "-h"})
   583  
   584  	if err != flag.ErrHelp {
   585  		t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
   586  	}
   587  }
   588  
   589  func TestAppHelpPrinter(t *testing.T) {
   590  	oldPrinter := HelpPrinter
   591  	defer func() {
   592  		HelpPrinter = oldPrinter
   593  	}()
   594  
   595  	var wasCalled = false
   596  	HelpPrinter = func(w io.Writer, template string, data interface{}) {
   597  		wasCalled = true
   598  	}
   599  
   600  	app := NewApp()
   601  	app.Run([]string{"-h"})
   602  
   603  	if wasCalled == false {
   604  		t.Errorf("Help printer expected to be called, but was not")
   605  	}
   606  }
   607  
   608  func TestAppVersionPrinter(t *testing.T) {
   609  	oldPrinter := VersionPrinter
   610  	defer func() {
   611  		VersionPrinter = oldPrinter
   612  	}()
   613  
   614  	var wasCalled = false
   615  	VersionPrinter = func(c *Context) {
   616  		wasCalled = true
   617  	}
   618  
   619  	app := NewApp()
   620  	ctx := NewContext(app, nil, nil)
   621  	ShowVersion(ctx)
   622  
   623  	if wasCalled == false {
   624  		t.Errorf("Version printer expected to be called, but was not")
   625  	}
   626  }
   627  
   628  func TestAppCommandNotFound(t *testing.T) {
   629  	beforeRun, subcommandRun := false, false
   630  	app := NewApp()
   631  
   632  	app.CommandNotFound = func(c *Context, command string) {
   633  		beforeRun = true
   634  	}
   635  
   636  	app.Commands = []Command{
   637  		Command{
   638  			Name: "bar",
   639  			Action: func(c *Context) {
   640  				subcommandRun = true
   641  			},
   642  		},
   643  	}
   644  
   645  	app.Run([]string{"command", "foo"})
   646  
   647  	expect(t, beforeRun, true)
   648  	expect(t, subcommandRun, false)
   649  }
   650  
   651  func TestGlobalFlag(t *testing.T) {
   652  	var globalFlag string
   653  	var globalFlagSet bool
   654  	app := NewApp()
   655  	app.Flags = []Flag{
   656  		StringFlag{Name: "global, g", Usage: "global"},
   657  	}
   658  	app.Action = func(c *Context) {
   659  		globalFlag = c.GlobalString("global")
   660  		globalFlagSet = c.GlobalIsSet("global")
   661  	}
   662  	app.Run([]string{"command", "-g", "foo"})
   663  	expect(t, globalFlag, "foo")
   664  	expect(t, globalFlagSet, true)
   665  
   666  }
   667  
   668  func TestGlobalFlagsInSubcommands(t *testing.T) {
   669  	subcommandRun := false
   670  	parentFlag := false
   671  	app := NewApp()
   672  
   673  	app.Flags = []Flag{
   674  		BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
   675  	}
   676  
   677  	app.Commands = []Command{
   678  		Command{
   679  			Name: "foo",
   680  			Flags: []Flag{
   681  				BoolFlag{Name: "parent, p", Usage: "Parent flag"},
   682  			},
   683  			Subcommands: []Command{
   684  				{
   685  					Name: "bar",
   686  					Action: func(c *Context) {
   687  						if c.GlobalBool("debug") {
   688  							subcommandRun = true
   689  						}
   690  						if c.GlobalBool("parent") {
   691  							parentFlag = true
   692  						}
   693  					},
   694  				},
   695  			},
   696  		},
   697  	}
   698  
   699  	app.Run([]string{"command", "-d", "foo", "-p", "bar"})
   700  
   701  	expect(t, subcommandRun, true)
   702  	expect(t, parentFlag, true)
   703  }
   704  
   705  func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
   706  	var subcommandHelpTopics = [][]string{
   707  		{"command", "foo", "--help"},
   708  		{"command", "foo", "-h"},
   709  		{"command", "foo", "help"},
   710  	}
   711  
   712  	for _, flagSet := range subcommandHelpTopics {
   713  		t.Logf("==> checking with flags %v", flagSet)
   714  
   715  		app := NewApp()
   716  		buf := new(bytes.Buffer)
   717  		app.Writer = buf
   718  
   719  		subCmdBar := Command{
   720  			Name:  "bar",
   721  			Usage: "does bar things",
   722  		}
   723  		subCmdBaz := Command{
   724  			Name:  "baz",
   725  			Usage: "does baz things",
   726  		}
   727  		cmd := Command{
   728  			Name:        "foo",
   729  			Description: "descriptive wall of text about how it does foo things",
   730  			Subcommands: []Command{subCmdBar, subCmdBaz},
   731  		}
   732  
   733  		app.Commands = []Command{cmd}
   734  		err := app.Run(flagSet)
   735  
   736  		if err != nil {
   737  			t.Error(err)
   738  		}
   739  
   740  		output := buf.String()
   741  		t.Logf("output: %q\n", buf.Bytes())
   742  
   743  		if strings.Contains(output, "No help topic for") {
   744  			t.Errorf("expect a help topic, got none: \n%q", output)
   745  		}
   746  
   747  		for _, shouldContain := range []string{
   748  			cmd.Name, cmd.Description,
   749  			subCmdBar.Name, subCmdBar.Usage,
   750  			subCmdBaz.Name, subCmdBaz.Usage,
   751  		} {
   752  			if !strings.Contains(output, shouldContain) {
   753  				t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
   754  			}
   755  		}
   756  	}
   757  }
   758  
   759  func TestApp_Run_SubcommandFullPath(t *testing.T) {
   760  	app := NewApp()
   761  	buf := new(bytes.Buffer)
   762  	app.Writer = buf
   763  	app.Name = "command"
   764  	subCmd := Command{
   765  		Name:  "bar",
   766  		Usage: "does bar things",
   767  	}
   768  	cmd := Command{
   769  		Name:        "foo",
   770  		Description: "foo commands",
   771  		Subcommands: []Command{subCmd},
   772  	}
   773  	app.Commands = []Command{cmd}
   774  
   775  	err := app.Run([]string{"command", "foo", "bar", "--help"})
   776  	if err != nil {
   777  		t.Error(err)
   778  	}
   779  
   780  	output := buf.String()
   781  	if !strings.Contains(output, "command foo bar - does bar things") {
   782  		t.Errorf("expected full path to subcommand: %s", output)
   783  	}
   784  	if !strings.Contains(output, "command foo bar [arguments...]") {
   785  		t.Errorf("expected full path to subcommand: %s", output)
   786  	}
   787  }
   788  
   789  func TestApp_Run_SubcommandHelpName(t *testing.T) {
   790  	app := NewApp()
   791  	buf := new(bytes.Buffer)
   792  	app.Writer = buf
   793  	app.Name = "command"
   794  	subCmd := Command{
   795  		Name:     "bar",
   796  		HelpName: "custom",
   797  		Usage:    "does bar things",
   798  	}
   799  	cmd := Command{
   800  		Name:        "foo",
   801  		Description: "foo commands",
   802  		Subcommands: []Command{subCmd},
   803  	}
   804  	app.Commands = []Command{cmd}
   805  
   806  	err := app.Run([]string{"command", "foo", "bar", "--help"})
   807  	if err != nil {
   808  		t.Error(err)
   809  	}
   810  
   811  	output := buf.String()
   812  	if !strings.Contains(output, "custom - does bar things") {
   813  		t.Errorf("expected HelpName for subcommand: %s", output)
   814  	}
   815  	if !strings.Contains(output, "custom [arguments...]") {
   816  		t.Errorf("expected HelpName to subcommand: %s", output)
   817  	}
   818  }
   819  
   820  func TestApp_Run_CommandHelpName(t *testing.T) {
   821  	app := NewApp()
   822  	buf := new(bytes.Buffer)
   823  	app.Writer = buf
   824  	app.Name = "command"
   825  	subCmd := Command{
   826  		Name:  "bar",
   827  		Usage: "does bar things",
   828  	}
   829  	cmd := Command{
   830  		Name:        "foo",
   831  		HelpName:    "custom",
   832  		Description: "foo commands",
   833  		Subcommands: []Command{subCmd},
   834  	}
   835  	app.Commands = []Command{cmd}
   836  
   837  	err := app.Run([]string{"command", "foo", "bar", "--help"})
   838  	if err != nil {
   839  		t.Error(err)
   840  	}
   841  
   842  	output := buf.String()
   843  	if !strings.Contains(output, "command foo bar - does bar things") {
   844  		t.Errorf("expected full path to subcommand: %s", output)
   845  	}
   846  	if !strings.Contains(output, "command foo bar [arguments...]") {
   847  		t.Errorf("expected full path to subcommand: %s", output)
   848  	}
   849  }
   850  
   851  func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
   852  	app := NewApp()
   853  	buf := new(bytes.Buffer)
   854  	app.Writer = buf
   855  	app.Name = "base"
   856  	subCmd := Command{
   857  		Name:     "bar",
   858  		HelpName: "custom",
   859  		Usage:    "does bar things",
   860  	}
   861  	cmd := Command{
   862  		Name:        "foo",
   863  		Description: "foo commands",
   864  		Subcommands: []Command{subCmd},
   865  	}
   866  	app.Commands = []Command{cmd}
   867  
   868  	err := app.Run([]string{"command", "foo", "--help"})
   869  	if err != nil {
   870  		t.Error(err)
   871  	}
   872  
   873  	output := buf.String()
   874  	if !strings.Contains(output, "base foo - foo commands") {
   875  		t.Errorf("expected full path to subcommand: %s", output)
   876  	}
   877  	if !strings.Contains(output, "base foo command [command options] [arguments...]") {
   878  		t.Errorf("expected full path to subcommand: %s", output)
   879  	}
   880  }
   881  
   882  func TestApp_Run_Help(t *testing.T) {
   883  	var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}
   884  
   885  	for _, args := range helpArguments {
   886  		buf := new(bytes.Buffer)
   887  
   888  		t.Logf("==> checking with arguments %v", args)
   889  
   890  		app := NewApp()
   891  		app.Name = "boom"
   892  		app.Usage = "make an explosive entrance"
   893  		app.Writer = buf
   894  		app.Action = func(c *Context) {
   895  			buf.WriteString("boom I say!")
   896  		}
   897  
   898  		err := app.Run(args)
   899  		if err != nil {
   900  			t.Error(err)
   901  		}
   902  
   903  		output := buf.String()
   904  		t.Logf("output: %q\n", buf.Bytes())
   905  
   906  		if !strings.Contains(output, "boom - make an explosive entrance") {
   907  			t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output)
   908  		}
   909  	}
   910  }
   911  
   912  func TestApp_Run_Version(t *testing.T) {
   913  	var versionArguments = [][]string{{"boom", "--version"}, {"boom", "-v"}}
   914  
   915  	for _, args := range versionArguments {
   916  		buf := new(bytes.Buffer)
   917  
   918  		t.Logf("==> checking with arguments %v", args)
   919  
   920  		app := NewApp()
   921  		app.Name = "boom"
   922  		app.Usage = "make an explosive entrance"
   923  		app.Version = "0.1.0"
   924  		app.Writer = buf
   925  		app.Action = func(c *Context) {
   926  			buf.WriteString("boom I say!")
   927  		}
   928  
   929  		err := app.Run(args)
   930  		if err != nil {
   931  			t.Error(err)
   932  		}
   933  
   934  		output := buf.String()
   935  		t.Logf("output: %q\n", buf.Bytes())
   936  
   937  		if !strings.Contains(output, "0.1.0") {
   938  			t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output)
   939  		}
   940  	}
   941  }
   942  
   943  func TestApp_Run_Categories(t *testing.T) {
   944  	app := NewApp()
   945  	app.Name = "categories"
   946  	app.Commands = []Command{
   947  		Command{
   948  			Name:     "command1",
   949  			Category: "1",
   950  		},
   951  		Command{
   952  			Name:     "command2",
   953  			Category: "1",
   954  		},
   955  		Command{
   956  			Name:     "command3",
   957  			Category: "2",
   958  		},
   959  	}
   960  	buf := new(bytes.Buffer)
   961  	app.Writer = buf
   962  
   963  	app.Run([]string{"categories"})
   964  
   965  	expect := CommandCategories{
   966  		&CommandCategory{
   967  			Name: "1",
   968  			Commands: []Command{
   969  				app.Commands[0],
   970  				app.Commands[1],
   971  			},
   972  		},
   973  		&CommandCategory{
   974  			Name: "2",
   975  			Commands: []Command{
   976  				app.Commands[2],
   977  			},
   978  		},
   979  	}
   980  	if !reflect.DeepEqual(app.Categories(), expect) {
   981  		t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
   982  	}
   983  
   984  	output := buf.String()
   985  	t.Logf("output: %q\n", buf.Bytes())
   986  
   987  	if !strings.Contains(output, "1:\n    command1") {
   988  		t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n    command1", output)
   989  	}
   990  }
   991  
   992  func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
   993  	app := NewApp()
   994  	app.Action = func(c *Context) {}
   995  	app.Before = func(c *Context) error { return fmt.Errorf("before error") }
   996  	app.After = func(c *Context) error { return fmt.Errorf("after error") }
   997  
   998  	err := app.Run([]string{"foo"})
   999  	if err == nil {
  1000  		t.Fatalf("expected to receive error from Run, got none")
  1001  	}
  1002  
  1003  	if !strings.Contains(err.Error(), "before error") {
  1004  		t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
  1005  	}
  1006  	if !strings.Contains(err.Error(), "after error") {
  1007  		t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
  1008  	}
  1009  }
  1010  
  1011  func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
  1012  	app := NewApp()
  1013  	app.Commands = []Command{
  1014  		Command{
  1015  			Subcommands: []Command{
  1016  				Command{
  1017  					Name: "sub",
  1018  				},
  1019  			},
  1020  			Name:   "bar",
  1021  			Before: func(c *Context) error { return fmt.Errorf("before error") },
  1022  			After:  func(c *Context) error { return fmt.Errorf("after error") },
  1023  		},
  1024  	}
  1025  
  1026  	err := app.Run([]string{"foo", "bar"})
  1027  	if err == nil {
  1028  		t.Fatalf("expected to receive error from Run, got none")
  1029  	}
  1030  
  1031  	if !strings.Contains(err.Error(), "before error") {
  1032  		t.Errorf("expected text of error from Before method, but got none in \"%v\"", err)
  1033  	}
  1034  	if !strings.Contains(err.Error(), "after error") {
  1035  		t.Errorf("expected text of error from After method, but got none in \"%v\"", err)
  1036  	}
  1037  }
  1038  
  1039  func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
  1040  	app := NewApp()
  1041  	app.Flags = []Flag{
  1042  		IntFlag{Name: "flag"},
  1043  	}
  1044  	app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
  1045  		if isSubcommand {
  1046  			t.Errorf("Expect no subcommand")
  1047  		}
  1048  		if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
  1049  			t.Errorf("Expect an invalid value error, but got \"%v\"", err)
  1050  		}
  1051  		return errors.New("intercepted: " + err.Error())
  1052  	}
  1053  	app.Commands = []Command{
  1054  		Command{
  1055  			Name: "bar",
  1056  		},
  1057  	}
  1058  
  1059  	err := app.Run([]string{"foo", "--flag=wrong"})
  1060  	if err == nil {
  1061  		t.Fatalf("expected to receive error from Run, got none")
  1062  	}
  1063  
  1064  	if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
  1065  		t.Errorf("Expect an intercepted error, but got \"%v\"", err)
  1066  	}
  1067  }
  1068  
  1069  func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
  1070  	app := NewApp()
  1071  	app.Flags = []Flag{
  1072  		IntFlag{Name: "flag"},
  1073  	}
  1074  	app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
  1075  		if isSubcommand {
  1076  			t.Errorf("Expect subcommand")
  1077  		}
  1078  		if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
  1079  			t.Errorf("Expect an invalid value error, but got \"%v\"", err)
  1080  		}
  1081  		return errors.New("intercepted: " + err.Error())
  1082  	}
  1083  	app.Commands = []Command{
  1084  		Command{
  1085  			Name: "bar",
  1086  		},
  1087  	}
  1088  
  1089  	err := app.Run([]string{"foo", "--flag=wrong", "bar"})
  1090  	if err == nil {
  1091  		t.Fatalf("expected to receive error from Run, got none")
  1092  	}
  1093  
  1094  	if !strings.HasPrefix(err.Error(), "intercepted: invalid value") {
  1095  		t.Errorf("Expect an intercepted error, but got \"%v\"", err)
  1096  	}
  1097  }