Skip to content
Permalink
Browse files

Fix test cases for context, docs, errors, fish, flags and funcs

  • Loading branch information
asahasrabuddhe committed Sep 15, 2019
1 parent f29d98a commit 2024bed22a3489a19768000198ffaa7ec3cfd41e
Showing with 233 additions and 226 deletions.
  1. +30 −39 context.go
  2. +8 −8 context_test.go
  3. +4 −5 docs.go
  4. +23 −20 docs_test.go
  5. +7 −10 errors.go
  6. +6 −8 fish.go
  7. +4 −2 flag.go
  8. +4 −1 flag_int.go
  9. +4 −1 flag_int64.go
  10. +6 −3 flag_path.go
  11. +5 −3 flag_string.go
  12. +4 −1 flag_string_slice.go
  13. +119 −122 flag_test.go
  14. +4 −1 flag_uint.go
  15. +4 −1 flag_uint64.go
  16. +1 −1 funcs.go
@@ -33,6 +33,9 @@ func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
c.Context = parentCtx.Context
c.shellComplete = parentCtx.shellComplete
}

c.Command = &Command{}

if c.Context == nil {
ctx, cancel := context.WithCancel(context.Background())
go func() {
@@ -60,12 +63,17 @@ func (c *Context) Set(name, value string) error {
// IsSet determines if the flag was actually set
func (c *Context) IsSet(name string) bool {
if fs := lookupFlagSet(name, c); fs != nil {
isSet := false
fs.Visit(func(f *flag.Flag) {
if f.Name == name {
isSet = true
if fs := lookupFlagSet(name, c); fs != nil {
isSet := false
fs.Visit(func(f *flag.Flag) {
if f.Name == name {
isSet = true
}
})
if isSet {
return true
}
})
}

// XXX hack to support IsSet for flags with EnvVar
//
@@ -78,45 +86,28 @@ func (c *Context) IsSet(name string) bool {
// variables is available.
//
// See https://github.com/urfave/cli/issues/294 for additional discussion
flags := c.Command.Flags
if c.Command.Name == "" { // cannot == Command{} since it contains slice types
if c.App != nil {
flags = c.App.Flags
}
f := lookupFlag(name, c)
if f == nil {
return false
}
for _, f := range flags {
for _, name := range f.Names() {
if isSet, ok := c.setFlags[name]; isSet || !ok {
continue
}

val := reflect.ValueOf(f)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
val := reflect.ValueOf(f)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}

filePathValue := val.FieldByName("FilePath")
if filePathValue.IsValid() {
eachName(filePathValue.String(), func(filePath string) {
if _, err := os.Stat(filePath); err == nil {
c.setFlags[name] = true
return
}
})
}
filePathValue := val.FieldByName("FilePath")
if !filePathValue.IsValid() {
return false
}

envVarValues := val.FieldByName("EnvVars")
if envVarValues.IsValid() {
for _, envVar := range envVarValues.Interface().([]string) {
envVar = strings.TrimSpace(envVar)
if _, ok := syscall.Getenv(envVar); ok {
c.setFlags[name] = true
continue
}
}
}
}
envVarValues := val.FieldByName("EnvVars")
if !envVarValues.IsValid() {
return false
}

_, ok := flagFromEnvOrFile(envVarValues.Interface().([]string), filePathValue.Interface().(string))
return ok
}

return false
@@ -452,7 +452,7 @@ func TestCheckRequiredFlags(t *testing.T) {
{
testCase: "required_and_present_via_env_var",
flags: []Flag{
&StringFlag{Name: "requiredFlag", Required: true, EnvVar: "REQUIRED_FLAG"},
&StringFlag{Name: "requiredFlag", Required: true, EnvVars: []string{"REQUIRED_FLAG"}},
},
envVarInput: [2]string{"REQUIRED_FLAG", "true"},
},
@@ -477,7 +477,7 @@ func TestCheckRequiredFlags(t *testing.T) {
testCase: "required_and_optional_and_optional_present_via_env_var",
flags: []Flag{
&StringFlag{Name: "requiredFlag", Required: true},
&StringFlag{Name: "optionalFlag", EnvVar: "OPTIONAL_FLAG"},
&StringFlag{Name: "optionalFlag", EnvVars: []string{"OPTIONAL_FLAG"}},
},
envVarInput: [2]string{"OPTIONAL_FLAG", "true"},
expectedAnError: true,
@@ -519,14 +519,14 @@ func TestCheckRequiredFlags(t *testing.T) {
{
testCase: "required_flag_with_short_name",
flags: []Flag{
&StringSliceFlag{Name: "names, N", Required: true},
&StringSliceFlag{Name: "names", Aliases: []string{"N"}, Required: true},
},
parseInput: []string{"-N", "asd", "-N", "qwe"},
},
{
testCase: "required_flag_with_multiple_short_names",
flags: []Flag{
&StringSliceFlag{Name: "names, N, n", Required: true},
&StringSliceFlag{Name: "names", Aliases: []string{"N", "n"}, Required: true},
},
parseInput: []string{"-n", "asd", "-n", "qwe"},
},
@@ -543,12 +543,12 @@ func TestCheckRequiredFlags(t *testing.T) {
os.Clearenv()
_ = os.Setenv(test.envVarInput[0], test.envVarInput[1])
}
ctx := &Context{}
context := NewContext(ctx.App, set, ctx)
context.Command.Flags = test.flags
c := &Context{}
ctx := NewContext(c.App, set, c)
ctx.Command.Flags = test.flags

// logic under test
err := checkRequiredFlags(test.flags, context)
err := checkRequiredFlags(test.flags, ctx)

// assertions
if test.expectedAnError && err == nil {
@@ -53,10 +53,9 @@ func (a *App) writeDocTemplate(w io.Writer) error {
})
}

func prepareCommands(commands []Command, level int) []string {
coms := []string{}
for i := range commands {
command := &commands[i]
func prepareCommands(commands []*Command, level int) []string {
var coms []string
for _, command := range commands {
if command.Hidden {
continue
}
@@ -110,7 +109,7 @@ func prepareFlags(
continue
}
modifiedArg := opener
for _, s := range strings.Split(flag.GetName(), ",") {
for _, s := range flag.Names() {
trimmed := strings.TrimSpace(s)
if len(modifiedArg) > len(opener) {
modifiedArg += sep
@@ -9,39 +9,44 @@ func testApp() *App {
app := NewApp()
app.Name = "greet"
app.Flags = []Flag{
StringFlag{
Name: "socket, s",
&StringFlag{
Name: "socket",
Aliases: []string{"s"},
Usage: "some 'usage' text",
Value: "value",
TakesFile: true,
},
StringFlag{Name: "flag, fl, f"},
BoolFlag{
Name: "another-flag, b",
Usage: "another usage text",
&StringFlag{Name: "flag", Aliases: []string{" fl", "f"}},
&BoolFlag{
Name: "another-flag",
Aliases: []string{"b"},
Usage: "another usage text",
},
}
app.Commands = []Command{{
app.Commands = []*Command{{
Aliases: []string{"c"},
Flags: []Flag{
StringFlag{
Name: "flag, fl, f",
&StringFlag{
Name: "flag",
Aliases: []string{" fl", "f"},
TakesFile: true,
},
BoolFlag{
Name: "another-flag, b",
Usage: "another usage text",
&BoolFlag{
Name: "another-flag",
Aliases: []string{"b"},
Usage: "another usage text",
},
},
Name: "config",
Usage: "another usage test",
Subcommands: []Command{{
Subcommands: []*Command{{
Aliases: []string{"s", "ss"},
Flags: []Flag{
StringFlag{Name: "sub-flag, sub-fl, s"},
BoolFlag{
Name: "sub-command-flag, s",
Usage: "some usage text",
&StringFlag{Name: "sub-flag", Aliases: []string{"sub-fl", "s"}},
&BoolFlag{
Name: "sub-command-flag",
Aliases: []string{"s"},
Usage: "some usage text",
},
},
Name: "sub-config",
@@ -59,9 +64,7 @@ func testApp() *App {
}}
app.UsageText = "app [first_arg] [second_arg]"
app.Usage = "Some app"
app.Author = "Harrison"
app.Email = "harrison@lolwut.com"
app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
app.Authors = []*Author{{Name: "Harrison", Email: "harrison@lolwut.com"}, {Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
return app
}

@@ -59,33 +59,30 @@ type ExitCoder interface {
ExitCode() int
}

type ExitError struct {
type exitError struct {
exitCode int
message interface{}
}

// NewExitError makes a new *ExitError
func NewExitError(message interface{}, exitCode int) *ExitError {
return &ExitError{
exitCode: exitCode,
message: message,
}
// NewExitError makes a new *exitError
func NewExitError(message interface{}, exitCode int) ExitCoder {
return Exit(message, exitCode)
}

// Exit wraps a message and exit code into an ExitCoder suitable for handling by
// HandleExitCoder
func Exit(message interface{}, exitCode int) ExitCoder {
return &ExitError{
return &exitError{
exitCode: exitCode,
message: message,
}
}

func (ee *ExitError) Error() string {
func (ee *exitError) Error() string {
return fmt.Sprintf("%v", ee.message)
}

func (ee *ExitError) ExitCode() int {
func (ee *exitError) ExitCode() int {
return ee.exitCode
}

14 fish.go
@@ -64,11 +64,9 @@ func (a *App) writeFishCompletionTemplate(w io.Writer) error {
})
}

func (a *App) prepareFishCommands(commands []Command, allCommands *[]string, previousCommands []string) []string {
func (a *App) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string {
completions := []string{}
for i := range commands {
command := &commands[i]

for _, command := range commands {
if command.Hidden {
continue
}
@@ -131,7 +129,7 @@ func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string

fishAddFileFlag(f, completion)

for idx, opt := range strings.Split(flag.GetName(), ",") {
for idx, opt := range flag.Names() {
if idx == 0 {
completion.WriteString(fmt.Sprintf(
" -l %s", strings.TrimSpace(opt),
@@ -161,15 +159,15 @@ func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string

func fishAddFileFlag(flag Flag, completion *strings.Builder) {
switch f := flag.(type) {
case GenericFlag:
case *GenericFlag:
if f.TakesFile {
return
}
case StringFlag:
case *StringFlag:
if f.TakesFile {
return
}
case StringSliceFlag:
case *StringSliceFlag:
if f.TakesFile {
return
}
@@ -49,15 +49,17 @@ var BashCompletionFlag Flag = &BoolFlag{

// VersionFlag prints the version for the application
var VersionFlag Flag = &BoolFlag{
Name: "version, v",
Name: "version",
Aliases: []string{"v"},
Usage: "print the version",
}

// HelpFlag prints the help for all commands and subcommands.
// Set to nil to disable the flag. The subcommand
// will still be added unless HideHelp is set to true.
var HelpFlag Flag = &BoolFlag{
Name: "help, h",
Name: "help",
Aliases: []string{"h"},
Usage: "show help",
}

@@ -78,7 +78,10 @@ func (f *IntFlag) Apply(set *flag.FlagSet) error {
// Int looks up the value of a local IntFlag, returns
// 0 if not found
func (c *Context) Int(name string) int {
return lookupInt(name, c.flagSet)
if fs := lookupFlagSet(name, c); fs != nil {
return lookupInt(name, fs)
}
return 0
}

// GlobalInt looks up the value of a global IntFlag, returns
@@ -78,7 +78,10 @@ func (f *Int64Flag) Apply(set *flag.FlagSet) error {
// Int64 looks up the value of a local Int64Flag, returns
// 0 if not found
func (c *Context) Int64(name string) int64 {
return lookupInt64(name, c.flagSet)
if fs := lookupFlagSet(name, c); fs != nil {
return lookupInt64(name, fs)
}
return 0
}

// GlobalInt64 looks up the value of a global Int64Flag, returns

0 comments on commit 2024bed

Please sign in to comment.
You can’t perform that action at this time.