mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 14:54:15 +00:00
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.
This commit is contained in:
parent
4dfa56a9e4
commit
78e4c90326
13 changed files with 271 additions and 336 deletions
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ mod subcommands {
|
||||||
/// foo
|
/// foo
|
||||||
Foo {
|
Foo {
|
||||||
/// foo
|
/// foo
|
||||||
bars: Vec<String>,
|
bars: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in a new issue