1use clap::builder::ArgPredicate; 2use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command}; 3 4#[cfg(feature = "error-context")] 5use super::utils; 6 7#[test] 8fn flag_required() { 9 let result = Command::new("flag_required") 10 .arg(arg!(-f --flag "some flag").requires("color")) 11 .arg(arg!(-c --color "third flag")) 12 .try_get_matches_from(vec!["", "-f"]); 13 assert!(result.is_err()); 14 let err = result.err().unwrap(); 15 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 16} 17 18#[test] 19fn flag_required_2() { 20 let m = Command::new("flag_required") 21 .arg( 22 arg!(-f --flag "some flag") 23 .requires("color") 24 .action(ArgAction::SetTrue), 25 ) 26 .arg(arg!(-c --color "third flag").action(ArgAction::SetTrue)) 27 .try_get_matches_from(vec!["", "-f", "-c"]) 28 .unwrap(); 29 assert!(*m.get_one::<bool>("color").expect("defaulted by clap")); 30 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap")); 31} 32 33#[test] 34fn option_required() { 35 let result = Command::new("option_required") 36 .arg(arg!(f: -f <flag> "some flag").requires("c")) 37 .arg(arg!(c: -c <color> "third flag")) 38 .try_get_matches_from(vec!["", "-f", "val"]); 39 assert!(result.is_err()); 40 let err = result.err().unwrap(); 41 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 42} 43 44#[test] 45fn option_required_2() { 46 let m = Command::new("option_required") 47 .arg(arg!(f: -f <flag> "some flag").requires("c")) 48 .arg(arg!(c: -c <color> "third flag")) 49 .try_get_matches_from(vec!["", "-f", "val", "-c", "other_val"]) 50 .unwrap(); 51 assert!(m.contains_id("c")); 52 assert_eq!( 53 m.get_one::<String>("c").map(|v| v.as_str()).unwrap(), 54 "other_val" 55 ); 56 assert!(m.contains_id("f")); 57 assert_eq!(m.get_one::<String>("f").map(|v| v.as_str()).unwrap(), "val"); 58} 59 60#[test] 61fn positional_required() { 62 let result = Command::new("positional_required") 63 .arg(Arg::new("flag").index(1).required(true)) 64 .try_get_matches_from(vec![""]); 65 assert!(result.is_err()); 66 let err = result.err().unwrap(); 67 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 68} 69 70#[test] 71fn positional_required_2() { 72 let m = Command::new("positional_required") 73 .arg(Arg::new("flag").index(1).required(true)) 74 .try_get_matches_from(vec!["", "someval"]) 75 .unwrap(); 76 assert!(m.contains_id("flag")); 77 assert_eq!( 78 m.get_one::<String>("flag").map(|v| v.as_str()).unwrap(), 79 "someval" 80 ); 81} 82 83#[test] 84#[cfg(feature = "error-context")] 85fn positional_required_with_requires() { 86 static POSITIONAL_REQ: &str = "\ 87error: the following required arguments were not provided: 88 <flag> 89 <opt> 90 91Usage: clap-test <flag> <opt> [bar] 92 93For more information, try '--help'. 94"; 95 96 let cmd = Command::new("positional_required") 97 .arg(Arg::new("flag").required(true).requires("opt")) 98 .arg(Arg::new("opt")) 99 .arg(Arg::new("bar")); 100 101 utils::assert_output(cmd, "clap-test", POSITIONAL_REQ, true); 102} 103 104#[test] 105#[cfg(feature = "error-context")] 106fn positional_required_with_requires_if_no_value() { 107 static POSITIONAL_REQ_IF_NO_VAL: &str = "\ 108error: the following required arguments were not provided: 109 <flag> 110 111Usage: clap-test <flag> [opt] [bar] 112 113For more information, try '--help'. 114"; 115 116 let cmd = Command::new("positional_required") 117 .arg(Arg::new("flag").required(true).requires_if("val", "opt")) 118 .arg(Arg::new("opt")) 119 .arg(Arg::new("bar")); 120 121 utils::assert_output(cmd, "clap-test", POSITIONAL_REQ_IF_NO_VAL, true); 122} 123 124#[test] 125#[cfg(feature = "error-context")] 126fn positional_required_with_requires_if_value() { 127 static POSITIONAL_REQ_IF_VAL: &str = "\ 128error: the following required arguments were not provided: 129 <foo> 130 <opt> 131 132Usage: clap-test <flag> <foo> <opt> [bar] 133 134For more information, try '--help'. 135"; 136 137 let cmd = Command::new("positional_required") 138 .arg(Arg::new("flag").required(true).requires_if("val", "opt")) 139 .arg(Arg::new("foo").required(true)) 140 .arg(Arg::new("opt")) 141 .arg(Arg::new("bar")); 142 143 utils::assert_output(cmd, "clap-test val", POSITIONAL_REQ_IF_VAL, true); 144} 145 146#[test] 147fn group_required() { 148 let result = Command::new("group_required") 149 .arg(arg!(-f --flag "some flag")) 150 .group(ArgGroup::new("gr").required(true).arg("some").arg("other")) 151 .arg(arg!(--some "some arg")) 152 .arg(arg!(--other "other arg")) 153 .try_get_matches_from(vec!["", "-f"]); 154 assert!(result.is_err()); 155 let err = result.err().unwrap(); 156 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 157} 158 159#[test] 160fn group_required_2() { 161 let m = Command::new("group_required") 162 .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue)) 163 .group(ArgGroup::new("gr").required(true).arg("some").arg("other")) 164 .arg(arg!(--some "some arg").action(ArgAction::SetTrue)) 165 .arg(arg!(--other "other arg").action(ArgAction::SetTrue)) 166 .try_get_matches_from(vec!["", "-f", "--some"]) 167 .unwrap(); 168 assert!(*m.get_one::<bool>("some").expect("defaulted by clap")); 169 assert!(!*m.get_one::<bool>("other").expect("defaulted by clap")); 170 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap")); 171} 172 173#[test] 174fn group_required_3() { 175 let m = Command::new("group_required") 176 .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue)) 177 .group(ArgGroup::new("gr").required(true).arg("some").arg("other")) 178 .arg(arg!(--some "some arg").action(ArgAction::SetTrue)) 179 .arg(arg!(--other "other arg").action(ArgAction::SetTrue)) 180 .try_get_matches_from(vec!["", "-f", "--other"]) 181 .unwrap(); 182 assert!(!*m.get_one::<bool>("some").expect("defaulted by clap")); 183 assert!(*m.get_one::<bool>("other").expect("defaulted by clap")); 184 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap")); 185} 186 187#[test] 188fn arg_require_group() { 189 let result = Command::new("arg_require_group") 190 .arg(arg!(-f --flag "some flag").requires("gr")) 191 .group(ArgGroup::new("gr").arg("some").arg("other")) 192 .arg(arg!(--some "some arg")) 193 .arg(arg!(--other "other arg")) 194 .try_get_matches_from(vec!["", "-f"]); 195 assert!(result.is_err()); 196 let err = result.err().unwrap(); 197 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 198} 199 200#[test] 201fn arg_require_group_2() { 202 let res = Command::new("arg_require_group") 203 .arg( 204 arg!(-f --flag "some flag") 205 .requires("gr") 206 .action(ArgAction::SetTrue), 207 ) 208 .group(ArgGroup::new("gr").arg("some").arg("other")) 209 .arg(arg!(--some "some arg").action(ArgAction::SetTrue)) 210 .arg(arg!(--other "other arg").action(ArgAction::SetTrue)) 211 .try_get_matches_from(vec!["", "-f", "--some"]); 212 assert!(res.is_ok(), "{}", res.unwrap_err()); 213 let m = res.unwrap(); 214 assert!(*m.get_one::<bool>("some").expect("defaulted by clap")); 215 assert!(!*m.get_one::<bool>("other").expect("defaulted by clap")); 216 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap")); 217} 218 219#[test] 220fn arg_require_group_3() { 221 let res = Command::new("arg_require_group") 222 .arg( 223 arg!(-f --flag "some flag") 224 .requires("gr") 225 .action(ArgAction::SetTrue), 226 ) 227 .group(ArgGroup::new("gr").arg("some").arg("other")) 228 .arg(arg!(--some "some arg").action(ArgAction::SetTrue)) 229 .arg(arg!(--other "other arg").action(ArgAction::SetTrue)) 230 .try_get_matches_from(vec!["", "-f", "--other"]); 231 assert!(res.is_ok(), "{}", res.unwrap_err()); 232 let m = res.unwrap(); 233 assert!(!*m.get_one::<bool>("some").expect("defaulted by clap")); 234 assert!(*m.get_one::<bool>("other").expect("defaulted by clap")); 235 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap")); 236} 237 238// REQUIRED_UNLESS 239 240#[test] 241fn issue_753() { 242 let m = Command::new("test") 243 .arg(arg!( 244 -l --list "List available interfaces (and stop there)" 245 )) 246 .arg( 247 arg!( 248 -i --iface <INTERFACE> "Ethernet interface for fetching NTP packets" 249 ) 250 .required(false) 251 .required_unless_present("list"), 252 ) 253 .arg( 254 arg!(-f --file <TESTFILE> "Fetch NTP packets from pcap file") 255 .conflicts_with("iface") 256 .required_unless_present("list"), 257 ) 258 .arg(arg!(-s --server <SERVER_IP> "NTP server IP address").required_unless_present("list")) 259 .try_get_matches_from(vec!["test", "--list"]); 260 assert!(m.is_ok(), "{}", m.unwrap_err()); 261} 262 263#[test] 264fn required_unless_present() { 265 let res = Command::new("unlesstest") 266 .arg( 267 Arg::new("cfg") 268 .required_unless_present("dbg") 269 .action(ArgAction::Set) 270 .long("config"), 271 ) 272 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 273 .try_get_matches_from(vec!["unlesstest", "--debug"]); 274 275 assert!(res.is_ok(), "{}", res.unwrap_err()); 276 let m = res.unwrap(); 277 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap")); 278 assert!(!m.contains_id("cfg")); 279} 280 281#[test] 282fn required_unless_present_err() { 283 let res = Command::new("unlesstest") 284 .arg( 285 Arg::new("cfg") 286 .required_unless_present("dbg") 287 .action(ArgAction::Set) 288 .long("config"), 289 ) 290 .arg(Arg::new("dbg").long("debug")) 291 .try_get_matches_from(vec!["unlesstest"]); 292 293 assert!(res.is_err()); 294 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 295} 296 297#[test] 298fn required_unless_present_with_optional_value() { 299 let res = Command::new("unlesstest") 300 .arg(Arg::new("opt").long("opt").num_args(0..=1)) 301 .arg( 302 Arg::new("cfg") 303 .required_unless_present("dbg") 304 .action(ArgAction::Set) 305 .long("config"), 306 ) 307 .arg(Arg::new("dbg").long("debug")) 308 .try_get_matches_from(vec!["unlesstest", "--opt"]); 309 310 assert!(res.is_err()); 311 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 312} 313 314// REQUIRED_UNLESS_ALL 315 316#[test] 317fn required_unless_present_all() { 318 let res = Command::new("unlessall") 319 .arg( 320 Arg::new("cfg") 321 .required_unless_present_all(["dbg", "infile"]) 322 .action(ArgAction::Set) 323 .long("config"), 324 ) 325 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 326 .arg(Arg::new("infile").short('i').action(ArgAction::Set)) 327 .try_get_matches_from(vec!["unlessall", "--debug", "-i", "file"]); 328 329 assert!(res.is_ok(), "{}", res.unwrap_err()); 330 let m = res.unwrap(); 331 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap")); 332 assert!(m.contains_id("infile")); 333 assert!(!m.contains_id("cfg")); 334} 335 336#[test] 337fn required_unless_all_err() { 338 let res = Command::new("unlessall") 339 .arg( 340 Arg::new("cfg") 341 .required_unless_present_all(["dbg", "infile"]) 342 .action(ArgAction::Set) 343 .long("config"), 344 ) 345 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 346 .arg(Arg::new("infile").short('i').action(ArgAction::Set)) 347 .try_get_matches_from(vec!["unlessall", "--debug"]); 348 349 assert!(res.is_err()); 350 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 351} 352 353// REQUIRED_UNLESS_ONE 354 355#[test] 356fn required_unless_present_any() { 357 let res = Command::new("unlessone") 358 .arg( 359 Arg::new("cfg") 360 .required_unless_present_any(["dbg", "infile"]) 361 .action(ArgAction::Set) 362 .long("config"), 363 ) 364 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 365 .arg(Arg::new("infile").short('i').action(ArgAction::Set)) 366 .try_get_matches_from(vec!["unlessone", "--debug"]); 367 368 assert!(res.is_ok(), "{}", res.unwrap_err()); 369 let m = res.unwrap(); 370 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap")); 371 assert!(!m.contains_id("cfg")); 372} 373 374#[test] 375fn required_unless_any_2() { 376 // This tests that the required_unless_present_any works when the second arg in the array is used 377 // instead of the first. 378 let res = Command::new("unlessone") 379 .arg( 380 Arg::new("cfg") 381 .required_unless_present_any(["dbg", "infile"]) 382 .action(ArgAction::Set) 383 .long("config"), 384 ) 385 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 386 .arg(Arg::new("infile").short('i').action(ArgAction::Set)) 387 .try_get_matches_from(vec!["unlessone", "-i", "file"]); 388 389 assert!(res.is_ok(), "{}", res.unwrap_err()); 390 let m = res.unwrap(); 391 assert!(m.contains_id("infile")); 392 assert!(!m.contains_id("cfg")); 393} 394 395#[test] 396fn required_unless_any_works_with_short() { 397 // GitHub issue: https://github.com/clap-rs/clap/issues/1135 398 let res = Command::new("unlessone") 399 .arg( 400 Arg::new("a") 401 .conflicts_with("b") 402 .short('a') 403 .action(ArgAction::SetTrue), 404 ) 405 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue)) 406 .arg( 407 Arg::new("x") 408 .short('x') 409 .action(ArgAction::SetTrue) 410 .required_unless_present_any(["a", "b"]), 411 ) 412 .try_get_matches_from(vec!["unlessone", "-a"]); 413 414 assert!(res.is_ok(), "{}", res.unwrap_err()); 415} 416 417#[test] 418fn required_unless_any_works_with_short_err() { 419 let res = Command::new("unlessone") 420 .arg( 421 Arg::new("a") 422 .conflicts_with("b") 423 .short('a') 424 .action(ArgAction::SetTrue), 425 ) 426 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue)) 427 .arg( 428 Arg::new("x") 429 .short('x') 430 .action(ArgAction::SetTrue) 431 .required_unless_present_any(["a", "b"]), 432 ) 433 .try_get_matches_from(vec!["unlessone"]); 434 435 assert!(res.is_err()); 436} 437 438#[test] 439fn required_unless_any_works_without() { 440 let res = Command::new("unlessone") 441 .arg( 442 Arg::new("a") 443 .conflicts_with("b") 444 .short('a') 445 .action(ArgAction::SetTrue), 446 ) 447 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue)) 448 .arg(Arg::new("x").required_unless_present_any(["a", "b"])) 449 .try_get_matches_from(vec!["unlessone", "-a"]); 450 451 assert!(res.is_ok(), "{}", res.unwrap_err()); 452} 453 454#[test] 455fn required_unless_any_works_with_long() { 456 let res = Command::new("unlessone") 457 .arg( 458 Arg::new("a") 459 .conflicts_with("b") 460 .short('a') 461 .action(ArgAction::SetTrue), 462 ) 463 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue)) 464 .arg( 465 Arg::new("x") 466 .long("x_is_the_option") 467 .action(ArgAction::SetTrue) 468 .required_unless_present_any(["a", "b"]), 469 ) 470 .try_get_matches_from(vec!["unlessone", "-a"]); 471 472 assert!(res.is_ok(), "{}", res.unwrap_err()); 473} 474 475#[test] 476fn required_unless_any_1() { 477 let res = Command::new("unlessone") 478 .arg( 479 Arg::new("cfg") 480 .required_unless_present_any(["dbg", "infile"]) 481 .action(ArgAction::Set) 482 .long("config"), 483 ) 484 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 485 .arg(Arg::new("infile").short('i').action(ArgAction::Set)) 486 .try_get_matches_from(vec!["unlessone", "--debug"]); 487 488 assert!(res.is_ok(), "{}", res.unwrap_err()); 489 let m = res.unwrap(); 490 assert!(!m.contains_id("infile")); 491 assert!(!m.contains_id("cfg")); 492 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap")); 493} 494 495#[test] 496fn required_unless_any_err() { 497 let res = Command::new("unlessone") 498 .arg( 499 Arg::new("cfg") 500 .required_unless_present_any(["dbg", "infile"]) 501 .action(ArgAction::Set) 502 .long("config"), 503 ) 504 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue)) 505 .arg(Arg::new("infile").short('i').action(ArgAction::Set)) 506 .try_get_matches_from(vec!["unlessone"]); 507 508 assert!(res.is_err()); 509 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 510} 511 512#[test] 513#[cfg(feature = "error-context")] 514fn missing_required_output() { 515 static MISSING_REQ: &str = "\ 516error: the following required arguments were not provided: 517 --long-option-2 <option2> 518 <positional> 519 <positional2> 520 521Usage: clap-test --long-option-2 <option2> -F <positional> <positional2> [positional3]... 522 523For more information, try '--help'. 524"; 525 526 utils::assert_output(utils::complex_app(), "clap-test -F", MISSING_REQ, true); 527} 528 529// Conditional external requirements 530 531#[test] 532fn requires_if_present_val() { 533 let res = Command::new("unlessone") 534 .arg( 535 Arg::new("cfg") 536 .requires_if("my.cfg", "extra") 537 .action(ArgAction::Set) 538 .long("config"), 539 ) 540 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue)) 541 .try_get_matches_from(vec!["unlessone", "--config=my.cfg"]); 542 543 assert!(res.is_err()); 544 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 545} 546 547#[test] 548fn requires_if_present_mult() { 549 let res = Command::new("unlessone") 550 .arg( 551 Arg::new("cfg") 552 .requires_ifs([("my.cfg", "extra"), ("other.cfg", "other")]) 553 .action(ArgAction::Set) 554 .long("config"), 555 ) 556 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue)) 557 .arg(Arg::new("other").long("other").action(ArgAction::SetTrue)) 558 .try_get_matches_from(vec!["unlessone", "--config=other.cfg"]); 559 560 assert!(res.is_err()); 561 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 562} 563 564#[test] 565fn requires_if_present_mult_pass() { 566 let res = Command::new("unlessone") 567 .arg( 568 Arg::new("cfg") 569 .requires_ifs([("my.cfg", "extra"), ("other.cfg", "other")]) 570 .action(ArgAction::Set) 571 .long("config"), 572 ) 573 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue)) 574 .arg(Arg::new("other").long("other").action(ArgAction::SetTrue)) 575 .try_get_matches_from(vec!["unlessone", "--config=some.cfg"]); 576 577 assert!(res.is_ok(), "{}", res.unwrap_err()); 578} 579 580#[test] 581fn requires_if_present_val_no_present_pass() { 582 let res = Command::new("unlessone") 583 .arg( 584 Arg::new("cfg") 585 .requires_if("my.cfg", "extra") 586 .action(ArgAction::Set) 587 .long("config"), 588 ) 589 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue)) 590 .try_get_matches_from(vec!["unlessone"]); 591 592 assert!(res.is_ok(), "{}", res.unwrap_err()); 593} 594 595// Conditionally required 596 597#[test] 598fn required_if_val_present_pass() { 599 let res = Command::new("ri") 600 .arg( 601 Arg::new("cfg") 602 .required_if_eq("extra", "val") 603 .action(ArgAction::Set) 604 .long("config"), 605 ) 606 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 607 .try_get_matches_from(vec!["ri", "--extra", "val", "--config", "my.cfg"]); 608 609 assert!(res.is_ok(), "{}", res.unwrap_err()); 610} 611 612#[test] 613fn required_if_val_present_fail() { 614 let res = Command::new("ri") 615 .arg( 616 Arg::new("cfg") 617 .required_if_eq("extra", "val") 618 .action(ArgAction::Set) 619 .long("config"), 620 ) 621 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 622 .try_get_matches_from(vec!["ri", "--extra", "val"]); 623 624 assert!(res.is_err()); 625 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 626} 627 628#[test] 629fn required_if_val_present_ignore_case_pass() { 630 let res = Command::new("ri") 631 .arg( 632 Arg::new("cfg") 633 .required_if_eq("extra", "Val") 634 .action(ArgAction::Set) 635 .long("config"), 636 ) 637 .arg( 638 Arg::new("extra") 639 .action(ArgAction::Set) 640 .long("extra") 641 .ignore_case(true), 642 ) 643 .try_get_matches_from(vec!["ri", "--extra", "vaL", "--config", "my.cfg"]); 644 645 assert!(res.is_ok(), "{}", res.unwrap_err()); 646} 647 648#[test] 649fn required_if_val_present_ignore_case_fail() { 650 let res = Command::new("ri") 651 .arg( 652 Arg::new("cfg") 653 .required_if_eq("extra", "Val") 654 .action(ArgAction::Set) 655 .long("config"), 656 ) 657 .arg( 658 Arg::new("extra") 659 .action(ArgAction::Set) 660 .long("extra") 661 .ignore_case(true), 662 ) 663 .try_get_matches_from(vec!["ri", "--extra", "vaL"]); 664 665 assert!(res.is_err()); 666 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 667} 668 669#[test] 670fn required_if_all_values_present_pass() { 671 let res = Command::new("ri") 672 .arg( 673 Arg::new("cfg") 674 .required_if_eq_all([("extra", "val"), ("option", "spec")]) 675 .action(ArgAction::Set) 676 .long("config"), 677 ) 678 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 679 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 680 .try_get_matches_from(vec![ 681 "ri", "--extra", "val", "--option", "spec", "--config", "my.cfg", 682 ]); 683 684 assert!(res.is_ok(), "{}", res.unwrap_err()); 685} 686 687#[test] 688fn required_if_some_values_present_pass() { 689 let res = Command::new("ri") 690 .arg( 691 Arg::new("cfg") 692 .required_if_eq_all([("extra", "val"), ("option", "spec")]) 693 .action(ArgAction::Set) 694 .long("config"), 695 ) 696 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 697 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 698 .try_get_matches_from(vec!["ri", "--extra", "val"]); 699 700 assert!(res.is_ok(), "{}", res.unwrap_err()); 701} 702 703#[test] 704fn required_if_all_values_present_fail() { 705 let res = Command::new("ri") 706 .arg( 707 Arg::new("cfg") 708 .required_if_eq_all([("extra", "val"), ("option", "spec")]) 709 .action(ArgAction::Set) 710 .long("config"), 711 ) 712 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 713 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 714 .try_get_matches_from(vec!["ri", "--extra", "val", "--option", "spec"]); 715 716 assert!(res.is_err()); 717 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 718} 719 720#[test] 721fn required_if_any_all_values_present_pass() { 722 let res = Command::new("ri") 723 .arg( 724 Arg::new("cfg") 725 .required_if_eq_all([("extra", "val"), ("option", "spec")]) 726 .required_if_eq_any([("extra", "val2"), ("option", "spec2")]) 727 .action(ArgAction::Set) 728 .long("config"), 729 ) 730 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 731 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 732 .try_get_matches_from(vec![ 733 "ri", "--extra", "val", "--option", "spec", "--config", "my.cfg", 734 ]); 735 736 assert!(res.is_ok(), "{}", res.unwrap_err()); 737} 738 739#[test] 740fn required_if_any_all_values_present_fail() { 741 let res = Command::new("ri") 742 .arg( 743 Arg::new("cfg") 744 .required_if_eq_all([("extra", "val"), ("option", "spec")]) 745 .required_if_eq_any([("extra", "val2"), ("option", "spec2")]) 746 .action(ArgAction::Set) 747 .long("config"), 748 ) 749 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 750 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 751 .try_get_matches_from(vec!["ri", "--extra", "val", "--option", "spec"]); 752 753 assert!(res.is_err()); 754 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 755} 756 757#[test] 758#[cfg(feature = "error-context")] 759fn list_correct_required_args() { 760 static COND_REQ_IN_USAGE: &str = "\ 761error: the following required arguments were not provided: 762 --output <output> 763 764Usage: test --target <target> --input <input> --output <output> 765 766For more information, try '--help'. 767"; 768 769 let cmd = Command::new("Test cmd") 770 .version("1.0") 771 .author("F0x06") 772 .about("Arg test") 773 .arg( 774 Arg::new("target") 775 .action(ArgAction::Set) 776 .required(true) 777 .value_parser(["file", "stdout"]) 778 .long("target"), 779 ) 780 .arg( 781 Arg::new("input") 782 .action(ArgAction::Set) 783 .required(true) 784 .long("input"), 785 ) 786 .arg( 787 Arg::new("output") 788 .action(ArgAction::Set) 789 .required(true) 790 .long("output"), 791 ); 792 793 utils::assert_output( 794 cmd, 795 "test --input somepath --target file", 796 COND_REQ_IN_USAGE, 797 true, 798 ); 799} 800 801#[test] 802#[cfg(feature = "error-context")] 803fn required_if_val_present_fail_error_output() { 804 static COND_REQ_IN_USAGE: &str = "\ 805error: the following required arguments were not provided: 806 --output <output> 807 808Usage: test --target <target> --input <input> --output <output> 809 810For more information, try '--help'. 811"; 812 813 let cmd = Command::new("Test cmd") 814 .version("1.0") 815 .author("F0x06") 816 .about("Arg test") 817 .arg( 818 Arg::new("target") 819 .action(ArgAction::Set) 820 .required(true) 821 .value_parser(["file", "stdout"]) 822 .long("target"), 823 ) 824 .arg( 825 Arg::new("input") 826 .action(ArgAction::Set) 827 .required(true) 828 .long("input"), 829 ) 830 .arg( 831 Arg::new("output") 832 .action(ArgAction::Set) 833 .required_if_eq("target", "file") 834 .long("output"), 835 ); 836 837 utils::assert_output( 838 cmd, 839 "test --input somepath --target file", 840 COND_REQ_IN_USAGE, 841 true, 842 ); 843} 844 845#[test] 846fn required_if_wrong_val() { 847 let res = Command::new("ri") 848 .arg( 849 Arg::new("cfg") 850 .required_if_eq("extra", "val") 851 .action(ArgAction::Set) 852 .long("config"), 853 ) 854 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 855 .try_get_matches_from(vec!["ri", "--extra", "other"]); 856 857 assert!(res.is_ok(), "{}", res.unwrap_err()); 858} 859 860#[test] 861fn required_ifs_val_present_pass() { 862 let res = Command::new("ri") 863 .arg( 864 Arg::new("cfg") 865 .required_if_eq_any([("extra", "val"), ("option", "spec")]) 866 .action(ArgAction::Set) 867 .long("config"), 868 ) 869 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 870 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 871 .try_get_matches_from(vec!["ri", "--option", "spec", "--config", "my.cfg"]); 872 873 assert!(res.is_ok(), "{}", res.unwrap_err()); 874} 875 876#[test] 877fn required_ifs_val_present_fail() { 878 let res = Command::new("ri") 879 .arg( 880 Arg::new("cfg") 881 .required_if_eq_any([("extra", "val"), ("option", "spec")]) 882 .action(ArgAction::Set) 883 .long("config"), 884 ) 885 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 886 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 887 .try_get_matches_from(vec!["ri", "--option", "spec"]); 888 889 assert!(res.is_err()); 890 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 891} 892 893#[test] 894fn required_ifs_wrong_val() { 895 let res = Command::new("ri") 896 .arg( 897 Arg::new("cfg") 898 .required_if_eq_any([("extra", "val"), ("option", "spec")]) 899 .action(ArgAction::Set) 900 .long("config"), 901 ) 902 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 903 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 904 .try_get_matches_from(vec!["ri", "--option", "other"]); 905 906 assert!(res.is_ok(), "{}", res.unwrap_err()); 907} 908 909#[test] 910fn required_ifs_wrong_val_mult_fail() { 911 let res = Command::new("ri") 912 .arg( 913 Arg::new("cfg") 914 .required_if_eq_any([("extra", "val"), ("option", "spec")]) 915 .action(ArgAction::Set) 916 .long("config"), 917 ) 918 .arg(Arg::new("extra").action(ArgAction::Set).long("extra")) 919 .arg(Arg::new("option").action(ArgAction::Set).long("option")) 920 .try_get_matches_from(vec!["ri", "--extra", "other", "--option", "spec"]); 921 922 assert!(res.is_err()); 923 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument); 924} 925 926#[test] 927#[cfg(feature = "error-context")] 928fn require_eq() { 929 static REQUIRE_EQUALS: &str = "\ 930error: the following required arguments were not provided: 931 --opt=<FILE> 932 933Usage: clap-test --opt=<FILE> 934 935For more information, try '--help'. 936"; 937 938 let cmd = Command::new("clap-test").version("v1.4.8").arg( 939 Arg::new("opt") 940 .long("opt") 941 .short('o') 942 .required(true) 943 .require_equals(true) 944 .value_name("FILE") 945 .help("some"), 946 ); 947 utils::assert_output(cmd, "clap-test", REQUIRE_EQUALS, true); 948} 949 950#[test] 951#[cfg(feature = "error-context")] 952fn require_eq_filtered() { 953 static REQUIRE_EQUALS_FILTERED: &str = "\ 954error: the following required arguments were not provided: 955 --opt=<FILE> 956 957Usage: clap-test --opt=<FILE> --foo=<FILE> 958 959For more information, try '--help'. 960"; 961 962 let cmd = Command::new("clap-test") 963 .version("v1.4.8") 964 .arg( 965 Arg::new("opt") 966 .long("opt") 967 .short('o') 968 .required(true) 969 .require_equals(true) 970 .value_name("FILE") 971 .help("some"), 972 ) 973 .arg( 974 Arg::new("foo") 975 .long("foo") 976 .short('f') 977 .required(true) 978 .require_equals(true) 979 .value_name("FILE") 980 .help("some other arg"), 981 ); 982 utils::assert_output(cmd, "clap-test -f=blah", REQUIRE_EQUALS_FILTERED, true); 983} 984 985#[test] 986#[cfg(feature = "error-context")] 987fn require_eq_filtered_group() { 988 static REQUIRE_EQUALS_FILTERED_GROUP: &str = "\ 989error: the following required arguments were not provided: 990 --opt=<FILE> 991 992Usage: clap-test --opt=<FILE> --foo=<FILE> <--g1=<FILE>|--g2=<FILE>> 993 994For more information, try '--help'. 995"; 996 997 let cmd = Command::new("clap-test") 998 .version("v1.4.8") 999 .arg( 1000 Arg::new("opt") 1001 .long("opt") 1002 .short('o') 1003 .required(true) 1004 .require_equals(true) 1005 .value_name("FILE") 1006 .help("some"), 1007 ) 1008 .arg( 1009 Arg::new("foo") 1010 .long("foo") 1011 .short('f') 1012 .required(true) 1013 .require_equals(true) 1014 .value_name("FILE") 1015 .help("some other arg"), 1016 ) 1017 .arg( 1018 Arg::new("g1") 1019 .long("g1") 1020 .require_equals(true) 1021 .value_name("FILE"), 1022 ) 1023 .arg( 1024 Arg::new("g2") 1025 .long("g2") 1026 .require_equals(true) 1027 .value_name("FILE"), 1028 ) 1029 .group( 1030 ArgGroup::new("test_group") 1031 .args(["g1", "g2"]) 1032 .required(true), 1033 ); 1034 utils::assert_output( 1035 cmd, 1036 "clap-test -f=blah --g1=blah", 1037 REQUIRE_EQUALS_FILTERED_GROUP, 1038 true, 1039 ); 1040} 1041 1042fn issue_1158_app() -> Command { 1043 Command::new("example") 1044 .arg( 1045 arg!(-c --config <FILE> "Custom config file.") 1046 .required_unless_present("ID") 1047 .conflicts_with("ID"), 1048 ) 1049 .arg( 1050 arg!([ID] "ID") 1051 .required_unless_present("config") 1052 .conflicts_with("config") 1053 .requires_ifs([ 1054 (ArgPredicate::IsPresent, "x"), 1055 (ArgPredicate::IsPresent, "y"), 1056 (ArgPredicate::IsPresent, "z"), 1057 ]), 1058 ) 1059 .arg(arg!(x: -x <X> "X")) 1060 .arg(arg!(y: -y <Y> "Y")) 1061 .arg(arg!(z: -z <Z> "Z")) 1062} 1063 1064#[test] 1065#[cfg(feature = "error-context")] 1066fn multiple_required_unless_usage_printing() { 1067 static MULTIPLE_REQUIRED_UNLESS_USAGE: &str = "\ 1068error: the following required arguments were not provided: 1069 --a <a> 1070 --b <b> 1071 1072Usage: test --c <c> --a <a> --b <b> 1073 1074For more information, try '--help'. 1075"; 1076 let cmd = Command::new("test") 1077 .arg( 1078 Arg::new("a") 1079 .long("a") 1080 .action(ArgAction::Set) 1081 .required_unless_present("b") 1082 .conflicts_with("b"), 1083 ) 1084 .arg( 1085 Arg::new("b") 1086 .long("b") 1087 .action(ArgAction::Set) 1088 .required_unless_present("a") 1089 .conflicts_with("a"), 1090 ) 1091 .arg( 1092 Arg::new("c") 1093 .long("c") 1094 .action(ArgAction::Set) 1095 .required_unless_present("d") 1096 .conflicts_with("d"), 1097 ) 1098 .arg( 1099 Arg::new("d") 1100 .long("d") 1101 .action(ArgAction::Set) 1102 .required_unless_present("c") 1103 .conflicts_with("c"), 1104 ); 1105 utils::assert_output(cmd, "test --c asd", MULTIPLE_REQUIRED_UNLESS_USAGE, true); 1106} 1107 1108#[test] 1109#[cfg(feature = "error-context")] 1110fn issue_1158_conflicting_requirements() { 1111 static ISSUE_1158: &str = "\ 1112error: the following required arguments were not provided: 1113 -x <X> 1114 -y <Y> 1115 -z <Z> 1116 1117Usage: example -x <X> -y <Y> -z <Z> <ID> 1118 1119For more information, try '--help'. 1120"; 1121 1122 let cmd = issue_1158_app(); 1123 1124 utils::assert_output(cmd, "example id", ISSUE_1158, true); 1125} 1126 1127#[test] 1128fn issue_1158_conflicting_requirements_rev() { 1129 let res = issue_1158_app().try_get_matches_from(["", "--config", "some.conf"]); 1130 1131 assert!(res.is_ok(), "{}", res.unwrap_err()); 1132} 1133 1134#[test] 1135fn issue_1643_args_mutually_require_each_other() { 1136 use clap::*; 1137 1138 let cmd = Command::new("test") 1139 .arg( 1140 Arg::new("relation_id") 1141 .help("The relation id to get the data from") 1142 .long("relation-id") 1143 .short('r') 1144 .action(ArgAction::Set) 1145 .requires("remote_unit_name"), 1146 ) 1147 .arg( 1148 Arg::new("remote_unit_name") 1149 .help("The name of the remote unit to get data from") 1150 .long("remote-unit") 1151 .short('u') 1152 .action(ArgAction::Set) 1153 .requires("relation_id"), 1154 ); 1155 1156 cmd.try_get_matches_from(["test", "-u", "hello", "-r", "farewell"]) 1157 .unwrap(); 1158} 1159 1160#[test] 1161fn short_flag_require_equals_with_minvals_zero() { 1162 let m = Command::new("foo") 1163 .arg( 1164 Arg::new("check") 1165 .short('c') 1166 .num_args(0..) 1167 .require_equals(true), 1168 ) 1169 .arg(Arg::new("unique").short('u').action(ArgAction::SetTrue)) 1170 .try_get_matches_from(["foo", "-cu"]) 1171 .unwrap(); 1172 assert!(m.contains_id("check")); 1173 assert!(*m.get_one::<bool>("unique").expect("defaulted by clap")); 1174} 1175 1176#[test] 1177fn issue_2624() { 1178 let matches = Command::new("foo") 1179 .arg( 1180 Arg::new("check") 1181 .short('c') 1182 .long("check") 1183 .require_equals(true) 1184 .num_args(0..) 1185 .value_parser(["silent", "quiet", "diagnose-first"]), 1186 ) 1187 .arg( 1188 Arg::new("unique") 1189 .short('u') 1190 .long("unique") 1191 .action(ArgAction::SetTrue), 1192 ) 1193 .try_get_matches_from(["foo", "-cu"]) 1194 .unwrap(); 1195 assert!(matches.contains_id("check")); 1196 assert!(*matches 1197 .get_one::<bool>("unique") 1198 .expect("defaulted by clap")); 1199} 1200 1201#[test] 1202fn required_unless_all_with_any() { 1203 let cmd = Command::new("prog") 1204 .arg(Arg::new("foo").long("foo").action(ArgAction::SetTrue)) 1205 .arg(Arg::new("bar").long("bar").action(ArgAction::SetTrue)) 1206 .arg(Arg::new("baz").long("baz").action(ArgAction::SetTrue)) 1207 .arg( 1208 Arg::new("flag") 1209 .long("flag") 1210 .action(ArgAction::SetTrue) 1211 .required_unless_present_any(["foo"]) 1212 .required_unless_present_all(["bar", "baz"]), 1213 ); 1214 1215 let result = cmd.clone().try_get_matches_from(vec!["myprog"]); 1216 assert!(result.is_err(), "{:?}", result.unwrap()); 1217 1218 let result = cmd.clone().try_get_matches_from(vec!["myprog", "--foo"]); 1219 assert!(result.is_ok(), "{:?}", result.unwrap_err()); 1220 let matches = result.unwrap(); 1221 assert!(!*matches.get_one::<bool>("flag").expect("defaulted by clap")); 1222 1223 let result = cmd 1224 .clone() 1225 .try_get_matches_from(vec!["myprog", "--bar", "--baz"]); 1226 assert!(result.is_ok(), "{:?}", result.unwrap_err()); 1227 let matches = result.unwrap(); 1228 assert!(!*matches.get_one::<bool>("flag").expect("defaulted by clap")); 1229 1230 let result = cmd.try_get_matches_from(vec!["myprog", "--bar"]); 1231 assert!(result.is_err(), "{:?}", result.unwrap()); 1232} 1233 1234#[cfg(debug_assertions)] 1235#[test] 1236#[should_panic = "Command prog: Argument or group 'extra' specified in 'requires*' for 'config' does not exist"] 1237fn requires_invalid_arg() { 1238 let _ = Command::new("prog") 1239 .arg(Arg::new("config").requires("extra").long("config")) 1240 .try_get_matches_from(vec!["", "--config"]); 1241} 1242 1243#[cfg(debug_assertions)] 1244#[test] 1245#[should_panic = "Command prog: Argument or group 'extra' specified in 'requires*' for 'config' does not exist"] 1246fn requires_if_invalid_arg() { 1247 let _ = Command::new("prog") 1248 .arg( 1249 Arg::new("config") 1250 .requires_if("val", "extra") 1251 .long("config"), 1252 ) 1253 .try_get_matches_from(vec!["", "--config"]); 1254} 1255 1256#[cfg(debug_assertions)] 1257#[test] 1258#[should_panic = "Command prog: Argument or group 'extra' specified in 'required_if_eq*' for 'config' does not exist"] 1259fn required_if_invalid_arg() { 1260 let _ = Command::new("prog") 1261 .arg( 1262 Arg::new("config") 1263 .required_if_eq("extra", "val") 1264 .long("config"), 1265 ) 1266 .try_get_matches_from(vec!["", "--config"]); 1267} 1268 1269#[cfg(debug_assertions)] 1270#[test] 1271#[should_panic = "Command prog: Argument or group 'extra' specified in 'required_unless*' for 'config' does not exist"] 1272fn required_unless_invalid_arg() { 1273 let _ = Command::new("prog") 1274 .arg( 1275 Arg::new("config") 1276 .required_unless_present("extra") 1277 .long("config"), 1278 ) 1279 .try_get_matches_from(vec![""]); 1280} 1281 1282#[test] 1283fn requires_with_default_value() { 1284 let result = Command::new("prog") 1285 .arg( 1286 Arg::new("opt") 1287 .long("opt") 1288 .default_value("default") 1289 .requires("flag"), 1290 ) 1291 .arg(Arg::new("flag").long("flag").action(ArgAction::SetTrue)) 1292 .try_get_matches_from(vec!["myprog"]); 1293 1294 assert!( 1295 result.is_ok(), 1296 "requires should ignore default_value: {:?}", 1297 result.unwrap_err() 1298 ); 1299 let m = result.unwrap(); 1300 1301 assert_eq!( 1302 m.get_one::<String>("opt").map(|v| v.as_str()), 1303 Some("default") 1304 ); 1305 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap")); 1306} 1307 1308#[test] 1309fn requires_if_with_default_value() { 1310 let result = Command::new("prog") 1311 .arg( 1312 Arg::new("opt") 1313 .long("opt") 1314 .default_value("default") 1315 .requires_if("default", "flag"), 1316 ) 1317 .arg(Arg::new("flag").long("flag").action(ArgAction::SetTrue)) 1318 .try_get_matches_from(vec!["myprog"]); 1319 1320 assert!( 1321 result.is_ok(), 1322 "requires_if should ignore default_value: {:?}", 1323 result.unwrap_err() 1324 ); 1325 let m = result.unwrap(); 1326 1327 assert_eq!( 1328 m.get_one::<String>("opt").map(|v| v.as_str()), 1329 Some("default") 1330 ); 1331 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap")); 1332} 1333 1334#[test] 1335fn group_requires_with_default_value() { 1336 let result = Command::new("prog") 1337 .arg(Arg::new("opt").long("opt").default_value("default")) 1338 .arg(Arg::new("flag").long("flag").action(ArgAction::SetTrue)) 1339 .group(ArgGroup::new("one").arg("opt").requires("flag")) 1340 .try_get_matches_from(vec!["myprog"]); 1341 1342 assert!( 1343 result.is_ok(), 1344 "arg group requires should ignore default_value: {:?}", 1345 result.unwrap_err() 1346 ); 1347 let m = result.unwrap(); 1348 1349 assert_eq!( 1350 m.get_one::<String>("opt").map(|v| v.as_str()), 1351 Some("default") 1352 ); 1353 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap")); 1354} 1355 1356#[test] 1357fn required_if_eq_on_default_value() { 1358 let result = Command::new("prog") 1359 .arg(Arg::new("opt").long("opt").default_value("default")) 1360 .arg( 1361 Arg::new("flag") 1362 .long("flag") 1363 .action(ArgAction::SetTrue) 1364 .required_if_eq("opt", "default"), 1365 ) 1366 .try_get_matches_from(vec!["myprog"]); 1367 1368 assert!( 1369 result.is_ok(), 1370 "required_if_eq should ignore default_value: {:?}", 1371 result.unwrap_err() 1372 ); 1373 let m = result.unwrap(); 1374 1375 assert_eq!( 1376 m.get_one::<String>("opt").map(|v| v.as_str()), 1377 Some("default") 1378 ); 1379 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap")); 1380} 1381 1382#[test] 1383fn required_if_eq_all_on_default_value() { 1384 let result = Command::new("prog") 1385 .arg(Arg::new("opt").long("opt").default_value("default")) 1386 .arg( 1387 Arg::new("flag") 1388 .long("flag") 1389 .action(ArgAction::SetTrue) 1390 .required_if_eq_all([("opt", "default")]), 1391 ) 1392 .try_get_matches_from(vec!["myprog"]); 1393 1394 assert!( 1395 result.is_ok(), 1396 "required_if_eq_all should ignore default_value: {:?}", 1397 result.unwrap_err() 1398 ); 1399 let m = result.unwrap(); 1400 1401 assert_eq!( 1402 m.get_one::<String>("opt").map(|v| v.as_str()), 1403 Some("default") 1404 ); 1405 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap")); 1406} 1407 1408#[test] 1409fn required_unless_on_default_value() { 1410 let result = Command::new("prog") 1411 .arg(Arg::new("opt").long("opt").default_value("default")) 1412 .arg(Arg::new("flag").long("flag").required_unless_present("opt")) 1413 .try_get_matches_from(vec!["myprog"]); 1414 1415 assert!(result.is_err(), "{:?}", result.unwrap()); 1416} 1417 1418#[test] 1419fn required_unless_all_on_default_value() { 1420 let result = Command::new("prog") 1421 .arg(Arg::new("opt").long("opt").default_value("default")) 1422 .arg( 1423 Arg::new("flag") 1424 .long("flag") 1425 .required_unless_present_all(["opt"]), 1426 ) 1427 .try_get_matches_from(vec!["myprog"]); 1428 1429 assert!(result.is_err(), "{:?}", result.unwrap()); 1430} 1431 1432#[test] 1433#[cfg(feature = "error-context")] 1434fn required_error_doesnt_duplicate() { 1435 let cmd = Command::new("Clap-created-USAGE-string-bug") 1436 .arg(Arg::new("a").required(true)) 1437 .arg( 1438 Arg::new("b") 1439 .short('b') 1440 .action(ArgAction::Set) 1441 .conflicts_with("c"), 1442 ) 1443 .arg( 1444 Arg::new("c") 1445 .short('c') 1446 .action(ArgAction::Set) 1447 .conflicts_with("b"), 1448 ); 1449 const EXPECTED: &str = "\ 1450error: the argument '-b <b>' cannot be used with '-c <c>' 1451 1452Usage: clap-test -b <b> <a> 1453 1454For more information, try '--help'. 1455"; 1456 utils::assert_output(cmd, "clap-test aaa -b bbb -c ccc", EXPECTED, true); 1457} 1458 1459#[test] 1460#[cfg(feature = "error-context")] 1461fn required_require_with_group_shows_flag() { 1462 let cmd = Command::new("test") 1463 .arg(arg!(--"require-first").requires("first")) 1464 .arg(arg!(--first).group("either_or_both")) 1465 .arg(arg!(--second).group("either_or_both")) 1466 .group( 1467 ArgGroup::new("either_or_both") 1468 .multiple(true) 1469 .required(true), 1470 ); 1471 const EXPECTED: &str = "\ 1472error: the following required arguments were not provided: 1473 --first 1474 1475Usage: test --require-first <--first|--second> 1476 1477For more information, try '--help'. 1478"; 1479 utils::assert_output(cmd, "test --require-first --second", EXPECTED, true); 1480} 1481