Skip to content

Commit

Permalink
Merge pull request #1941 from dearchap/issue_1930
Browse files Browse the repository at this point in the history
Fix:(issue_1930) Fix for invalid bool counts
  • Loading branch information
dearchap authored Jul 1, 2024
2 parents 37a4347 + 0faa177 commit 5b3eb1c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 68 deletions.
6 changes: 0 additions & 6 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -800,12 +800,6 @@ func (cmd *Command) parseFlags(args Args) (Args, error) {
return cmd.Args(), err
}

tracef("normalizing flags (cmd=%[1]q)", cmd.Name)

if err := normalizeFlags(cmd.Flags, cmd.flagSet); err != nil {
return cmd.Args(), err
}

tracef("done parsing flags (cmd=%[1]q)", cmd.Name)

return cmd.Args(), nil
Expand Down
63 changes: 53 additions & 10 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3204,17 +3204,60 @@ func TestCommand_Bool(t *testing.T) {
}

func TestCommand_Value(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
parentSet := flag.NewFlagSet("test", 0)
parentSet.Int("top-flag", 13, "doc")
pCmd := &Command{flagSet: parentSet}
cmd := &Command{flagSet: set, parent: pCmd}
subCmd := &Command{
Name: "test",
Flags: []Flag{
&IntFlag{
Name: "myflag",
Usage: "doc",
Aliases: []string{"m", "mf"},
},
},
Action: func(ctx context.Context, c *Command) error {
return nil
},
}

r := require.New(t)
r.Equal(12, cmd.Value("myflag"))
r.Equal(13, cmd.Value("top-flag"))
r.Nil(cmd.Value("unknown-flag"))
cmd := &Command{
Flags: []Flag{
&IntFlag{
Name: "top-flag",
Usage: "doc",
Aliases: []string{"t", "tf"},
},
},
Commands: []*Command{
subCmd,
},
}
t.Run("flag name", func(t *testing.T) {
r := require.New(t)
err := cmd.Run(buildTestContext(t), []string{"main", "--top-flag", "13", "test", "--myflag", "14"})

r.NoError(err)
r.Equal(int64(13), cmd.Value("top-flag"))
r.Equal(int64(13), cmd.Value("t"))
r.Equal(int64(13), cmd.Value("tf"))

r.Equal(int64(14), subCmd.Value("myflag"))
r.Equal(int64(14), subCmd.Value("m"))
r.Equal(int64(14), subCmd.Value("mf"))
})

t.Run("flag aliases", func(t *testing.T) {
r := require.New(t)
err := cmd.Run(buildTestContext(t), []string{"main", "-tf", "15", "test", "-m", "16"})

r.NoError(err)
r.Equal(int64(15), cmd.Value("top-flag"))
r.Equal(int64(15), cmd.Value("t"))
r.Equal(int64(15), cmd.Value("tf"))

r.Equal(int64(16), subCmd.Value("myflag"))
r.Equal(int64(16), subCmd.Value("m"))
r.Equal(int64(16), subCmd.Value("mf"))
r.Nil(cmd.Value("unknown-flag"))
})
}

func TestCommand_Value_InvalidFlagAccessHandler(t *testing.T) {
Expand Down
43 changes: 0 additions & 43 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cli

import (
"context"
"errors"
"flag"
"fmt"
"io"
Expand Down Expand Up @@ -198,48 +197,6 @@ func newFlagSet(name string, flags []Flag) (*flag.FlagSet, error) {
return set, nil
}

func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case Serializer:
_ = set.Set(name, ff.Value.(Serializer).Serialize())
default:
_ = set.Set(name, ff.Value.String())
}
}

func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited := make(map[string]bool)
set.Visit(func(f *flag.Flag) {
visited[f.Name] = true
})
for _, f := range flags {
parts := f.Names()
if len(parts) == 1 {
continue
}
var ff *flag.Flag
for _, name := range parts {
name = strings.Trim(name, " ")
if visited[name] {
if ff != nil {
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
}
ff = set.Lookup(name)
}
}
if ff == nil {
continue
}
for _, name := range parts {
name = strings.Trim(name, " ")
if !visited[name] {
copyFlag(name, ff, set)
}
}
}
return nil
}

func visibleFlags(fl []Flag) []Flag {
var visible []Flag
for _, f := range fl {
Expand Down
28 changes: 19 additions & 9 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,28 +83,38 @@ func TestBoolFlagCountFromCommand(t *testing.T) {
expectedCount int
}{
{
input: []string{"-tf", "-w", "-huh"},
input: []string{"main", "-tf", "-w", "-huh"},
expectedVal: true,
expectedCount: 3,
},
{
input: []string{},
input: []string{"main", "-huh"},
expectedVal: true,
expectedCount: 1,
},
{
input: []string{"main"},
expectedVal: false,
expectedCount: 0,
},
}

bf := &BoolFlag{Name: "tf", Aliases: []string{"w", "huh"}}
for _, bct := range boolCountTests {
set := flag.NewFlagSet("test", 0)
cmd := &Command{flagSet: set}
tf := &BoolFlag{Name: "tf", Aliases: []string{"w", "huh"}}
cmd := &Command{
Flags: []Flag{
bf,
},
}
r := require.New(t)

r.NoError(tf.Apply(set))
r.NoError(set.Parse(bct.input))
r.NoError(cmd.Run(buildTestContext(t), bct.input))

r.Equal(bct.expectedVal, tf.Get(cmd))
r.Equal(bct.expectedCount, cmd.Count("tf"))
r.Equal(bct.expectedVal, cmd.Value(bf.Name))
r.Equal(bct.expectedCount, cmd.Count(bf.Name))
for _, alias := range bf.Aliases {
r.Equal(bct.expectedCount, cmd.Count(alias))
}
}
}

Expand Down

0 comments on commit 5b3eb1c

Please sign in to comment.