2988: refactor(tests): Prepare for Special Type experiments r=pksunkara a=epage



Co-authored-by: Ed Page <eopage@gmail.com>
This commit is contained in:
bors[bot] 2021-11-05 07:44:30 +00:00 committed by GitHub
commit b9d007d262
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 271 additions and 336 deletions

View file

@ -297,7 +297,41 @@ fn multiple_alias() {
} }
#[test] #[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<_>>(),
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)] #[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice { enum ArgChoice {
Foo, Foo,
@ -327,7 +361,7 @@ fn option() {
} }
#[test] #[test]
fn option_option() { fn option_option_type() {
#[derive(ArgEnum, PartialEq, Debug, Clone)] #[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice { enum ArgChoice {
Foo, Foo,
@ -361,7 +395,7 @@ fn option_option() {
} }
#[test] #[test]
fn vector() { fn vec_type() {
#[derive(ArgEnum, PartialEq, Debug, Clone)] #[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice { enum ArgChoice {
Foo, Foo,
@ -391,7 +425,7 @@ fn vector() {
} }
#[test] #[test]
fn option_vector() { fn option_vec_type() {
#[derive(ArgEnum, PartialEq, Debug, Clone)] #[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice { enum ArgChoice {
Foo, Foo,
@ -423,37 +457,3 @@ fn option_vector() {
); );
assert!(Opt::try_parse_from(&["", "-a", "fOo"]).is_err()); 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<_>>(),
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());
}

View file

@ -29,20 +29,6 @@ fn required_argument() {
assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
} }
#[test]
fn optional_argument() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
arg: Option<i32>,
}
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] #[test]
fn argument_with_default() { fn argument_with_default() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
@ -58,45 +44,6 @@ fn argument_with_default() {
assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
} }
#[test]
fn arguments() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
arg: Vec<i32>,
}
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<i32>,
}
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] #[test]
fn auto_value_name() { fn auto_value_name() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
@ -136,3 +83,38 @@ fn explicit_value_name() {
Opt::try_parse_from(&["test", "10"]).unwrap() Opt::try_parse_from(&["test", "10"]).unwrap()
); );
} }
#[test]
fn option_type_is_optional() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
arg: Option<i32>,
}
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<i32>,
}
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
);
}

View file

@ -19,17 +19,12 @@ fn basic() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short = 'a', long = "arg")] #[clap(short = 'a', long = "arg")]
arg: Vec<i32>, arg: i32,
} }
assert_eq!( assert_eq!(
Opt { arg: vec![24] }, Opt { arg: 24 },
Opt::try_parse_from(&["test", "-a24"]).unwrap() 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] #[test]

View file

@ -108,7 +108,7 @@ fn top_long_doc_comment_both_help_long_help() {
/// Or something else /// Or something else
Foo { Foo {
#[clap(about = "foo")] #[clap(about = "foo")]
bars: Vec<String>, bars: String,
}, },
} }

View file

@ -7,15 +7,20 @@ use utils::*;
fn explicit_short_long_no_rename() { fn explicit_short_long_no_rename() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short = '.', long = ".foo", multiple_occurrences(true))] #[clap(short = '.', long = ".foo")]
foo: Vec<String>, foo: String,
} }
assert_eq!(
Opt { foo: "long".into() },
Opt::try_parse_from(&["test", "--.foo", "long"]).unwrap()
);
assert_eq!( assert_eq!(
Opt { 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)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(name = ".options")] #[clap(name = ".options")]
foo: Vec<String>, foo: String,
} }
let help = get_long_help::<Opt>(); let help = get_long_help::<Opt>();
assert!(help.contains("[.options]...")) assert!(help.contains("<.options>"))
} }

View file

@ -15,7 +15,7 @@
use clap::Parser; use clap::Parser;
#[test] #[test]
fn unique_flag() { fn bool_type_is_flag() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long)] #[clap(short, long)]
@ -41,7 +41,7 @@ fn unique_flag() {
} }
#[test] #[test]
fn multiple_flag() { fn from_occurrences() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long, parse(from_occurrences))] #[clap(short, long, parse(from_occurrences))]
@ -74,12 +74,12 @@ fn multiple_flag() {
assert!(Opt::try_parse_from(&["test", "-a", "foo"]).is_err()); 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] #[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)] #[derive(Parser, Debug)]
struct Opt { struct Opt {
#[clap(short, long, parse(from_flag = parse_from_flag))] #[clap(short, long, parse(from_flag = parse_from_flag))]
@ -106,7 +106,7 @@ fn non_bool_flags() {
} }
#[test] #[test]
fn combined_flags() { fn mixed_type_flags() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, long)] #[clap(short, long)]
@ -158,3 +158,32 @@ fn combined_flags() {
Opt::try_parse_from(&["test", "-bb", "-a", "-bb"]).unwrap() 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<Self, Self::Err> {
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()
);
}

View file

@ -6,10 +6,10 @@ fn arg_help_heading_applied() {
struct CliOptions { struct CliOptions {
#[clap(long)] #[clap(long)]
#[clap(help_heading = Some("HEADING A"))] #[clap(help_heading = Some("HEADING A"))]
should_be_in_section_a: Option<u32>, should_be_in_section_a: u32,
#[clap(long)] #[clap(long)]
no_section: Option<u32>, no_section: u32,
} }
let app = CliOptions::into_app(); let app = CliOptions::into_app();
@ -34,10 +34,10 @@ fn app_help_heading_applied() {
struct CliOptions { struct CliOptions {
#[clap(long)] #[clap(long)]
#[clap(help_heading = Some("HEADING A"))] #[clap(help_heading = Some("HEADING A"))]
should_be_in_section_a: Option<u32>, should_be_in_section_a: u32,
#[clap(long)] #[clap(long)]
should_be_in_default_section: Option<u32>, should_be_in_default_section: u32,
} }
let app = CliOptions::into_app(); let app = CliOptions::into_app();
@ -72,21 +72,21 @@ fn app_help_heading_flattened() {
sub_a: SubA, sub_a: SubA,
#[clap(long)] #[clap(long)]
should_be_in_default_section: Option<u32>, should_be_in_default_section: u32,
} }
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
#[clap(help_heading = "HEADING A")] #[clap(help_heading = "HEADING A")]
struct OptionsA { struct OptionsA {
#[clap(long)] #[clap(long)]
should_be_in_section_a: Option<u32>, should_be_in_section_a: u32,
} }
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
#[clap(help_heading = "HEADING B")] #[clap(help_heading = "HEADING B")]
struct OptionsB { struct OptionsB {
#[clap(long)] #[clap(long)]
should_be_in_section_b: Option<u32>, should_be_in_section_b: u32,
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
@ -98,20 +98,20 @@ fn app_help_heading_flattened() {
SubAOne, SubAOne,
#[clap(help_heading = "SUB A")] #[clap(help_heading = "SUB A")]
SubATwo { SubATwo {
should_be_in_sub_a: Option<u32>, should_be_in_sub_a: u32,
}, },
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
enum SubB { enum SubB {
#[clap(help_heading = "SUB B")] #[clap(help_heading = "SUB B")]
SubBOne { should_be_in_sub_b: Option<u32> }, SubBOne { should_be_in_sub_b: u32 },
} }
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
enum SubC { enum SubC {
#[clap(help_heading = "SUB C")] #[clap(help_heading = "SUB C")]
SubCOne { should_be_in_sub_c: Option<u32> }, SubCOne { should_be_in_sub_c: u32 },
} }
let app = CliOptions::into_app(); let app = CliOptions::into_app();
@ -172,7 +172,7 @@ fn flatten_field_with_help_heading() {
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
struct OptionsA { struct OptionsA {
#[clap(long)] #[clap(long)]
should_be_in_section_a: Option<u32>, should_be_in_section_a: u32,
} }
let app = CliOptions::into_app(); let app = CliOptions::into_app();

View file

@ -63,7 +63,7 @@ fn issue_324() {
#[clap(version = my_version())] #[clap(version = my_version())]
struct Opt { struct Opt {
#[clap(subcommand)] #[clap(subcommand)]
_cmd: Option<SubCommand>, _cmd: SubCommand,
} }
#[derive(Subcommand)] #[derive(Subcommand)]

View file

@ -42,21 +42,6 @@ fn required_option() {
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err()); assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
} }
#[test]
fn optional_option() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(short)]
arg: Option<i32>,
}
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] #[test]
fn option_with_default() { fn option_with_default() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
@ -87,41 +72,6 @@ fn option_with_raw_default() {
assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err()); assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
} }
#[test]
fn options() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(short, long, multiple_occurrences(true))]
arg: Vec<i32>,
}
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 default_value() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(short, default_value = "test")]
arg: String,
}
assert_eq!(
Opt { arg: "test".into() },
Opt::try_parse_from(&["test"]).unwrap()
);
assert_eq!(
Opt { arg: "foo".into() },
Opt::try_parse_from(&["test", "-afoo"]).unwrap()
);
}
#[test] #[test]
fn option_from_str() { fn option_from_str() {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -147,7 +97,81 @@ fn option_from_str() {
} }
#[test] #[test]
fn optional_argument_for_optional_option() { fn option_type_is_optional() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(short)]
arg: Option<i32>,
}
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 required_with_option_type() {
#[derive(Debug, PartialEq, Eq, Parser)]
#[clap(setting(clap::AppSettings::SubcommandsNegateReqs))]
struct Opt {
#[clap(required = true)]
req_str: Option<String>,
#[clap(subcommand)]
cmd: Option<SubCommands>,
}
#[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());
}
#[test]
fn ignore_qualified_option_type() {
fn parser(s: &str) -> Option<String> {
Some(s.to_string())
}
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(parse(from_str = parser))]
arg: ::std::option::Option<String>,
}
assert_eq!(
Opt {
arg: Some("success".into())
},
Opt::try_parse_from(&["test", "success"]).unwrap()
);
}
#[test]
fn option_option_type_is_optional_value() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, multiple_occurrences(true))] #[clap(short, multiple_occurrences(true))]
@ -169,7 +193,7 @@ fn optional_argument_for_optional_option() {
} }
#[test] #[test]
fn option_option_help() { fn option_option_type_help() {
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct Opt { struct Opt {
#[clap(long, value_name = "val")] #[clap(long, value_name = "val")]
@ -181,7 +205,7 @@ fn option_option_help() {
} }
#[test] #[test]
fn two_option_options() { fn two_option_option_types() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short)] #[clap(short)]
@ -235,10 +259,48 @@ fn two_option_options() {
} }
#[test] #[test]
fn optional_vec() { fn vec_type_is_multiple_values() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, multiple_occurrences(true))] #[clap(short, long)]
arg: Vec<i32>,
}
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", "-a", "24", "42"]).unwrap()
);
}
#[test]
fn ignore_qualified_vec_type() {
fn parser(s: &str) -> Vec<String> {
vec![s.to_string()]
}
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(parse(from_str = parser))]
arg: ::std::vec::Vec<String>,
}
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)]
arg: Option<Vec<i32>>, arg: Option<Vec<i32>>,
} }
assert_eq!( assert_eq!(
@ -246,27 +308,6 @@ fn optional_vec() {
Opt::try_parse_from(&["test", "-a", "1"]).unwrap() Opt::try_parse_from(&["test", "-a", "1"]).unwrap()
); );
assert_eq!(
Opt {
arg: Some(vec![1, 2])
},
Opt::try_parse_from(&["test", "-a1", "-a2"]).unwrap()
);
assert_eq!(
Opt {
arg: Some(vec![1, 2])
},
Opt::try_parse_from(&["test", "-a1", "-a2", "-a"]).unwrap()
);
assert_eq!(
Opt {
arg: Some(vec![1, 2])
},
Opt::try_parse_from(&["test", "-a1", "-a", "-a2"]).unwrap()
);
assert_eq!( assert_eq!(
Opt { Opt {
arg: Some(vec![1, 2]) arg: Some(vec![1, 2])
@ -274,34 +315,22 @@ fn optional_vec() {
Opt::try_parse_from(&["test", "-a", "1", "2"]).unwrap() Opt::try_parse_from(&["test", "-a", "1", "2"]).unwrap()
); );
assert_eq!(
Opt {
arg: Some(vec![1, 2, 3])
},
Opt::try_parse_from(&["test", "-a", "1", "2", "-a", "3"]).unwrap()
);
assert_eq!( assert_eq!(
Opt { arg: Some(vec![]) }, Opt { arg: Some(vec![]) },
Opt::try_parse_from(&["test", "-a"]).unwrap() Opt::try_parse_from(&["test", "-a"]).unwrap()
); );
assert_eq!(
Opt { arg: Some(vec![]) },
Opt::try_parse_from(&["test", "-a", "-a"]).unwrap()
);
assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap()); assert_eq!(Opt { arg: None }, Opt::try_parse_from(&["test"]).unwrap());
} }
#[test] #[test]
fn two_optional_vecs() { fn two_option_vec_types() {
#[derive(Parser, PartialEq, Debug)] #[derive(Parser, PartialEq, Debug)]
struct Opt { struct Opt {
#[clap(short, multiple_occurrences(true))] #[clap(short)]
arg: Option<Vec<i32>>, arg: Option<Vec<i32>>,
#[clap(short, multiple_occurrences(true))] #[clap(short)]
b: Option<Vec<i32>>, b: Option<Vec<i32>>,
} }
@ -316,9 +345,9 @@ fn two_optional_vecs() {
assert_eq!( assert_eq!(
Opt { Opt {
arg: Some(vec![1]), arg: Some(vec![1]),
b: Some(vec![]) b: Some(vec![1])
}, },
Opt::try_parse_from(&["test", "-a", "-b", "-a1"]).unwrap() Opt::try_parse_from(&["test", "-a", "1", "-b", "1"]).unwrap()
); );
assert_eq!( assert_eq!(
@ -326,7 +355,7 @@ fn two_optional_vecs() {
arg: Some(vec![1, 2]), arg: Some(vec![1, 2]),
b: Some(vec![1, 2]) b: Some(vec![1, 2])
}, },
Opt::try_parse_from(&["test", "-a1", "-a2", "-b1", "-b2"]).unwrap() Opt::try_parse_from(&["test", "-a", "1", "2", "-b", "1", "2"]).unwrap()
); );
assert_eq!( assert_eq!(
@ -334,42 +363,3 @@ fn two_optional_vecs() {
Opt::try_parse_from(&["test"]).unwrap() 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<String>,
#[clap(subcommand)]
cmd: Option<SubCommands>,
}
#[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());
}

View file

@ -30,7 +30,7 @@ mod subcommands {
/// foo /// foo
Foo { Foo {
/// foo /// foo
bars: Vec<String>, bars: String,
}, },
} }
} }

View file

@ -4,14 +4,21 @@ use clap::Parser;
fn raw_idents() { fn raw_idents() {
#[derive(Parser, Debug, PartialEq)] #[derive(Parser, Debug, PartialEq)]
struct Opt { struct Opt {
#[clap(short, long, multiple_occurrences(true))] #[clap(short, long)]
r#type: Vec<String>, r#type: String,
} }
assert_eq!( assert_eq!(
Opt { 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()
); );
} }

View file

@ -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<Self, Self::Err> {
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<String> {
Some(s.to_string())
}
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(parse(from_str = parser))]
arg: ::std::option::Option<String>,
}
assert_eq!(
Opt {
arg: Some("success".into())
},
Opt::try_parse_from(&["test", "success"]).unwrap()
);
}
#[test]
fn special_types_vec() {
fn parser(s: &str) -> Vec<String> {
vec![s.to_string()]
}
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(parse(from_str = parser))]
arg: ::std::vec::Vec<String>,
}
assert_eq!(
Opt {
arg: vec!["success".into()]
},
Opt::try_parse_from(&["test", "success"]).unwrap()
);
}