1// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>, 2// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and 3// Ana Hobden (@hoverbear) <operator@hoverbear.org> 4// 5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 8// option. This file may not be copied, modified, or distributed 9// except according to those terms. 10use clap::Parser; 11 12#[test] 13fn basic() { 14 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 15 enum ArgChoice { 16 Foo, 17 Bar, 18 } 19 20 #[derive(Parser, PartialEq, Debug)] 21 struct Opt { 22 #[arg(value_enum)] 23 arg: ArgChoice, 24 } 25 26 assert_eq!( 27 Opt { 28 arg: ArgChoice::Foo 29 }, 30 Opt::try_parse_from(["", "foo"]).unwrap() 31 ); 32 assert_eq!( 33 Opt { 34 arg: ArgChoice::Bar 35 }, 36 Opt::try_parse_from(["", "bar"]).unwrap() 37 ); 38 assert!(Opt::try_parse_from(["", "fOo"]).is_err()); 39} 40 41#[test] 42fn default_value() { 43 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 44 enum ArgChoice { 45 Foo, 46 Bar, 47 } 48 49 impl Default for ArgChoice { 50 fn default() -> Self { 51 Self::Bar 52 } 53 } 54 55 #[derive(Parser, PartialEq, Debug)] 56 struct Opt { 57 #[arg(value_enum, default_value_t)] 58 arg: ArgChoice, 59 } 60 61 assert_eq!( 62 Opt { 63 arg: ArgChoice::Foo 64 }, 65 Opt::try_parse_from(["", "foo"]).unwrap() 66 ); 67 assert_eq!( 68 Opt { 69 arg: ArgChoice::Bar 70 }, 71 Opt::try_parse_from(["", "bar"]).unwrap() 72 ); 73 assert_eq!( 74 Opt { 75 arg: ArgChoice::Bar 76 }, 77 Opt::try_parse_from([""]).unwrap() 78 ); 79} 80 81#[test] 82fn vec_for_default_values_t() { 83 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 84 enum ArgChoice { 85 Foo, 86 Bar, 87 } 88 89 #[derive(Parser, PartialEq, Debug)] 90 struct Opt { 91 #[arg(value_enum, default_values_t = vec![ArgChoice::Foo, ArgChoice::Bar])] 92 arg1: Vec<ArgChoice>, 93 94 #[arg( 95 long, 96 value_enum, 97 default_values_t = clap::ValueEnum::value_variants() 98 )] 99 arg2: Vec<ArgChoice>, 100 } 101 102 assert_eq!( 103 Opt { 104 arg1: vec![ArgChoice::Foo], 105 arg2: vec![ArgChoice::Foo, ArgChoice::Bar] 106 }, 107 Opt::try_parse_from(["", "foo"]).unwrap() 108 ); 109 assert_eq!( 110 Opt { 111 arg1: vec![ArgChoice::Bar], 112 arg2: vec![ArgChoice::Foo, ArgChoice::Bar] 113 }, 114 Opt::try_parse_from(["", "bar"]).unwrap() 115 ); 116 assert_eq!( 117 Opt { 118 arg1: vec![ArgChoice::Foo, ArgChoice::Bar], 119 arg2: vec![ArgChoice::Foo, ArgChoice::Bar] 120 }, 121 Opt::try_parse_from([""]).unwrap() 122 ); 123 assert_eq!( 124 Opt { 125 arg1: vec![ArgChoice::Foo, ArgChoice::Bar], 126 arg2: vec![ArgChoice::Foo] 127 }, 128 Opt::try_parse_from(["", "--arg2", "foo"]).unwrap() 129 ); 130} 131 132#[test] 133fn vec_for_default_values_os_t() { 134 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 135 enum ArgChoice { 136 Foo, 137 Bar, 138 } 139 140 #[derive(Parser, PartialEq, Debug)] 141 struct Opt { 142 #[arg(value_enum, default_values_os_t = vec![ArgChoice::Foo, ArgChoice::Bar])] 143 arg: Vec<ArgChoice>, 144 145 #[arg( 146 long, 147 value_enum, 148 default_values_os_t = clap::ValueEnum::value_variants() 149 )] 150 arg2: Vec<ArgChoice>, 151 } 152 153 assert_eq!( 154 Opt { 155 arg: vec![ArgChoice::Foo], 156 arg2: vec![ArgChoice::Foo, ArgChoice::Bar] 157 }, 158 Opt::try_parse_from(["", "foo"]).unwrap() 159 ); 160 assert_eq!( 161 Opt { 162 arg: vec![ArgChoice::Bar], 163 arg2: vec![ArgChoice::Foo, ArgChoice::Bar] 164 }, 165 Opt::try_parse_from(["", "bar"]).unwrap() 166 ); 167 assert_eq!( 168 Opt { 169 arg: vec![ArgChoice::Foo, ArgChoice::Bar], 170 arg2: vec![ArgChoice::Foo, ArgChoice::Bar] 171 }, 172 Opt::try_parse_from([""]).unwrap() 173 ); 174 assert_eq!( 175 Opt { 176 arg: vec![ArgChoice::Foo, ArgChoice::Bar], 177 arg2: vec![ArgChoice::Foo] 178 }, 179 Opt::try_parse_from(["", "--arg2", "foo"]).unwrap() 180 ); 181} 182 183#[test] 184fn multi_word_is_renamed_kebab() { 185 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 186 #[allow(non_camel_case_types)] 187 enum ArgChoice { 188 FooBar, 189 BAR_BAZ, 190 } 191 192 #[derive(Parser, PartialEq, Debug)] 193 struct Opt { 194 #[arg(value_enum)] 195 arg: ArgChoice, 196 } 197 198 assert_eq!( 199 Opt { 200 arg: ArgChoice::FooBar 201 }, 202 Opt::try_parse_from(["", "foo-bar"]).unwrap() 203 ); 204 assert_eq!( 205 Opt { 206 arg: ArgChoice::BAR_BAZ 207 }, 208 Opt::try_parse_from(["", "bar-baz"]).unwrap() 209 ); 210 assert!(Opt::try_parse_from(["", "FooBar"]).is_err()); 211} 212 213#[test] 214fn variant_with_defined_casing() { 215 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 216 enum ArgChoice { 217 #[value(rename_all = "screaming_snake")] 218 FooBar, 219 } 220 221 #[derive(Parser, PartialEq, Debug)] 222 struct Opt { 223 #[arg(value_enum)] 224 arg: ArgChoice, 225 } 226 227 assert_eq!( 228 Opt { 229 arg: ArgChoice::FooBar 230 }, 231 Opt::try_parse_from(["", "FOO_BAR"]).unwrap() 232 ); 233 assert!(Opt::try_parse_from(["", "FooBar"]).is_err()); 234} 235 236#[test] 237fn casing_is_propagated_from_parent() { 238 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 239 #[value(rename_all = "screaming_snake")] 240 enum ArgChoice { 241 FooBar, 242 } 243 244 #[derive(Parser, PartialEq, Debug)] 245 struct Opt { 246 #[arg(value_enum)] 247 arg: ArgChoice, 248 } 249 250 assert_eq!( 251 Opt { 252 arg: ArgChoice::FooBar 253 }, 254 Opt::try_parse_from(["", "FOO_BAR"]).unwrap() 255 ); 256 assert!(Opt::try_parse_from(["", "FooBar"]).is_err()); 257} 258 259#[test] 260fn casing_propagation_is_overridden() { 261 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 262 #[value(rename_all = "screaming_snake")] 263 enum ArgChoice { 264 #[value(rename_all = "camel")] 265 FooBar, 266 } 267 268 #[derive(Parser, PartialEq, Debug)] 269 struct Opt { 270 #[arg(value_enum)] 271 arg: ArgChoice, 272 } 273 274 assert_eq!( 275 Opt { 276 arg: ArgChoice::FooBar 277 }, 278 Opt::try_parse_from(["", "fooBar"]).unwrap() 279 ); 280 assert!(Opt::try_parse_from(["", "FooBar"]).is_err()); 281 assert!(Opt::try_parse_from(["", "FOO_BAR"]).is_err()); 282} 283 284#[test] 285fn ignore_case() { 286 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 287 enum ArgChoice { 288 Foo, 289 } 290 291 #[derive(Parser, PartialEq, Debug)] 292 struct Opt { 293 #[arg(value_enum, ignore_case(true))] 294 arg: ArgChoice, 295 } 296 297 assert_eq!( 298 Opt { 299 arg: ArgChoice::Foo 300 }, 301 Opt::try_parse_from(["", "foo"]).unwrap() 302 ); 303 assert_eq!( 304 Opt { 305 arg: ArgChoice::Foo 306 }, 307 Opt::try_parse_from(["", "fOo"]).unwrap() 308 ); 309} 310 311#[test] 312fn ignore_case_set_to_false() { 313 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 314 enum ArgChoice { 315 Foo, 316 } 317 318 #[derive(Parser, PartialEq, Debug)] 319 struct Opt { 320 #[arg(value_enum, ignore_case(false))] 321 arg: ArgChoice, 322 } 323 324 assert_eq!( 325 Opt { 326 arg: ArgChoice::Foo 327 }, 328 Opt::try_parse_from(["", "foo"]).unwrap() 329 ); 330 assert!(Opt::try_parse_from(["", "fOo"]).is_err()); 331} 332 333#[test] 334fn alias() { 335 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 336 enum ArgChoice { 337 #[value(alias = "TOTP")] 338 Totp, 339 } 340 341 #[derive(Parser, PartialEq, Debug)] 342 struct Opt { 343 #[arg(value_enum, ignore_case(false))] 344 arg: ArgChoice, 345 } 346 347 assert_eq!( 348 Opt { 349 arg: ArgChoice::Totp 350 }, 351 Opt::try_parse_from(["", "totp"]).unwrap() 352 ); 353 assert_eq!( 354 Opt { 355 arg: ArgChoice::Totp 356 }, 357 Opt::try_parse_from(["", "TOTP"]).unwrap() 358 ); 359} 360 361#[test] 362fn multiple_alias() { 363 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 364 enum ArgChoice { 365 #[value(alias = "TOTP", alias = "t")] 366 Totp, 367 } 368 369 #[derive(Parser, PartialEq, Debug)] 370 struct Opt { 371 #[arg(value_enum, ignore_case(false))] 372 arg: ArgChoice, 373 } 374 375 assert_eq!( 376 Opt { 377 arg: ArgChoice::Totp 378 }, 379 Opt::try_parse_from(["", "totp"]).unwrap() 380 ); 381 assert_eq!( 382 Opt { 383 arg: ArgChoice::Totp 384 }, 385 Opt::try_parse_from(["", "TOTP"]).unwrap() 386 ); 387 assert_eq!( 388 Opt { 389 arg: ArgChoice::Totp 390 }, 391 Opt::try_parse_from(["", "t"]).unwrap() 392 ); 393} 394 395#[test] 396fn skip_variant() { 397 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 398 #[allow(dead_code)] // silence warning about `Baz` being unused 399 enum ArgChoice { 400 Foo, 401 Bar, 402 #[value(skip)] 403 Baz, 404 } 405 406 assert_eq!( 407 <ArgChoice as clap::ValueEnum>::value_variants() 408 .iter() 409 .map(clap::ValueEnum::to_possible_value) 410 .map(Option::unwrap) 411 .collect::<Vec<_>>(), 412 vec![ 413 clap::builder::PossibleValue::new("foo"), 414 clap::builder::PossibleValue::new("bar") 415 ] 416 ); 417 418 { 419 use clap::ValueEnum; 420 assert!(ArgChoice::from_str("foo", true).is_ok()); 421 assert!(ArgChoice::from_str("bar", true).is_ok()); 422 assert!(ArgChoice::from_str("baz", true).is_err()); 423 } 424} 425 426#[test] 427fn skip_non_unit_variant() { 428 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 429 #[allow(dead_code)] // silence warning about `Baz` being unused 430 enum ArgChoice { 431 Foo, 432 Bar, 433 #[value(skip)] 434 Baz(usize), 435 } 436 437 assert_eq!( 438 <ArgChoice as clap::ValueEnum>::value_variants() 439 .iter() 440 .map(clap::ValueEnum::to_possible_value) 441 .map(Option::unwrap) 442 .collect::<Vec<_>>(), 443 vec![ 444 clap::builder::PossibleValue::new("foo"), 445 clap::builder::PossibleValue::new("bar") 446 ] 447 ); 448 449 { 450 use clap::ValueEnum; 451 assert!(ArgChoice::from_str("foo", true).is_ok()); 452 assert!(ArgChoice::from_str("bar", true).is_ok()); 453 assert!(ArgChoice::from_str("baz", true).is_err()); 454 } 455} 456 457#[test] 458fn from_str_invalid() { 459 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 460 enum ArgChoice { 461 Foo, 462 } 463 464 { 465 use clap::ValueEnum; 466 assert!(ArgChoice::from_str("bar", true).is_err()); 467 } 468} 469 470#[test] 471fn option_type() { 472 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 473 enum ArgChoice { 474 Foo, 475 Bar, 476 } 477 478 #[derive(Parser, PartialEq, Debug)] 479 struct Opt { 480 #[arg(value_enum)] 481 arg: Option<ArgChoice>, 482 } 483 484 assert_eq!(Opt { arg: None }, Opt::try_parse_from([""]).unwrap()); 485 assert_eq!( 486 Opt { 487 arg: Some(ArgChoice::Foo) 488 }, 489 Opt::try_parse_from(["", "foo"]).unwrap() 490 ); 491 assert_eq!( 492 Opt { 493 arg: Some(ArgChoice::Bar) 494 }, 495 Opt::try_parse_from(["", "bar"]).unwrap() 496 ); 497 assert!(Opt::try_parse_from(["", "fOo"]).is_err()); 498} 499 500#[test] 501fn option_option_type() { 502 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 503 enum ArgChoice { 504 Foo, 505 Bar, 506 } 507 508 #[derive(Parser, PartialEq, Debug)] 509 struct Opt { 510 #[arg(value_enum, long)] 511 arg: Option<Option<ArgChoice>>, 512 } 513 514 assert_eq!(Opt { arg: None }, Opt::try_parse_from([""]).unwrap()); 515 assert_eq!( 516 Opt { arg: Some(None) }, 517 Opt::try_parse_from(["", "--arg"]).unwrap() 518 ); 519 assert_eq!( 520 Opt { 521 arg: Some(Some(ArgChoice::Foo)) 522 }, 523 Opt::try_parse_from(["", "--arg", "foo"]).unwrap() 524 ); 525 assert_eq!( 526 Opt { 527 arg: Some(Some(ArgChoice::Bar)) 528 }, 529 Opt::try_parse_from(["", "--arg", "bar"]).unwrap() 530 ); 531 assert!(Opt::try_parse_from(["", "--arg", "fOo"]).is_err()); 532} 533 534#[test] 535fn vec_type() { 536 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 537 enum ArgChoice { 538 Foo, 539 Bar, 540 } 541 542 #[derive(Parser, PartialEq, Debug)] 543 struct Opt { 544 #[arg(value_enum, short, long)] 545 arg: Vec<ArgChoice>, 546 } 547 548 assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from([""]).unwrap()); 549 assert_eq!( 550 Opt { 551 arg: vec![ArgChoice::Foo] 552 }, 553 Opt::try_parse_from(["", "-a", "foo"]).unwrap() 554 ); 555 assert_eq!( 556 Opt { 557 arg: vec![ArgChoice::Foo, ArgChoice::Bar] 558 }, 559 Opt::try_parse_from(["", "-a", "foo", "-a", "bar"]).unwrap() 560 ); 561 assert!(Opt::try_parse_from(["", "-a", "fOo"]).is_err()); 562} 563 564#[test] 565fn option_vec_type() { 566 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 567 enum ArgChoice { 568 Foo, 569 Bar, 570 } 571 572 #[derive(Parser, PartialEq, Debug)] 573 struct Opt { 574 #[arg(value_enum, short, long)] 575 arg: Option<Vec<ArgChoice>>, 576 } 577 578 assert_eq!(Opt { arg: None }, Opt::try_parse_from([""]).unwrap()); 579 assert_eq!( 580 Opt { 581 arg: Some(vec![ArgChoice::Foo]) 582 }, 583 Opt::try_parse_from(["", "-a", "foo"]).unwrap() 584 ); 585 assert_eq!( 586 Opt { 587 arg: Some(vec![ArgChoice::Foo, ArgChoice::Bar]) 588 }, 589 Opt::try_parse_from(["", "-a", "foo", "-a", "bar"]).unwrap() 590 ); 591 assert!(Opt::try_parse_from(["", "-a", "fOo"]).is_err()); 592} 593 594#[test] 595fn vec_type_default_value() { 596 #[derive(clap::ValueEnum, PartialEq, Debug, Clone)] 597 enum ArgChoice { 598 Foo, 599 Bar, 600 Baz, 601 } 602 603 #[derive(Parser, PartialEq, Debug)] 604 struct Opt { 605 #[arg( 606 value_enum, 607 short, 608 long, 609 default_value = "foo,bar", 610 value_delimiter = ',' 611 )] 612 arg: Vec<ArgChoice>, 613 } 614 615 assert_eq!( 616 Opt { 617 arg: vec![ArgChoice::Foo, ArgChoice::Bar] 618 }, 619 Opt::try_parse_from([""]).unwrap() 620 ); 621 622 assert_eq!( 623 Opt { 624 arg: vec![ArgChoice::Foo, ArgChoice::Baz] 625 }, 626 Opt::try_parse_from(["", "-a", "foo,baz"]).unwrap() 627 ); 628} 629