From 1fbe26cf479f4a93a103cbfd9c9f7f4e4c9d40a5 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Thu, 21 Jan 2016 23:18:52 -0500 Subject: [PATCH] tests(v2): fixing more tests on the new v2 base --- examples/01c_quick_example.rs | 5 +- examples/12_typed_values.rs | 4 +- examples/13b_enum_values_manual.rs | 2 +- examples/18_builder_macro.rs | 6 +- src/app/macros.rs | 34 ++++-- src/app/mod.rs | 4 +- src/app/parser.rs | 178 +++++++++++++++++------------ src/app/settings.rs | 34 +++--- src/args/arg.rs | 12 +- src/args/group.rs | 2 +- src/errors.rs | 76 +++++++----- src/lib.rs | 2 +- src/macros.rs | 168 ++++++++++++++++++++------- src/osstringext.rs | 2 +- tests/groups.rs | 12 +- tests/multiple_values.rs | 30 ++--- tests/opts.rs | 33 ++++-- tests/positionals.rs | 6 +- tests/unicode.rs | 10 +- 19 files changed, 393 insertions(+), 227 deletions(-) diff --git a/examples/01c_quick_example.rs b/examples/01c_quick_example.rs index 77c5da228c7..24c1b892555 100644 --- a/examples/01c_quick_example.rs +++ b/examples/01c_quick_example.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate clap; -#[cfg(feature = "nightly")] +#[cfg(feature = "unstable")] fn main() { // This example shows how to create an application with several arguments using macro builder. // It combines the simplicity of the from_usage methods and the performance of the Builder Pattern. @@ -74,3 +74,6 @@ fn main() { // more program logic goes here... } + +#[cfg(not(feature = "unstable"))] +fn main() {} diff --git a/examples/12_typed_values.rs b/examples/12_typed_values.rs index e42690b4b46..647f09705ac 100644 --- a/examples/12_typed_values.rs +++ b/examples/12_typed_values.rs @@ -38,13 +38,13 @@ fn main() { // // Using other methods such as unwrap_or_else(|e| println!("{}",e)) // are possible too. - let len = value_t!(matches.value_of("len"), u32).unwrap_or(10); + let len = value_t!(matches, "len", u32).unwrap_or(10); println!("len ({}) + 2 = {}", len, len + 2); // This code loops through all the values provided to "seq" and adds 2 // If seq fails to parse, the program exits, you don't have an option - for v in value_t_or_exit!(matches.values_of("seq"), u32) { + for v in values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()) { println!("Sequence part {} + 2: {}", v, v + 2); } } diff --git a/examples/13b_enum_values_manual.rs b/examples/13b_enum_values_manual.rs index 54bebed1036..e378d11723e 100644 --- a/examples/13b_enum_values_manual.rs +++ b/examples/13b_enum_values_manual.rs @@ -43,7 +43,7 @@ fn main() { .possible_values(&enum_vals)) .get_matches(); - let t = value_t!(m.value_of("type"), Vals).or_else(|e| e.exit()); + let t = value_t!(m, "type", Vals).unwrap_or_else(|e| e.exit()); // Now we can use our enum like normal. match t { diff --git a/examples/18_builder_macro.rs b/examples/18_builder_macro.rs index 67db5de7925..d139e7710d3 100644 --- a/examples/18_builder_macro.rs +++ b/examples/18_builder_macro.rs @@ -4,7 +4,7 @@ extern crate clap; // Note, there isn't a need for "use clap::{ ... };" Because the clap_app! macro uses // $crate:: internally -#[cfg(feature = "nightly")] +#[cfg(feature = "unstable")] fn main() { // Validation example testing that a file exists @@ -80,6 +80,8 @@ fn main() { } } - // Continued program logic goes here... } + +#[cfg(not(feature = "unstable"))] +fn main() {} diff --git a/src/app/macros.rs b/src/app/macros.rs index d9ad93eb9ca..f982afd3ffb 100644 --- a/src/app/macros.rs +++ b/src/app/macros.rs @@ -56,40 +56,51 @@ macro_rules! arg_post_processing( ($me:ident, $arg:ident, $matcher:ident) => ({ use args::AnyArg; // Handle POSIX overrides + debug!("Is '{}' in overrides...", $arg.to_string()); if $me.overrides.contains(&$arg.name()) { - if let Some(ref name) = $me.overriden_from(&*$arg.name(), $matcher) { + if let Some(ref name) = $me.overriden_from($arg.name(), $matcher) { + sdebugln!("Yes by {}", name); $matcher.remove(name); remove_overriden!($me, name); } - } + } else { sdebugln!("No"); } + + // Add overrides + debug!("Does '{}' have overrides...", $arg.to_string()); if let Some(or) = $arg.overrides() { for pa in or { + sdebugln!("\tYes '{}'", pa); $matcher.remove(&*pa); remove_overriden!($me, pa); $me.overrides.push(pa); vec_remove!($me.required, pa); } - } + } else { sdebugln!("No"); } + // Handle conflicts + debugln!("Does '{}' have conflicts...", $arg.to_string()); if let Some(bl) = $arg.blacklist() { for name in bl { + sdebugln!("\tYes '{}'", name); $me.blacklist.push(name); vec_remove!($me.overrides, name); vec_remove!($me.required, name); } - } + } else { sdebugln!("No"); } // Add all required args which aren't already found in matcher to the master // list + debug!("Does '{}' have requirements...", $arg.to_string()); if let Some(reqs) = $arg.requires() { for n in reqs { - if $matcher.contains(&*n) { + if $matcher.contains(&n) { + sdebugln!("\tYes '{}' but it's already met", n); continue; - } + } else { sdebugln!("\tYes '{}'", n); } $me.required.push(n); } - } + } else { sdebugln!("No"); } _handle_group_reqs!($me, $arg); }) @@ -128,3 +139,12 @@ macro_rules! _handle_group_reqs{ } }) } + +macro_rules! validate_multiples { + ($_self:ident, $a:ident, $m:ident) => { + if $m.contains(&$a.name) && !$a.settings.is_set(ArgSettings::Multiple) { + // Not the first time, and we don't allow multiples + return Err(Error::unexpected_multiple_usage($a, &*$_self.create_current_usage($m))) + } + }; +} diff --git a/src/app/mod.rs b/src/app/mod.rs index e9243163f8a..cba3455aa8e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -423,8 +423,8 @@ impl<'a, 'b> App<'a, 'b> { /// # use clap::{App, Arg}; /// App::new("myprog") /// .args( - /// vec![Arg::from_usage("[debug] -d 'turns on debugging info"), - /// Arg::with_name("input").index(1).help("the input file to use")] + /// &[Arg::from_usage("[debug] -d 'turns on debugging info"), + /// Arg::with_name("input").index(1).help("the input file to use")] /// ) /// # ; /// ``` diff --git a/src/app/parser.rs b/src/app/parser.rs index 18a597451f3..2a692e542dc 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -34,7 +34,7 @@ pub struct Parser<'a, 'b> where 'a: 'b { positionals: VecMap>, // A list of subcommands subcommands: Vec>, - groups: HashMap<&'b str, ArgGroup<'a>>, + groups: HashMap<&'a str, ArgGroup<'a>>, global_args: Vec>, overrides: Vec<&'b str>, help_short: Option, @@ -491,7 +491,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { if let Some(p) = self.positionals.get(&pos_counter) { - try!(self.validate_arg(p, matcher)); + validate_multiples!(self, p, matcher); try!(self.add_val_to_arg(p, &arg_os, matcher)); @@ -640,21 +640,21 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { for k in matcher.arg_names() { if let Some(f) = self.flags.iter().filter(|f| &f.name == &k).next() { if let Some(ref bl) = f.blacklist { - if bl.contains(&name.into()) { + if bl.contains(&name) { return Some(format!("{}", f)); } } } if let Some(o) = self.opts.iter().filter(|o| &o.name == &k).next() { if let Some(ref bl) = o.blacklist { - if bl.contains(&name.into()) { + if bl.contains(&name) { return Some(format!("{}", o)); } } } if let Some(pos) = self.positionals.values().filter(|p| &p.name == &k).next() { if let Some(ref bl) = pos.blacklist { - if bl.contains(&name.into()) { + if bl.contains(&name) { return Some(format!("{}", pos)); } } @@ -691,12 +691,21 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { } fn groups_for_arg(&self, name: &str) -> Option> { + debugln!("fn=groups_for_arg;"); + if self.groups.is_empty() { + debugln!("No groups defined"); return None; } let mut res = vec![]; - for (_, grp) in &self.groups { - res.extend(grp.args.iter().filter(|&g| g == &name).map(|&g| g).collect::>()); + debugln!("Searching through groups..."); + for (gn, grp) in &self.groups { + for a in &grp.args { + if a == &name { + sdebugln!("\tFound '{}'", gn); + res.push(*gn); + } + } } if res.is_empty() { return None; @@ -841,19 +850,23 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { } fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> { + debug!("Checking if --{} is help or version...", arg.to_str().unwrap()); if arg == "help" && self.settings.is_set(AppSettings::NeedsLongHelp) { try!(self._help()); } if arg == "version" && self.settings.is_set(AppSettings::NeedsLongVersion) { try!(self._version()); } + sdebugln!("Neither"); Ok(()) } fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> { + debug!("Checking if -{} is help or version...", arg); if let Some(h) = self.help_short { if arg == h { try!(self._help()); } } if let Some(v) = self.version_short { if arg == v { try!(self._version()); } } + sdebugln!("Neither"); Ok(()) } @@ -881,12 +894,16 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { matcher: &mut ArgMatcher<'a>, full_arg: &OsStr) -> ClapResult> { // maybe here lifetime should be 'a + debugln!("fn=parse_long_arg;"); let mut val = None; + debug!("Does it contain '='..."); let arg = if full_arg.contains_byte(b'=') { let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'='); + sdebugln!("Yes '{:?}'", p1); val = Some(p1); p0 } else { + sdebugln!("No"); full_arg.trim_left_matches(b'-') }; @@ -894,6 +911,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { .iter() .filter(|v| v.long.is_some() && &*v.long.unwrap() == arg) .next() { + debugln!("Found valid opt '{}'", opt.to_string()); let ret = try!(self.parse_opt(val, opt, matcher)); arg_post_processing!(self, opt, matcher); @@ -902,6 +920,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { .iter() .filter(|v| v.long.is_some() && &*v.long.unwrap() == arg) .next() { + debugln!("Found valid flag '{}'", flag.to_string()); // Only flags could be help or version, and we need to check the raw long // so this is the first point to check try!(self.check_for_help_and_version_str(&arg)); @@ -914,6 +933,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { return Ok(None); } + debugln!("Didn't match anything"); self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher).map(|_| None) } @@ -921,6 +941,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { matcher: &mut ArgMatcher<'a>, full_arg: &OsStr) -> ClapResult> { + debugln!("fn=parse_short_arg;"); // let mut utf8 = true; let arg_os = full_arg.trim_left_matches(b'-'); let arg = arg_os.to_string_lossy(); @@ -934,19 +955,24 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { .iter() .filter(|&v| v.short.is_some() && v.short.unwrap() == c) .next() { + debugln!("Found valid short opt -{} in '{}'", c, arg); // Check for trailing concatenated value - let val = { - let i = arg.splitn(2, c).next().unwrap().as_bytes().len() - 1; - full_arg.split_at(i).1 + let p: Vec<_> = arg.splitn(2, c).collect(); + let i = p[0].as_bytes().len(); + let val = if i != 0 { + Some(full_arg.split_at(i + 1).1) + } else { + None }; // Default to "we're expecting a value later" - let ret = try!(self.parse_opt(Some(val), opt, matcher)); + let ret = try!(self.parse_opt(val, opt, matcher)); arg_post_processing!(self, opt, matcher); return Ok(ret); } else if let Some(flag) = self.flags.iter().filter(|&v| v.short.is_some() && v.short.unwrap() == c).next() { + debugln!("Found valid short flag -{}", c); // Only flags can be help or version try!(self.check_for_help_and_version_char(c)); try!(self.parse_flag(flag, matcher)); @@ -969,26 +995,21 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { opt: &OptBuilder<'a, 'b>, matcher: &mut ArgMatcher<'a>) -> ClapResult> { - try!(self.validate_arg(opt, matcher)); - - if matcher.contains(&*opt.name) && !opt.settings.is_set(ArgSettings::Multiple) { - // Not the first time, but we don't allow multiples - return Err( - Error::unexpected_multiple_usage(opt, &*self.create_current_usage(matcher))); - } + debugln!("fn=parse_opt;"); + validate_multiples!(self, opt, matcher); - if val.is_none() || val.unwrap().len() == 0 { - if opt.is_set(ArgSettings::EmptyValues) { - try!(self.add_val_to_arg(opt, val.unwrap(), matcher)); - return Ok(None); + debug!("Checking for val..."); + if let Some(v) = val { + if !opt.is_set(ArgSettings::EmptyValues) && v.len() == 0 { + sdebugln!("Found Empty - Error"); + return Err(Error::empty_value(opt, &*self.create_current_usage(matcher))); } - return Err(Error::empty_value(opt, &*self.create_current_usage(matcher))); - } + sdebugln!("Found"); + try!(self.add_val_to_arg(opt, v, matcher)); + } else { sdebugln!("None"); } - // If it doesn't allow mutliples, (or a specific number of values), or we don't have any - // values yet, we want to return the name of this arg so the next arg is parsed as a value - // otherwise we're done getting values - if opt.settings.is_set(ArgSettings::Multiple) || opt.num_vals.is_some() || !matcher.contains(&*opt.name) { + if (opt.is_set(ArgSettings::Multiple) || opt.num_vals().is_some()) + || val.is_none() { return Ok(Some(opt.name)); } Ok(None) @@ -1077,79 +1098,88 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { } fn parse_flag(&self, flag: &FlagBuilder<'a, 'b>, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { - // Validate that we can actually accept this arg - try!(self.validate_arg(flag, matcher)); - - // First occurrence or not? - if !matcher.contains(&*flag.name) { - // If this is the first, then add this flag itself - matcher.insert(&*flag.name.clone()); - } else if !flag.settings.is_set(ArgSettings::Multiple) { - // Not the first time, but we don't allow multiples - return Err( - Error::unexpected_multiple_usage(flag, &*self.create_current_usage(matcher))); - } else { - matcher.inc_occurrence_of(&*flag.name.clone()); - } + debugln!("fn=parse_flag;"); + validate_multiples!(self, flag, matcher); + + matcher.inc_occurrence_of(&*flag.name.clone()); // Increment or create the group "args" - self.groups_for_arg(&*flag.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); + self.groups_for_arg(flag.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); Ok(()) } - fn validate_arg(&self, arg: &A, matcher: &mut ArgMatcher) -> ClapResult<()> - where A: AnyArg<'a, 'b> + Display { - // Ensure this arg isn't on the mutually excludes list - if self.blacklist.contains(&arg.name()) { - matcher.remove(&*arg.name()); - return Err( - Error::argument_conflict(arg, - self.blacklisted_from(&*arg.name(), &matcher), - &*self.create_current_usage(matcher))); - } - - // Make sure this isn't one being added multiple times if it doesn't support it - if matcher.contains(&*arg.name()) && !arg.is_set(ArgSettings::Multiple) { - return Err( - Error::unexpected_multiple_usage(arg, &*self.create_current_usage(matcher))); - } - - Ok(()) - } + // fn validate_arg(&self, arg: &A, matcher: &mut ArgMatcher) -> ClapResult<()> + // where A: AnyArg<'a, 'b> + Display { + // debugln!("fn=validate_arg;"); + // + // /* + // Might not be required if we validate the blacklist later on as well too... + // + // debug!("Can we use '{}'...", arg.to_string()); + // // Ensure this arg isn't on the mutually excludes list + // if self.blacklist.contains(&arg.name()) { + // sdebugln!("No"); + // matcher.remove(&*arg.name()); + // return Err( + // Error::argument_conflict(arg, + // self.blacklisted_from(&*arg.name(), &matcher), + // &*self.create_current_usage(matcher))); + // } + // sdebugln!("Yes"); + // */ + // + // // Make sure this isn't one being added multiple times if it doesn't support it + // if matcher.contains(&*arg.name()) && !arg.is_set(ArgSettings::Multiple) { + // return Err( + // Error::unexpected_multiple_usage(arg, &*self.create_current_usage(matcher))); + // } + // + // Ok(()) + // } fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { macro_rules! build_err { - ($me:ident, $name:ident, $matcher:ident) => ({ + ($me:ident, $name:expr, $matcher:ident) => ({ let c_with = $me.blacklisted_from($name, &$matcher); + debugln!("'{:?}' conflicts with '{}'", c_with, $name); let usg = $me.create_current_usage($matcher); - if let Some(f) = $me.flags.iter().filter(|f| &f.name == $name).next() { - + if let Some(f) = $me.flags.iter().filter(|f| f.name == $name).next() { + debugln!("It was a flag..."); Error::argument_conflict(f, c_with, &*usg) } else if let Some(o) = $me.opts.iter() - .filter(|o| &o.name == $name) + .filter(|o| o.name == $name) .next() { + debugln!("It was an option..."); Error::argument_conflict(o, c_with, &*usg) } else { match $me.positionals.values() - .filter(|p| p.name == *$name) + .filter(|p| p.name == $name) .next() { - Some(p) => Error::argument_conflict(p, c_with, &*usg), + Some(p) => { + debugln!("It was a positional..."); + Error::argument_conflict(p, c_with, &*usg) + }, None => panic!(INTERNAL_ERROR_MSG) } } }); } - for name in self.blacklist.iter() { - if matcher.contains(name) { - return Err(build_err!(self, name, matcher)); - } else if self.groups.contains_key(name) { + for name in &self.blacklist { + debugln!("Checking blacklisted name: {}", name); + if self.groups.contains_key(name) { + debugln!("groups contains it..."); for n in self.arg_names_in_group(name) { - if matcher.contains(&*n) { - return Err(build_err!(self, name, matcher)); + debugln!("Checking arg '{}' in group...", n); + if matcher.contains(&n) { + debugln!("matcher contains it..."); + return Err(build_err!(self, n, matcher)); } } + } else if matcher.contains(name) { + debugln!("matcher contains it..."); + return Err(build_err!(self, *name, matcher)); } } Ok(()) diff --git a/src/app/settings.rs b/src/app/settings.rs index 025d4d77bf8..d3a64555e80 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -268,9 +268,9 @@ pub enum AppSettings { /// let m = App::new("myprog") /// .setting(AppSettings::TrailingVarArg) /// .arg(Arg::from_usage("... 'commands to run'")) - /// .get_matches_from(vec!vec!["myprog", "some_command", "-r", "set"]); + /// .get_matches_from(vec!["myprog", "some_command", "-r", "set"]); /// - /// assert_eq!(m.values_of("cmd").unwrap(), &["some_command", "-r", "set"]); + /// assert_eq!(m.values_of("cmd").unwrap().collect::>(), &["some_command", "-r", "set"]); /// ``` TrailingVarArg, /// Specifies that the parser should not assume the first argument passed is the binary name. @@ -289,36 +289,40 @@ pub enum AppSettings { /// .arg(Arg::from_usage("... 'commands to run'")) /// .get_matches_from(vec!["some_command", "-r", "set"]); /// - /// assert_eq!(m.values_of("cmd").unwrap(), &["some_command", "-r", "set"]); + /// assert_eq!(m.values_of("cmd").unwrap().collect::>(), &["some_command", "-r", "set"]); /// ``` NoBinaryName, /// Specifies that an unexpected argument positional arguments which would otherwise cause a - /// `ErrorKind::UnexpectedArgument` error, should instead be treated as a subcommand in the + /// `ErrorKind::UnknownArgument` error, should instead be treated as a subcommand in the /// `ArgMatches` struct. /// /// **NOTE:** Use this setting with caution, as a truly unexpected argument (i.e. one that is - /// **NOT** an external subcommand, will not cause an error, and you shoud inform the user - /// appropriatly) + /// *NOT* an external subcommand) will not cause an error and instead be treatd as a potential + /// subcommand. You shoud inform the user appropriatly. /// /// # Examples /// /// ```no_run /// # use clap::{App, Arg, AppSettings}; - /// # use std::process::Command; - /// // Assume there is a third party subcommand installed to $PATH named myprog-subcmd + /// use std::process::{self, Command}; + /// + /// // Assume there is a third party subcommand named myprog-subcmd /// let m = App::new("myprog") /// .setting(AppSettings::AllowExternalSubcommands) - /// .get_matches_from(vec!vec!["myprog", "subcmd", "--option", "value"]); + /// .get_matches_from(vec!["myprog", "subcmd", "--option", "value"]); /// + /// // All trailing arguments will be stored under the subcommands sub-matches under a value + /// // of their runtime name (in this case "subcmd") /// match m.subcommand() { - /// ("", Some(sub_m)) => { - /// let unk_subcmd = sub_m.subcommand_name().unwrap(); - /// let cmd = Command::new(format!("myprog-{}", unk_subcmd)) - /// .args(sub_m.values_of(unk_subcmd).unwrap()); - /// let exit_status = cmd.status().unwrap_or_else(|e| { + /// (external, Some(ext_m)) => { + /// let args: Vec<&str> = ext_m.values_of(external).unwrap().collect(); + /// let exit_status = Command::new(format!("myprog-{}", external)) + /// .args(&*args) + /// .status() + /// .unwrap_or_else(|e| { /// // Invalid subcommand. Here you would probably inform the user and list valid /// // subcommands for them to try...but in this example we just panic! - /// panic!("failed to execute process: {}", e) + /// process::exit(1); /// }); /// }, /// _ => unreachable!() diff --git a/src/args/arg.rs b/src/args/arg.rs index 75c9931a34e..f93795db422 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -25,19 +25,15 @@ use usageparser::{UsageParser, UsageToken}; /// # Examples /// /// ```no_run -/// # use clap::{App, Arg}; -/// # let matches = App::new("myprog") -/// # .arg( +/// # use clap::Arg; /// // Using the traditional builder pattern and setting each option manually -/// Arg::with_name("config") +/// let cfg = Arg::with_name("config") /// .short("c") /// .long("config") /// .takes_value(true) -/// .help("Provides a config file to myprog") -/// # ).arg( +/// .help("Provides a config file to myprog"); /// // Using a usage string (setting a similar argument to the one above) -/// Arg::from_usage("-i --input=[input] 'Provides an input file to the program'") -/// # ).get_matches(); +/// let input = Arg::from_usage("-i --input=[input] 'Provides an input file to the program'"); #[allow(missing_debug_implementations)] pub struct Arg<'a, 'b> where 'a: 'b { /// The unique name of the argument diff --git a/src/args/group.rs b/src/args/group.rs index de994e83724..47bc9eaf9ae 100644 --- a/src/args/group.rs +++ b/src/args/group.rs @@ -334,7 +334,7 @@ mod test { .requires_all(&["r2", "r3"]) .requires("r4"); - let args = vec!["a1", "a2", "a3", "a4"]; + let args = vec!["a1", "a4", "a2", "a3"]; let reqs = vec!["r1", "r2", "r3", "r4"]; let confs = vec!["c1", "c2", "c3", "c4"]; diff --git a/src/errors.rs b/src/errors.rs index e7d0bfbc1b0..0662d8b0ca6 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -21,14 +21,14 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("speed") /// .possible_value("fast") /// .possible_value("slow")) - /// .get_matches_from_safe(vec!vec!["myprog", "other"]); + /// .get_matches_from_safe(vec!["myprog", "other"]); /// assert!(result.is_err()); - /// assert_eq!(result.unwrap_err(), Error::InvalidValue); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidValue); /// ``` InvalidValue, /// Occurs when a user provides a flag, option, or argument which wasn't defined @@ -36,10 +36,10 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::from_usage("--flag 'some flag'")) - /// .get_matches_from_safe(vec!vec!["myprog", "--other"]); + /// .get_matches_from_safe(vec!["myprog", "--other"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnknownArgument); /// ``` @@ -51,14 +51,14 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg, SubCommand}; + /// # use clap::{App, Arg, ErrorKind, SubCommand}; /// let result = App::new("myprog") /// .subcommand(SubCommand::with_name("config") /// .about("Used for configuration") /// .arg(Arg::with_name("config_file") /// .help("The configuration file to use") /// .index(1))) - /// .get_matches_from_safe(vec!vec!["myprog", "other"]); + /// .get_matches_from_safe(vec!["myprog", "other"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidSubcommand); /// ``` @@ -68,7 +68,7 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("color") /// .empty_values(false)) @@ -83,7 +83,7 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// fn is_numeric(val: String) -> Result<(), String> { /// match val.parse::() { /// Ok(..) => Ok(()), @@ -94,7 +94,7 @@ pub enum ErrorKind { /// let result = App::new("myprog") /// .arg(Arg::with_name("num") /// .validator(is_numeric)) - /// .get_matches_from_safe(vec!vec!["myprog", "NotANumber"]); + /// .get_matches_from_safe(vec!["myprog", "NotANumber"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::ValueValidation); /// ``` @@ -105,13 +105,13 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("some_opt") /// .long("opt") /// .takes_value(true) /// .max_values(2)) - /// .get_matches_from_safe(vec!vec!["myprog", "--opt", "too", "many", "values"]); + /// .get_matches_from_safe(vec!["myprog", "--opt", "too", "many", "values"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooManyValues); /// ``` @@ -122,12 +122,12 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("some_opt") /// .long("opt") /// .min_values(3)) - /// .get_matches_from_safe(vec!vec!["myprog", "--opt", "too", "few"]); + /// .get_matches_from_safe(vec!["myprog", "--opt", "too", "few"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooFewValues); /// ``` @@ -138,13 +138,13 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("some_opt") /// .long("opt") /// .takes_value(true) /// .number_of_values(2)) - /// .get_matches_from_safe(vec!vec!["myprog", "--opt", "wrong", "number", "of", "vals"]); + /// .get_matches_from_safe(vec!["myprog", "--opt", "wrong", "number", "of", "vals"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::WrongNumberOfValues); /// ``` @@ -154,14 +154,14 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("debug") /// .long("debug") /// .conflicts_with("color")) /// .arg(Arg::with_name("color") /// .long("color")) - /// .get_matches_from_safe(vec!vec!["myprog", "--debug", "--color"]); + /// .get_matches_from_safe(vec!["myprog", "--debug", "--color"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::ArgumentConflict); /// ``` @@ -171,7 +171,7 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("debug") /// .required(true)) @@ -186,7 +186,7 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// # use clap::{App, Arg, AppSettings, ErrorKind, SubCommand}; /// let result = App::new("myprog") /// .setting(AppSettings::SubcommandRequired) /// .subcommand(SubCommand::with_name("config") @@ -204,7 +204,7 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// # use clap::{App, Arg, AppSettings, ErrorKind, SubCommand}; /// let result = App::new("myprog") /// .setting(AppSettings::ArgRequiredElseHelp) /// .subcommand(SubCommand::with_name("config") @@ -222,11 +222,11 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .arg(Arg::with_name("debug") /// .multiple(false)) - /// .get_matches_from_safe(vec!vec!["myprog", "--debug", "--debug"]); + /// .get_matches_from_safe(vec!["myprog", "--debug", "--debug"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnexpectedMultipleUsage); /// ``` @@ -244,7 +244,7 @@ pub enum ErrorKind { /// # Examples /// /// ```ignore - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// # use std::os::unix::ffi::OsStringExt; /// # use std::ffi::OsString; /// let result = App::new("myprog") @@ -267,12 +267,11 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; - /// # use clap::ErrorType; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") - /// .get_matches_from_safe(vec!vec!["myprog", "--help"]); + /// .get_matches_from_safe(vec!["myprog", "--help"]); /// assert!(result.is_err()); - /// assert_eq!(result.unwrap_err().kind, ErrorType::HelpDisplayed); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::HelpDisplayed); /// ``` HelpDisplayed, /// Not a true "error" as it means `--version` or similar was used. The message will be sent @@ -281,14 +280,17 @@ pub enum ErrorKind { /// # Examples /// /// ```no_run - /// # use clap::{App, Arg}; - /// # use clap::ErrorType; + /// # use clap::{App, Arg, ErrorKind}; /// let result = App::new("myprog") /// .get_matches_from_safe(vec!["myprog", "--version"]); /// assert!(result.is_err()); - /// assert_eq!(result.unwrap_err().kind, ErrorType::VersionDisplayed); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::VersionDisplayed); /// ``` VersionDisplayed, + /// Occurs when using the `value_t!` and `values_t!` macros to convert an argument value into + /// type `T`, but the argument you requested wasn't used. I.e. you asked for an argument with + /// name `config` to be converted, but `config` wasn't used by the user. + ArgumentNotFound, /// Represents an I/O error, typically white writing to stderr or stdout Io, /// Represents an Rust Display Format error, typically white writing to stderr or stdout @@ -612,6 +614,18 @@ impl Error { info: Some(vec![a]), } } + + #[doc(hidden)] + pub fn argument_not_found(arg: A) -> Self + where A: Into, + { + let a = arg.into(); + Error { + message: format!("{} The argument '{}' wasn't found", Format::Error("error:"), a.clone()), + kind: ErrorKind::ArgumentNotFound, + info: Some(vec![a]), + } + } } impl StdError for Error { diff --git a/src/lib.rs b/src/lib.rs index ef812f9776d..648ca42f7be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -291,7 +291,7 @@ //! the `from_usage` //! methods and the performance of the Builder Pattern. //! -//! ```no_run +//! ```ignore //! // (Full example with detailed comments in examples/01c_quick_example.rs) //! // //! // This example demonstrates clap's "usage strings" method of creating diff --git a/src/macros.rs b/src/macros.rs index bb581b147a7..f30eb920b6d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -129,9 +129,9 @@ macro_rules! for_match { ($it:ident, $($p:pat => $($e:expr);+),*) => { for i in $it { match i { - $( - $p => { $($e)+ } - )* + $( + $p => { $($e)+ } + )* } } }; @@ -147,7 +147,6 @@ macro_rules! for_match { /// **NOTE:** Be cautious, as since this a macro invocation it's not exactly like /// standard syntax. /// -/// /// # Examples /// /// ```no_run @@ -158,22 +157,17 @@ macro_rules! for_match { /// let matches = App::new("myapp") /// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") /// .get_matches(); -/// let len = value_t!(matches.value_of("length"), u32) -/// .unwrap_or_else(|e|{ -/// println!("{}",e); -/// std::process::exit(1) -/// }); +/// +/// let len = value_t!(matches.value_of("length"), u32).unwrap_or_else(|e| e.exit()); +/// let also_len = value_t!(matches, "length", u32).unwrap_or_else(|e| e.exit()); /// /// println!("{} + 2: {}", len, len + 2); /// # } /// ``` #[macro_export] macro_rules! value_t { - (@callback $c:ident $m:ident.value_of($v:expr), $t:ty) => { - $c!($m.value_of($e), $t); - }; ($m:ident, $v:expr, $t:ty) => { - value_t!(@callback value_t $m.value_of($v), $t) + value_t!($m.value_of($v), $t) }; ($m:ident.value_of($v:expr), $t:ty) => { if let Some(v) = $m.value_of($v) { @@ -184,15 +178,56 @@ macro_rules! value_t { format!("The argument '{}' isn't a valid value", v))), } } else { - Err(::clap::Error::value_validation(format!("The argument '{}' was not found", $v))) + Err(::clap::Error::argument_not_found($v)) + } + }; +} + +/// Convenience macro getting a typed value `T` where `T` implements `std::str::FromStr` or +/// exiting upon error. +/// +/// **NOTE:** This macro is for backwards compatibility sake. Prefer +/// `value_t!(/* ... */).unwrap_or_else(|e| e.exit())` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") +/// .get_matches(); +/// +/// let len = value_t_or_exit!(matches.value_of("length"), u32); +/// let also_len = value_t_or_exit!(matches, "length", u32); +/// +/// println!("{} + 2: {}", len, len + 2); +/// # } +/// ``` +#[macro_export] +macro_rules! value_t_or_exit { + ($m:ident, $v:expr, $t:ty) => { + value_t!($m.value_of($v), $t) + }; + ($m:ident.value_of($v:expr), $t:ty) => { + if let Some(v) = $m.value_of($v) { + match v.parse::<$t>() { + Ok(val) => val, + Err(_) => + ::clap::Error::value_validation( + format!("The argument '{}' isn't a valid value", v)).exit(), + } + } else { + ::clap::Error::argument_not_found($v).exit() } }; } /// Convenience macro getting a typed value `T` where `T` implements `std::str::FromStr` -/// This macro returns a `Result` which allows you as the developer to decide -/// what you'd like to do on a failed parse. There are two types of errors, parse failures -/// and those where the argument wasn't present (such as a non-required argument). +/// This macro returns a `clap::Result` (`Result`) which allows you as the +/// developer to decide what you'd like to do on a failed parse. /// /// # Examples /// @@ -204,47 +239,92 @@ macro_rules! value_t { /// let matches = App::new("myapp") /// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") /// .get_matches(); -/// for v in value_t!(matches.values_of("seq"), u32) -/// .unwrap_or_else(|e|{ -/// println!("{}",e); -/// std::process::exit(1) -/// }) { +/// +/// let vals = values_t!(matches.values_of("seq"), u32).unwrap_or_else(|e| e.exit()); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// +/// let vals = values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()); +/// for v in &vals { /// println!("{} + 2: {}", v, v + 2); /// } /// # } /// ``` #[macro_export] macro_rules! values_t { - ($m:expr, $v:expr, $t:ty) => { + ($m:ident, $v:expr, $t:ty) => { values_t!($m.values_of($v), $t) }; ($m:ident.values_of($v:expr), $t:ty) => { - match $m { - Some(ref v) => values_t!(v, $t), - None => - Err(::clap::Error::value_validation(format!("The argument was not found", v))), - } - }; - ($v:ident, $t:ty) => { - let mut tmp = Vec::with_capacity($v.len()); - let mut err = None; - for pv in &$v { - match pv.parse::<$t>() { - Ok(rv) => tmp.push(rv), - Err(e) => { - err = Some(::clap::Error::value_validation( - format!("The argument '{}' isn't a valid value", v))); - break + if let Some(vals) = $m.values_of($v) { + let mut tmp = vec![]; + let mut err = None; + for pv in vals { + match pv.parse::<$t>() { + Ok(rv) => tmp.push(rv), + Err(..) => { + err = Some(::clap::Error::value_validation( + format!("The argument '{}' isn't a valid value", pv))); + break + } } } - } - match err { - Some(e) => Err(e), - None => Ok(tmp) + match err { + Some(e) => Err(e), + None => Ok(tmp), + } + } else { + Err(::clap::Error::argument_not_found($v)) } }; } +/// Convenience macro getting a typed value `T` where `T` implements `std::str::FromStr` or +/// exiting upon error. +/// +/// **NOTE:** This macro is for backwards compatibility sake. Prefer +/// `value_t!(/* ... */).unwrap_or_else(|e| e.exit())` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") +/// .get_matches(); +/// +/// let vals = values_t_or_exit!(matches.values_of("seq"), u32); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// +/// // type for example only +/// let vals: Vec = values_t_or_exit!(matches, "seq", u32); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// # } +/// ``` +#[macro_export] +macro_rules! values_t_or_exit { + ($m:ident, $v:expr, $t:ty) => { + values_t_or_exit!($m.values_of($v), $t) + }; + ($m:ident.values_of($v:expr), $t:ty) => { + if let Some(vals) = $m.values_of($v) { + vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{ + ::clap::Error::value_validation( + format!("One or more arguments aren't valid values")).exit() + })).collect::>() + } else { + ::clap::Error::argument_not_found($v).exit() + } + }; +} /// Convenience macro to generate more complete enums with variants to be used as a type when /// parsing arguments. This enum also provides a `variants()` function which can be used to retrieve a @@ -277,7 +357,7 @@ macro_rules! values_t { /// let m = App::new("app") /// .arg_from_usage(" 'the foo'") /// .get_matches(); -/// let f = value_t_or_exit!(m.value_of("foo"), Foo); +/// let f = value_t!(m, "foo", Foo).unwrap_or_else(|e| e.exit()); /// /// // Use f like any other Foo variant... /// } diff --git a/src/osstringext.rs b/src/osstringext.rs index e706940b90a..75dcaac8080 100644 --- a/src/osstringext.rs +++ b/src/osstringext.rs @@ -31,7 +31,7 @@ impl OsStrExt2 for OsStr { fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) { let mut i = 0; for b in self.as_bytes() { - if b == &byte { return (OsStr::from_bytes(&self.as_bytes()[..i]), OsStr::from_bytes(&self.as_bytes()[i..])); } + if b == &byte { return (OsStr::from_bytes(&self.as_bytes()[..i]), OsStr::from_bytes(&self.as_bytes()[i+1..])); } i += 1; } (&*self, OsStr::from_bytes(&self.as_bytes()[self.len()..self.len()])) diff --git a/tests/groups.rs b/tests/groups.rs index f854512da75..4053e07a2ef 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -18,12 +18,14 @@ fn required_group_missing_arg() { #[test] fn group_single_value() { - let m = App::new("group") + let r = App::new("group") .args_from_usage("-f, --flag 'some flag' -c, --color [color] 'some option'") .group(ArgGroup::with_name("grp") .args(&["flag", "color"])) - .get_matches_from(vec!["myprog", "-c", "blue"]); + .get_matches_from_safe(vec!["myprog", "-c", "blue"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("grp")); assert_eq!(m.value_of("grp").unwrap(), "blue"); } @@ -68,12 +70,14 @@ fn group_reqired_flags_empty() { #[test] fn group_multi_value_single_arg() { - let m = App::new("group") + let r = App::new("group") .args_from_usage("-f, --flag 'some flag' -c, --color [color]... 'some option'") .group(ArgGroup::with_name("grp") .args(&["flag", "color"])) - .get_matches_from(vec!["myprog", "-c", "blue", "red", "green"]); + .get_matches_from_safe(vec!["myprog", "-c", "blue", "red", "green"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("grp")); assert_eq!(m.values_of("grp").unwrap().collect::>(), &["blue", "red", "green"]); } diff --git a/tests/multiple_values.rs b/tests/multiple_values.rs index da633b2ed66..6b941768357 100644 --- a/tests/multiple_values.rs +++ b/tests/multiple_values.rs @@ -45,7 +45,7 @@ fn multiple_values_of_option_short() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 3); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -70,7 +70,7 @@ fn multiple_values_of_option_mixed() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 4); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3", "val4"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3", "val4"]); } #[test] @@ -94,7 +94,7 @@ fn multiple_values_of_option_exact_exact() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 3); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -113,7 +113,7 @@ fn multiple_values_of_option_exact_less() { ]); assert!(m.is_err()); - assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumValues); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); } #[test] @@ -134,7 +134,7 @@ fn multiple_values_of_option_exact_more() { ]); assert!(m.is_err()); - assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumValues); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); } #[test] @@ -157,7 +157,7 @@ fn multiple_values_of_option_min_exact() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 3); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -199,7 +199,7 @@ fn multiple_values_of_option_min_more() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 4); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3", "val4"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3", "val4"]); } #[test] @@ -222,7 +222,7 @@ fn multiple_values_of_option_max_exact() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 3); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -244,7 +244,7 @@ fn multiple_values_of_option_max_less() { assert!(m.is_present("option")); assert_eq!(m.occurrences_of("option"), 2); - assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2"])); + assert_eq!(m.values_of("option").unwrap().collect::>(), vec!["val1", "val2"]); } #[test] @@ -281,7 +281,7 @@ fn multiple_values_of_positional() { assert!(m.is_present("pos")); assert_eq!(m.occurrences_of("pos"), 3); - assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -299,7 +299,7 @@ fn multiple_values_of_positional_exact_exact() { assert!(m.is_present("pos")); assert_eq!(m.occurrences_of("pos"), 3); - assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -313,7 +313,7 @@ fn multiple_values_of_positional_exact_less() { .get_matches_from_safe(vec!["myprog", "val1", "val2"]); assert!(m.is_err()); - assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumValues); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); } #[test] @@ -327,7 +327,7 @@ fn multiple_values_of_positional_exact_more() { .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]); assert!(m.is_err()); - assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumValues); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); } #[test] @@ -344,7 +344,7 @@ fn multiple_values_of_positional_min_exact() { assert!(m.is_present("pos")); assert_eq!(m.occurrences_of("pos"), 3); - assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3"])); + assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3"]); } #[test] @@ -374,7 +374,7 @@ fn multiple_values_of_positional_min_more() { assert!(m.is_present("pos")); assert_eq!(m.occurrences_of("pos"), 4); - assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3", "val4"])); + assert_eq!(m.values_of("pos").unwrap().collect::>(), vec!["val1", "val2", "val3", "val4"]); } #[test] diff --git a/tests/opts.rs b/tests/opts.rs index c1c37ec5474..978726ea669 100644 --- a/tests/opts.rs +++ b/tests/opts.rs @@ -4,12 +4,14 @@ use clap::{App, Arg}; #[test] fn opts_using_short() { - let m = App::new("opts") + let r = App::new("opts") .args(&mut [ Arg::from_usage("-f [flag] 'some flag'"), Arg::from_usage("-c [color] 'some other flag'") ]) - .get_matches_from(vec!["myprog", "-f", "some", "-c", "other"]); + .get_matches_from_safe(vec!["myprog", "-f", "some", "-c", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("flag")); assert_eq!(m.value_of("flag").unwrap(), "some"); assert!(m.is_present("color")); @@ -18,12 +20,14 @@ fn opts_using_short() { #[test] fn opts_using_long_space() { - let m = App::new("opts") + let r = App::new("opts") .args(&[ Arg::from_usage("--flag [flag] 'some flag'"), Arg::from_usage("--color [color] 'some other flag'") ]) - .get_matches_from(vec!["myprog", "--flag", "some", "--color", "other"]); + .get_matches_from_safe(vec!["myprog", "--flag", "some", "--color", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("flag")); assert_eq!(m.value_of("flag").unwrap(), "some"); assert!(m.is_present("color")); @@ -32,12 +36,14 @@ fn opts_using_long_space() { #[test] fn opts_using_long_equals() { - let m = App::new("opts") + let r = App::new("opts") .args(&[ Arg::from_usage("--flag [flag] 'some flag'"), Arg::from_usage("--color [color] 'some other flag'") ]) - .get_matches_from(vec!["myprog", "--flag=some", "--color=other"]); + .get_matches_from_safe(vec!["myprog", "--flag=some", "--color=other"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("flag")); assert_eq!(m.value_of("flag").unwrap(), "some"); assert!(m.is_present("color")); @@ -46,23 +52,30 @@ fn opts_using_long_equals() { #[test] fn opts_using_mixed() { - let m = App::new("opts") + let r = App::new("opts") .args(&[ Arg::from_usage("-f, --flag [flag] 'some flag'"), Arg::from_usage("-c, --color [color] 'some other flag'") ]) - .get_matches_from(vec!["myprog", "-f", "some", "--color", "other"]); + .get_matches_from_safe(vec!["myprog", "-f", "some", "--color", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("flag")); assert_eq!(m.value_of("flag").unwrap(), "some"); assert!(m.is_present("color")); assert_eq!(m.value_of("color").unwrap(), "other"); +} - let m = App::new("opts") +#[test] +fn opts_using_mixed2() { + let r = App::new("opts") .args(&[ Arg::from_usage("-f, --flag [flag] 'some flag'"), Arg::from_usage("-c, --color [color] 'some other flag'") ]) - .get_matches_from(vec!["myprog", "--flag=some", "-c", "other"]); + .get_matches_from_safe(vec!["myprog", "--flag=some", "-c", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); assert!(m.is_present("flag")); assert_eq!(m.value_of("flag").unwrap(), "some"); assert!(m.is_present("color")); diff --git a/tests/positionals.rs b/tests/positionals.rs index 7e8d011f3fb..cdca79429a4 100644 --- a/tests/positionals.rs +++ b/tests/positionals.rs @@ -13,7 +13,7 @@ fn positional() { .get_matches_from(vec!["myprog", "-f", "test"]); assert!(m.is_present("positional")); assert!(m.is_present("flag")); - assert_eq!(m.value_of("positional"), "test"); + assert_eq!(m.value_of("positional"), Some("test")); let m = App::new("positional") .args(&[ @@ -24,7 +24,7 @@ fn positional() { .get_matches_from(vec!["myprog", "test", "--flag"]); assert!(m.is_present("positional")); assert!(m.is_present("flag")); - assert_eq!(m.value_of("positional"), "test"); + assert_eq!(m.value_of("positional"), Some("test")); } #[test] @@ -65,5 +65,5 @@ fn positional_multiple_2() { .get_matches_from_safe(vec!["myprog", "-f", "test1", "test2", "test3"]); assert!(result.is_err()); let err = result.err().unwrap(); - assert_eq!(err.kind, ErrorKind::UnexpectedArgument); + assert_eq!(err.kind, ErrorKind::UnknownArgument); } diff --git a/tests/unicode.rs b/tests/unicode.rs index 5ed26215c8b..7e5868ff223 100644 --- a/tests/unicode.rs +++ b/tests/unicode.rs @@ -4,7 +4,7 @@ extern crate clap; use std::ffi::OsString; use std::os::unix::ffi::OsStringExt; -use clap::{App, Arg, ErrorKind}; +use clap::{App, Arg, AppSettings, ErrorKind}; #[test] fn invalid_unicode_safe() { @@ -20,11 +20,11 @@ fn invalid_unicode_safe() { #[test] fn invalid_unicode_lossy() { - App::new("bad_unicode") + let m = App::new("bad_unicode") .arg(Arg::from_usage(" 'some arg'")) - .setting(AppSetting::AllowInvalidUtf8) - .get_matches_from_safe(vec![OsString::from_vec(vec![0x20]), - OsString::from_vec(vec![0xe9])]) { + .setting(AppSettings::AllowInvalidUtf8) + .get_matches_from(vec![OsString::from_vec(vec![0x20]), + OsString::from_vec(vec![0xe9])]); assert!(m.is_present("arg")); assert_eq!(m.value_of("arg").unwrap(), "\u{FFFD}"); }