Tests on flags passing

This commit is contained in:
Alena Yuryeva 2018-08-11 20:34:40 +03:00
parent f4e19a3193
commit c501773ed3
6 changed files with 3154 additions and 61 deletions

View file

@ -18,7 +18,7 @@ use yaml_rust::Yaml;
// Internal // Internal
use build::{Arg, ArgGroup, ArgSettings}; use build::{Arg, ArgGroup, ArgSettings};
use completions::{ComplGen, Shell}; use completions::{ComplGen, Shell};
use mkeymap::{KeyType, MKeyMap}; use mkeymap::MKeyMap;
use output::fmt::ColorWhen; use output::fmt::ColorWhen;
use output::{Help, Usage}; use output::{Help, Usage};
use parse::errors::Result as ClapResult; use parse::errors::Result as ClapResult;
@ -639,7 +639,7 @@ impl<'a, 'b> App<'a, 'b> {
None None
}; };
let arg = a.into().help_heading(help_heading); let arg = a.into().help_heading(help_heading);
self.args.push(arg); self.args.make_entries(arg);
self self
} }
@ -1508,7 +1508,7 @@ impl<'a, 'b> App<'a, 'b> {
} }
{ {
for a in self.args.values().filter(|a| a.is_set(ArgSettings::Global)) { for a in self.args.values().filter(|a| a.is_set(ArgSettings::Global)) {
sc.args.push(a.clone()); sc.args.make_entries(a.clone());
} }
} }
// @TODO @deadcode @perf @v3-alpha: Currently we're not propagating // @TODO @deadcode @perf @v3-alpha: Currently we're not propagating

View file

@ -1,5 +1,4 @@
// Std // Std
use std::ffi::OsStr;
use std::io::Write; use std::io::Write;
// Internal // Internal

View file

@ -903,14 +903,14 @@ macro_rules! flags {
use mkeymap::KeyType::*; use mkeymap::KeyType::*;
$app.args $app.args
.$how() .$how()
.filter(|(k, a)| !a.settings.is_set(::build::ArgSettings::TakesValue)) .filter(|(_, a)| !a.settings.is_set(::build::ArgSettings::TakesValue))
.filter(|(k, a)| match k { .filter(|(k, _)| match k {
Long(_) => true, Long(_) => true,
Short(_) => true, Short(_) => true,
Position(_) => false, Position(_) => false,
}) })
.filter(|(k, a)| !a.help_heading.is_some()) .filter(|(_, a)| !a.help_heading.is_some())
.map(|(k, v)| v) .map(|(_, v)| v)
}}; }};
($app:expr) => { ($app:expr) => {
flags!($app, iter) flags!($app, iter)
@ -929,14 +929,14 @@ macro_rules! opts {
use mkeymap::KeyType::*; use mkeymap::KeyType::*;
$app.args $app.args
.$how() .$how()
.filter(|(k, a)| a.settings.is_set(::build::ArgSettings::TakesValue)) .filter(|(_, a)| a.settings.is_set(::build::ArgSettings::TakesValue))
.filter(|(k, a)| match k { .filter(|(k, _)| match k {
Long(_) => true, Long(_) => true,
Short(_) => true, Short(_) => true,
Position(_) => false, Position(_) => false,
}) })
.filter(|(k, a)| !a.help_heading.is_some()) .filter(|(_, a)| !a.help_heading.is_some())
.map(|(k, v)| v) .map(|(_, v)| v)
}}; }};
($app:expr) => { ($app:expr) => {
opts!($app, iter) opts!($app, iter)

View file

@ -4,7 +4,6 @@ use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ffi::OsString; use std::ffi::OsString;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem;
use std::slice; use std::slice;
// ! rustdoc // ! rustdoc
@ -97,9 +96,9 @@ where
pub fn is_empty(&self) -> bool { self.keys.is_empty() && self.values.is_empty() } pub fn is_empty(&self) -> bool { self.keys.is_empty() && self.values.is_empty() }
pub fn remove_by_name(&mut self, name: &str) -> Option<T> { unimplemented!() } pub fn remove_by_name(&mut self, _name: &str) -> Option<T> { unimplemented!() }
pub fn remove(&mut self, key: KeyType) -> Option<T> { unimplemented!() } pub fn remove(&mut self, _key: KeyType) -> Option<T> { unimplemented!() }
//TODO ::remove_many([KeyA, KeyB]) //TODO ::remove_many([KeyA, KeyB])
//? probably shouldn't add a possibility for removal? //? probably shouldn't add a possibility for removal?
//? or remove by replacement by some dummy object, so the order is preserved //? or remove by replacement by some dummy object, so the order is preserved
@ -301,7 +300,6 @@ where
mod tests { mod tests {
use self::KeyType::*; use self::KeyType::*;
use super::*; use super::*;
use std::ffi::OsStr;
#[test] #[test]
fn get_some_value() { fn get_some_value() {

View file

@ -19,9 +19,6 @@ use std::mem;
)] )]
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
// Third party facade
use util::VecMap;
// Internal // Internal
use build::app::Propagation; use build::app::Propagation;
use build::AppSettings as AS; use build::AppSettings as AS;
@ -60,9 +57,6 @@ where
pub app: &'c mut App<'a, 'b>, pub app: &'c mut App<'a, 'b>,
pub required: ChildGraph<&'a str>, pub required: ChildGraph<&'a str>,
pub overriden: Vec<&'a str>, pub overriden: Vec<&'a str>,
//cache: Option<&'a str>,
num_opts: usize,
num_flags: usize,
seen: Vec<&'a str>, seen: Vec<&'a str>,
cur_idx: Cell<usize>, cur_idx: Cell<usize>,
} }
@ -88,8 +82,6 @@ where
app: app, app: app,
required: ChildGraph::from(reqs), required: ChildGraph::from(reqs),
overriden: Vec::new(), overriden: Vec::new(),
num_opts: 0,
num_flags: 0,
seen: Vec::new(), seen: Vec::new(),
cur_idx: Cell::new(0), cur_idx: Cell::new(0),
} }
@ -157,14 +149,6 @@ where
// * a value terminator // * a value terminator
// * ArgSettings::Last // * ArgSettings::Last
// * The last arg is Required // * The last arg is Required
let mut it = self.app.args.keys().filter(|x| {
if let KeyType::Position(_) = x {
true
} else {
false
}
});
//self.positionals.values().rev();
// We can't pass the closure (it.next()) to the macro directly because each call to // We can't pass the closure (it.next()) to the macro directly because each call to
// find() (iterator, not macro) gets called repeatedly. // find() (iterator, not macro) gets called repeatedly.
@ -173,8 +157,7 @@ where
.args .args
.get(KeyType::Position(highest_idx)) .get(KeyType::Position(highest_idx))
.expect(INTERNAL_ERROR_MSG); .expect(INTERNAL_ERROR_MSG);
//let second_to_last_name = it.next().expect(INTERNAL_ERROR_MSG);
//let last = find!(self.app, last_name).expect(INTERNAL_ERROR_MSG);
let second_to_last = self let second_to_last = self
.app .app
.args .args
@ -306,6 +289,8 @@ where
// Does all the initializing and prepares the parser // Does all the initializing and prepares the parser
pub(crate) fn _build(&mut self) { pub(crate) fn _build(&mut self) {
debugln!("Parser::_build;"); debugln!("Parser::_build;");
//I wonder whether this part is even needed if we insert all Args using make_entries
let mut key: Vec<(KeyType, usize)> = Vec::new(); let mut key: Vec<(KeyType, usize)> = Vec::new();
for (i, a) in self.app.args.values().enumerate() { for (i, a) in self.app.args.values().enumerate() {
if let Some(ref index) = a.index { if let Some(ref index) = a.index {
@ -530,30 +515,20 @@ where
} }
} }
let low_index_mults = self.is_set(AS::LowIndexMultiplePositional) let positional_count = self
&& pos_counter
== (
//TODO make a macro for that
self
.app .app
.args .args
.keys() .keys()
.filter(|x| if let KeyType::Position(_) = x { true } else { false }) .filter(|x| if let KeyType::Position(_) = x { true } else { false })
.count() - 1); .count();
let missing_pos = self.is_set(AS::AllowMissingPositional) let is_second_to_last = positional_count > 1
&& (pos_counter && (pos_counter
== (self == (positional_count - 1));
.app
.args let low_index_mults = self.is_set(AS::LowIndexMultiplePositional)
.keys() && is_second_to_last;
.filter(|x| { let missing_pos = self.is_set(AS::AllowMissingPositional)
if let KeyType::Position(_) = x { && is_second_to_last && !self.is_set(AS::TrailingValues);
true
} else {
false
}
})
.count() - 1) && !self.is_set(AS::TrailingValues));
debugln!( debugln!(
"Parser::get_matches_with: Positional counter...{}", "Parser::get_matches_with: Positional counter...{}",
pos_counter pos_counter
@ -825,7 +800,7 @@ where
} }
sc sc
}; };
let mut parser = Parser::new(&mut sc); let parser = Parser::new(&mut sc);
if help_help { if help_help {
let mut pb = Arg::with_name("subcommand") let mut pb = Arg::with_name("subcommand")
.index(1) .index(1)
@ -1106,8 +1081,15 @@ where
// Option: -o // Option: -o
// Value: val // Value: val
if let Some(opt) = self.app.args.get(KeyType::Short(c)) { if let Some(opt) = self.app.args.get(KeyType::Short(c)) {
debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c); debugln!("Parser::parse_short_arg:iter:{}: Found valid opt or flag", c);
self.app.settings.set(AS::ValidArgFound); self.app.settings.set(AS::ValidArgFound);
if !opt.is_set(ArgSettings::TakesValue) {
self.check_for_help_and_version_char(c)?;
ret = self.parse_flag(opt, matcher)?;
continue;
}
// Check for trailing concatenated value // Check for trailing concatenated value
let p: Vec<_> = arg.splitn(2, c).collect(); let p: Vec<_> = arg.splitn(2, c).collect();
debugln!( debugln!(
@ -1133,12 +1115,6 @@ where
let ret = self.parse_opt(val, opt, false, matcher)?; let ret = self.parse_opt(val, opt, false, matcher)?;
return Ok(ret); return Ok(ret);
} else if let Some(flag) = self.app.args.get(KeyType::Short(c)) {
debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c);
self.app.settings.set(AS::ValidArgFound);
// Only flags can be help or version
self.check_for_help_and_version_char(c)?;
ret = self.parse_flag(flag, matcher)?;
} else { } else {
let arg = format!("-{}", c); let arg = format!("-{}", c);
return Err(ClapError::unknown_argument( return Err(ClapError::unknown_argument(

3120
tests.test Normal file

File diff suppressed because it is too large Load diff