1package flags 2 3import ( 4 "fmt" 5 "testing" 6) 7 8func TestCommandInline(t *testing.T) { 9 var opts = struct { 10 Value bool `short:"v"` 11 12 Command struct { 13 G bool `short:"g"` 14 } `command:"cmd"` 15 }{} 16 17 p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g") 18 19 assertStringArray(t, ret, []string{}) 20 21 if p.Active == nil { 22 t.Errorf("Expected active command") 23 } 24 25 if !opts.Value { 26 t.Errorf("Expected Value to be true") 27 } 28 29 if !opts.Command.G { 30 t.Errorf("Expected Command.G to be true") 31 } 32 33 if p.Command.Find("cmd") != p.Active { 34 t.Errorf("Expected to find command `cmd' to be active") 35 } 36} 37 38func TestCommandInlineMulti(t *testing.T) { 39 var opts = struct { 40 Value bool `short:"v"` 41 42 C1 struct { 43 } `command:"c1"` 44 45 C2 struct { 46 G bool `short:"g"` 47 } `command:"c2"` 48 }{} 49 50 p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g") 51 52 assertStringArray(t, ret, []string{}) 53 54 if p.Active == nil { 55 t.Errorf("Expected active command") 56 } 57 58 if !opts.Value { 59 t.Errorf("Expected Value to be true") 60 } 61 62 if !opts.C2.G { 63 t.Errorf("Expected C2.G to be true") 64 } 65 66 if p.Command.Find("c1") == nil { 67 t.Errorf("Expected to find command `c1'") 68 } 69 70 if c2 := p.Command.Find("c2"); c2 == nil { 71 t.Errorf("Expected to find command `c2'") 72 } else if c2 != p.Active { 73 t.Errorf("Expected to find command `c2' to be active") 74 } 75} 76 77func TestCommandFlagOrder1(t *testing.T) { 78 var opts = struct { 79 Value bool `short:"v"` 80 81 Command struct { 82 G bool `short:"g"` 83 } `command:"cmd"` 84 }{} 85 86 assertParseFail(t, ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd") 87} 88 89func TestCommandFlagOrder2(t *testing.T) { 90 var opts = struct { 91 Value bool `short:"v"` 92 93 Command struct { 94 G bool `short:"g"` 95 } `command:"cmd"` 96 }{} 97 98 assertParseSuccess(t, &opts, "cmd", "-v", "-g") 99 100 if !opts.Value { 101 t.Errorf("Expected Value to be true") 102 } 103 104 if !opts.Command.G { 105 t.Errorf("Expected Command.G to be true") 106 } 107} 108 109func TestCommandFlagOrderSub(t *testing.T) { 110 var opts = struct { 111 Value bool `short:"v"` 112 113 Command struct { 114 G bool `short:"g"` 115 116 SubCommand struct { 117 B bool `short:"b"` 118 } `command:"sub"` 119 } `command:"cmd"` 120 }{} 121 122 assertParseSuccess(t, &opts, "cmd", "sub", "-v", "-g", "-b") 123 124 if !opts.Value { 125 t.Errorf("Expected Value to be true") 126 } 127 128 if !opts.Command.G { 129 t.Errorf("Expected Command.G to be true") 130 } 131 132 if !opts.Command.SubCommand.B { 133 t.Errorf("Expected Command.SubCommand.B to be true") 134 } 135} 136 137func TestCommandFlagOverride1(t *testing.T) { 138 var opts = struct { 139 Value bool `short:"v"` 140 141 Command struct { 142 Value bool `short:"v"` 143 } `command:"cmd"` 144 }{} 145 146 assertParseSuccess(t, &opts, "-v", "cmd") 147 148 if !opts.Value { 149 t.Errorf("Expected Value to be true") 150 } 151 152 if opts.Command.Value { 153 t.Errorf("Expected Command.Value to be false") 154 } 155} 156 157func TestCommandFlagOverride2(t *testing.T) { 158 var opts = struct { 159 Value bool `short:"v"` 160 161 Command struct { 162 Value bool `short:"v"` 163 } `command:"cmd"` 164 }{} 165 166 assertParseSuccess(t, &opts, "cmd", "-v") 167 168 if opts.Value { 169 t.Errorf("Expected Value to be false") 170 } 171 172 if !opts.Command.Value { 173 t.Errorf("Expected Command.Value to be true") 174 } 175} 176 177func TestCommandFlagOverrideSub(t *testing.T) { 178 var opts = struct { 179 Value bool `short:"v"` 180 181 Command struct { 182 Value bool `short:"v"` 183 184 SubCommand struct { 185 Value bool `short:"v"` 186 } `command:"sub"` 187 } `command:"cmd"` 188 }{} 189 190 assertParseSuccess(t, &opts, "cmd", "sub", "-v") 191 192 if opts.Value { 193 t.Errorf("Expected Value to be false") 194 } 195 196 if opts.Command.Value { 197 t.Errorf("Expected Command.Value to be false") 198 } 199 200 if !opts.Command.SubCommand.Value { 201 t.Errorf("Expected Command.Value to be true") 202 } 203} 204 205func TestCommandFlagOverrideSub2(t *testing.T) { 206 var opts = struct { 207 Value bool `short:"v"` 208 209 Command struct { 210 Value bool `short:"v"` 211 212 SubCommand struct { 213 G bool `short:"g"` 214 } `command:"sub"` 215 } `command:"cmd"` 216 }{} 217 218 assertParseSuccess(t, &opts, "cmd", "sub", "-v") 219 220 if opts.Value { 221 t.Errorf("Expected Value to be false") 222 } 223 224 if !opts.Command.Value { 225 t.Errorf("Expected Command.Value to be true") 226 } 227} 228 229func TestCommandEstimate(t *testing.T) { 230 var opts = struct { 231 Value bool `short:"v"` 232 233 Cmd1 struct { 234 } `command:"remove"` 235 236 Cmd2 struct { 237 } `command:"add"` 238 }{} 239 240 p := NewParser(&opts, None) 241 _, err := p.ParseArgs([]string{}) 242 243 assertError(t, err, ErrCommandRequired, "Please specify one command of: add or remove") 244} 245 246func TestCommandEstimate2(t *testing.T) { 247 var opts = struct { 248 Value bool `short:"v"` 249 250 Cmd1 struct { 251 } `command:"remove"` 252 253 Cmd2 struct { 254 } `command:"add"` 255 }{} 256 257 p := NewParser(&opts, None) 258 _, err := p.ParseArgs([]string{"rmive"}) 259 260 assertError(t, err, ErrUnknownCommand, "Unknown command `rmive', did you mean `remove'?") 261} 262 263type testCommand struct { 264 G bool `short:"g"` 265 Executed bool 266 EArgs []string 267} 268 269func (c *testCommand) Execute(args []string) error { 270 c.Executed = true 271 c.EArgs = args 272 273 return nil 274} 275 276func TestCommandExecute(t *testing.T) { 277 var opts = struct { 278 Value bool `short:"v"` 279 280 Command testCommand `command:"cmd"` 281 }{} 282 283 assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b") 284 285 if !opts.Value { 286 t.Errorf("Expected Value to be true") 287 } 288 289 if !opts.Command.Executed { 290 t.Errorf("Did not execute command") 291 } 292 293 if !opts.Command.G { 294 t.Errorf("Expected Command.C to be true") 295 } 296 297 assertStringArray(t, opts.Command.EArgs, []string{"a", "b"}) 298} 299 300func TestCommandClosest(t *testing.T) { 301 var opts = struct { 302 Value bool `short:"v"` 303 304 Cmd1 struct { 305 } `command:"remove"` 306 307 Cmd2 struct { 308 } `command:"add"` 309 }{} 310 311 args := assertParseFail(t, ErrUnknownCommand, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd") 312 313 assertStringArray(t, args, []string{"addd"}) 314} 315 316func TestCommandAdd(t *testing.T) { 317 var opts = struct { 318 Value bool `short:"v"` 319 }{} 320 321 var cmd = struct { 322 G bool `short:"g"` 323 }{} 324 325 p := NewParser(&opts, Default) 326 c, err := p.AddCommand("cmd", "", "", &cmd) 327 328 if err != nil { 329 t.Fatalf("Unexpected error: %v", err) 330 return 331 } 332 333 ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"}) 334 335 if err != nil { 336 t.Fatalf("Unexpected error: %v", err) 337 return 338 } 339 340 assertStringArray(t, ret, []string{"rest"}) 341 342 if !opts.Value { 343 t.Errorf("Expected Value to be true") 344 } 345 346 if !cmd.G { 347 t.Errorf("Expected Command.G to be true") 348 } 349 350 if p.Command.Find("cmd") != c { 351 t.Errorf("Expected to find command `cmd'") 352 } 353 354 if p.Commands()[0] != c { 355 t.Errorf("Expected command %#v, but got %#v", c, p.Commands()[0]) 356 } 357 358 if c.Options()[0].ShortName != 'g' { 359 t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName) 360 } 361} 362 363func TestCommandNestedInline(t *testing.T) { 364 var opts = struct { 365 Value bool `short:"v"` 366 367 Command struct { 368 G bool `short:"g"` 369 370 Nested struct { 371 N string `long:"n"` 372 } `command:"nested"` 373 } `command:"cmd"` 374 }{} 375 376 p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest") 377 378 assertStringArray(t, ret, []string{"rest"}) 379 380 if !opts.Value { 381 t.Errorf("Expected Value to be true") 382 } 383 384 if !opts.Command.G { 385 t.Errorf("Expected Command.G to be true") 386 } 387 388 assertString(t, opts.Command.Nested.N, "n") 389 390 if c := p.Command.Find("cmd"); c == nil { 391 t.Errorf("Expected to find command `cmd'") 392 } else { 393 if c != p.Active { 394 t.Errorf("Expected `cmd' to be the active parser command") 395 } 396 397 if nested := c.Find("nested"); nested == nil { 398 t.Errorf("Expected to find command `nested'") 399 } else if nested != c.Active { 400 t.Errorf("Expected to find command `nested' to be the active `cmd' command") 401 } 402 } 403} 404 405func TestRequiredOnCommand(t *testing.T) { 406 var opts = struct { 407 Value bool `short:"v" required:"true"` 408 409 Command struct { 410 G bool `short:"g"` 411 } `command:"cmd"` 412 }{} 413 414 assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts, "cmd") 415} 416 417func TestRequiredAllOnCommand(t *testing.T) { 418 var opts = struct { 419 Value bool `short:"v" required:"true"` 420 Missing bool `long:"missing" required:"true"` 421 422 Command struct { 423 G bool `short:"g"` 424 } `command:"cmd"` 425 }{} 426 427 assertParseFail(t, ErrRequired, fmt.Sprintf("the required flags `%smissing' and `%cv' were not specified", defaultLongOptDelimiter, defaultShortOptDelimiter), &opts, "cmd") 428} 429 430func TestDefaultOnCommand(t *testing.T) { 431 var opts = struct { 432 Command struct { 433 G string `short:"g" default:"value"` 434 } `command:"cmd"` 435 }{} 436 437 assertParseSuccess(t, &opts, "cmd") 438 439 if opts.Command.G != "value" { 440 t.Errorf("Expected G to be \"value\"") 441 } 442} 443 444func TestAfterNonCommand(t *testing.T) { 445 var opts = struct { 446 Value bool `short:"v"` 447 448 Cmd1 struct { 449 } `command:"remove"` 450 451 Cmd2 struct { 452 } `command:"add"` 453 }{} 454 455 assertParseFail(t, ErrUnknownCommand, "Unknown command `nocmd'. Please specify one command of: add or remove", &opts, "nocmd", "remove") 456} 457 458func TestSubcommandsOptional(t *testing.T) { 459 var opts = struct { 460 Value bool `short:"v"` 461 462 Cmd1 struct { 463 } `command:"remove"` 464 465 Cmd2 struct { 466 } `command:"add"` 467 }{} 468 469 p := NewParser(&opts, None) 470 p.SubcommandsOptional = true 471 472 _, err := p.ParseArgs([]string{"-v"}) 473 474 if err != nil { 475 t.Fatalf("Unexpected error: %v", err) 476 return 477 } 478 479 if !opts.Value { 480 t.Errorf("Expected Value to be true") 481 } 482} 483 484func TestSubcommandsOptionalAfterNonCommand(t *testing.T) { 485 var opts = struct { 486 Value bool `short:"v"` 487 488 Cmd1 struct { 489 } `command:"remove"` 490 491 Cmd2 struct { 492 } `command:"add"` 493 }{} 494 495 p := NewParser(&opts, None) 496 p.SubcommandsOptional = true 497 498 retargs, err := p.ParseArgs([]string{"nocmd", "remove"}) 499 500 if err != nil { 501 t.Fatalf("Unexpected error: %v", err) 502 return 503 } 504 505 assertStringArray(t, retargs, []string{"nocmd", "remove"}) 506} 507 508func TestCommandAlias(t *testing.T) { 509 var opts = struct { 510 Command struct { 511 G string `short:"g" default:"value"` 512 } `command:"cmd" alias:"cm"` 513 }{} 514 515 assertParseSuccess(t, &opts, "cm") 516 517 if opts.Command.G != "value" { 518 t.Errorf("Expected G to be \"value\"") 519 } 520} 521 522func TestSubCommandFindOptionByLongFlag(t *testing.T) { 523 var opts struct { 524 Testing bool `long:"testing" description:"Testing"` 525 } 526 527 var cmd struct { 528 Other bool `long:"other" description:"Other"` 529 } 530 531 p := NewParser(&opts, Default) 532 c, _ := p.AddCommand("command", "Short", "Long", &cmd) 533 534 opt := c.FindOptionByLongName("other") 535 536 if opt == nil { 537 t.Errorf("Expected option, but found none") 538 } 539 540 assertString(t, opt.LongName, "other") 541 542 opt = c.FindOptionByLongName("testing") 543 544 if opt == nil { 545 t.Errorf("Expected option, but found none") 546 } 547 548 assertString(t, opt.LongName, "testing") 549} 550 551func TestSubCommandFindOptionByShortFlag(t *testing.T) { 552 var opts struct { 553 Testing bool `short:"t" description:"Testing"` 554 } 555 556 var cmd struct { 557 Other bool `short:"o" description:"Other"` 558 } 559 560 p := NewParser(&opts, Default) 561 c, _ := p.AddCommand("command", "Short", "Long", &cmd) 562 563 opt := c.FindOptionByShortName('o') 564 565 if opt == nil { 566 t.Errorf("Expected option, but found none") 567 } 568 569 if opt.ShortName != 'o' { 570 t.Errorf("Expected 'o', but got %v", opt.ShortName) 571 } 572 573 opt = c.FindOptionByShortName('t') 574 575 if opt == nil { 576 t.Errorf("Expected option, but found none") 577 } 578 579 if opt.ShortName != 't' { 580 t.Errorf("Expected 'o', but got %v", opt.ShortName) 581 } 582} 583 584type fooCmd struct { 585 Flag bool `short:"f"` 586 args []string 587} 588 589func (foo *fooCmd) Execute(s []string) error { 590 foo.args = s 591 return nil 592} 593 594func TestCommandPassAfterNonOption(t *testing.T) { 595 var opts = struct { 596 Value bool `short:"v"` 597 Foo fooCmd `command:"foo"` 598 }{} 599 p := NewParser(&opts, PassAfterNonOption) 600 ret, err := p.ParseArgs([]string{"-v", "foo", "-f", "bar", "-v", "-g"}) 601 602 if err != nil { 603 t.Fatalf("Unexpected error: %v", err) 604 return 605 } 606 607 if !opts.Value { 608 t.Errorf("Expected Value to be true") 609 } 610 611 if !opts.Foo.Flag { 612 t.Errorf("Expected Foo.Flag to be true") 613 } 614 615 assertStringArray(t, ret, []string{"bar", "-v", "-g"}) 616 assertStringArray(t, opts.Foo.args, []string{"bar", "-v", "-g"}) 617} 618 619type barCmd struct { 620 fooCmd 621 Positional struct { 622 Args []string 623 } `positional-args:"yes"` 624} 625 626func TestCommandPassAfterNonOptionWithPositional(t *testing.T) { 627 var opts = struct { 628 Value bool `short:"v"` 629 Bar barCmd `command:"bar"` 630 }{} 631 p := NewParser(&opts, PassAfterNonOption) 632 ret, err := p.ParseArgs([]string{"-v", "bar", "-f", "baz", "-v", "-g"}) 633 634 if err != nil { 635 t.Fatalf("Unexpected error: %v", err) 636 return 637 } 638 639 if !opts.Value { 640 t.Errorf("Expected Value to be true") 641 } 642 643 if !opts.Bar.Flag { 644 t.Errorf("Expected Bar.Flag to be true") 645 } 646 647 assertStringArray(t, ret, []string{}) 648 assertStringArray(t, opts.Bar.args, []string{}) 649 assertStringArray(t, opts.Bar.Positional.Args, []string{"baz", "-v", "-g"}) 650} 651