Assert for require* on args

This commit is contained in:
Pavan Kumar Sunkara 2020-04-09 14:03:52 +02:00
parent f632aedc72
commit 00a0b9660a
3 changed files with 88 additions and 15 deletions

View file

@ -1523,13 +1523,44 @@ impl<'b> App<'b> {
} else { } else {
acc acc
}) < 2, }) < 2,
"Argument '{}' has the same index as another positional \ "Argument '{}' has the same index as another positional argument\n\n\t \
argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \ Use Arg::setting(ArgSettings::MultipleValues) to allow one \
positional argument to take multiple values", positional argument to take multiple values",
arg.name 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 // blacklist
if let Some(reqs) = &arg.blacklist { if let Some(reqs) = &arg.blacklist {
for req in reqs { for req in reqs {

View file

@ -64,10 +64,11 @@ pub struct Arg<'help> {
#[doc(hidden)] #[doc(hidden)]
pub blacklist: Option<Vec<Id>>, pub blacklist: Option<Vec<Id>>,
pub(crate) settings: ArgFlags, pub(crate) settings: ArgFlags,
pub(crate) r_unless: Option<Vec<Id>>,
pub(crate) overrides: Option<Vec<Id>>, pub(crate) overrides: Option<Vec<Id>>,
pub(crate) groups: Option<Vec<Id>>, pub(crate) groups: Option<Vec<Id>>,
pub(crate) requires: Option<Vec<(Option<&'help str>, Id)>>, pub(crate) requires: Option<Vec<(Option<&'help str>, Id)>>,
pub(crate) r_ifs: Option<Vec<(Id, &'help str)>>,
pub(crate) r_unless: Option<Vec<Id>>,
#[doc(hidden)] #[doc(hidden)]
pub short: Option<char>, pub short: Option<char>,
#[doc(hidden)] #[doc(hidden)]
@ -90,7 +91,6 @@ pub struct Arg<'help> {
pub(crate) terminator: Option<&'help str>, pub(crate) terminator: Option<&'help str>,
#[doc(hidden)] #[doc(hidden)]
pub index: Option<u64>, pub index: Option<u64>,
pub(crate) r_ifs: Option<Vec<(Id, &'help str)>>,
#[doc(hidden)] #[doc(hidden)]
pub help_heading: Option<&'help str>, pub help_heading: Option<&'help str>,
pub(crate) global: bool, pub(crate) global: bool,
@ -1114,13 +1114,11 @@ impl<'help> Arg<'help> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with /// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires<T: Key>(mut self, arg_id: T) -> Self { pub fn requires<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key(); let arg = arg_id.key();
if let Some(ref mut vec) = self.requires { if let Some(ref mut vec) = self.requires {
vec.push((None, name)); vec.push((None, arg));
} else { } else {
let mut vec = vec![]; self.requires = Some(vec![(None, arg)]);
vec.push((None, name));
self.requires = Some(vec);
} }
self self
} }
@ -1496,11 +1494,7 @@ impl<'help> Arg<'help> {
vec.push((None, s.key())); vec.push((None, s.key()));
} }
} else { } else {
let mut vec = vec![]; self.requires = Some(names.iter().map(|s| (None, s.key())).collect());
for s in names {
vec.push((None, s.key()));
}
self.requires = Some(vec);
} }
self self
} }

View file

@ -728,3 +728,51 @@ fn issue_1643_args_mutually_require_each_other() {
app.get_matches_from(&["test", "-u", "hello", "-r", "farewell"]); 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![""]);
}