Auto merge of #727 - kbknapp:issue-725, r=kbknapp

Issue 725
This commit is contained in:
Homu 2016-11-02 07:14:52 +09:00
commit 1ff9791fb4
8 changed files with 375 additions and 105 deletions

View file

@ -1,3 +1,13 @@
<a name="v2.17.0"></a>
## v2.17.0 (2016-11-01)
#### Features
* **Positional Args:** allows specifying the second to last positional argument as multiple(true) ([1ced2a74](https://github.com/kbknapp/clap-rs/commit/1ced2a7433ea8937a1b260ea65d708f32ca7c95e), closes [#725](https://github.com/kbknapp/clap-rs/issues/725))
<a name="v2.16.4"></a>
### v2.16.4 (2016-10-31)

View file

@ -1,7 +1,7 @@
[package]
name = "clap"
version = "2.16.4"
version = "2.17.0"
authors = ["Kevin K. <kbknapp@gmail.com>"]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
repository = "https://github.com/kbknapp/clap-rs.git"

View file

@ -41,6 +41,11 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## What's New
Here's what's new in v2.17.0
* Allows specifying the second to last positional argument as `multiple(true)` (i.e. things such as `mv <files>... <target>`)
* Adds an `App::get_name` and `App::get_bin_name`
Here's what's new in v2.16.4
* Fixes bug that caused panic on subcommands with aliases

View file

@ -131,7 +131,7 @@ macro_rules! validate_multiples {
($_self:ident, $a:ident, $m:ident) => {
debugln!("macro=validate_multiples!;");
if $m.contains(&$a.name) && !$a.settings.is_set(ArgSettings::Multiple) {
// Not the first time, and we don't allow multiples
// Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage($a,
&*$_self.create_current_usage($m),
$_self.color()))

View file

@ -1250,7 +1250,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches<'a>
where I: IntoIterator<Item = T>,
T: Into<OsString>
T: Into<OsString> + Clone
{
self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| {
// Otherwise, write to stderr and exit
@ -1292,7 +1292,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from_safe<I, T>(mut self, itr: I) -> ClapResult<ArgMatches<'a>>
where I: IntoIterator<Item = T>,
T: Into<OsString>
T: Into<OsString> + Clone
{
self.get_matches_from_safe_borrow(itr)
}
@ -1320,7 +1320,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from_safe_borrow<I, T>(&mut self, itr: I) -> ClapResult<ArgMatches<'a>>
where I: IntoIterator<Item = T>,
T: Into<OsString>
T: Into<OsString> + Clone
{
// Verify all positional assertions pass
self.p.verify_positionals();
@ -1355,7 +1355,7 @@ impl<'a, 'b> App<'a, 'b> {
}
// do the real parsing
if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it) {
if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it.peekable()) {
return Err(e);
}

View file

@ -8,6 +8,7 @@ use std::io::{self, BufWriter, Write};
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;
use std::slice::Iter;
use std::iter::Peekable;
// Third Party
use vec_map::{self, VecMap};
@ -118,15 +119,14 @@ impl<'a, 'b> Parser<'a, 'b>
let out_dir = PathBuf::from(od);
let name = &*self.meta.bin_name.as_ref().unwrap().clone();
let file_name = match for_shell {
Shell::Bash => format!("{}.bash-completion", name),
Shell::Fish => format!("{}.fish", name),
Shell::Zsh => format!("_{}", name)
Shell::Zsh => format!("_{}", name),
};
let mut file = match File::create(out_dir.join(file_name)) {
Err(why) => panic!("couldn't create bash completion file: {}",
why.description()),
Err(why) => panic!("couldn't create completion file: {}", why.description()),
Ok(file) => file,
};
self.gen_completions_to(for_shell, &mut file)
@ -266,10 +266,16 @@ impl<'a, 'b> Parser<'a, 'b>
for (i, o) in self.opts.iter_mut().enumerate().filter(|&(_, ref o)| o.disp_ord == 999) {
o.disp_ord = if unified { o.unified_ord } else { i };
}
for (i, f) in self.flags.iter_mut().enumerate().filter(|&(_, ref f)| f.disp_ord == 999) {
for (i, f) in self.flags
.iter_mut()
.enumerate()
.filter(|&(_, ref f)| f.disp_ord == 999) {
f.disp_ord = if unified { f.unified_ord } else { i };
}
for (i, sc) in &mut self.subcommands.iter_mut().enumerate().filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) {
for (i, sc) in &mut self.subcommands
.iter_mut()
.enumerate()
.filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) {
sc.p.meta.disp_ord = i;
}
}
@ -517,12 +523,40 @@ impl<'a, 'b> Parser<'a, 'b>
}
// Next we verify that only the highest index has a .multiple(true) (if any)
debug_assert!(!self.positionals
.values()
.any(|a| a.settings.is_set(ArgSettings::Multiple) &&
(a.index as usize != self.positionals.len())
),
"Only the positional argument with the highest index may accept multiple values");
if self.positionals()
.any(|a| {
a.settings.is_set(ArgSettings::Multiple) &&
(a.index as usize != self.positionals.len())
}) {
debug_assert!(self.positionals()
.filter(|p| p.settings.is_set(ArgSettings::Multiple)
&& p.num_vals.is_none()).map(|_| 1).sum::<u64>() <= 1,
"Only one positional argument with .multiple(true) set is allowed per command");
debug_assert!(self.positionals()
.rev()
.next()
.unwrap()
.is_set(ArgSettings::Required),
"When using a positional argument with .multiple(true) that is *not the last* \
positional argument, the last positional argument (i.e the one with the highest \
index) *must* have .required(true) set.");
debug_assert!({
let num = self.positionals.len() - 1;
self.positionals.get(num).unwrap().is_set(ArgSettings::Multiple)
},
"Only the last positional argument, or second to last positional argument may be set to .multiple(true)");
self.set(AppSettings::LowIndexMultiplePositional);
}
debug_assert!(self.positionals()
.filter(|p| p.settings.is_set(ArgSettings::Multiple)
&& p.num_vals.is_none())
.map(|_| 1)
.sum::<u64>() <= 1,
"Only one positional argument with .multiple(true) set is allowed per command");
// If it's required we also need to ensure all previous positionals are
// required too
@ -666,10 +700,10 @@ impl<'a, 'b> Parser<'a, 'b>
#[cfg_attr(feature = "lints", allow(while_let_on_iterator))]
pub fn get_matches_with<I, T>(&mut self,
matcher: &mut ArgMatcher<'a>,
it: &mut I)
it: &mut Peekable<I>)
-> ClapResult<()>
where I: Iterator<Item = T>,
T: Into<OsString>
T: Into<OsString> + Clone
{
debugln!("fn=get_matches_with;");
// First we create the `--help` and `--version` arguments and add them if
@ -684,15 +718,7 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("Begin parsing '{:?}' ({:?})", arg_os, &*arg_os.as_bytes());
// Is this a new argument, or values from a previous option?
debug!("Starts new arg...");
let starts_new_arg = if arg_os.starts_with(b"-") {
sdebugln!("Maybe");
// a singe '-' by itself is a value and typically means "stdin" on unix systems
!(arg_os.len_() == 1)
} else {
sdebugln!("No");
false
};
let starts_new_arg = is_new_arg(&arg_os);
// Has the user already passed '--'? Meaning only positional args follow
if !self.trailing_vals {
@ -739,7 +765,8 @@ impl<'a, 'b> Parser<'a, 'b>
arg_os.to_string_lossy().parse::<f64>().is_ok()));
if needs_val_of.is_none() {
if self.is_set(AppSettings::AllowNegativeNumbers) {
if !(arg_os.to_string_lossy().parse::<i64>().is_ok() || arg_os.to_string_lossy().parse::<f64>().is_ok()) {
if !(arg_os.to_string_lossy().parse::<i64>().is_ok() ||
arg_os.to_string_lossy().parse::<f64>().is_ok()) {
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
"",
&*self.create_current_usage(matcher),
@ -747,7 +774,7 @@ impl<'a, 'b> Parser<'a, 'b>
}
} else if !self.is_set(AppSettings::AllowLeadingHyphen) {
continue;
}
}
} else {
continue;
}
@ -775,6 +802,26 @@ impl<'a, 'b> Parser<'a, 'b>
}
}
debugln!("Positional counter...{}", pos_counter);
debug!("Checking for low index multiples...");
if self.is_set(AppSettings::LowIndexMultiplePositional) && pos_counter == (self.positionals.len() - 1) {
sdebugln!("Found");
if let Some(na) = it.peek() {
let n = (*na).clone().into();
if is_new_arg(&n) || self.possible_subcommand(&n) || suggestions::did_you_mean(&n.to_string_lossy(),
self.subcommands
.iter()
.map(|s| &s.p.meta.name)).is_some() {
debugln!("Bumping the positional counter...");
pos_counter += 1;
}
} else {
debugln!("Bumping the positional counter...");
pos_counter += 1;
}
} else {
sdebugln!("None");
}
if let Some(p) = self.positionals.get(pos_counter) {
parse_positional!(self, p, arg_os, pos_counter, matcher);
} else if self.settings.is_set(AppSettings::AllowExternalSubcommands) {
@ -953,10 +1000,10 @@ impl<'a, 'b> Parser<'a, 'b>
fn parse_subcommand<I, T>(&mut self,
sc_name: String,
matcher: &mut ArgMatcher<'a>,
it: &mut I)
it: &mut Peekable<I>)
-> ClapResult<()>
where I: Iterator<Item = T>,
T: Into<OsString>
T: Into<OsString> + Clone
{
use std::fmt::Write;
debugln!("fn=parse_subcommand;");
@ -1949,10 +1996,11 @@ impl<'a, 'b> Parser<'a, 'b>
}
None
}
fn find_flag(&self, name: &str) -> Option<&FlagBuilder<'a, 'b>> {
for f in self.flags() {
if f.name == name || f.aliases.as_ref().unwrap_or(&vec![("",false)]).iter().any(|&(n,_)| n == name) {
if f.name == name ||
f.aliases.as_ref().unwrap_or(&vec![("",false)]).iter().any(|&(n, _)| n == name) {
return Some(f);
}
}
@ -1961,7 +2009,8 @@ impl<'a, 'b> Parser<'a, 'b>
fn find_option(&self, name: &str) -> Option<&OptBuilder<'a, 'b>> {
for o in self.opts() {
if o.name == name || o.aliases.as_ref().unwrap_or(&vec![("",false)]).iter().any(|&(n,_)| n == name) {
if o.name == name ||
o.aliases.as_ref().unwrap_or(&vec![("",false)]).iter().any(|&(n, _)| n == name) {
return Some(o);
}
}
@ -1983,7 +2032,15 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("Looking for sc...{}", sc);
debugln!("Currently in Parser...{}", self.meta.bin_name.as_ref().unwrap());
for s in self.subcommands.iter() {
if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc || (s.p.meta.aliases.is_some() && s.p.meta.aliases.as_ref().unwrap().iter().any(|&(s,_)| s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG))) {
if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(s, _)| s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG))) {
return Some(s);
}
if let Some(app) = s.p.find_subcommand(sc) {
@ -2019,3 +2076,17 @@ impl<'a, 'b> Clone for Parser<'a, 'b>
}
}
}
#[inline]
fn is_new_arg(arg_os: &OsStr) -> bool {
// Is this a new argument, or values from a previous option?
debug!("Starts new arg...");
if arg_os.starts_with(b"-") {
sdebugln!("Maybe");
// a singe '-' by itself is a value and typically means "stdin" on unix systems
!(arg_os.len_() == 1)
} else {
sdebugln!("No");
false
}
}

View file

@ -4,34 +4,35 @@ use std::str::FromStr;
bitflags! {
flags Flags: u32 {
const SC_NEGATE_REQS = 0b0000000000000000000000000001,
const SC_REQUIRED = 0b0000000000000000000000000010,
const A_REQUIRED_ELSE_HELP = 0b0000000000000000000000000100,
const GLOBAL_VERSION = 0b0000000000000000000000001000,
const VERSIONLESS_SC = 0b0000000000000000000000010000,
const UNIFIED_HELP = 0b0000000000000000000000100000,
const WAIT_ON_ERROR = 0b0000000000000000000001000000,
const SC_REQUIRED_ELSE_HELP= 0b0000000000000000000010000000,
const NEEDS_LONG_HELP = 0b0000000000000000000100000000,
const NEEDS_LONG_VERSION = 0b0000000000000000001000000000,
const NEEDS_SC_HELP = 0b0000000000000000010000000000,
const DISABLE_VERSION = 0b0000000000000000100000000000,
const HIDDEN = 0b0000000000000001000000000000,
const TRAILING_VARARG = 0b0000000000000010000000000000,
const NO_BIN_NAME = 0b0000000000000100000000000000,
const ALLOW_UNK_SC = 0b0000000000001000000000000000,
const UTF8_STRICT = 0b0000000000010000000000000000,
const UTF8_NONE = 0b0000000000100000000000000000,
const LEADING_HYPHEN = 0b0000000001000000000000000000,
const NO_POS_VALUES = 0b0000000010000000000000000000,
const NEXT_LINE_HELP = 0b0000000100000000000000000000,
const DERIVE_DISP_ORDER = 0b0000001000000000000000000000,
const COLORED_HELP = 0b0000010000000000000000000000,
const COLOR_ALWAYS = 0b0000100000000000000000000000,
const COLOR_AUTO = 0b0001000000000000000000000000,
const COLOR_NEVER = 0b0010000000000000000000000000,
const DONT_DELIM_TRAIL = 0b0100000000000000000000000000,
const ALLOW_NEG_NUMS = 0b1000000000000000000000000000,
const SC_NEGATE_REQS = 0b00000000000000000000000000001,
const SC_REQUIRED = 0b00000000000000000000000000010,
const A_REQUIRED_ELSE_HELP = 0b00000000000000000000000000100,
const GLOBAL_VERSION = 0b00000000000000000000000001000,
const VERSIONLESS_SC = 0b00000000000000000000000010000,
const UNIFIED_HELP = 0b00000000000000000000000100000,
const WAIT_ON_ERROR = 0b00000000000000000000001000000,
const SC_REQUIRED_ELSE_HELP= 0b00000000000000000000010000000,
const NEEDS_LONG_HELP = 0b00000000000000000000100000000,
const NEEDS_LONG_VERSION = 0b00000000000000000001000000000,
const NEEDS_SC_HELP = 0b00000000000000000010000000000,
const DISABLE_VERSION = 0b00000000000000000100000000000,
const HIDDEN = 0b00000000000000001000000000000,
const TRAILING_VARARG = 0b00000000000000010000000000000,
const NO_BIN_NAME = 0b00000000000000100000000000000,
const ALLOW_UNK_SC = 0b00000000000001000000000000000,
const UTF8_STRICT = 0b00000000000010000000000000000,
const UTF8_NONE = 0b00000000000100000000000000000,
const LEADING_HYPHEN = 0b00000000001000000000000000000,
const NO_POS_VALUES = 0b00000000010000000000000000000,
const NEXT_LINE_HELP = 0b00000000100000000000000000000,
const DERIVE_DISP_ORDER = 0b00000001000000000000000000000,
const COLORED_HELP = 0b00000010000000000000000000000,
const COLOR_ALWAYS = 0b00000100000000000000000000000,
const COLOR_AUTO = 0b00001000000000000000000000000,
const COLOR_NEVER = 0b00010000000000000000000000000,
const DONT_DELIM_TRAIL = 0b00100000000000000000000000000,
const ALLOW_NEG_NUMS = 0b01000000000000000000000000000,
const LOW_INDEX_MUL_POS = 0b10000000000000000000000000000,
}
}
@ -72,6 +73,7 @@ impl AppFlags {
GlobalVersion => GLOBAL_VERSION,
HidePossibleValuesInHelp => NO_POS_VALUES,
Hidden => HIDDEN,
LowIndexMultiplePositional => LOW_INDEX_MUL_POS,
NeedsLongHelp => NEEDS_LONG_HELP,
NeedsLongVersion => NEEDS_LONG_VERSION,
NeedsSubcommandHelp => NEEDS_SC_HELP,
@ -663,6 +665,9 @@ pub enum AppSettings {
#[doc(hidden)]
NeedsSubcommandHelp,
#[doc(hidden)]
LowIndexMultiplePositional,
}
impl FromStr for AppSettings {
@ -684,6 +689,7 @@ impl FromStr for AppSettings {
"globalversion" => Ok(AppSettings::GlobalVersion),
"hidden" => Ok(AppSettings::Hidden),
"hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp),
"lowindexmultiplepositional" => Ok(AppSettings::LowIndexMultiplePositional),
"nobinaryname" => Ok(AppSettings::NoBinaryName),
"nextlinehelp" => Ok(AppSettings::NextLineHelp),
"strictutf8" => Ok(AppSettings::StrictUtf8),
@ -735,6 +741,8 @@ mod test {
AppSettings::Hidden);
assert_eq!("hidepossiblevaluesinhelp".parse::<AppSettings>().unwrap(),
AppSettings::HidePossibleValuesInHelp);
assert_eq!("lowindexmultiplePositional".parse::<AppSettings>().unwrap(),
AppSettings::LowIndexMultiplePositional);
assert_eq!("nobinaryname".parse::<AppSettings>().unwrap(),
AppSettings::NoBinaryName);
assert_eq!("nextlinehelp".parse::<AppSettings>().unwrap(),

View file

@ -3,7 +3,7 @@ extern crate clap;
use clap::{App, Arg, ErrorKind, SubCommand};
#[test]
fn multiple_values_of_option_long() {
fn option_long() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -26,7 +26,7 @@ fn multiple_values_of_option_long() {
}
#[test]
fn multiple_values_with_subcmd() {
fn with_subcmd() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -50,7 +50,7 @@ fn multiple_values_with_subcmd() {
}
#[test]
fn multiple_values_of_option_short() {
fn option_short() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -73,7 +73,7 @@ fn multiple_values_of_option_short() {
}
#[test]
fn multiple_values_of_option_mixed() {
fn option_mixed() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -98,7 +98,7 @@ fn multiple_values_of_option_mixed() {
}
#[test]
fn multiple_values_of_option_exact_exact() {
fn option_exact_exact() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -122,7 +122,7 @@ fn multiple_values_of_option_exact_exact() {
}
#[test]
fn multiple_values_of_option_exact_exact_not_mult() {
fn option_exact_exact_not_mult() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -143,7 +143,7 @@ fn multiple_values_of_option_exact_exact_not_mult() {
}
#[test]
fn multiple_values_of_option_exact_exact_mult() {
fn option_exact_exact_mult() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -166,7 +166,7 @@ fn multiple_values_of_option_exact_exact_mult() {
}
#[test]
fn multiple_values_of_option_exact_less() {
fn option_exact_less() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -185,7 +185,7 @@ fn multiple_values_of_option_exact_less() {
}
#[test]
fn multiple_values_of_option_exact_more() {
fn option_exact_more() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -206,7 +206,7 @@ fn multiple_values_of_option_exact_more() {
}
#[test]
fn multiple_values_of_option_min_exact() {
fn option_min_exact() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -230,7 +230,7 @@ fn multiple_values_of_option_min_exact() {
}
#[test]
fn multiple_values_of_option_min_less() {
fn option_min_less() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -307,7 +307,7 @@ fn option_short_min_more_single_occur() {
}
#[test]
fn multiple_values_of_option_max_exact() {
fn option_max_exact() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -331,7 +331,7 @@ fn multiple_values_of_option_max_exact() {
}
#[test]
fn multiple_values_of_option_max_less() {
fn option_max_less() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -354,7 +354,7 @@ fn multiple_values_of_option_max_less() {
}
#[test]
fn multiple_values_of_option_max_more() {
fn option_max_more() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -375,7 +375,7 @@ fn multiple_values_of_option_max_more() {
}
#[test]
fn multiple_values_of_positional() {
fn positional() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -391,7 +391,7 @@ fn multiple_values_of_positional() {
}
#[test]
fn multiple_values_of_positional_exact_exact() {
fn positional_exact_exact() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -407,7 +407,7 @@ fn multiple_values_of_positional_exact_exact() {
}
#[test]
fn multiple_values_of_positional_exact_less() {
fn positional_exact_less() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -419,7 +419,7 @@ fn multiple_values_of_positional_exact_less() {
}
#[test]
fn multiple_values_of_positional_exact_more() {
fn positional_exact_more() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -431,7 +431,7 @@ fn multiple_values_of_positional_exact_more() {
}
#[test]
fn multiple_values_of_positional_min_exact() {
fn positional_min_exact() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -447,7 +447,7 @@ fn multiple_values_of_positional_min_exact() {
}
#[test]
fn multiple_values_of_positional_min_less() {
fn positional_min_less() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -459,7 +459,7 @@ fn multiple_values_of_positional_min_less() {
}
#[test]
fn multiple_values_of_positional_min_more() {
fn positional_min_more() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -475,7 +475,7 @@ fn multiple_values_of_positional_min_more() {
}
#[test]
fn multiple_values_of_positional_max_exact() {
fn positional_max_exact() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -491,7 +491,7 @@ fn multiple_values_of_positional_max_exact() {
}
#[test]
fn multiple_values_of_positional_max_less() {
fn positional_max_less() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -507,7 +507,7 @@ fn multiple_values_of_positional_max_less() {
}
#[test]
fn multiple_values_of_positional_max_more() {
fn positional_max_more() {
let m = App::new("multiple_values")
.arg(Arg::with_name("pos")
.help("multiple positionals")
@ -519,7 +519,7 @@ fn multiple_values_of_positional_max_more() {
}
#[test]
fn multiple_values_sep_long_equals() {
fn sep_long_equals() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -541,7 +541,7 @@ fn multiple_values_sep_long_equals() {
}
#[test]
fn multiple_values_sep_long_space() {
fn sep_long_space() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -564,7 +564,7 @@ fn multiple_values_sep_long_space() {
}
#[test]
fn multiple_values_sep_short_equals() {
fn sep_short_equals() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -586,7 +586,7 @@ fn multiple_values_sep_short_equals() {
}
#[test]
fn multiple_values_sep_short_space() {
fn sep_short_space() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -609,7 +609,7 @@ fn multiple_values_sep_short_space() {
}
#[test]
fn multiple_values_sep_short_no_space() {
fn sep_short_no_space() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -631,7 +631,7 @@ fn multiple_values_sep_short_no_space() {
}
#[test]
fn multiple_values_sep_positional() {
fn sep_positional() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.help("multiple options")
@ -651,7 +651,7 @@ fn multiple_values_sep_positional() {
}
#[test]
fn multiple_values_different_sep() {
fn different_sep() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -672,7 +672,7 @@ fn multiple_values_different_sep() {
}
#[test]
fn multiple_values_different_sep_positional() {
fn different_sep_positional() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.help("multiple options")
@ -691,7 +691,7 @@ fn multiple_values_different_sep_positional() {
}
#[test]
fn multiple_values_no_sep() {
fn no_sep() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -712,7 +712,7 @@ fn multiple_values_no_sep() {
}
#[test]
fn multiple_values_no_sep_positional() {
fn no_sep_positional() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.help("multiple options")
@ -731,7 +731,7 @@ fn multiple_values_no_sep_positional() {
}
#[test]
fn multiple_values_req_delimiter_long() {
fn req_delimiter_long() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -757,7 +757,7 @@ fn multiple_values_req_delimiter_long() {
}
#[test]
fn multiple_values_req_delimiter_long_with_equal() {
fn req_delimiter_long_with_equal() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -783,7 +783,7 @@ fn multiple_values_req_delimiter_long_with_equal() {
}
#[test]
fn multiple_values_req_delimiter_short_with_space() {
fn req_delimiter_short_with_space() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -809,7 +809,7 @@ fn multiple_values_req_delimiter_short_with_space() {
}
#[test]
fn multiple_values_req_delimiter_short_with_no_space() {
fn req_delimiter_short_with_no_space() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("o")
@ -835,7 +835,7 @@ fn multiple_values_req_delimiter_short_with_no_space() {
}
#[test]
fn multiple_values_req_delimiter_short_with_equal() {
fn req_delimiter_short_with_equal() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.short("option")
@ -861,7 +861,7 @@ fn multiple_values_req_delimiter_short_with_equal() {
}
#[test]
fn multiple_values_req_delimiter_complex() {
fn req_delimiter_complex() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
@ -900,3 +900,179 @@ fn multiple_values_req_delimiter_complex() {
&["val1", "val3", "val5", "val7", "val9", "val11", "val14", "val17",
"val20", "val23", "val26"]);
}
#[test]
#[should_panic]
fn low_index_positional_not_required() {
let _ = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.index(2))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
]);
}
#[test]
#[should_panic]
fn low_index_positional_last_multiple_too() {
let _ = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.index(2)
.required(true)
.multiple(true))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
]);
}
#[test]
#[should_panic]
fn low_index_positional_too_far_back() {
let _ = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.required(true)
.index(2))
.arg(Arg::with_name("target2")
.required(true)
.index(3))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
]);
}
#[test]
fn low_index_positional() {
let m = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.index(2)
.required(true))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
let m = m.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.occurrences_of("files"), 3);
assert!(m.is_present("target"));
assert_eq!(m.occurrences_of("target"), 1);
assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
assert_eq!(m.value_of("target").unwrap(), "target");
}
#[test]
fn low_index_positional_with_subcmd() {
let m = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.index(2)
.required(true))
.subcommand(SubCommand::with_name("test").arg(Arg::with_name("other")))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
"test"
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
let m = m.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.occurrences_of("files"), 3);
assert!(m.is_present("target"));
assert_eq!(m.occurrences_of("target"), 1);
assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
assert_eq!(m.value_of("target").unwrap(), "target");
}
#[test]
fn low_index_positional_with_option() {
let m = App::new("lip")
.arg(Arg::with_name("files")
.required(true)
.index(1)
.multiple(true))
.arg(Arg::with_name("target")
.index(2)
.required(true))
.arg(Arg::with_name("opt")
.long("option")
.takes_value(true))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
"--option", "test"
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
let m = m.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.occurrences_of("files"), 3);
assert!(m.is_present("target"));
assert_eq!(m.occurrences_of("target"), 1);
assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
assert_eq!(m.value_of("target").unwrap(), "target");
assert_eq!(m.value_of("opt").unwrap(), "test");
}
#[test]
fn low_index_positional_with_flag() {
let m = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.index(2)
.required(true))
.arg(Arg::with_name("flg")
.long("flag"))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
"--flag"
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
let m = m.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.occurrences_of("files"), 3);
assert!(m.is_present("target"));
assert_eq!(m.occurrences_of("target"), 1);
assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
assert_eq!(m.value_of("target").unwrap(), "target");
assert!(m.is_present("flg"));
}