From 4a29de340705f0e1ec0093c964edcb42a446a400 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 08:51:48 -0400 Subject: [PATCH 01/10] Add more tests for map --- flag_map_impl.go | 6 +----- flag_test.go | 12 ++++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/flag_map_impl.go b/flag_map_impl.go index e0ba88be5d..b03514b7d1 100644 --- a/flag_map_impl.go +++ b/flag_map_impl.go @@ -58,11 +58,7 @@ func (i *MapBase[T, C, VC]) Set(value string) error { if err := i.value.Set(value); err != nil { return err } - tmp, ok := i.value.Get().(T) - if !ok { - return fmt.Errorf("unable to cast %v", i.value) - } - (*i.dict)[key] = tmp + (*i.dict)[key] = i.value.Get().(T) } return nil diff --git a/flag_test.go b/flag_test.go index 038fc45cfb..21e1daecc2 100644 --- a/flag_test.go +++ b/flag_test.go @@ -3077,3 +3077,15 @@ func TestFlagsByName(t *testing.T) { prev = f } } + +func TestNonStringMap(t *testing.T) { + type ( + floatMap = MapBase[float64, NoConfig, floatValue] + //floatMapFlag = FlagBase[map[string]float64, NoConfig, floatMap] + ) + + f := &floatMap{} + + assert.Equal(t, map[string]float64{}, f.Value()) + assert.Equal(t, "map[string]float64{}", f.String()) +} From 058e53d2c5c710755f90fb7ff4fda1e443b25cd8 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 08:58:53 -0400 Subject: [PATCH 02/10] Update test --- flag_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/flag_test.go b/flag_test.go index 21e1daecc2..734d7411fe 100644 --- a/flag_test.go +++ b/flag_test.go @@ -3081,11 +3081,16 @@ func TestFlagsByName(t *testing.T) { func TestNonStringMap(t *testing.T) { type ( floatMap = MapBase[float64, NoConfig, floatValue] - //floatMapFlag = FlagBase[map[string]float64, NoConfig, floatMap] ) - f := &floatMap{} + p := map[string]float64{} + + f := &floatMap{ + dict: &p, + } assert.Equal(t, map[string]float64{}, f.Value()) assert.Equal(t, "map[string]float64{}", f.String()) + + assert.Error(t, f.Set("invalid value")) } From 2c2765083480c249366054445835e74299a0bea1 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 09:05:46 -0400 Subject: [PATCH 03/10] Update test --- flag_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/flag_test.go b/flag_test.go index 734d7411fe..d5104f6051 100644 --- a/flag_test.go +++ b/flag_test.go @@ -3085,12 +3085,16 @@ func TestNonStringMap(t *testing.T) { p := map[string]float64{} + var fv floatValue + f := &floatMap{ - dict: &p, + value: &fv, } + assert.Equal(t, map[string]float64{}, f.Value()) + f.dict = &p assert.Equal(t, map[string]float64{}, f.Value()) assert.Equal(t, "map[string]float64{}", f.String()) - assert.Error(t, f.Set("invalid value")) + assert.ErrorContains(t, f.Set("invalid=value"), "ParseFloat") } From 30ba6c87b839f5ea08d063b37129ef423743bd35 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 09:21:55 -0400 Subject: [PATCH 04/10] Add test for visible categories --- command_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/command_test.go b/command_test.go index e61bc52246..544a21e64e 100644 --- a/command_test.go +++ b/command_test.go @@ -3990,6 +3990,34 @@ func TestCommandInvalidName(t *testing.T) { assert.Equal(t, []string(nil), cmd.StringSlice("foo")) } +func TestCommandCategories(t *testing.T) { + var cc commandCategories = []*commandCategory{ + { + name: "foo", + commands: []*Command{}, + }, + { + name: "bar", + commands: []*Command{}, + }, + { + name: "goo", + commands: nil, + }, + } + + sort.Sort(&cc) + + var prev *commandCategory + for _, c := range cc { + if prev != nil { + assert.LessOrEqual(t, prev.name, c.name) + } + prev = c + assert.Equal(t, []*Command(nil), c.VisibleCommands()) + } +} + func TestJSONExportCommand(t *testing.T) { cmd := buildExtendedTestCommand() cmd.Arguments = []Argument{ From c4f256ca1bea5411731fa4517737593a0018849d Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 09:36:20 -0400 Subject: [PATCH 05/10] Remove error check --- flag_bool_with_inverse.go | 5 +---- flag_bool_with_inverse_test.go | 9 ++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/flag_bool_with_inverse.go b/flag_bool_with_inverse.go index 00871d6143..91cf4e30a9 100644 --- a/flag_bool_with_inverse.go +++ b/flag_bool_with_inverse.go @@ -45,10 +45,7 @@ func (parent *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) } if *parent.negDest { - err := cmd.Set(parent.positiveFlag.Name, "false") - if err != nil { - return err - } + _ = cmd.Set(parent.positiveFlag.Name, "false") } if parent.BoolFlag.Action != nil { diff --git a/flag_bool_with_inverse_test.go b/flag_bool_with_inverse_test.go index bdf64c90f2..6c7124d140 100644 --- a/flag_bool_with_inverse_test.go +++ b/flag_bool_with_inverse_test.go @@ -391,11 +391,10 @@ func TestBoolWithInverseString(t *testing.T) { expected: "--[nope-]env\t", }, { - testName: "empty inverse prefix", - flagName: "env", - required: true, - inversePrefix: "", - expected: "--[no-]env\t", + testName: "empty inverse prefix", + flagName: "env", + required: true, + expected: "--[no-]env\t", }, } From 59da6a537f8c633a8fcfbfafa5f1d7fc86de1967 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 14:30:27 -0400 Subject: [PATCH 06/10] Add bool inverse tests --- flag_bool_with_inverse.go | 8 ++------ flag_bool_with_inverse_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/flag_bool_with_inverse.go b/flag_bool_with_inverse.go index 91cf4e30a9..cc401bb9fc 100644 --- a/flag_bool_with_inverse.go +++ b/flag_bool_with_inverse.go @@ -113,16 +113,12 @@ func (parent *BoolWithInverseFlag) initialize() { } func (parent *BoolWithInverseFlag) inverseName() string { - if parent.InversePrefix == "" { - parent.InversePrefix = DefaultInverseBoolPrefix - } - - return parent.InversePrefix + parent.BoolFlag.Name + return parent.inversePrefix() + parent.BoolFlag.Name } func (parent *BoolWithInverseFlag) inversePrefix() string { if parent.InversePrefix == "" { - return DefaultInverseBoolPrefix + parent.InversePrefix = DefaultInverseBoolPrefix } return parent.InversePrefix diff --git a/flag_bool_with_inverse_test.go b/flag_bool_with_inverse_test.go index 6c7124d140..a456357d70 100644 --- a/flag_bool_with_inverse_test.go +++ b/flag_bool_with_inverse_test.go @@ -237,6 +237,18 @@ func TestBoolWithInverseEnvVars(t *testing.T) { "NO-ENV": "true", }, }, + { + err: fmt.Errorf("could not parse \"true_env\" as bool value from environment variable \"ENV\" for flag env: parse error"), + envVars: map[string]string{ + "ENV": "true_env", + }, + }, + { + err: fmt.Errorf("could not parse \"false_env\" as bool value from environment variable \"NO-ENV\" for flag no-env: parse error"), + envVars: map[string]string{ + "NO-ENV": "false_env", + }, + }, } err := runBoolWithInverseFlagTests(t, flagMethod, testCases) From 097b5e54c959364b331b7fb57e90cfc5fa325d10 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 14:40:36 -0400 Subject: [PATCH 07/10] Add fish tests --- fish.go | 4 ---- fish_test.go | 24 ++++++++++++++++++++---- testdata/expected-fish-full.fish | 1 + 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fish.go b/fish.go index b2b6ec93b7..c807dcc7e5 100644 --- a/fish.go +++ b/fish.go @@ -67,10 +67,6 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string { completions := []string{} for _, command := range commands { - if command.Hidden { - continue - } - var completion strings.Builder completion.WriteString(fmt.Sprintf( "complete -r -c %s -n '%s' -a '%s'", diff --git a/fish_test.go b/fish_test.go index 098f6b45cd..0a5dfb7f55 100644 --- a/fish_test.go +++ b/fish_test.go @@ -3,17 +3,33 @@ package cli import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestFishCompletion(t *testing.T) { // Given cmd := buildExtendedTestCommand() - cmd.Flags = append(cmd.Flags, &StringFlag{ - Name: "logfile", - TakesFile: true, - }) + cmd.Flags = append(cmd.Flags, + &StringFlag{ + Name: "logfile", + TakesFile: true, + }, + &StringSliceFlag{ + Name: "foofile", + TakesFile: true, + }) + oldTemplate := FishCompletionTemplate + defer func() { FishCompletionTemplate = oldTemplate }() + FishCompletionTemplate = "{{something" + + // test error case + _, err1 := cmd.ToFishCompletion() + assert.Error(t, err1) + + // reset the template + FishCompletionTemplate = oldTemplate // When res, err := cmd.ToFishCompletion() diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index cc449c5f46..95f135ae72 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -13,6 +13,7 @@ complete -c greet -n '__fish_greet_no_subcommand' -l socket -s s -r -d 'some \'u complete -c greet -n '__fish_greet_no_subcommand' -f -l flag -s fl -s f -r complete -c greet -n '__fish_greet_no_subcommand' -f -l another-flag -s b -d 'another usage text' complete -c greet -n '__fish_greet_no_subcommand' -l logfile -r +complete -c greet -n '__fish_greet_no_subcommand' -l foofile -r complete -c greet -n '__fish_greet_no_subcommand' -f -l help -s h -d 'show help' complete -c greet -n '__fish_greet_no_subcommand' -f -l version -s v -d 'print the version' complete -c greet -n '__fish_seen_subcommand_from config c' -f -l help -s h -d 'show help' From f47879a27b96a89e4272da2b8a80d8925b282a50 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 18:08:09 -0400 Subject: [PATCH 08/10] Add completion test --- completion_test.go | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/completion_test.go b/completion_test.go index b0248169c0..c204ae2521 100644 --- a/completion_test.go +++ b/completion_test.go @@ -2,6 +2,7 @@ package cli import ( "bytes" + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -98,11 +99,47 @@ func TestCompletionSubcommand(t *testing.T) { ) } +type mockWriter struct { + err error +} + +func (mw *mockWriter) Write(p []byte) (int, error) { + if mw.err != nil { + return 0, mw.err + } + return len(p), nil +} + func TestCompletionInvalidShell(t *testing.T) { cmd := &Command{ EnableShellCompletion: true, } - err := cmd.Run(buildTestContext(t), []string{"foo", completionCommandName, "junky-sheell"}) + unknownShellName := "junky-sheell" + err := cmd.Run(buildTestContext(t), []string{"foo", completionCommandName, unknownShellName}) assert.ErrorContains(t, err, "unknown shell junky-sheell") + + enableError := true + shellCompletions[unknownShellName] = func(c *Command) (string, error) { + if enableError { + return "", fmt.Errorf("cant do completion") + } + return "something", nil + } + defer func() { + delete(shellCompletions, unknownShellName) + }() + + err = cmd.Run(buildTestContext(t), []string{"foo", completionCommandName, unknownShellName}) + assert.ErrorContains(t, err, "cant do completion") + + // now disable shell completion error + enableError = false + c := cmd.Command(completionCommandName) + assert.NotNil(t, c) + c.Writer = &mockWriter{ + err: fmt.Errorf("writer error"), + } + err = cmd.Run(buildTestContext(t), []string{"foo", completionCommandName, unknownShellName}) + assert.ErrorContains(t, err, "writer error") } From 1e7d51f5e93698f52d7b193f89d15bd8990b6b0e Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 19:04:10 -0400 Subject: [PATCH 09/10] Remove ptr checks for bool --- flag_bool.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/flag_bool.go b/flag_bool.go index 4ad81d58b8..d576448240 100644 --- a/flag_bool.go +++ b/flag_bool.go @@ -71,17 +71,11 @@ func (b *boolValue) Set(s string) error { func (b *boolValue) Get() interface{} { return *b.destination } func (b *boolValue) String() string { - if b.destination != nil { - return strconv.FormatBool(*b.destination) - } - return strconv.FormatBool(false) + return strconv.FormatBool(*b.destination) } func (b *boolValue) IsBoolFlag() bool { return true } func (b *boolValue) Count() int { - if b.count != nil { - return *b.count - } - return 0 + return *b.count } From fb6aad223bfc81227b740b4663057534acafb272 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Wed, 23 Oct 2024 19:26:53 -0400 Subject: [PATCH 10/10] Add windows test --- flag_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/flag_test.go b/flag_test.go index d5104f6051..87146d5f55 100644 --- a/flag_test.go +++ b/flag_test.go @@ -9,6 +9,7 @@ import ( "os" "reflect" "regexp" + "runtime" "sort" "strings" "testing" @@ -3098,3 +3099,31 @@ func TestNonStringMap(t *testing.T) { assert.ErrorContains(t, f.Set("invalid=value"), "ParseFloat") } + +func TestUnqouteUsage(t *testing.T) { + tests := []struct { + str string + expStr string + expUsage string + }{ + {"foo", "", "foo"}, + {"foo something", "", "foo something"}, + {"foo `bar 11`", "bar 11", "foo bar 11"}, + {"foo `bar 11` sobar", "bar 11", "foo bar 11 sobar"}, + {"foo `bar 11", "", "foo `bar 11"}, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("unquote %d", i), func(t *testing.T) { + str, usage := unquoteUsage(test.str) + assert.Equal(t, test.expStr, str) + assert.Equal(t, test.expUsage, usage) + }) + } +} + +func TestEnvHintWindows(t *testing.T) { + if runtime.GOOS == "windows" && os.Getenv("PSHOME") == "" { + assert.Equal(t, "something [%foo%, %bar%, %ss%]", withEnvHint([]string{"foo", "bar", "ss"}, "something")) + } +}