From 00a0b9660a9d6b30984c64f27a3975194fcd8087 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 9 Apr 2020 14:03:52 +0200 Subject: [PATCH] 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![""]); +}