Skip to content

Commit

Permalink
refactor(tests): Prepare for Special Type experiments
Browse files Browse the repository at this point in the history
In experimenting on clap-rs#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 clap-rs#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.
  • Loading branch information
epage committed Nov 4, 2021
1 parent 4dfa56a commit 78e4c90
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 325 deletions.
76 changes: 38 additions & 38 deletions clap_derive/tests/arg_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<_>>(),
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,
Expand Down Expand Up @@ -327,7 +361,7 @@ fn option() {
}

#[test]
fn option_option() {
fn option_option_type() {
#[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice {
Foo,
Expand Down Expand Up @@ -361,7 +395,7 @@ fn option_option() {
}

#[test]
fn vector() {
fn vec_type() {
#[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice {
Foo,
Expand Down Expand Up @@ -391,7 +425,7 @@ fn vector() {
}

#[test]
fn option_vector() {
fn option_vec_type() {
#[derive(ArgEnum, PartialEq, Debug, Clone)]
enum ArgChoice {
Foo,
Expand Down Expand Up @@ -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<_>>(),
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());
}
88 changes: 35 additions & 53 deletions clap_derive/tests/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<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 argument_with_default() {
#[derive(Parser, PartialEq, Debug)]
Expand All @@ -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<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]
fn auto_value_name() {
#[derive(Parser, PartialEq, Debug)]
Expand Down Expand Up @@ -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<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
);
}
9 changes: 2 additions & 7 deletions clap_derive/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,12 @@ fn basic() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(short = 'a', long = "arg")]
arg: Vec<i32>,
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]
Expand Down
2 changes: 1 addition & 1 deletion clap_derive/tests/doc-comments-help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fn top_long_doc_comment_both_help_long_help() {
/// Or something else
Foo {
#[clap(about = "foo")]
bars: Vec<String>,
bars: String,
},
}

Expand Down
17 changes: 11 additions & 6 deletions clap_derive/tests/explicit_name_no_renaming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
#[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()
);
}

Expand All @@ -24,9 +29,9 @@ fn explicit_name_no_rename() {
#[derive(Parser, PartialEq, Debug)]
struct Opt {
#[clap(name = ".options")]
foo: Vec<String>,
foo: String,
}

let help = get_long_help::<Opt>();
assert!(help.contains("[.options]..."))
assert!(help.contains("<.options>"))
}
45 changes: 37 additions & 8 deletions clap_derive/tests/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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))]
Expand Down Expand Up @@ -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))]
Expand All @@ -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)]
Expand Down Expand Up @@ -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<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()
);
}

0 comments on commit 78e4c90

Please sign in to comment.