From 1c16f73c10ea77a6838b0092eca54567b02c27ca Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Wed, 8 Apr 2020 22:26:05 +0200 Subject: [PATCH 1/6] Start cleaning up debug_assertion validations --- .travis.yml | 4 ++ src/build/app/mod.rs | 163 ++++++++++++++++++++----------------------- src/parse/parser.rs | 1 + tests/groups.rs | 1 + tests/help.rs | 31 ++++++++ tests/unique_args.rs | 2 +- 6 files changed, 114 insertions(+), 88 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e3c826c..bf39ab1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,10 @@ jobs: - rust: beta - rust: nightly cache: false + - name: Release profile tests + script: + - cargo test --release --no-default-features + - cargo test --release --features yaml unstable - name: Linting (fmt + clippy) before_script: - rustup component add clippy diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 8dd69ae5..45164c38 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -1422,12 +1422,6 @@ impl<'b> App<'b> { self._derive_display_order(); self._create_help_and_version(); - // Perform expensive debug assertions - #[cfg(debug_assertions)] - for a in self.args.args.iter() { - self._arg_debug_asserts(a); - } - let mut pos_counter = 1; for a in self.args.args.iter_mut() { // Fill in the groups @@ -1460,19 +1454,14 @@ impl<'b> App<'b> { } } - debug_assert!(self._app_debug_asserts()); + debug_assert!(self._debug_asserts()); self.args._build(); self.settings.set(AppSettings::Built); - Self::_panic_on_missing_help(&self, self.g_settings.is_set(AppSettings::HelpRequired)); } - #[cfg(not(debug_assertions))] - fn _panic_on_missing_help(_app: &App, _help_required_globally: bool) {} - - #[cfg(debug_assertions)] - fn _panic_on_missing_help(app: &App, help_required_globally: bool) { - if app.is_set(AppSettings::HelpRequired) || help_required_globally { - let args_missing_help: Vec = app + fn _panic_on_missing_help(&self, help_required_globally: bool) { + if self.is_set(AppSettings::HelpRequired) || help_required_globally { + let args_missing_help: Vec = self .args .args .iter() @@ -1481,26 +1470,86 @@ impl<'b> App<'b> { .collect(); if !args_missing_help.is_empty() { - let abort_message = format!("AppSettings::HelpRequired is enabled for the App {}, but at least one of its arguments does not have either `help` or `long_help` set. List of such arguments: {}", app.name, args_missing_help.join(", ")); - panic!(abort_message); + panic!(format!( + "AppSettings::HelpRequired is enabled for the App {}, but at least one of its arguments does not have either `help` or `long_help` set. List of such arguments: {}", + self.name, + args_missing_help.join(", ") + )); } } - for sub_app in &app.subcommands { - Self::_panic_on_missing_help(&sub_app, help_required_globally); + + for sub_app in &self.subcommands { + sub_app._panic_on_missing_help(help_required_globally); } } // Perform some expensive assertions on the Parser itself - fn _app_debug_asserts(&self) -> bool { - debugln!("App::_app_debug_asserts;"); - for name in self.args.args.iter().map(|x| x.id) { - if self.args.args.iter().filter(|x| x.id == name).count() > 1 { - panic!(format!( - "Arg names must be unique, found '{}' more than once", - name - )); + fn _debug_asserts(&self) -> bool { + debugln!("App::_debug_asserts;"); + + for arg in &self.args.args { + // Name conflicts + assert!( + self.args.args.iter().filter(|x| x.id == arg.id).count() < 2, + "Argument name must be unique\n\n\t'{}' is already in use", + arg.id, + ); + + // Long conflicts + if let Some(l) = arg.long { + assert!( + self.args.args.iter().filter(|x| x.long == Some(l)).count() < 2, + "Argument long must be unique\n\n\t'--{}' is already in use", + l + ); } + + // Short conflicts + if let Some(s) = arg.short { + assert!( + self.args.args.iter().filter(|x| x.short == Some(s)).count() < 2, + "Argument short must be unique\n\n\t'-{}' is already in use", + s + ); + } + + // Index conflicts + if let Some(idx) = arg.index { + assert!( + positionals!(self).fold(0, |acc, p| if p.index == Some(idx) { + acc + 1 + } else { + acc + }) < 2, + "Argument '{}' has the same index as another positional \ + argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \ + positional argument to take multiple values", + arg.name + ); + } + + if arg.is_set(ArgSettings::Last) { + assert!( + arg.long.is_none(), + "Flags or Options may not have last(true) set. '{}' has both a long and last(true) set.", + arg.name + ); + assert!( + arg.short.is_none(), + "Flags or Options may not have last(true) set. '{}' has both a short and last(true) set.", + arg.name + ); + } + + assert!( + !(arg.is_set(ArgSettings::Required) && arg.global), + "Global arguments cannot be required.\n\n\t'{}' is marked as global and required", + arg.name + ); } + + self._panic_on_missing_help(self.g_settings.is_set(AppSettings::HelpRequired)); + // * Args listed inside groups should exist // * Groups should not have naming conflicts with Args @@ -1641,66 +1690,6 @@ impl<'b> App<'b> { } } - // Perform expensive assertions on the Arg instance - fn _arg_debug_asserts(&self, a: &Arg) -> bool { - debugln!("App::_arg_debug_asserts:{}", a.name); - - // Long conflicts - if let Some(l) = a.long { - assert!( - self.args.args.iter().filter(|x| x.long == Some(l)).count() < 2, - "Argument long must be unique\n\n\t'--{}' is already in use", - l - ); - } - - // Short conflicts - if let Some(s) = a.short { - assert!( - self.args.args.iter().filter(|x| x.short == Some(s)).count() < 2, - "Argument short must be unique\n\n\t'-{}' is already in use", - s - ); - } - - if let Some(idx) = a.index { - // No index conflicts - assert!( - positionals!(self).fold(0, |acc, p| if p.index == Some(idx) { - acc + 1 - } else { - acc - }) < 2, - "Argument '{}' has the same index as another positional \ - argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \ - positional argument to take multiple values", - a.name - ); - } - if a.is_set(ArgSettings::Last) { - assert!( - a.long.is_none(), - "Flags or Options may not have last(true) set. '{}' has both a long and \ - last(true) set.", - a.name - ); - assert!( - a.short.is_none(), - "Flags or Options may not have last(true) set. '{}' has both a short and \ - last(true) set.", - a.name - ); - } - assert!( - !(a.is_set(ArgSettings::Required) && a.global), - "Global arguments cannot be required.\n\n\t'{}' is marked as \ - global and required", - a.name - ); - - true - } - // used in clap_generate (https://github.com/clap-rs/clap_generate) #[doc(hidden)] pub fn _build_bin_names(&mut self) { diff --git a/src/parse/parser.rs b/src/parse/parser.rs index caecdfda..e9c2a1fa 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -373,6 +373,7 @@ where } debug_assert!(self._verify_positionals()); + // Set the LowIndexMultiple flag if required if positionals!(self.app).any(|a| { a.is_set(ArgSettings::MultipleValues) diff --git a/tests/groups.rs b/tests/groups.rs index b7ea3f43..be98602c 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -43,6 +43,7 @@ fn required_group_missing_arg() { // This tests a programmer error and will only succeed with debug_assertions // #[cfg(debug_assertions)] +// TODO: Enable this #[test] // This used to provide a nice, programmer-friendly error. // Now the error directs the programmer to file a bug report with clap. diff --git a/tests/help.rs b/tests/help.rs index 853b0ad5..0da21e4c 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -347,6 +347,16 @@ FLAGS: -H, --help Print help information -v, --version Print version information"; +static HELP_CONFLICT: &str = "conflict + +USAGE: + conflict [FLAGS] + +FLAGS: + --help Prints help information + -h + -V, --version Prints version information"; + static LAST_ARG: &str = "last 0.1 USAGE: @@ -1162,6 +1172,27 @@ fn customize_version_and_help() { )); } +#[test] +fn arg_short_conflict_with_help() { + let app = App::new("conflict").arg(Arg::with_name("home").short('h')); + + assert!(utils::compare_output( + app, + "conflict --help", + HELP_CONFLICT, + false + )); +} + +#[test] +#[should_panic(expected = "Argument short must be unique\n\n\t'-h' is already in use")] +fn arg_short_conflict_with_help_mut_arg() { + let _ = App::new("conflict") + .arg(Arg::with_name("home").short('h')) + .mut_arg("help", |h| h.short('h')) + .try_get_matches_from(vec![""]); +} + #[test] fn last_arg_mult_usage() { let app = App::new("last") diff --git a/tests/unique_args.rs b/tests/unique_args.rs index 5b8ae149..754b6dc2 100644 --- a/tests/unique_args.rs +++ b/tests/unique_args.rs @@ -3,7 +3,7 @@ use clap::{App, Arg}; // This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Arg names must be unique")] +#[should_panic(expected = "Argument name must be unique")] fn unique_arg_names() { let _ = App::new("some") .args(&[ From f632aedc72457560af4b4be4c26cb99e5215f42a Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 9 Apr 2020 12:20:46 +0200 Subject: [PATCH 2/6] Started on arg asserts --- src/build/app/mod.rs | 15 +++++++- src/build/arg/mod.rs | 18 ++++++++++ tests/arg_conflicts.rs | 52 ---------------------------- tests/conflicts.rs | 77 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 53 deletions(-) delete mode 100644 tests/arg_conflicts.rs diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 45164c38..611603a2 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -1454,9 +1454,9 @@ impl<'b> App<'b> { } } - debug_assert!(self._debug_asserts()); self.args._build(); self.settings.set(AppSettings::Built); + debug_assert!(self._debug_asserts()); } fn _panic_on_missing_help(&self, help_required_globally: bool) { @@ -1488,6 +1488,8 @@ impl<'b> App<'b> { debugln!("App::_debug_asserts;"); for arg in &self.args.args { + debug_assert!(arg._debug_asserts()); + // Name conflicts assert!( self.args.args.iter().filter(|x| x.id == arg.id).count() < 2, @@ -1528,6 +1530,17 @@ impl<'b> App<'b> { ); } + // blacklist + if let Some(reqs) = &arg.blacklist { + for req in reqs { + assert!( + self.args.args.iter().any(|x| x.id == *req), + "Argument specified in 'conflicts_with*' for '{}' does not exist", + arg.name, + ); + } + } + if arg.is_set(ArgSettings::Last) { assert!( arg.long.is_none(), diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 892dc989..219b5180 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -107,6 +107,7 @@ impl<'help> Arg<'help> { ..Default::default() } } + /// Creates a new instance of [`Arg`] using a unique string name. The name will be used to get /// information about whether or not the argument was used at runtime, get values, set /// relationships with other args, etc.. @@ -4132,6 +4133,23 @@ impl<'help> Arg<'help> { } } +impl<'a> Arg<'a> { + pub(crate) fn _debug_asserts(&self) -> bool { + debugln!("Arg::_debug_asserts:{};", self.name); + + // Self conflict + if let Some(vec) = &self.blacklist { + assert!( + !vec.iter().any(|&x| x == self.id), + "Argument '{}' cannot conflict with itself", + self.name, + ); + } + + true + } +} + impl<'help, 'z> From<&'z Arg<'help>> for Arg<'help> { fn from(a: &'z Arg<'help>) -> Self { a.clone() diff --git a/tests/arg_conflicts.rs b/tests/arg_conflicts.rs deleted file mode 100644 index 28acb97f..00000000 --- a/tests/arg_conflicts.rs +++ /dev/null @@ -1,52 +0,0 @@ -use clap::{App, Arg}; - -#[test] -fn two_conflicting_arguments() { - let a = App::new("two_conflicting_arguments") - .arg( - Arg::with_name("develop") - .long("develop") - .conflicts_with("production"), - ) - .arg( - Arg::with_name("production") - .long("production") - .conflicts_with("develop"), - ) - .try_get_matches_from(vec!["", "--develop", "--production"]); - - assert!(a.is_err()); - let a = a.unwrap_err(); - assert_eq!( - a.cause, - "The argument \'--develop\' cannot be used with \'--production\'" - ); -} - -#[test] -fn three_conflicting_arguments() { - let a = App::new("two_conflicting_arguments") - .arg( - Arg::with_name("one") - .long("one") - .conflicts_with_all(&["two", "three"]), - ) - .arg( - Arg::with_name("two") - .long("two") - .conflicts_with_all(&["one", "three"]), - ) - .arg( - Arg::with_name("three") - .long("three") - .conflicts_with_all(&["one", "two"]), - ) - .try_get_matches_from(vec!["", "--one", "--two", "--three"]); - - assert!(a.is_err()); - let a = a.unwrap_err(); - assert_eq!( - a.cause, - "The argument \'--one\' cannot be used with \'--two\'" - ); -} diff --git a/tests/conflicts.rs b/tests/conflicts.rs index d4b12da0..a1adbf32 100644 --- a/tests/conflicts.rs +++ b/tests/conflicts.rs @@ -127,3 +127,80 @@ fn conflict_with_unused_default_value() { assert_eq!(m.value_of("opt"), Some("default")); assert!(m.is_present("flag")); } + +#[test] +fn two_conflicting_arguments() { + let a = App::new("two_conflicting_arguments") + .arg( + Arg::with_name("develop") + .long("develop") + .conflicts_with("production"), + ) + .arg( + Arg::with_name("production") + .long("production") + .conflicts_with("develop"), + ) + .try_get_matches_from(vec!["", "--develop", "--production"]); + + assert!(a.is_err()); + let a = a.unwrap_err(); + assert_eq!( + a.cause, + "The argument \'--develop\' cannot be used with \'--production\'" + ); +} + +#[test] +fn three_conflicting_arguments() { + let a = App::new("two_conflicting_arguments") + .arg( + Arg::with_name("one") + .long("one") + .conflicts_with_all(&["two", "three"]), + ) + .arg( + Arg::with_name("two") + .long("two") + .conflicts_with_all(&["one", "three"]), + ) + .arg( + Arg::with_name("three") + .long("three") + .conflicts_with_all(&["one", "two"]), + ) + .try_get_matches_from(vec!["", "--one", "--two", "--three"]); + + assert!(a.is_err()); + let a = a.unwrap_err(); + assert_eq!( + a.cause, + "The argument \'--one\' cannot be used with \'--two\'" + ); +} + +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument 'config' cannot conflict with itself")] +fn self_conflicting_arg() { + let _ = App::new("prog") + .arg( + Arg::with_name("config") + .long("config") + .conflicts_with("config"), + ) + .try_get_matches_from(vec!["", "--config"]); +} + +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument specified in 'conflicts_with*' for 'config' does not exist")] +fn conflicts_with_invalid_arg() { + let _ = App::new("prog") + .arg( + Arg::with_name("config") + .long("config") + .conflicts_with("extra"), + ) + .try_get_matches_from(vec!["", "--config"]); +} From 00a0b9660a9d6b30984c64f27a3975194fcd8087 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 9 Apr 2020 14:03:52 +0200 Subject: [PATCH 3/6] Assert for require* on args --- src/build/app/mod.rs | 37 +++++++++++++++++++++++++++++++--- src/build/arg/mod.rs | 18 ++++++----------- tests/require.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 611603a2..6aa869b8 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -1523,13 +1523,44 @@ impl<'b> App<'b> { } else { acc }) < 2, - "Argument '{}' has the same index as another positional \ - argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \ - positional argument to take multiple values", + "Argument '{}' has the same index as another positional argument\n\n\t \ + Use Arg::setting(ArgSettings::MultipleValues) to allow one \ + positional argument to take multiple values", arg.name ); } + // requires, r_if, r_unless + if let Some(reqs) = &arg.requires { + for req in reqs { + assert!( + self.args.args.iter().any(|x| x.id == req.1), + "Argument specified in 'requires*' for '{}' does not exist", + arg.name, + ); + } + } + + if let Some(reqs) = &arg.r_ifs { + for req in reqs { + assert!( + self.args.args.iter().any(|x| x.id == req.0), + "Argument specified in 'required_if*' for '{}' does not exist", + arg.name, + ); + } + } + + if let Some(reqs) = &arg.r_unless { + for req in reqs { + assert!( + self.args.args.iter().any(|x| x.id == *req), + "Argument specified in 'required_unless*' for '{}' does not exist", + arg.name, + ); + } + } + // blacklist if let Some(reqs) = &arg.blacklist { for req in reqs { diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 219b5180..d0afd78b 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -64,10 +64,11 @@ pub struct Arg<'help> { #[doc(hidden)] pub blacklist: Option>, pub(crate) settings: ArgFlags, - pub(crate) r_unless: Option>, pub(crate) overrides: Option>, pub(crate) groups: Option>, pub(crate) requires: Option, Id)>>, + pub(crate) r_ifs: Option>, + pub(crate) r_unless: Option>, #[doc(hidden)] pub short: Option, #[doc(hidden)] @@ -90,7 +91,6 @@ pub struct Arg<'help> { pub(crate) terminator: Option<&'help str>, #[doc(hidden)] pub index: Option, - pub(crate) r_ifs: Option>, #[doc(hidden)] pub help_heading: Option<&'help str>, pub(crate) global: bool, @@ -1114,13 +1114,11 @@ impl<'help> Arg<'help> { /// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [override]: ./struct.Arg.html#method.overrides_with pub fn requires(mut self, arg_id: T) -> Self { - let name = arg_id.key(); + let arg = arg_id.key(); if let Some(ref mut vec) = self.requires { - vec.push((None, name)); + vec.push((None, arg)); } else { - let mut vec = vec![]; - vec.push((None, name)); - self.requires = Some(vec); + self.requires = Some(vec![(None, arg)]); } self } @@ -1496,11 +1494,7 @@ impl<'help> Arg<'help> { vec.push((None, s.key())); } } else { - let mut vec = vec![]; - for s in names { - vec.push((None, s.key())); - } - self.requires = Some(vec); + self.requires = Some(names.iter().map(|s| (None, s.key())).collect()); } self } diff --git a/tests/require.rs b/tests/require.rs index ae8f9a6a..3d39dba7 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -728,3 +728,51 @@ fn issue_1643_args_mutually_require_each_other() { app.get_matches_from(&["test", "-u", "hello", "-r", "farewell"]); } + +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument specified in 'requires*' for 'config' does not exist")] +fn requires_invalid_arg() { + let _ = App::new("prog") + .arg(Arg::with_name("config").requires("extra").long("config")) + .try_get_matches_from(vec!["", "--config"]); +} + +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument specified in 'requires*' for 'config' does not exist")] +fn requires_if_invalid_arg() { + let _ = App::new("prog") + .arg( + Arg::with_name("config") + .requires_if("val", "extra") + .long("config"), + ) + .try_get_matches_from(vec!["", "--config"]); +} + +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument specified in 'required_if*' for 'config' does not exist")] +fn required_if_invalid_arg() { + let _ = App::new("prog") + .arg( + Arg::with_name("config") + .required_if("extra", "val") + .long("config"), + ) + .try_get_matches_from(vec!["", "--config"]); +} + +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument specified in 'required_unless*' for 'config' does not exist")] +fn required_unless_invalid_arg() { + let _ = App::new("prog") + .arg( + Arg::with_name("config") + .required_unless("extra") + .long("config"), + ) + .try_get_matches_from(vec![""]); +} From 92449a47776fa43142d60c4b8226fcab6d7d0084 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 9 Apr 2020 16:21:45 +0200 Subject: [PATCH 4/6] Assert arg groups --- src/build/app/mod.rs | 41 ++++++++++++++++++++++++++--------------- tests/groups.rs | 38 +++++++++++++++++++++++++++++++------- tests/unique_args.rs | 9 +++------ 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 6aa869b8..c6c4a2e6 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -1494,7 +1494,7 @@ impl<'b> App<'b> { assert!( self.args.args.iter().filter(|x| x.id == arg.id).count() < 2, "Argument name must be unique\n\n\t'{}' is already in use", - arg.id, + arg.name, ); // Long conflicts @@ -1592,22 +1592,33 @@ impl<'b> App<'b> { ); } + for group in &self.groups { + // Name conflicts + assert!( + self.groups.iter().filter(|x| x.id == group.id).count() < 2, + "Argument group name must be unique\n\n\t'{}' is already in use", + group.name, + ); + + // Groups should not have naming conflicts with Args + assert!( + !self.args.args.iter().any(|x| x.id == group.id), + "Argument group name '{}' must not conflict with argument name", + group.name, + ); + + // Args listed inside groups should exist + for arg in &group.args { + assert!( + self.args.args.iter().any(|x| x.id == *arg), + "Argument group '{}' contains non-existent argument", + group.name, + ) + } + } + self._panic_on_missing_help(self.g_settings.is_set(AppSettings::HelpRequired)); - // * Args listed inside groups should exist - // * Groups should not have naming conflicts with Args - - // * Will be removed as a part of removing String types - // let g = groups!(self).find(|g| { - // g.args - // .iter() - // .any(|arg| !(find!(self, arg).is_some() || groups!(self).any(|g| &g.name == arg))) - // }); - // assert!( - // g.is_none(), - // "The group '{}' contains an arg that doesn't exist or has a naming conflict with a group.", - // g.unwrap().name - // ); true } diff --git a/tests/groups.rs b/tests/groups.rs index be98602c..7200d663 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -41,14 +41,9 @@ fn required_group_missing_arg() { assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); } -// This tests a programmer error and will only succeed with debug_assertions -// #[cfg(debug_assertions)] -// TODO: Enable this +#[cfg(debug_assertions)] #[test] -// This used to provide a nice, programmer-friendly error. -// Now the error directs the programmer to file a bug report with clap. -// #[should_panic(expected = "The group 'req' contains the arg 'flg' that doesn't actually exist.")] -#[should_panic(expected = "internal error")] +#[should_panic(expected = "Argument group 'req' contains non-existent argument")] fn non_existing_arg() { let _ = App::new("group") .arg("-f, --flag 'some flag'") @@ -61,6 +56,35 @@ fn non_existing_arg() { .try_get_matches_from(vec![""]); } +#[cfg(debug_assertions)] +#[test] +#[should_panic(expected = "Argument group name must be unique\n\n\t'req' is already in use")] +fn unique_group_name() { + let _ = App::new("group") + .arg("-f, --flag 'some flag'") + .arg("-c, --color 'some other flag'") + .group(ArgGroup::with_name("req").args(&["flag"]).required(true)) + .group(ArgGroup::with_name("req").args(&["color"]).required(true)) + .try_get_matches_from(vec![""]); +} + +#[test] +#[should_panic(expected = "Argument group name '' must not conflict with argument name")] +fn groups_with_name_of_arg_name() { + let _ = App::new("group") + .arg(Arg::with_name("a").long("a").group("a")) + .try_get_matches_from(vec!["", "--a"]); +} + +#[test] +#[should_panic(expected = "Argument group name 'a' must not conflict with argument name")] +fn arg_group_with_name_of_arg_name() { + let _ = App::new("group") + .arg(Arg::with_name("a").long("a").group("a")) + .group(ArgGroup::with_name("a")) + .try_get_matches_from(vec!["", "--a"]); +} + #[test] fn group_single_value() { let res = App::new("group") diff --git a/tests/unique_args.rs b/tests/unique_args.rs index 754b6dc2..cffa04b5 100644 --- a/tests/unique_args.rs +++ b/tests/unique_args.rs @@ -1,9 +1,8 @@ use clap::{App, Arg}; -// This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument name must be unique")] +#[should_panic(expected = "Argument name must be unique\n\n\t'arg1' is already in use")] fn unique_arg_names() { let _ = App::new("some") .args(&[ @@ -13,10 +12,9 @@ fn unique_arg_names() { .try_get_matches(); } -// This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument short must be unique")] +#[should_panic(expected = "Argument short must be unique\n\n\t'-a' is already in use")] fn unique_arg_shorts() { let _ = App::new("some") .args(&[ @@ -26,10 +24,9 @@ fn unique_arg_shorts() { .try_get_matches(); } -// This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument long must be unique")] +#[should_panic(expected = "Argument long must be unique\n\n\t'--long' is already in use")] fn unique_arg_longs() { let _ = App::new("some") .args(&[ From f0a216036bf0d167a590f5b2cc3566fab6cdf491 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 9 Apr 2020 18:19:05 +0200 Subject: [PATCH 5/6] Fix some issues --- .travis.yml | 1 - clap_derive/tests/flatten.rs | 1 + src/build/app/mod.rs | 21 +++++++++++++-------- src/build/app/settings.rs | 2 +- tests/conflicts.rs | 4 +++- tests/fixtures/app.yml | 2 +- tests/groups.rs | 2 ++ tests/help.rs | 13 +++++++++---- tests/macros.rs | 6 +++--- tests/require.rs | 12 ++++++++---- 10 files changed, 41 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index bf39ab1d..edc7de7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,6 @@ jobs: cache: false - name: Release profile tests script: - - cargo test --release --no-default-features - cargo test --release --features yaml unstable - name: Linting (fmt + clippy) before_script: diff --git a/clap_derive/tests/flatten.rs b/clap_derive/tests/flatten.rs index 1ccf257b..77f99add 100644 --- a/clap_derive/tests/flatten.rs +++ b/clap_derive/tests/flatten.rs @@ -36,6 +36,7 @@ fn flatten() { assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err()); } +#[cfg(debug_assertions)] #[test] #[should_panic] fn flatten_twice() { diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index c6c4a2e6..ddbc8e8d 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -1484,6 +1484,7 @@ impl<'b> App<'b> { } // Perform some expensive assertions on the Parser itself + #[allow(clippy::cognitive_complexity)] fn _debug_asserts(&self) -> bool { debugln!("App::_debug_asserts;"); @@ -1534,8 +1535,9 @@ impl<'b> App<'b> { if let Some(reqs) = &arg.requires { for req in reqs { assert!( - self.args.args.iter().any(|x| x.id == req.1), - "Argument specified in 'requires*' for '{}' does not exist", + self.args.args.iter().any(|x| x.id == req.1) + || self.groups.iter().any(|x| x.id == req.1), + "Argument or group specified in 'requires*' for '{}' does not exist", arg.name, ); } @@ -1544,8 +1546,9 @@ impl<'b> App<'b> { if let Some(reqs) = &arg.r_ifs { for req in reqs { assert!( - self.args.args.iter().any(|x| x.id == req.0), - "Argument specified in 'required_if*' for '{}' does not exist", + self.args.args.iter().any(|x| x.id == req.0) + || self.groups.iter().any(|x| x.id == req.0), + "Argument or group specified in 'required_if*' for '{}' does not exist", arg.name, ); } @@ -1554,8 +1557,9 @@ impl<'b> App<'b> { if let Some(reqs) = &arg.r_unless { for req in reqs { assert!( - self.args.args.iter().any(|x| x.id == *req), - "Argument specified in 'required_unless*' for '{}' does not exist", + self.args.args.iter().any(|x| x.id == *req) + || self.groups.iter().any(|x| x.id == *req), + "Argument or group specified in 'required_unless*' for '{}' does not exist", arg.name, ); } @@ -1565,8 +1569,9 @@ impl<'b> App<'b> { if let Some(reqs) = &arg.blacklist { for req in reqs { assert!( - self.args.args.iter().any(|x| x.id == *req), - "Argument specified in 'conflicts_with*' for '{}' does not exist", + self.args.args.iter().any(|x| x.id == *req) + || self.groups.iter().any(|x| x.id == *req), + "Argument or group specified in 'conflicts_with*' for '{}' does not exist", arg.name, ); } diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs index a0edf7a0..364dff98 100644 --- a/src/build/app/settings.rs +++ b/src/build/app/settings.rs @@ -666,7 +666,7 @@ pub enum AppSettings { /// /// # Panics /// - /// ```rust,should_panic + /// ```rust,no_run /// # use clap::{App, Arg, AppSettings}; /// App::new("myapp") /// .setting(AppSettings::HelpRequired) diff --git a/tests/conflicts.rs b/tests/conflicts.rs index a1adbf32..33dc5d8c 100644 --- a/tests/conflicts.rs +++ b/tests/conflicts.rs @@ -194,7 +194,9 @@ fn self_conflicting_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument specified in 'conflicts_with*' for 'config' does not exist")] +#[should_panic( + expected = "Argument or group specified in 'conflicts_with*' for 'config' does not exist" +)] fn conflicts_with_invalid_arg() { let _ = App::new("prog") .arg( diff --git a/tests/fixtures/app.yml b/tests/fixtures/app.yml index 7d3759f7..2db04b68 100644 --- a/tests/fixtures/app.yml +++ b/tests/fixtures/app.yml @@ -9,7 +9,7 @@ args: short: h long: help help: prints help with a nonstandard description - - opt: + - option: short: o long: option multiple: true diff --git a/tests/groups.rs b/tests/groups.rs index 7200d663..0451f0fb 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -68,6 +68,7 @@ fn unique_group_name() { .try_get_matches_from(vec![""]); } +#[cfg(debug_assertions)] #[test] #[should_panic(expected = "Argument group name '' must not conflict with argument name")] fn groups_with_name_of_arg_name() { @@ -76,6 +77,7 @@ fn groups_with_name_of_arg_name() { .try_get_matches_from(vec!["", "--a"]); } +#[cfg(debug_assertions)] #[test] #[should_panic(expected = "Argument group name 'a' must not conflict with argument name")] fn arg_group_with_name_of_arg_name() { diff --git a/tests/help.rs b/tests/help.rs index 0da21e4c..fe281622 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -1184,6 +1184,7 @@ fn arg_short_conflict_with_help() { )); } +#[cfg(debug_assertions)] #[test] #[should_panic(expected = "Argument short must be unique\n\n\t'-h' is already in use")] fn arg_short_conflict_with_help_mut_arg() { @@ -1600,8 +1601,9 @@ fn issue_1487() { assert!(utils::compare_output(app, "ctest -h", ISSUE_1487, false)); } +#[cfg(debug_assertions)] #[test] -#[should_panic] +#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] fn help_required_but_not_given() { App::new("myapp") .setting(AppSettings::HelpRequired) @@ -1609,8 +1611,9 @@ fn help_required_but_not_given() { .get_matches(); } +#[cfg(debug_assertions)] #[test] -#[should_panic] +#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] fn help_required_but_not_given_settings_after_args() { App::new("myapp") .arg(Arg::with_name("foo")) @@ -1618,8 +1621,9 @@ fn help_required_but_not_given_settings_after_args() { .get_matches(); } +#[cfg(debug_assertions)] #[test] -#[should_panic] +#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] fn help_required_but_not_given_for_one_of_two_arguments() { App::new("myapp") .setting(AppSettings::HelpRequired) @@ -1641,8 +1645,9 @@ fn help_required_locally_but_not_given_for_subcommand() { .get_matches(); } +#[cfg(debug_assertions)] #[test] -#[should_panic] +#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] fn help_required_globally_but_not_given_for_subcommand() { App::new("myapp") .global_setting(AppSettings::HelpRequired) diff --git a/tests/macros.rs b/tests/macros.rs index d24e20ef..24744223 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -39,7 +39,7 @@ fn quoted_app_name() { (version: "0.1") (about: "tests clap library") (author: "Kevin K. ") - (@arg opt: -o --option +takes_value ... "tests options") + (@arg option: -o --option +takes_value ... "tests options") (@arg positional: index(1) "tests positionals") (@arg flag: -f --flag ... +global "tests flags") (@arg flag2: -F conflicts_with[flag] requires[option2] @@ -80,7 +80,7 @@ fn quoted_arg_long_name() { (version: "0.1") (about: "tests clap library") (author: "Kevin K. ") - (@arg opt: -o --option +takes_value ... "tests options") + (@arg option: -o --option +takes_value ... "tests options") (@arg positional: index(1) "tests positionals") (@arg flag: -f --flag ... +global "tests flags") (@arg flag2: -F conflicts_with[flag] requires[option2] @@ -118,7 +118,7 @@ fn quoted_arg_name() { (version: "0.1") (about: "tests clap library") (author: "Kevin K. ") - (@arg opt: -o --option +takes_value ... "tests options") + (@arg option: -o --option +takes_value ... "tests options") (@arg ("positional-arg"): index(1) "tests positionals") (@arg flag: -f --flag ... +global "tests flags") (@arg flag2: -F conflicts_with[flag] requires[option2] diff --git a/tests/require.rs b/tests/require.rs index 3d39dba7..37e11cbc 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -731,7 +731,7 @@ fn issue_1643_args_mutually_require_each_other() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument specified in 'requires*' for 'config' does not exist")] +#[should_panic(expected = "Argument or group specified in 'requires*' for 'config' does not exist")] fn requires_invalid_arg() { let _ = App::new("prog") .arg(Arg::with_name("config").requires("extra").long("config")) @@ -740,7 +740,7 @@ fn requires_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument specified in 'requires*' for 'config' does not exist")] +#[should_panic(expected = "Argument or group specified in 'requires*' for 'config' does not exist")] fn requires_if_invalid_arg() { let _ = App::new("prog") .arg( @@ -753,7 +753,9 @@ fn requires_if_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument specified in 'required_if*' for 'config' does not exist")] +#[should_panic( + expected = "Argument or group specified in 'required_if*' for 'config' does not exist" +)] fn required_if_invalid_arg() { let _ = App::new("prog") .arg( @@ -766,7 +768,9 @@ fn required_if_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument specified in 'required_unless*' for 'config' does not exist")] +#[should_panic( + expected = "Argument or group specified in 'required_unless*' for 'config' does not exist" +)] fn required_unless_invalid_arg() { let _ = App::new("prog") .arg( From 15edb69a0df2aab88c8c6afb2e13d4439ec19231 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Fri, 10 Apr 2020 00:33:16 +0200 Subject: [PATCH 6/6] Address review comments --- src/build/app/mod.rs | 10 +++++----- src/build/arg/mod.rs | 4 +--- tests/conflicts.rs | 6 ++---- tests/groups.rs | 8 ++++---- tests/help.rs | 10 +++++----- tests/multiple_values.rs | 12 ++++++------ tests/positionals.rs | 4 ++-- tests/require.rs | 12 ++++-------- tests/unique_args.rs | 6 +++--- 9 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index ddbc8e8d..79c49cc0 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -1456,7 +1456,9 @@ impl<'b> App<'b> { self.args._build(); self.settings.set(AppSettings::Built); - debug_assert!(self._debug_asserts()); + + #[cfg(debug_assertions)] + self._debug_asserts(); } fn _panic_on_missing_help(&self, help_required_globally: bool) { @@ -1485,11 +1487,11 @@ impl<'b> App<'b> { // Perform some expensive assertions on the Parser itself #[allow(clippy::cognitive_complexity)] - fn _debug_asserts(&self) -> bool { + fn _debug_asserts(&self) { debugln!("App::_debug_asserts;"); for arg in &self.args.args { - debug_assert!(arg._debug_asserts()); + arg._debug_asserts(); // Name conflicts assert!( @@ -1623,8 +1625,6 @@ impl<'b> App<'b> { } self._panic_on_missing_help(self.g_settings.is_set(AppSettings::HelpRequired)); - - true } pub(crate) fn _propagate(&mut self, prop: Propagation) { diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index d0afd78b..090057ec 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -4128,7 +4128,7 @@ impl<'help> Arg<'help> { } impl<'a> Arg<'a> { - pub(crate) fn _debug_asserts(&self) -> bool { + pub(crate) fn _debug_asserts(&self) { debugln!("Arg::_debug_asserts:{};", self.name); // Self conflict @@ -4139,8 +4139,6 @@ impl<'a> Arg<'a> { self.name, ); } - - true } } diff --git a/tests/conflicts.rs b/tests/conflicts.rs index 33dc5d8c..e3b31c27 100644 --- a/tests/conflicts.rs +++ b/tests/conflicts.rs @@ -181,7 +181,7 @@ fn three_conflicting_arguments() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument 'config' cannot conflict with itself")] +#[should_panic = "Argument 'config' cannot conflict with itself"] fn self_conflicting_arg() { let _ = App::new("prog") .arg( @@ -194,9 +194,7 @@ fn self_conflicting_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic( - expected = "Argument or group specified in 'conflicts_with*' for 'config' does not exist" -)] +#[should_panic = "Argument or group specified in 'conflicts_with*' for 'config' does not exist"] fn conflicts_with_invalid_arg() { let _ = App::new("prog") .arg( diff --git a/tests/groups.rs b/tests/groups.rs index 0451f0fb..46265e1a 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -43,7 +43,7 @@ fn required_group_missing_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument group 'req' contains non-existent argument")] +#[should_panic = "Argument group 'req' contains non-existent argument"] fn non_existing_arg() { let _ = App::new("group") .arg("-f, --flag 'some flag'") @@ -58,7 +58,7 @@ fn non_existing_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument group name must be unique\n\n\t'req' is already in use")] +#[should_panic = "Argument group name must be unique\n\n\t'req' is already in use"] fn unique_group_name() { let _ = App::new("group") .arg("-f, --flag 'some flag'") @@ -70,7 +70,7 @@ fn unique_group_name() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument group name '' must not conflict with argument name")] +#[should_panic = "Argument group name '' must not conflict with argument name"] fn groups_with_name_of_arg_name() { let _ = App::new("group") .arg(Arg::with_name("a").long("a").group("a")) @@ -79,7 +79,7 @@ fn groups_with_name_of_arg_name() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument group name 'a' must not conflict with argument name")] +#[should_panic = "Argument group name 'a' must not conflict with argument name"] fn arg_group_with_name_of_arg_name() { let _ = App::new("group") .arg(Arg::with_name("a").long("a").group("a")) diff --git a/tests/help.rs b/tests/help.rs index fe281622..16985e0a 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -1186,7 +1186,7 @@ fn arg_short_conflict_with_help() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument short must be unique\n\n\t'-h' is already in use")] +#[should_panic = "Argument short must be unique\n\n\t'-h' is already in use"] fn arg_short_conflict_with_help_mut_arg() { let _ = App::new("conflict") .arg(Arg::with_name("home").short('h')) @@ -1603,7 +1603,7 @@ fn issue_1487() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] +#[should_panic = "AppSettings::HelpRequired is enabled for the App"] fn help_required_but_not_given() { App::new("myapp") .setting(AppSettings::HelpRequired) @@ -1613,7 +1613,7 @@ fn help_required_but_not_given() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] +#[should_panic = "AppSettings::HelpRequired is enabled for the App"] fn help_required_but_not_given_settings_after_args() { App::new("myapp") .arg(Arg::with_name("foo")) @@ -1623,7 +1623,7 @@ fn help_required_but_not_given_settings_after_args() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] +#[should_panic = "AppSettings::HelpRequired is enabled for the App"] fn help_required_but_not_given_for_one_of_two_arguments() { App::new("myapp") .setting(AppSettings::HelpRequired) @@ -1647,7 +1647,7 @@ fn help_required_locally_but_not_given_for_subcommand() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "AppSettings::HelpRequired is enabled for the App")] +#[should_panic = "AppSettings::HelpRequired is enabled for the App"] fn help_required_globally_but_not_given_for_subcommand() { App::new("myapp") .global_setting(AppSettings::HelpRequired) diff --git a/tests/multiple_values.rs b/tests/multiple_values.rs index 616f5ea5..4e5a9440 100644 --- a/tests/multiple_values.rs +++ b/tests/multiple_values.rs @@ -964,10 +964,10 @@ fn req_delimiter_complex() { // This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "When using a positional argument with \ +#[should_panic = "When using a positional argument with \ .multiple(true) that is *not the last* positional argument, the last \ positional argument (i.e the one with the highest index) *must* have \ -.required(true) or .last(true) set.")] +.required(true) or .last(true) set."] fn low_index_positional_not_required() { let _ = App::new("lip") .arg( @@ -983,8 +983,8 @@ fn low_index_positional_not_required() { // This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Only one positional argument with .multiple(true) \ -set is allowed per command, unless the second one also has .last(true) set")] +#[should_panic = "Only one positional argument with .multiple(true) \ +set is allowed per command, unless the second one also has .last(true) set"] fn low_index_positional_last_multiple_too() { let _ = App::new("lip") .arg( @@ -1005,8 +1005,8 @@ fn low_index_positional_last_multiple_too() { // This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Only the last positional argument, or second to \ -last positional argument may be set to .multiple(true)")] +#[should_panic = "Only the last positional argument, or second to \ +last positional argument may be set to .multiple(true)"] fn low_index_positional_too_far_back() { let _ = App::new("lip") .arg( diff --git a/tests/positionals.rs b/tests/positionals.rs index 54c3584a..ff3e00c9 100644 --- a/tests/positionals.rs +++ b/tests/positionals.rs @@ -219,8 +219,8 @@ fn single_positional_required_usage_string() { // This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Found positional argument which is not required \ -with a lower index than a required positional argument")] +#[should_panic = "Found positional argument which is not required \ +with a lower index than a required positional argument"] fn missing_required() { let _ = App::new("test") .arg("[FILE1] 'some file'") diff --git a/tests/require.rs b/tests/require.rs index 37e11cbc..607d47d2 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -731,7 +731,7 @@ fn issue_1643_args_mutually_require_each_other() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument or group specified in 'requires*' for 'config' does not exist")] +#[should_panic = "Argument or group specified in 'requires*' for 'config' does not exist"] fn requires_invalid_arg() { let _ = App::new("prog") .arg(Arg::with_name("config").requires("extra").long("config")) @@ -740,7 +740,7 @@ fn requires_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument or group specified in 'requires*' for 'config' does not exist")] +#[should_panic = "Argument or group specified in 'requires*' for 'config' does not exist"] fn requires_if_invalid_arg() { let _ = App::new("prog") .arg( @@ -753,9 +753,7 @@ fn requires_if_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic( - expected = "Argument or group specified in 'required_if*' for 'config' does not exist" -)] +#[should_panic = "Argument or group specified in 'required_if*' for 'config' does not exist"] fn required_if_invalid_arg() { let _ = App::new("prog") .arg( @@ -768,9 +766,7 @@ fn required_if_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic( - expected = "Argument or group specified in 'required_unless*' for 'config' does not exist" -)] +#[should_panic = "Argument or group specified in 'required_unless*' for 'config' does not exist"] fn required_unless_invalid_arg() { let _ = App::new("prog") .arg( diff --git a/tests/unique_args.rs b/tests/unique_args.rs index cffa04b5..758731c1 100644 --- a/tests/unique_args.rs +++ b/tests/unique_args.rs @@ -2,7 +2,7 @@ use clap::{App, Arg}; #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument name must be unique\n\n\t'arg1' is already in use")] +#[should_panic = "Argument name must be unique\n\n\t'arg1' is already in use"] fn unique_arg_names() { let _ = App::new("some") .args(&[ @@ -14,7 +14,7 @@ fn unique_arg_names() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument short must be unique\n\n\t'-a' is already in use")] +#[should_panic = "Argument short must be unique\n\n\t'-a' is already in use"] fn unique_arg_shorts() { let _ = App::new("some") .args(&[ @@ -26,7 +26,7 @@ fn unique_arg_shorts() { #[cfg(debug_assertions)] #[test] -#[should_panic(expected = "Argument long must be unique\n\n\t'--long' is already in use")] +#[should_panic = "Argument long must be unique\n\n\t'--long' is already in use"] fn unique_arg_longs() { let _ = App::new("some") .args(&[