@@ -823,7 +823,7 @@ var defaultCommandTests = []struct {
823823 {"f" , "" , nil , true },
824824 {"" , "foobar" , nil , true },
825825 {"" , "" , nil , true },
826- {" " , "" , nil , true },
826+ {" " , "" , nil , false },
827827 {"bat" , "batbaz" , nil , true },
828828 {"nothing" , "batbaz" , nil , true },
829829 {"nothing" , "" , nil , false },
@@ -911,10 +911,10 @@ var defaultCommandSubCommandTests = []struct {
911911 {"" , "carly" , "foobar" , true },
912912 {"" , "jimmers" , "foobar" , false },
913913 {"" , "jimmers" , "" , false },
914- {" " , "jimmers" , "foobar" , true },
914+ {" " , "jimmers" , "foobar" , false },
915915 {"" , "" , "" , true },
916- {" " , "" , "" , true },
917- {" " , "j" , "" , true },
916+ {" " , "" , "" , false },
917+ {" " , "j" , "" , false },
918918 {"bat" , "" , "batbaz" , false },
919919 {"nothing" , "" , "batbaz" , false },
920920 {"nothing" , "" , "" , false },
@@ -977,10 +977,10 @@ var defaultCommandFlagTests = []struct {
977977 {"" , "--carly=derp" , "foobar" , true },
978978 {"" , "-j" , "foobar" , true },
979979 {"" , "-j" , "" , true },
980- {" " , "-j" , "foobar" , true },
980+ {" " , "-j" , "foobar" , false },
981981 {"" , "" , "" , true },
982- {" " , "" , "" , true },
983- {" " , "-j" , "" , true },
982+ {" " , "" , "" , false },
983+ {" " , "-j" , "" , false },
984984 {"bat" , "" , "batbaz" , false },
985985 {"nothing" , "" , "batbaz" , false },
986986 {"nothing" , "" , "" , false },
@@ -2185,6 +2185,54 @@ func TestCommand_OrderOfOperations(t *testing.T) {
21852185 })
21862186}
21872187
2188+ func TestFlagActionOrder (t * testing.T ) {
2189+ tests := []struct {
2190+ Name string
2191+ Args []string
2192+ }{
2193+ {
2194+ Name : "abc" ,
2195+ Args : []string {"" , "--a" , "--b" , "--c" },
2196+ },
2197+ {
2198+ Name : "bca" ,
2199+ Args : []string {"" , "--b" , "--c" , "--a" },
2200+ },
2201+ {
2202+ Name : "cba" ,
2203+ Args : []string {"" , "--c" , "--b" , "--a" },
2204+ },
2205+ }
2206+ for _ , tt := range tests {
2207+ t .Run (tt .Name , func (t * testing.T ) {
2208+ str := ""
2209+ action := func (name string ) func (context.Context , * Command , bool ) error {
2210+ return func (_ context.Context , _ * Command , _ bool ) error {
2211+ str += name
2212+ return nil
2213+ }
2214+ }
2215+ cmd := & Command {
2216+ Flags : []Flag {
2217+ & BoolFlag {Name : "a" , Action : action ("a" )},
2218+ & BoolFlag {Name : "b" , Action : action ("b" )},
2219+ & BoolFlag {Name : "c" , Action : action ("c" )},
2220+ },
2221+ Action : func (_ context.Context , cmd * Command ) error {
2222+ return nil
2223+ },
2224+ }
2225+
2226+ err := cmd .Run (buildTestContext (t ), tt .Args )
2227+ require .NoError (t , err )
2228+
2229+ if str != "abc" {
2230+ t .Errorf ("expected 'abc' got '%s'" , str )
2231+ }
2232+ })
2233+ }
2234+ }
2235+
21882236func TestCommand_Run_CommandWithSubcommandHasHelpTopic (t * testing.T ) {
21892237 subcommandHelpTopics := [][]string {
21902238 {"foo" , "--help" },
@@ -2801,12 +2849,12 @@ func TestFlagAction(t *testing.T) {
28012849 {
28022850 name : "flag_string_error" ,
28032851 args : []string {"app" , "--f_string=" },
2804- err : "flag needs an argument: --f_string= " ,
2852+ err : "empty string " ,
28052853 },
28062854 {
28072855 name : "flag_string_error2" ,
28082856 args : []string {"app" , "--f_string=" , "--f_bool" },
2809- err : "flag needs an argument: --f_string= " ,
2857+ err : "empty string " ,
28102858 },
28112859 {
28122860 name : "flag_string_slice" ,
@@ -3105,6 +3153,39 @@ func TestFlagAction(t *testing.T) {
31053153 }
31063154}
31073155
3156+ func TestLocalSliceFlagAccumulation (t * testing.T ) {
3157+ var got []string
3158+
3159+ app := & Command {
3160+ Name : "app" ,
3161+ Commands : []* Command {
3162+ {
3163+ Name : "sub" ,
3164+ Flags : []Flag {
3165+ & StringSliceFlag {
3166+ Name : "paths" ,
3167+ Aliases : []string {"p" },
3168+ Local : true ,
3169+ Destination : & got ,
3170+ },
3171+ },
3172+ Action : func (_ context.Context , cmd * Command ) error {
3173+ return nil
3174+ },
3175+ },
3176+ },
3177+ }
3178+
3179+ err := app .Run (context .Background (), []string {"app" , "sub" , "-p" , "/a" , "-p" , "/b" , "-p" , "/c" })
3180+ if err != nil {
3181+ t .Fatal (err )
3182+ }
3183+
3184+ if len (got ) != 3 {
3185+ t .Errorf ("expected 3 values, got %d: %v" , len (got ), got )
3186+ }
3187+ }
3188+
31083189func TestLocalFlagError (t * testing.T ) {
31093190 var topInt int64
31103191
@@ -5542,3 +5623,86 @@ func TestCommand_ExclusiveFlagsPersistent(t *testing.T) {
55425623 })
55435624 }
55445625}
5626+
5627+ func TestEmptyPositionalArgs (t * testing.T ) {
5628+ testCases := []struct {
5629+ Name string
5630+ Args []string
5631+ Expected []string
5632+ }{
5633+ {
5634+ Name : "empty arg between values" ,
5635+ Args : []string {"app" , "hello" , "" , "world" },
5636+ Expected : []string {"hello" , "" , "world" },
5637+ },
5638+ {
5639+ Name : "empty arg at start" ,
5640+ Args : []string {"app" , "" , "hello" },
5641+ Expected : []string {"" , "hello" },
5642+ },
5643+ {
5644+ Name : "whitespace-only arg" ,
5645+ Args : []string {"app" , "hello" , " " , "world" },
5646+ Expected : []string {"hello" , " " , "world" },
5647+ },
5648+ }
5649+
5650+ for _ , tc := range testCases {
5651+ t .Run (tc .Name , func (t * testing.T ) {
5652+ var args []string
5653+
5654+ cmd := & Command {
5655+ Action : func (_ context.Context , cmd * Command ) error {
5656+ args = cmd .Args ().Slice ()
5657+ return nil
5658+ },
5659+ }
5660+
5661+ err := cmd .Run (buildTestContext (t ), tc .Args )
5662+ assert .NoError (t , err )
5663+ assert .Equal (t , tc .Expected , args )
5664+ })
5665+ }
5666+ }
5667+
5668+ func TestFlagEqualsEmptyValue (t * testing.T ) {
5669+ t .Run ("--flag= sets empty string" , func (t * testing.T ) {
5670+ var val string
5671+
5672+ cmd := & Command {
5673+ Flags : []Flag {
5674+ & StringFlag {
5675+ Name : "name" ,
5676+ Destination : & val ,
5677+ },
5678+ },
5679+ }
5680+
5681+ err := cmd .Run (buildTestContext (t ), []string {"app" , "--name=" })
5682+ assert .NoError (t , err )
5683+ assert .Equal (t , "" , val )
5684+ })
5685+
5686+ t .Run ("--flag= does not consume next positional arg" , func (t * testing.T ) {
5687+ var val string
5688+ var args []string
5689+
5690+ cmd := & Command {
5691+ Flags : []Flag {
5692+ & StringFlag {
5693+ Name : "name" ,
5694+ Destination : & val ,
5695+ },
5696+ },
5697+ Action : func (_ context.Context , cmd * Command ) error {
5698+ args = cmd .Args ().Slice ()
5699+ return nil
5700+ },
5701+ }
5702+
5703+ err := cmd .Run (buildTestContext (t ), []string {"app" , "--name=" , "positional" })
5704+ assert .NoError (t , err )
5705+ assert .Equal (t , "" , val )
5706+ assert .Equal (t , []string {"positional" }, args )
5707+ })
5708+ }
0 commit comments