From 7ef88453e31a98b1c81e6976a3d4167391cecea9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 4 Nov 2021 10:15:04 -0500 Subject: [PATCH] refactor(tests): Prepare for Special Type experiments In experimenting on #1772, I want to write test cases for various combinations of required or not, values vs occurrences, etc. There wasn't really a clear place to put these. On top of that, I wanted there to be a clear place in the tests for describing the behavior of special types, to make it easier to audit and easier to see how a PR for #1772 changes things. As part of this effort in organizing these tests, I reduced the number of tests that use special types. This better focuses these tests on the cases they are intending to cover, rather than pulling in unrelated features. This makes it easier to audit special types and makes it so failures give more focused results, making it easier to see what broke. --- clap_derive/tests/arg_enum.rs | 76 +++---- clap_derive/tests/arguments.rs | 88 +++----- clap_derive/tests/basic.rs | 9 +- clap_derive/tests/doc-comments-help.rs | 2 +- .../tests/explicit_name_no_renaming.rs | 17 +- clap_derive/tests/flags.rs | 45 +++- clap_derive/tests/help.rs | 22 +- clap_derive/tests/issues.rs | 2 +- clap_derive/tests/{nested.rs => macros.rs} | 0 clap_derive/tests/options.rs | 203 ++++++++++-------- clap_derive/tests/privacy.rs | 2 +- clap_derive/tests/raw_idents.rs | 15 +- clap_derive/tests/special_types.rs | 73 ------- 13 files changed, 261 insertions(+), 293 deletions(-) rename clap_derive/tests/{nested.rs => macros.rs} (100%) delete mode 100644 clap_derive/tests/special_types.rs diff --git a/clap_derive/tests/arg_enum.rs b/clap_derive/tests/arg_enum.rs index 4ca646c617e3..809734ed8140 100644 --- a/clap_derive/tests/arg_enum.rs +++ b/clap_derive/tests/arg_enum.rs @@ -297,7 +297,41 @@ fn multiple_alias() { } #[test] -fn option() { +fn skip_variant() { + #[derive(ArgEnum, PartialEq, Debug, Clone)] + #[allow(dead_code)] // silence warning about `Baz` being unused + enum ArgChoice { + Foo, + Bar, + #[clap(skip)] + Baz, + } + + assert_eq!( + ArgChoice::value_variants() + .iter() + .map(ArgEnum::to_possible_value) + .map(Option::unwrap) + .collect::>(), + vec![PossibleValue::new("foo"), PossibleValue::new("bar")] + ); + assert!(ArgChoice::from_str("foo", true).is_ok()); + assert!(ArgChoice::from_str("bar", true).is_ok()); + assert!(ArgChoice::from_str("baz", true).is_err()); +} + +#[test] +fn from_str_invalid() { + #[derive(ArgEnum, PartialEq, Debug, Clone)] + enum ArgChoice { + Foo, + } + + assert!(ArgChoice::from_str("bar", true).is_err()); +} + +#[test] +fn option_type() { #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, @@ -327,7 +361,7 @@ fn option() { } #[test] -fn option_option() { +fn option_option_type() { #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, @@ -361,7 +395,7 @@ fn option_option() { } #[test] -fn vector() { +fn vec_type() { #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, @@ -391,7 +425,7 @@ fn vector() { } #[test] -fn option_vector() { +fn option_vec_type() { #[derive(ArgEnum, PartialEq, Debug, Clone)] enum ArgChoice { Foo, @@ -423,37 +457,3 @@ fn option_vector() { ); assert!(Opt::try_parse_from(&["", "-a", "fOo"]).is_err()); } - -#[test] -fn skip_variant() { - #[derive(ArgEnum, PartialEq, Debug, Clone)] - #[allow(dead_code)] // silence warning about `Baz` being unused - enum ArgChoice { - Foo, - Bar, - #[clap(skip)] - Baz, - } - - assert_eq!( - ArgChoice::value_variants() - .iter() - .map(ArgEnum::to_possible_value) - .map(Option::unwrap) - .collect::>(), - vec![PossibleValue::new("foo"), PossibleValue::new("bar")] - ); - assert!(ArgChoice::from_str("foo", true).is_ok()); - assert!(ArgChoice::from_str("bar", true).is_ok()); - assert!(ArgChoice::from_str("baz", true).is_err()); -} - -#[test] -fn from_str_invalid() { - #[derive(ArgEnum, PartialEq, Debug, Clone)] - enum ArgChoice { - Foo, - } - - assert!(ArgChoice::from_str("bar", true).is_err()); -} diff --git a/clap_derive/tests/arguments.rs b/clap_derive/tests/arguments.rs index e08b624ccd0f..2a1b0d113310 100644 --- a/clap_derive/tests/arguments.rs +++ b/clap_derive/tests/arguments.rs @@ -29,20 +29,6 @@ fn required_argument() { assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); } -#[test] -fn optional_argument() { - #[derive(Parser, PartialEq, Debug)] - struct Opt { - arg: Option, - } - assert_eq!( - Opt { arg: Some(42) }, - Opt::try_parse_from(&["test", "42"]).unwrap() - ); - assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap()); - assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); -} - #[test] fn argument_with_default() { #[derive(Parser, PartialEq, Debug)] @@ -58,45 +44,6 @@ fn argument_with_default() { assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); } -#[test] -fn arguments() { - #[derive(Parser, PartialEq, Debug)] - struct Opt { - arg: Vec, - } - assert_eq!( - Opt { arg: vec![24] }, - Opt::try_parse_from(&["test", "24"]).unwrap() - ); - assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap()); - assert_eq!( - Opt { arg: vec![24, 42] }, - Opt::try_parse_from(&["test", "24", "42"]).unwrap() - ); -} - -#[test] -fn arguments_safe() { - #[derive(Parser, PartialEq, Debug)] - struct Opt { - arg: Vec, - } - assert_eq!( - Opt { arg: vec![24] }, - Opt::try_parse_from(&["test", "24"]).unwrap() - ); - assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap()); - assert_eq!( - Opt { arg: vec![24, 42] }, - Opt::try_parse_from(&["test", "24", "42"]).unwrap() - ); - - assert_eq!( - clap::ErrorKind::ValueValidation, - Opt::try_parse_from(&["test", "NOPE"]).err().unwrap().kind - ); -} - #[test] fn auto_value_name() { #[derive(Parser, PartialEq, Debug)] @@ -136,3 +83,38 @@ fn explicit_value_name() { Opt::try_parse_from(&["test", "10"]).unwrap() ); } + +#[test] +fn option_type_is_optional() { + #[derive(Parser, PartialEq, Debug)] + struct Opt { + arg: Option, + } + assert_eq!( + Opt { arg: Some(42) }, + Opt::try_parse_from(&["test", "42"]).unwrap() + ); + assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap()); + assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); +} + +#[test] +fn vec_type_is_multiple_values() { + #[derive(Parser, PartialEq, Debug)] + struct Opt { + arg: Vec, + } + assert_eq!( + Opt { arg: vec![24] }, + Opt::try_parse_from(&["test", "24"]).unwrap() + ); + assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap()); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::try_parse_from(&["test", "24", "42"]).unwrap() + ); + assert_eq!( + clap::ErrorKind::ValueValidation, + Opt::try_parse_from(&["test", "NOPE"]).err().unwrap().kind + ); +} diff --git a/clap_derive/tests/basic.rs b/clap_derive/tests/basic.rs index 69f7ee298b9f..917fa6dd18aa 100644 --- a/clap_derive/tests/basic.rs +++ b/clap_derive/tests/basic.rs @@ -19,17 +19,12 @@ fn basic() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short = 'a', long = "arg")] - arg: Vec, + arg: i32, } assert_eq!( - Opt { arg: vec![24] }, + Opt { arg: 24 }, Opt::try_parse_from(&["test", "-a24"]).unwrap() ); - assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap()); - assert_eq!( - Opt { arg: vec![24, 42] }, - Opt::try_parse_from(&["test", "--arg", "24", "42"]).unwrap() - ); } #[test] diff --git a/clap_derive/tests/doc-comments-help.rs b/clap_derive/tests/doc-comments-help.rs index 1d6b0c2478e2..d502a2b699f5 100644 --- a/clap_derive/tests/doc-comments-help.rs +++ b/clap_derive/tests/doc-comments-help.rs @@ -108,7 +108,7 @@ fn top_long_doc_comment_both_help_long_help() { /// Or something else Foo { #[clap(about = "foo")] - bars: Vec, + bars: String, }, } diff --git a/clap_derive/tests/explicit_name_no_renaming.rs b/clap_derive/tests/explicit_name_no_renaming.rs index 8ea9955a7fb9..477fea2a4aea 100644 --- a/clap_derive/tests/explicit_name_no_renaming.rs +++ b/clap_derive/tests/explicit_name_no_renaming.rs @@ -7,15 +7,20 @@ use utils::*; fn explicit_short_long_no_rename() { #[derive(Parser, PartialEq, Debug)] struct Opt { - #[clap(short = '.', long = ".foo", multiple_occurrences(true))] - foo: Vec, + #[clap(short = '.', long = ".foo")] + foo: String, } + assert_eq!( + Opt { foo: "long".into() }, + Opt::try_parse_from(&["test", "--.foo", "long"]).unwrap() + ); + assert_eq!( Opt { - foo: vec!["short".into(), "long".into()] + foo: "short".into(), }, - Opt::try_parse_from(&["test", "-.", "short", "--.foo", "long"]).unwrap() + Opt::try_parse_from(&["test", "-.", "short"]).unwrap() ); } @@ -24,9 +29,9 @@ fn explicit_name_no_rename() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(name = ".options")] - foo: Vec, + foo: String, } let help = get_long_help::(); - assert!(help.contains("[.options]...")) + assert!(help.contains("<.options>")) } diff --git a/clap_derive/tests/flags.rs b/clap_derive/tests/flags.rs index 9c57683a75cd..176c63691821 100644 --- a/clap_derive/tests/flags.rs +++ b/clap_derive/tests/flags.rs @@ -15,7 +15,7 @@ use clap::Parser; #[test] -fn unique_flag() { +fn bool_type_is_flag() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short, long)] @@ -41,7 +41,7 @@ fn unique_flag() { } #[test] -fn multiple_flag() { +fn from_occurrences() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short, long, parse(from_occurrences))] @@ -74,12 +74,12 @@ fn multiple_flag() { assert!(Opt::try_parse_from(&["test", "-a", "foo"]).is_err()); } -fn parse_from_flag(b: bool) -> std::sync::atomic::AtomicBool { - std::sync::atomic::AtomicBool::new(b) -} - #[test] -fn non_bool_flags() { +fn non_bool_type_flag() { + fn parse_from_flag(b: bool) -> std::sync::atomic::AtomicBool { + std::sync::atomic::AtomicBool::new(b) + } + #[derive(Parser, Debug)] struct Opt { #[clap(short, long, parse(from_flag = parse_from_flag))] @@ -106,7 +106,7 @@ fn non_bool_flags() { } #[test] -fn combined_flags() { +fn mixed_type_flags() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short, long)] @@ -158,3 +158,32 @@ fn combined_flags() { Opt::try_parse_from(&["test", "-bb", "-a", "-bb"]).unwrap() ); } + +#[test] +fn ignore_qualified_bool_type() { + mod inner { + #[allow(non_camel_case_types)] + #[derive(PartialEq, Debug)] + pub struct bool(pub String); + + impl std::str::FromStr for self::bool { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(self::bool(s.into())) + } + } + } + + #[derive(Parser, PartialEq, Debug)] + struct Opt { + arg: inner::bool, + } + + assert_eq!( + Opt { + arg: inner::bool("success".into()) + }, + Opt::try_parse_from(&["test", "success"]).unwrap() + ); +} diff --git a/clap_derive/tests/help.rs b/clap_derive/tests/help.rs index b14a37221e21..48de630164f0 100644 --- a/clap_derive/tests/help.rs +++ b/clap_derive/tests/help.rs @@ -6,10 +6,10 @@ fn arg_help_heading_applied() { struct CliOptions { #[clap(long)] #[clap(help_heading = Some("HEADING A"))] - should_be_in_section_a: Option, + should_be_in_section_a: u32, #[clap(long)] - no_section: Option, + no_section: u32, } let app = CliOptions::into_app(); @@ -34,10 +34,10 @@ fn app_help_heading_applied() { struct CliOptions { #[clap(long)] #[clap(help_heading = Some("HEADING A"))] - should_be_in_section_a: Option, + should_be_in_section_a: u32, #[clap(long)] - should_be_in_default_section: Option, + should_be_in_default_section: u32, } let app = CliOptions::into_app(); @@ -72,21 +72,21 @@ fn app_help_heading_flattened() { sub_a: SubA, #[clap(long)] - should_be_in_default_section: Option, + should_be_in_default_section: u32, } #[derive(Debug, Clone, Args)] #[clap(help_heading = "HEADING A")] struct OptionsA { #[clap(long)] - should_be_in_section_a: Option, + should_be_in_section_a: u32, } #[derive(Debug, Clone, Args)] #[clap(help_heading = "HEADING B")] struct OptionsB { #[clap(long)] - should_be_in_section_b: Option, + should_be_in_section_b: u32, } #[derive(Debug, Clone, Subcommand)] @@ -98,20 +98,20 @@ fn app_help_heading_flattened() { SubAOne, #[clap(help_heading = "SUB A")] SubATwo { - should_be_in_sub_a: Option, + should_be_in_sub_a: u32, }, } #[derive(Debug, Clone, Subcommand)] enum SubB { #[clap(help_heading = "SUB B")] - SubBOne { should_be_in_sub_b: Option }, + SubBOne { should_be_in_sub_b: u32 }, } #[derive(Debug, Clone, Subcommand)] enum SubC { #[clap(help_heading = "SUB C")] - SubCOne { should_be_in_sub_c: Option }, + SubCOne { should_be_in_sub_c: u32 }, } let app = CliOptions::into_app(); @@ -172,7 +172,7 @@ fn flatten_field_with_help_heading() { #[derive(Debug, Clone, Args)] struct OptionsA { #[clap(long)] - should_be_in_section_a: Option, + should_be_in_section_a: u32, } let app = CliOptions::into_app(); diff --git a/clap_derive/tests/issues.rs b/clap_derive/tests/issues.rs index 1e4730c466f7..4201cd4209c6 100644 --- a/clap_derive/tests/issues.rs +++ b/clap_derive/tests/issues.rs @@ -63,7 +63,7 @@ fn issue_324() { #[clap(version = my_version())] struct Opt { #[clap(subcommand)] - _cmd: Option, + _cmd: SubCommand, } #[derive(Subcommand)] diff --git a/clap_derive/tests/nested.rs b/clap_derive/tests/macros.rs similarity index 100% rename from clap_derive/tests/nested.rs rename to clap_derive/tests/macros.rs diff --git a/clap_derive/tests/options.rs b/clap_derive/tests/options.rs index 9d62ff8e4f90..04e8d5636e7f 100644 --- a/clap_derive/tests/options.rs +++ b/clap_derive/tests/options.rs @@ -42,21 +42,6 @@ fn required_option() { assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err()); } -#[test] -fn optional_option() { - #[derive(Parser, PartialEq, Debug)] - struct Opt { - #[clap(short)] - arg: Option, - } - assert_eq!( - Opt { arg: Some(42) }, - Opt::try_parse_from(&["test", "-a42"]).unwrap() - ); - assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap()); - assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err()); -} - #[test] fn option_with_default() { #[derive(Parser, PartialEq, Debug)] @@ -88,66 +73,105 @@ fn option_with_raw_default() { } #[test] -fn options() { - #[derive(Parser, PartialEq, Debug)] +fn option_from_str() { + #[derive(Debug, PartialEq)] + struct A; + + impl<'a> From<&'a str> for A { + fn from(_: &str) -> A { + A + } + } + + #[derive(Debug, Parser, PartialEq)] struct Opt { - #[clap(short, long, multiple_occurrences(true))] - arg: Vec, + #[clap(parse(from_str))] + a: Option, } + + assert_eq!(Opt { a: None }, Opt::try_parse_from(&["test"]).unwrap()); assert_eq!( - Opt { arg: vec![24] }, - Opt::try_parse_from(&["test", "-a24"]).unwrap() + Opt { a: Some(A) }, + Opt::try_parse_from(&["test", "foo"]).unwrap() ); - assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap()); +} + +#[test] +fn option_type_is_optional() { + #[derive(Parser, PartialEq, Debug)] + struct Opt { + #[clap(short)] + arg: Option, + } assert_eq!( - Opt { arg: vec![24, 42] }, - Opt::try_parse_from(&["test", "-a24", "--arg", "42"]).unwrap() + Opt { arg: Some(42) }, + Opt::try_parse_from(&["test", "-a42"]).unwrap() ); + assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap()); + assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err()); } #[test] -fn default_value() { - #[derive(Parser, PartialEq, Debug)] +fn required_with_option_type() { + #[derive(Debug, PartialEq, Eq, Parser)] + #[clap(setting(clap::AppSettings::SubcommandsNegateReqs))] struct Opt { - #[clap(short, default_value = "test")] - arg: String, + #[clap(required = true)] + req_str: Option, + + #[clap(subcommand)] + cmd: Option, + } + + #[derive(Debug, PartialEq, Eq, Subcommand)] + enum SubCommands { + ExSub { + #[clap(short, long, parse(from_occurrences))] + verbose: u8, + }, } + assert_eq!( - Opt { arg: "test".into() }, - Opt::try_parse_from(&["test"]).unwrap() + Opt { + req_str: Some(("arg").into()), + cmd: None, + }, + Opt::try_parse_from(&["test", "arg"]).unwrap() ); + assert_eq!( - Opt { arg: "foo".into() }, - Opt::try_parse_from(&["test", "-afoo"]).unwrap() + Opt { + req_str: None, + cmd: Some(SubCommands::ExSub { verbose: 1 }), + }, + Opt::try_parse_from(&["test", "ex-sub", "-v"]).unwrap() ); + + assert!(Opt::try_parse_from(&["test"]).is_err()); } #[test] -fn option_from_str() { - #[derive(Debug, PartialEq)] - struct A; - - impl<'a> From<&'a str> for A { - fn from(_: &str) -> A { - A - } +fn ignore_qualified_option_type() { + fn parser(s: &str) -> Option { + Some(s.to_string()) } - #[derive(Debug, Parser, PartialEq)] + #[derive(Parser, PartialEq, Debug)] struct Opt { - #[clap(parse(from_str))] - a: Option, + #[clap(parse(from_str = parser))] + arg: ::std::option::Option, } - assert_eq!(Opt { a: None }, Opt::try_parse_from(&["test"]).unwrap()); assert_eq!( - Opt { a: Some(A) }, - Opt::try_parse_from(&["test", "foo"]).unwrap() + Opt { + arg: Some("success".into()) + }, + Opt::try_parse_from(&["test", "success"]).unwrap() ); } #[test] -fn optional_argument_for_optional_option() { +fn option_option_type_is_optional_value() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short, multiple_occurrences(true))] @@ -169,7 +193,7 @@ fn optional_argument_for_optional_option() { } #[test] -fn option_option_help() { +fn option_option_type_help() { #[derive(Parser, Debug)] struct Opt { #[clap(long, value_name = "val")] @@ -181,7 +205,7 @@ fn option_option_help() { } #[test] -fn two_option_options() { +fn two_option_option_types() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short)] @@ -235,7 +259,45 @@ fn two_option_options() { } #[test] -fn optional_vec() { +fn vec_type_is_multiple_occurrences() { + #[derive(Parser, PartialEq, Debug)] + struct Opt { + #[clap(short, long, multiple_occurrences(true))] + arg: Vec, + } + assert_eq!( + Opt { arg: vec![24] }, + Opt::try_parse_from(&["test", "-a24"]).unwrap() + ); + assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap()); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::try_parse_from(&["test", "-a24", "--arg", "42"]).unwrap() + ); +} + +#[test] +fn ignore_qualified_vec_type() { + fn parser(s: &str) -> Vec { + vec![s.to_string()] + } + + #[derive(Parser, PartialEq, Debug)] + struct Opt { + #[clap(parse(from_str = parser))] + arg: ::std::vec::Vec, + } + + assert_eq!( + Opt { + arg: vec!["success".into()] + }, + Opt::try_parse_from(&["test", "success"]).unwrap() + ); +} + +#[test] +fn option_vec_type() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short, multiple_occurrences(true))] @@ -295,7 +357,7 @@ fn optional_vec() { } #[test] -fn two_optional_vecs() { +fn two_option_vec_types() { #[derive(Parser, PartialEq, Debug)] struct Opt { #[clap(short, multiple_occurrences(true))] @@ -334,42 +396,3 @@ fn two_optional_vecs() { Opt::try_parse_from(&["test"]).unwrap() ); } - -#[test] -fn required_option_type() { - #[derive(Debug, PartialEq, Eq, Parser)] - #[clap(setting(clap::AppSettings::SubcommandsNegateReqs))] - struct Opt { - #[clap(required = true)] - req_str: Option, - - #[clap(subcommand)] - cmd: Option, - } - - #[derive(Debug, PartialEq, Eq, Subcommand)] - enum SubCommands { - ExSub { - #[clap(short, long, parse(from_occurrences))] - verbose: u8, - }, - } - - assert_eq!( - Opt { - req_str: Some(("arg").into()), - cmd: None, - }, - Opt::try_parse_from(&["test", "arg"]).unwrap() - ); - - assert_eq!( - Opt { - req_str: None, - cmd: Some(SubCommands::ExSub { verbose: 1 }), - }, - Opt::try_parse_from(&["test", "ex-sub", "-v"]).unwrap() - ); - - assert!(Opt::try_parse_from(&["test"]).is_err()); -} diff --git a/clap_derive/tests/privacy.rs b/clap_derive/tests/privacy.rs index b4609b8312dd..12b53b1f2b4a 100644 --- a/clap_derive/tests/privacy.rs +++ b/clap_derive/tests/privacy.rs @@ -30,7 +30,7 @@ mod subcommands { /// foo Foo { /// foo - bars: Vec, + bars: String, }, } } diff --git a/clap_derive/tests/raw_idents.rs b/clap_derive/tests/raw_idents.rs index 1091379c3b61..12c5d1658f0a 100644 --- a/clap_derive/tests/raw_idents.rs +++ b/clap_derive/tests/raw_idents.rs @@ -4,14 +4,21 @@ use clap::Parser; fn raw_idents() { #[derive(Parser, Debug, PartialEq)] struct Opt { - #[clap(short, long, multiple_occurrences(true))] - r#type: Vec, + #[clap(short, long)] + r#type: String, } assert_eq!( Opt { - r#type: vec!["long".into(), "short".into()] + r#type: "long".into() }, - Opt::try_parse_from(&["test", "--type", "long", "-t", "short"]).unwrap() + Opt::try_parse_from(&["test", "--type", "long"]).unwrap() + ); + + assert_eq!( + Opt { + r#type: "short".into() + }, + Opt::try_parse_from(&["test", "-t", "short"]).unwrap() ); } diff --git a/clap_derive/tests/special_types.rs b/clap_derive/tests/special_types.rs deleted file mode 100644 index e1f9d26eb796..000000000000 --- a/clap_derive/tests/special_types.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Checks that types like `::std::option::Option` are not special - -use clap::Parser; - -#[rustversion::all(since(1.37), stable)] -#[test] -fn special_types_bool() { - mod inner { - #[allow(non_camel_case_types)] - #[derive(PartialEq, Debug)] - pub struct bool(pub String); - - impl std::str::FromStr for self::bool { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(self::bool(s.into())) - } - } - } - - #[derive(Parser, PartialEq, Debug)] - struct Opt { - arg: inner::bool, - } - - assert_eq!( - Opt { - arg: inner::bool("success".into()) - }, - Opt::try_parse_from(&["test", "success"]).unwrap() - ); -} - -#[test] -fn special_types_option() { - fn parser(s: &str) -> Option { - Some(s.to_string()) - } - - #[derive(Parser, PartialEq, Debug)] - struct Opt { - #[clap(parse(from_str = parser))] - arg: ::std::option::Option, - } - - assert_eq!( - Opt { - arg: Some("success".into()) - }, - Opt::try_parse_from(&["test", "success"]).unwrap() - ); -} - -#[test] -fn special_types_vec() { - fn parser(s: &str) -> Vec { - vec![s.to_string()] - } - - #[derive(Parser, PartialEq, Debug)] - struct Opt { - #[clap(parse(from_str = parser))] - arg: ::std::vec::Vec, - } - - assert_eq!( - Opt { - arg: vec!["success".into()] - }, - Opt::try_parse_from(&["test", "success"]).unwrap() - ); -}