git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/cobra/flag_groups_test.go (about)

     1  // Copyright 2013-2022 The Cobra Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cobra
    16  
    17  import (
    18  	"strings"
    19  	"testing"
    20  )
    21  
    22  func TestValidateFlagGroups(t *testing.T) {
    23  	getCmd := func() *Command {
    24  		c := &Command{
    25  			Use: "testcmd",
    26  			Run: func(cmd *Command, args []string) {
    27  			}}
    28  		// Define lots of flags to utilize for testing.
    29  		for _, v := range []string{"a", "b", "c", "d"} {
    30  			c.Flags().String(v, "", "")
    31  		}
    32  		for _, v := range []string{"e", "f", "g"} {
    33  			c.PersistentFlags().String(v, "", "")
    34  		}
    35  		subC := &Command{
    36  			Use: "subcmd",
    37  			Run: func(cmd *Command, args []string) {
    38  			}}
    39  		subC.Flags().String("subonly", "", "")
    40  		c.AddCommand(subC)
    41  		return c
    42  	}
    43  
    44  	// Each test case uses a unique command from the function above.
    45  	testcases := []struct {
    46  		desc                      string
    47  		flagGroupsRequired        []string
    48  		flagGroupsExclusive       []string
    49  		subCmdFlagGroupsRequired  []string
    50  		subCmdFlagGroupsExclusive []string
    51  		args                      []string
    52  		expectErr                 string
    53  	}{
    54  		{
    55  			desc: "No flags no problem",
    56  		}, {
    57  			desc:                "No flags no problem even with conflicting groups",
    58  			flagGroupsRequired:  []string{"a b"},
    59  			flagGroupsExclusive: []string{"a b"},
    60  		}, {
    61  			desc:               "Required flag group not satisfied",
    62  			flagGroupsRequired: []string{"a b c"},
    63  			args:               []string{"--a=foo"},
    64  			expectErr:          "if any flags in the group [a b c] are set they must all be set; missing [b c]",
    65  		}, {
    66  			desc:                "Exclusive flag group not satisfied",
    67  			flagGroupsExclusive: []string{"a b c"},
    68  			args:                []string{"--a=foo", "--b=foo"},
    69  			expectErr:           "if any flags in the group [a b c] are set none of the others can be; [a b] were all set",
    70  		}, {
    71  			desc:               "Multiple required flag group not satisfied returns first error",
    72  			flagGroupsRequired: []string{"a b c", "a d"},
    73  			args:               []string{"--c=foo", "--d=foo"},
    74  			expectErr:          `if any flags in the group [a b c] are set they must all be set; missing [a b]`,
    75  		}, {
    76  			desc:                "Multiple exclusive flag group not satisfied returns first error",
    77  			flagGroupsExclusive: []string{"a b c", "a d"},
    78  			args:                []string{"--a=foo", "--c=foo", "--d=foo"},
    79  			expectErr:           `if any flags in the group [a b c] are set none of the others can be; [a c] were all set`,
    80  		}, {
    81  			desc:               "Validation of required groups occurs on groups in sorted order",
    82  			flagGroupsRequired: []string{"a d", "a b", "a c"},
    83  			args:               []string{"--a=foo"},
    84  			expectErr:          `if any flags in the group [a b] are set they must all be set; missing [b]`,
    85  		}, {
    86  			desc:                "Validation of exclusive groups occurs on groups in sorted order",
    87  			flagGroupsExclusive: []string{"a d", "a b", "a c"},
    88  			args:                []string{"--a=foo", "--b=foo", "--c=foo"},
    89  			expectErr:           `if any flags in the group [a b] are set none of the others can be; [a b] were all set`,
    90  		}, {
    91  			desc:                "Persistent flags utilize both features and can fail required groups",
    92  			flagGroupsRequired:  []string{"a e", "e f"},
    93  			flagGroupsExclusive: []string{"f g"},
    94  			args:                []string{"--a=foo", "--f=foo", "--g=foo"},
    95  			expectErr:           `if any flags in the group [a e] are set they must all be set; missing [e]`,
    96  		}, {
    97  			desc:                "Persistent flags utilize both features and can fail mutually exclusive groups",
    98  			flagGroupsRequired:  []string{"a e", "e f"},
    99  			flagGroupsExclusive: []string{"f g"},
   100  			args:                []string{"--a=foo", "--e=foo", "--f=foo", "--g=foo"},
   101  			expectErr:           `if any flags in the group [f g] are set none of the others can be; [f g] were all set`,
   102  		}, {
   103  			desc:                "Persistent flags utilize both features and can pass",
   104  			flagGroupsRequired:  []string{"a e", "e f"},
   105  			flagGroupsExclusive: []string{"f g"},
   106  			args:                []string{"--a=foo", "--e=foo", "--f=foo"},
   107  		}, {
   108  			desc:                     "Subcmds can use required groups using inherited flags",
   109  			subCmdFlagGroupsRequired: []string{"e subonly"},
   110  			args:                     []string{"subcmd", "--e=foo", "--subonly=foo"},
   111  		}, {
   112  			desc:                      "Subcmds can use exclusive groups using inherited flags",
   113  			subCmdFlagGroupsExclusive: []string{"e subonly"},
   114  			args:                      []string{"subcmd", "--e=foo", "--subonly=foo"},
   115  			expectErr:                 "if any flags in the group [e subonly] are set none of the others can be; [e subonly] were all set",
   116  		}, {
   117  			desc:                      "Subcmds can use exclusive groups using inherited flags and pass",
   118  			subCmdFlagGroupsExclusive: []string{"e subonly"},
   119  			args:                      []string{"subcmd", "--e=foo"},
   120  		}, {
   121  			desc:                     "Flag groups not applied if not found on invoked command",
   122  			subCmdFlagGroupsRequired: []string{"e subonly"},
   123  			args:                     []string{"--e=foo"},
   124  		},
   125  	}
   126  	for _, tc := range testcases {
   127  		t.Run(tc.desc, func(t *testing.T) {
   128  			c := getCmd()
   129  			sub := c.Commands()[0]
   130  			for _, flagGroup := range tc.flagGroupsRequired {
   131  				c.MarkFlagsRequiredTogether(strings.Split(flagGroup, " ")...)
   132  			}
   133  			for _, flagGroup := range tc.flagGroupsExclusive {
   134  				c.MarkFlagsMutuallyExclusive(strings.Split(flagGroup, " ")...)
   135  			}
   136  			for _, flagGroup := range tc.subCmdFlagGroupsRequired {
   137  				sub.MarkFlagsRequiredTogether(strings.Split(flagGroup, " ")...)
   138  			}
   139  			for _, flagGroup := range tc.subCmdFlagGroupsExclusive {
   140  				sub.MarkFlagsMutuallyExclusive(strings.Split(flagGroup, " ")...)
   141  			}
   142  			c.SetArgs(tc.args)
   143  			err := c.Execute()
   144  			switch {
   145  			case err == nil && len(tc.expectErr) > 0:
   146  				t.Errorf("Expected error %q but got nil", tc.expectErr)
   147  			case err != nil && err.Error() != tc.expectErr:
   148  				t.Errorf("Expected error %q but got %q", tc.expectErr, err)
   149  			}
   150  		})
   151  	}
   152  }