diff --git a/completion_test.go b/completion_test.go index 0323764e59..35ad8601d3 100644 --- a/completion_test.go +++ b/completion_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "os" "testing" "github.com/stretchr/testify/assert" @@ -181,6 +182,119 @@ func TestCompletionSubcommand(t *testing.T) { } } +func TestMutuallyExclusiveFlagsCompletion(t *testing.T) { + osArgsBak := os.Args + defer func() { + os.Args = osArgsBak + }() + out := &bytes.Buffer{} + + cmd := &Command{ + EnableShellCompletion: true, + Writer: out, + Flags: []Flag{ + &StringFlag{ + Name: "gf", + }, + }, + MutuallyExclusiveFlags: []MutuallyExclusiveFlags{ + { + Flags: [][]Flag{ + { + &StringFlag{ + Name: "mexg1_1", + }, + &StringFlag{ + Name: "mexg1_2", + }, + }, + { + &StringFlag{ + Name: "mexg2_1", + }, + }, + }, + }, + }, + } + + tests := []struct { + name string + args []string + expectGlobal bool + expectMexg1_1 bool + expectMexg1_2 bool + expectMexg2_1 bool + }{ + { + name: "flag completion all", + args: []string{"foo", "-", completionFlag}, + expectGlobal: true, + expectMexg1_1: true, + expectMexg1_2: true, + expectMexg2_1: true, + }, + { + name: "flag completion local", + args: []string{"foo", "-mex", completionFlag}, + expectMexg1_1: true, + expectMexg1_2: true, + expectMexg2_1: true, + }, + { + name: "flag completion local group-1", + args: []string{"foo", "-mexg1", completionFlag}, + expectMexg1_1: true, + expectMexg1_2: true, + }, + { + name: "flag completion local group-2", + args: []string{"foo", "-mexg2", completionFlag}, + expectMexg2_1: true, + }, + { + name: "flag completion local group-1 twice", + args: []string{"foo", "-mexg1-1", "-mex", completionFlag}, + expectMexg1_1: true, + expectMexg1_2: true, + }, + { + name: "flag completion local group-2 twice", + args: []string{"foo", "-mexg2-1", "-mex", completionFlag}, + expectMexg2_1: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + out.Reset() + os.Args = test.args + err := cmd.Run(buildTestContext(t), os.Args) + assert.NoError(t, err, "Expected no error for completion") + if test.expectGlobal { + assert.Contains(t, out.String(), "gf", "Expected output to contain flag gf") + } else { + assert.NotContains(t, out.String(), "gf", "Expected output to not contain flag gf") + } + if test.expectMexg1_1 { + assert.Contains(t, out.String(), "mexg1_1", "Expected output to contain flag mexg1_1") + } else { + assert.NotContains(t, out.String(), "mexg1_1", "Expected output to not contain flag mexg1_1") + } + if test.expectMexg1_2 { + assert.Contains(t, out.String(), "mexg1_2", "Expected output to contain flag mexg1_2") + } else { + assert.NotContains(t, out.String(), "mexg1_2", "Expected output to not contain flag mexg1_2") + } + if test.expectMexg2_1 { + assert.Contains(t, out.String(), "mexg2_1", "Expected output to contain flag mexg2_1") + } else { + assert.NotContains(t, out.String(), "mexg2_1", "Expected output to not contain flag mexg2_1") + } + }) + } +} + type mockWriter struct { err error } diff --git a/help.go b/help.go index 78686b1422..56bc20d4a0 100644 --- a/help.go +++ b/help.go @@ -277,7 +277,7 @@ func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) { if strings.HasPrefix(lastArg, "-") { tracef("printing flag suggestion for flag[%v] on command %[1]q", lastArg, cmd.Name) - printFlagSuggestions(lastArg, cmd.Flags, cmd.Root().Writer) + printFlagSuggestions(lastArg, cmd.appliedFlags, cmd.Root().Writer) return } diff --git a/help_test.go b/help_test.go index 0f7f5d5981..4ae3af34cb 100644 --- a/help_test.go +++ b/help_test.go @@ -1371,6 +1371,7 @@ func TestDefaultCompleteWithFlags(t *testing.T) { tc.cmd.parsedArgs = &stringSliceArgs{ tc.argv[1:], } + tc.cmd.appliedFlags = tc.cmd.Flags f := DefaultCompleteWithFlags f(buildTestContext(ct), tc.cmd)