2022-09-16 11:55:56 +00:00
|
|
|
// Copyright 2013-2022 The Cobra Authors
|
2022-04-17 21:04:57 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
2022-09-16 11:55:56 +00:00
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2022-04-17 21:04:57 +00:00
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package cobra
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestValidateFlagGroups(t *testing.T) {
|
|
|
|
getCmd := func() *Command {
|
2022-08-11 13:35:14 +00:00
|
|
|
cmd := &Command{
|
2022-04-17 21:04:57 +00:00
|
|
|
Use: "testcmd",
|
2022-08-11 13:35:14 +00:00
|
|
|
Run: func(cmd *Command, args []string) {},
|
2022-04-17 21:04:57 +00:00
|
|
|
}
|
2022-08-11 13:35:14 +00:00
|
|
|
|
|
|
|
cmd.Flags().String("a", "", "")
|
|
|
|
cmd.Flags().String("b", "", "")
|
|
|
|
cmd.Flags().String("c", "", "")
|
|
|
|
cmd.Flags().String("d", "", "")
|
|
|
|
cmd.PersistentFlags().String("p-a", "", "")
|
|
|
|
cmd.PersistentFlags().String("p-b", "", "")
|
|
|
|
cmd.PersistentFlags().String("p-c", "", "")
|
|
|
|
|
|
|
|
subCmd := &Command{
|
2022-04-17 21:04:57 +00:00
|
|
|
Use: "subcmd",
|
2022-08-11 13:35:14 +00:00
|
|
|
Run: func(cmd *Command, args []string) {},
|
|
|
|
}
|
|
|
|
subCmd.Flags().String("sub-a", "", "")
|
|
|
|
|
|
|
|
cmd.AddCommand(subCmd)
|
|
|
|
|
|
|
|
return cmd
|
2022-04-17 21:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Each test case uses a unique command from the function above.
|
|
|
|
testcases := []struct {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc string
|
|
|
|
requiredTogether []string
|
|
|
|
mutuallyExclusive []string
|
|
|
|
subRequiredTogether []string
|
|
|
|
subMutuallyExclusive []string
|
|
|
|
args []string
|
|
|
|
expectErr string
|
2022-04-17 21:04:57 +00:00
|
|
|
}{
|
|
|
|
{
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "No flags no problems",
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "No flags no problems even with conflicting groups",
|
|
|
|
requiredTogether: []string{"a b"},
|
|
|
|
mutuallyExclusive: []string{"a b"},
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Required together flag group validation fails",
|
|
|
|
requiredTogether: []string{"a b c"},
|
|
|
|
args: []string{"--a=foo"},
|
|
|
|
expectErr: `flags [a b c] must be set together, but [b c] were not set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Required together flag group validation passes",
|
|
|
|
requiredTogether: []string{"a b c"},
|
|
|
|
args: []string{"--c=bar", "--a=foo", "--b=baz"},
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Mutually exclusive flag group validation fails",
|
|
|
|
mutuallyExclusive: []string{"a b c"},
|
|
|
|
args: []string{"--b=foo", "--c=bar"},
|
|
|
|
expectErr: `exactly one of the flags [a b c] can be set, but [b c] were set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Mutually exclusive flag group validation passes",
|
|
|
|
mutuallyExclusive: []string{"a b c"},
|
|
|
|
args: []string{"--b=foo"},
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Multiple required together flag groups failed validation returns first error",
|
|
|
|
requiredTogether: []string{"a b c", "a d"},
|
|
|
|
args: []string{"--d=foo", "--c=foo"},
|
|
|
|
expectErr: `flags [a b c] must be set together, but [a b] were not set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Multiple mutually exclusive flag groups failed validation returns first error",
|
|
|
|
mutuallyExclusive: []string{"a b c", "a d"},
|
|
|
|
args: []string{"--a=foo", "--c=foo", "--d=foo"},
|
|
|
|
expectErr: `exactly one of the flags [a b c] can be set, but [a c] were set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Flag and persistent flags being in multiple groups fail required together group",
|
|
|
|
requiredTogether: []string{"a p-a", "p-a p-b"},
|
|
|
|
mutuallyExclusive: []string{"p-b p-c"},
|
|
|
|
args: []string{"--a=foo", "--p-b=foo", "--p-c=foo"},
|
|
|
|
expectErr: `flags [a p-a] must be set together, but [p-a] were not set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Flag and persistent flags being in multiple groups fail mutually exclusive group",
|
|
|
|
requiredTogether: []string{"a p-a", "p-a p-b"},
|
|
|
|
mutuallyExclusive: []string{"p-b p-c"},
|
|
|
|
args: []string{"--a=foo", "--p-a=foo", "--p-b=foo", "--p-c=foo"},
|
|
|
|
expectErr: `exactly one of the flags [p-b p-c] can be set, but [p-b p-c] were set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Flag and persistent flags pass required together and mutually exclusive groups",
|
|
|
|
requiredTogether: []string{"a p-a", "p-a p-b"},
|
|
|
|
mutuallyExclusive: []string{"p-b p-c"},
|
|
|
|
args: []string{"--a=foo", "--p-a=foo", "--p-b=foo"},
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Required together flag group validation fails on subcommand with inherited flag",
|
|
|
|
subRequiredTogether: []string{"p-a sub-a"},
|
|
|
|
args: []string{"subcmd", "--sub-a=foo"},
|
|
|
|
expectErr: `flags [p-a sub-a] must be set together, but [p-a] were not set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Required together flag group validation passes on subcommand with inherited flag",
|
|
|
|
subRequiredTogether: []string{"p-a sub-a"},
|
|
|
|
args: []string{"subcmd", "--p-a=foo", "--sub-a=foo"},
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Mutually exclusive flag group validation fails on subcommand with inherited flag",
|
|
|
|
subMutuallyExclusive: []string{"p-a sub-a"},
|
|
|
|
args: []string{"subcmd", "--p-a=foo", "--sub-a=foo"},
|
|
|
|
expectErr: `exactly one of the flags [p-a sub-a] can be set, but [p-a sub-a] were set`,
|
2022-04-17 21:04:57 +00:00
|
|
|
}, {
|
2022-08-11 13:35:14 +00:00
|
|
|
desc: "Mutually exclusive flag group validation passes on subcommand with inherited flag",
|
|
|
|
subMutuallyExclusive: []string{"p-a sub-a"},
|
|
|
|
args: []string{"subcmd", "--p-a=foo"},
|
|
|
|
}, {
|
|
|
|
desc: "Required together flag group validation is not applied on other command",
|
|
|
|
subRequiredTogether: []string{"p-a sub-a"},
|
|
|
|
args: []string{"--p-a=foo"},
|
2022-04-17 21:04:57 +00:00
|
|
|
},
|
|
|
|
}
|
2022-08-11 13:35:14 +00:00
|
|
|
|
2022-04-17 21:04:57 +00:00
|
|
|
for _, tc := range testcases {
|
|
|
|
t.Run(tc.desc, func(t *testing.T) {
|
2022-08-11 13:35:14 +00:00
|
|
|
cmd := getCmd()
|
|
|
|
subCmd := cmd.Commands()[0]
|
|
|
|
|
|
|
|
for _, group := range tc.requiredTogether {
|
|
|
|
cmd.MarkFlagsRequiredTogether(strings.Split(group, " ")...)
|
2022-04-17 21:04:57 +00:00
|
|
|
}
|
2022-08-11 13:35:14 +00:00
|
|
|
for _, group := range tc.mutuallyExclusive {
|
|
|
|
cmd.MarkFlagsMutuallyExclusive(strings.Split(group, " ")...)
|
2022-04-17 21:04:57 +00:00
|
|
|
}
|
2022-08-11 13:35:14 +00:00
|
|
|
for _, group := range tc.subRequiredTogether {
|
|
|
|
subCmd.MarkFlagsRequiredTogether(strings.Split(group, " ")...)
|
2022-04-17 21:04:57 +00:00
|
|
|
}
|
2022-08-11 13:35:14 +00:00
|
|
|
for _, group := range tc.subMutuallyExclusive {
|
|
|
|
subCmd.MarkFlagsMutuallyExclusive(strings.Split(group, " ")...)
|
2022-04-17 21:04:57 +00:00
|
|
|
}
|
2022-08-11 13:35:14 +00:00
|
|
|
|
|
|
|
cmd.SetArgs(tc.args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
|
2022-04-17 21:04:57 +00:00
|
|
|
switch {
|
|
|
|
case err == nil && len(tc.expectErr) > 0:
|
|
|
|
t.Errorf("Expected error %q but got nil", tc.expectErr)
|
|
|
|
case err != nil && err.Error() != tc.expectErr:
|
|
|
|
t.Errorf("Expected error %q but got %q", tc.expectErr, err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|