tests(v2): fixing more tests on the new v2 base

This commit is contained in:
Kevin K 2016-01-21 23:18:52 -05:00
parent 0031d78564
commit c3e96232c9
19 changed files with 404 additions and 238 deletions

View file

@ -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() {}

View file

@ -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);
}
}

View file

@ -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 {

View file

@ -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() {}

View file

@ -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)))
}
};
}

View file

@ -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")]
/// )
/// # ;
/// ```

View file

@ -34,7 +34,7 @@ pub struct Parser<'a, 'b> where 'a: 'b {
positionals: VecMap<PosBuilder<'a, 'b>>,
// A list of subcommands
subcommands: Vec<App<'a, 'b>>,
groups: HashMap<&'b str, ArgGroup<'a>>,
groups: HashMap<&'a str, ArgGroup<'a>>,
global_args: Vec<Arg<'a, 'b>>,
overrides: Vec<&'b str>,
help_short: Option<char>,
@ -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<Vec<&'a str>> {
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::<Vec<_>>());
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<Option<&'b str>> { // 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<Option<&'a str>> {
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<Option<&'a str>> {
try!(self.validate_arg(opt, matcher));
debugln!("fn=parse_opt;");
validate_multiples!(self, 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)));
}
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));
debugln!("fn=parse_flag;");
validate_multiples!(self, 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());
}
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<A>(&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<A>(&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(())

View file

@ -268,9 +268,9 @@ pub enum AppSettings {
/// let m = App::new("myprog")
/// .setting(AppSettings::TrailingVarArg)
/// .arg(Arg::from_usage("<cmd>... '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::<Vec<_>>(), &["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("<cmd>... '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::<Vec<_>>(), &["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!()

View file

@ -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

View file

@ -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"];

View file

@ -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::<i64>() {
/// 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<A>(arg: A) -> Self
where A: Into<String>,
{
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 {

View file

@ -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

View file

@ -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,6 +147,47 @@ macro_rules! for_match {
/// **NOTE:** Be cautious, as since this a macro invocation it's not exactly like
/// standard syntax.
///
/// # 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!(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 {
($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) => Ok(val),
Err(_) =>
Err(::clap::Error::value_validation(
format!("The argument '{}' isn't a valid value", v))),
}
} 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
///
@ -158,41 +199,35 @@ 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_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 {
(@callback $c:ident $m:ident.value_of($v:expr), $t:ty) => {
$c!($m.value_of($e), $t);
};
macro_rules! value_t_or_exit {
($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) {
match v.parse::<$t>() {
Ok(val) => Ok(val),
Ok(val) => val,
Err(_) =>
Err(::clap::Error::value_validation(
format!("The argument '{}' isn't a valid value", v))),
::clap::Error::value_validation(
format!("The argument '{}' isn't a valid value", v)).exit(),
}
} else {
Err(::clap::Error::value_validation(format!("The argument '{}' was not found", $v)))
::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<T,String>` 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<T>` (`Result<T, clap::Error>`) 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<u32> = 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::<Vec<$t>>()
} 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("<foo> '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...
/// }

View file

@ -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()]))

View file

@ -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::<Vec<_>>(), &["blue", "red", "green"]);
}

View file

@ -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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3", "val4"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3", "val4"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2"]));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3"]));
assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), 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<_>>(), vec!["val1", "val2", "val3", "val4"]));
assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), vec!["val1", "val2", "val3", "val4"]);
}
#[test]

View file

@ -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"]);
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")
.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", "-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");
}
#[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_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"));

View file

@ -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);
}

View file

@ -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("<arg> '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}");
}