git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/cobra/args_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 "fmt" 19 "strings" 20 "testing" 21 ) 22 23 func getCommand(args PositionalArgs, withValid bool) *Command { 24 c := &Command{ 25 Use: "c", 26 Args: args, 27 Run: emptyRun, 28 } 29 if withValid { 30 c.ValidArgs = []string{"one", "two", "three"} 31 } 32 return c 33 } 34 35 func expectSuccess(output string, err error, t *testing.T) { 36 if output != "" { 37 t.Errorf("Unexpected output: %v", output) 38 } 39 if err != nil { 40 t.Fatalf("Unexpected error: %v", err) 41 } 42 } 43 44 func validOnlyWithInvalidArgs(err error, t *testing.T) { 45 if err == nil { 46 t.Fatal("Expected an error") 47 } 48 got := err.Error() 49 expected := `invalid argument "a" for "c"` 50 if got != expected { 51 t.Errorf("Expected: %q, got: %q", expected, got) 52 } 53 } 54 55 func noArgsWithArgs(err error, t *testing.T, arg string) { 56 if err == nil { 57 t.Fatal("Expected an error") 58 } 59 got := err.Error() 60 expected := `unknown command "` + arg + `" for "c"` 61 if got != expected { 62 t.Errorf("Expected: %q, got: %q", expected, got) 63 } 64 } 65 66 func minimumNArgsWithLessArgs(err error, t *testing.T) { 67 if err == nil { 68 t.Fatal("Expected an error") 69 } 70 got := err.Error() 71 expected := "requires at least 2 arg(s), only received 1" 72 if got != expected { 73 t.Fatalf("Expected %q, got %q", expected, got) 74 } 75 } 76 77 func maximumNArgsWithMoreArgs(err error, t *testing.T) { 78 if err == nil { 79 t.Fatal("Expected an error") 80 } 81 got := err.Error() 82 expected := "accepts at most 2 arg(s), received 3" 83 if got != expected { 84 t.Fatalf("Expected %q, got %q", expected, got) 85 } 86 } 87 88 func exactArgsWithInvalidCount(err error, t *testing.T) { 89 if err == nil { 90 t.Fatal("Expected an error") 91 } 92 got := err.Error() 93 expected := "accepts 2 arg(s), received 3" 94 if got != expected { 95 t.Fatalf("Expected %q, got %q", expected, got) 96 } 97 } 98 99 func rangeArgsWithInvalidCount(err error, t *testing.T) { 100 if err == nil { 101 t.Fatal("Expected an error") 102 } 103 got := err.Error() 104 expected := "accepts between 2 and 4 arg(s), received 1" 105 if got != expected { 106 t.Fatalf("Expected %q, got %q", expected, got) 107 } 108 } 109 110 // NoArgs 111 112 func TestNoArgs(t *testing.T) { 113 c := getCommand(NoArgs, false) 114 output, err := executeCommand(c) 115 expectSuccess(output, err, t) 116 } 117 118 func TestNoArgs_WithArgs(t *testing.T) { 119 c := getCommand(NoArgs, false) 120 _, err := executeCommand(c, "one") 121 noArgsWithArgs(err, t, "one") 122 } 123 124 func TestNoArgs_WithValid_WithArgs(t *testing.T) { 125 c := getCommand(NoArgs, true) 126 _, err := executeCommand(c, "one") 127 noArgsWithArgs(err, t, "one") 128 } 129 130 func TestNoArgs_WithValid_WithInvalidArgs(t *testing.T) { 131 c := getCommand(NoArgs, true) 132 _, err := executeCommand(c, "a") 133 noArgsWithArgs(err, t, "a") 134 } 135 136 func TestNoArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 137 c := getCommand(MatchAll(OnlyValidArgs, NoArgs), true) 138 _, err := executeCommand(c, "a") 139 validOnlyWithInvalidArgs(err, t) 140 } 141 142 // OnlyValidArgs 143 144 func TestOnlyValidArgs(t *testing.T) { 145 c := getCommand(OnlyValidArgs, true) 146 output, err := executeCommand(c, "one", "two") 147 expectSuccess(output, err, t) 148 } 149 150 func TestOnlyValidArgs_WithInvalidArgs(t *testing.T) { 151 c := getCommand(OnlyValidArgs, true) 152 _, err := executeCommand(c, "a") 153 validOnlyWithInvalidArgs(err, t) 154 } 155 156 // ArbitraryArgs 157 158 func TestArbitraryArgs(t *testing.T) { 159 c := getCommand(ArbitraryArgs, false) 160 output, err := executeCommand(c, "a", "b") 161 expectSuccess(output, err, t) 162 } 163 164 func TestArbitraryArgs_WithValid(t *testing.T) { 165 c := getCommand(ArbitraryArgs, true) 166 output, err := executeCommand(c, "one", "two") 167 expectSuccess(output, err, t) 168 } 169 170 func TestArbitraryArgs_WithValid_WithInvalidArgs(t *testing.T) { 171 c := getCommand(ArbitraryArgs, true) 172 output, err := executeCommand(c, "a") 173 expectSuccess(output, err, t) 174 } 175 176 func TestArbitraryArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 177 c := getCommand(MatchAll(OnlyValidArgs, ArbitraryArgs), true) 178 _, err := executeCommand(c, "a") 179 validOnlyWithInvalidArgs(err, t) 180 } 181 182 // MinimumNArgs 183 184 func TestMinimumNArgs(t *testing.T) { 185 c := getCommand(MinimumNArgs(2), false) 186 output, err := executeCommand(c, "a", "b", "c") 187 expectSuccess(output, err, t) 188 } 189 190 func TestMinimumNArgs_WithValid(t *testing.T) { 191 c := getCommand(MinimumNArgs(2), true) 192 output, err := executeCommand(c, "one", "three") 193 expectSuccess(output, err, t) 194 } 195 196 func TestMinimumNArgs_WithValid__WithInvalidArgs(t *testing.T) { 197 c := getCommand(MinimumNArgs(2), true) 198 output, err := executeCommand(c, "a", "b") 199 expectSuccess(output, err, t) 200 } 201 202 func TestMinimumNArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 203 c := getCommand(MatchAll(OnlyValidArgs, MinimumNArgs(2)), true) 204 _, err := executeCommand(c, "a", "b") 205 validOnlyWithInvalidArgs(err, t) 206 } 207 208 func TestMinimumNArgs_WithLessArgs(t *testing.T) { 209 c := getCommand(MinimumNArgs(2), false) 210 _, err := executeCommand(c, "a") 211 minimumNArgsWithLessArgs(err, t) 212 } 213 214 func TestMinimumNArgs_WithLessArgs_WithValid(t *testing.T) { 215 c := getCommand(MinimumNArgs(2), true) 216 _, err := executeCommand(c, "one") 217 minimumNArgsWithLessArgs(err, t) 218 } 219 220 func TestMinimumNArgs_WithLessArgs_WithValid_WithInvalidArgs(t *testing.T) { 221 c := getCommand(MinimumNArgs(2), true) 222 _, err := executeCommand(c, "a") 223 minimumNArgsWithLessArgs(err, t) 224 } 225 226 func TestMinimumNArgs_WithLessArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 227 c := getCommand(MatchAll(OnlyValidArgs, MinimumNArgs(2)), true) 228 _, err := executeCommand(c, "a") 229 validOnlyWithInvalidArgs(err, t) 230 } 231 232 // MaximumNArgs 233 234 func TestMaximumNArgs(t *testing.T) { 235 c := getCommand(MaximumNArgs(3), false) 236 output, err := executeCommand(c, "a", "b") 237 expectSuccess(output, err, t) 238 } 239 240 func TestMaximumNArgs_WithValid(t *testing.T) { 241 c := getCommand(MaximumNArgs(2), true) 242 output, err := executeCommand(c, "one", "three") 243 expectSuccess(output, err, t) 244 } 245 246 func TestMaximumNArgs_WithValid_WithInvalidArgs(t *testing.T) { 247 c := getCommand(MaximumNArgs(2), true) 248 output, err := executeCommand(c, "a", "b") 249 expectSuccess(output, err, t) 250 } 251 252 func TestMaximumNArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 253 c := getCommand(MatchAll(OnlyValidArgs, MaximumNArgs(2)), true) 254 _, err := executeCommand(c, "a", "b") 255 validOnlyWithInvalidArgs(err, t) 256 } 257 258 func TestMaximumNArgs_WithMoreArgs(t *testing.T) { 259 c := getCommand(MaximumNArgs(2), false) 260 _, err := executeCommand(c, "a", "b", "c") 261 maximumNArgsWithMoreArgs(err, t) 262 } 263 264 func TestMaximumNArgs_WithMoreArgs_WithValid(t *testing.T) { 265 c := getCommand(MaximumNArgs(2), true) 266 _, err := executeCommand(c, "one", "three", "two") 267 maximumNArgsWithMoreArgs(err, t) 268 } 269 270 func TestMaximumNArgs_WithMoreArgs_WithValid_WithInvalidArgs(t *testing.T) { 271 c := getCommand(MaximumNArgs(2), true) 272 _, err := executeCommand(c, "a", "b", "c") 273 maximumNArgsWithMoreArgs(err, t) 274 } 275 276 func TestMaximumNArgs_WithMoreArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 277 c := getCommand(MatchAll(OnlyValidArgs, MaximumNArgs(2)), true) 278 _, err := executeCommand(c, "a", "b", "c") 279 validOnlyWithInvalidArgs(err, t) 280 } 281 282 // ExactArgs 283 284 func TestExactArgs(t *testing.T) { 285 c := getCommand(ExactArgs(3), false) 286 output, err := executeCommand(c, "a", "b", "c") 287 expectSuccess(output, err, t) 288 } 289 290 func TestExactArgs_WithValid(t *testing.T) { 291 c := getCommand(ExactArgs(3), true) 292 output, err := executeCommand(c, "three", "one", "two") 293 expectSuccess(output, err, t) 294 } 295 296 func TestExactArgs_WithValid_WithInvalidArgs(t *testing.T) { 297 c := getCommand(ExactArgs(3), true) 298 output, err := executeCommand(c, "three", "a", "two") 299 expectSuccess(output, err, t) 300 } 301 302 func TestExactArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 303 c := getCommand(MatchAll(OnlyValidArgs, ExactArgs(3)), true) 304 _, err := executeCommand(c, "three", "a", "two") 305 validOnlyWithInvalidArgs(err, t) 306 } 307 308 func TestExactArgs_WithInvalidCount(t *testing.T) { 309 c := getCommand(ExactArgs(2), false) 310 _, err := executeCommand(c, "a", "b", "c") 311 exactArgsWithInvalidCount(err, t) 312 } 313 314 func TestExactArgs_WithInvalidCount_WithValid(t *testing.T) { 315 c := getCommand(ExactArgs(2), true) 316 _, err := executeCommand(c, "three", "one", "two") 317 exactArgsWithInvalidCount(err, t) 318 } 319 320 func TestExactArgs_WithInvalidCount_WithValid_WithInvalidArgs(t *testing.T) { 321 c := getCommand(ExactArgs(2), true) 322 _, err := executeCommand(c, "three", "a", "two") 323 exactArgsWithInvalidCount(err, t) 324 } 325 326 func TestExactArgs_WithInvalidCount_WithValidOnly_WithInvalidArgs(t *testing.T) { 327 c := getCommand(MatchAll(OnlyValidArgs, ExactArgs(2)), true) 328 _, err := executeCommand(c, "three", "a", "two") 329 validOnlyWithInvalidArgs(err, t) 330 } 331 332 // RangeArgs 333 334 func TestRangeArgs(t *testing.T) { 335 c := getCommand(RangeArgs(2, 4), false) 336 output, err := executeCommand(c, "a", "b", "c") 337 expectSuccess(output, err, t) 338 } 339 340 func TestRangeArgs_WithValid(t *testing.T) { 341 c := getCommand(RangeArgs(2, 4), true) 342 output, err := executeCommand(c, "three", "one", "two") 343 expectSuccess(output, err, t) 344 } 345 346 func TestRangeArgs_WithValid_WithInvalidArgs(t *testing.T) { 347 c := getCommand(RangeArgs(2, 4), true) 348 output, err := executeCommand(c, "three", "a", "two") 349 expectSuccess(output, err, t) 350 } 351 352 func TestRangeArgs_WithValidOnly_WithInvalidArgs(t *testing.T) { 353 c := getCommand(MatchAll(OnlyValidArgs, RangeArgs(2, 4)), true) 354 _, err := executeCommand(c, "three", "a", "two") 355 validOnlyWithInvalidArgs(err, t) 356 } 357 358 func TestRangeArgs_WithInvalidCount(t *testing.T) { 359 c := getCommand(RangeArgs(2, 4), false) 360 _, err := executeCommand(c, "a") 361 rangeArgsWithInvalidCount(err, t) 362 } 363 364 func TestRangeArgs_WithInvalidCount_WithValid(t *testing.T) { 365 c := getCommand(RangeArgs(2, 4), true) 366 _, err := executeCommand(c, "two") 367 rangeArgsWithInvalidCount(err, t) 368 } 369 370 func TestRangeArgs_WithInvalidCount_WithValid_WithInvalidArgs(t *testing.T) { 371 c := getCommand(RangeArgs(2, 4), true) 372 _, err := executeCommand(c, "a") 373 rangeArgsWithInvalidCount(err, t) 374 } 375 376 func TestRangeArgs_WithInvalidCount_WithValidOnly_WithInvalidArgs(t *testing.T) { 377 c := getCommand(MatchAll(OnlyValidArgs, RangeArgs(2, 4)), true) 378 _, err := executeCommand(c, "a") 379 validOnlyWithInvalidArgs(err, t) 380 } 381 382 // Takes(No)Args 383 384 func TestRootTakesNoArgs(t *testing.T) { 385 rootCmd := &Command{Use: "root", Run: emptyRun} 386 childCmd := &Command{Use: "child", Run: emptyRun} 387 rootCmd.AddCommand(childCmd) 388 389 _, err := executeCommand(rootCmd, "illegal", "args") 390 if err == nil { 391 t.Fatal("Expected an error") 392 } 393 394 got := err.Error() 395 expected := `unknown command "illegal" for "root"` 396 if !strings.Contains(got, expected) { 397 t.Errorf("expected %q, got %q", expected, got) 398 } 399 } 400 401 func TestRootTakesArgs(t *testing.T) { 402 rootCmd := &Command{Use: "root", Args: ArbitraryArgs, Run: emptyRun} 403 childCmd := &Command{Use: "child", Run: emptyRun} 404 rootCmd.AddCommand(childCmd) 405 406 _, err := executeCommand(rootCmd, "legal", "args") 407 if err != nil { 408 t.Errorf("Unexpected error: %v", err) 409 } 410 } 411 412 func TestChildTakesNoArgs(t *testing.T) { 413 rootCmd := &Command{Use: "root", Run: emptyRun} 414 childCmd := &Command{Use: "child", Args: NoArgs, Run: emptyRun} 415 rootCmd.AddCommand(childCmd) 416 417 _, err := executeCommand(rootCmd, "child", "illegal", "args") 418 if err == nil { 419 t.Fatal("Expected an error") 420 } 421 422 got := err.Error() 423 expected := `unknown command "illegal" for "root child"` 424 if !strings.Contains(got, expected) { 425 t.Errorf("expected %q, got %q", expected, got) 426 } 427 } 428 429 func TestChildTakesArgs(t *testing.T) { 430 rootCmd := &Command{Use: "root", Run: emptyRun} 431 childCmd := &Command{Use: "child", Args: ArbitraryArgs, Run: emptyRun} 432 rootCmd.AddCommand(childCmd) 433 434 _, err := executeCommand(rootCmd, "child", "legal", "args") 435 if err != nil { 436 t.Fatalf("Unexpected error: %v", err) 437 } 438 } 439 440 func TestMatchAll(t *testing.T) { 441 // Somewhat contrived example check that ensures there are exactly 3 442 // arguments, and each argument is exactly 2 bytes long. 443 pargs := MatchAll( 444 ExactArgs(3), 445 func(cmd *Command, args []string) error { 446 for _, arg := range args { 447 if len([]byte(arg)) != 2 { 448 return fmt.Errorf("expected to be exactly 2 bytes long") 449 } 450 } 451 return nil 452 }, 453 ) 454 455 testCases := map[string]struct { 456 args []string 457 fail bool 458 }{ 459 "happy path": { 460 []string{"aa", "bb", "cc"}, 461 false, 462 }, 463 "incorrect number of args": { 464 []string{"aa", "bb", "cc", "dd"}, 465 true, 466 }, 467 "incorrect number of bytes in one arg": { 468 []string{"aa", "bb", "abc"}, 469 true, 470 }, 471 } 472 473 rootCmd := &Command{Use: "root", Args: pargs, Run: emptyRun} 474 475 for name, tc := range testCases { 476 t.Run(name, func(t *testing.T) { 477 _, err := executeCommand(rootCmd, tc.args...) 478 if err != nil && !tc.fail { 479 t.Errorf("unexpected: %v\n", err) 480 } 481 if err == nil && tc.fail { 482 t.Errorf("expected error") 483 } 484 }) 485 } 486 } 487 488 // DEPRECATED 489 490 func TestExactValidArgs(t *testing.T) { 491 c := getCommand(ExactValidArgs(3), true) 492 output, err := executeCommand(c, "three", "one", "two") 493 expectSuccess(output, err, t) 494 } 495 496 func TestExactValidArgs_WithInvalidCount(t *testing.T) { 497 c := getCommand(ExactValidArgs(2), false) 498 _, err := executeCommand(c, "three", "one", "two") 499 exactArgsWithInvalidCount(err, t) 500 } 501 502 func TestExactValidArgs_WithInvalidCount_WithInvalidArgs(t *testing.T) { 503 c := getCommand(ExactValidArgs(2), true) 504 _, err := executeCommand(c, "three", "a", "two") 505 exactArgsWithInvalidCount(err, t) 506 } 507 508 func TestExactValidArgs_WithInvalidArgs(t *testing.T) { 509 c := getCommand(ExactValidArgs(2), true) 510 _, err := executeCommand(c, "three", "a") 511 validOnlyWithInvalidArgs(err, t) 512 } 513 514 // This test make sure we keep backwards-compatibility with respect 515 // to the legacyArgs() function. 516 // It makes sure the root command accepts arguments if it does not have 517 // sub-commands. 518 func TestLegacyArgsRootAcceptsArgs(t *testing.T) { 519 rootCmd := &Command{Use: "root", Args: nil, Run: emptyRun} 520 521 _, err := executeCommand(rootCmd, "somearg") 522 if err != nil { 523 t.Fatalf("Unexpected error: %v", err) 524 } 525 } 526 527 // This test make sure we keep backwards-compatibility with respect 528 // to the legacyArgs() function. 529 // It makes sure a sub-command accepts arguments and further sub-commands 530 func TestLegacyArgsSubcmdAcceptsArgs(t *testing.T) { 531 rootCmd := &Command{Use: "root", Args: nil, Run: emptyRun} 532 childCmd := &Command{Use: "child", Args: nil, Run: emptyRun} 533 grandchildCmd := &Command{Use: "grandchild", Args: nil, Run: emptyRun} 534 rootCmd.AddCommand(childCmd) 535 childCmd.AddCommand(grandchildCmd) 536 537 _, err := executeCommand(rootCmd, "child", "somearg") 538 if err != nil { 539 t.Fatalf("Unexpected error: %v", err) 540 } 541 }