perf: refactor to remove unneeded vectors and allocations and checks for significant performance increases

Building an `App` struct with a fair number of args/flags/switches, etc. (used ripgrep as test case)
went from taking ~21,000 ns to ~13,000ns.
This commit is contained in:
Kevin K 2017-02-20 23:51:20 -05:00
parent b55cae5fdb
commit 0efa411963
No known key found for this signature in database
GPG key ID: 17218E4B3692F01A
14 changed files with 971 additions and 872 deletions

View file

@ -9,11 +9,12 @@ mod test {
fn compare<S, S2>(l: S, r: S2) -> bool
where S: AsRef<str>,
S2: AsRef<str> {
S2: AsRef<str>
{
let re = Regex::new("\x1b[^m]*m").unwrap();
// Strip out any mismatching \r character on windows that might sneak in on either side
let left = re.replace_all(&l.as_ref().trim().replace("\r", "")[..], "").into_owned();
let right = re.replace_all(&r.as_ref().trim().replace("\r", "")[..], "").into_owned();
let left = re.replace_all(&l.as_ref().trim().replace("\r", "")[..], "");
let right = re.replace_all(&r.as_ref().trim().replace("\r", "")[..], "");
let b = left == right;
if !b {
println!("");

View file

@ -19,11 +19,14 @@ macro_rules! remove_overriden {
};
($_self:ident, $name:expr) => {
debugln!("remove_overriden!;");
if let Some(ref o) = $_self.opts.iter().filter(|o| o.b.name == *$name).next() {
if let Some(o) = $_self.opts.iter() .find(|o| o.b.name == *$name) {
remove_overriden!(@arg $_self, o);
} else if let Some(ref f) = $_self.flags.iter().filter(|f| f.b.name == *$name).next() {
} else if let Some(f) = $_self.flags.iter() .find(|f| f.b.name == *$name) {
remove_overriden!(@arg $_self, f);
} else if let Some(p) = $_self.positionals.values().filter(|p| p.b.name == *$name).next() {
} else {
let p = $_self.positionals.values()
.find(|p| p.b.name == *$name)
.expect(INTERNAL_ERROR_MSG);
remove_overriden!(@arg $_self, p);
}
};
@ -69,20 +72,19 @@ macro_rules! arg_post_processing {
}
}
$me.blacklist.extend(bl);
$me.blacklist.extend_from_slice(bl);
vec_remove_all!($me.overrides, bl.iter());
vec_remove_all!($me.required, bl.iter());
// vec_remove_all!($me.required, bl.iter());
} else { sdebugln!("No"); }
// Add all required args which aren't already found in matcher to the master
// list
debug!("arg_post_processing!: Does '{}' have requirements...", $arg.to_string());
if let Some(reqs) = $arg.requires() {
for n in reqs.iter().filter(|&&(val, _)| val.is_none()).map(|&(_, name)| name) {
if $matcher.contains(&n) {
sdebugln!("\tYes '{}' but it's already met", n);
continue;
} else { sdebugln!("\tYes '{}'", n); }
for n in reqs.iter()
.filter(|&&(val, _)| val.is_none())
.filter(|&&(_, req)| !$matcher.contains(&req))
.map(|&(_, name)| name) {
$me.required.push(n);
}
@ -96,9 +98,9 @@ macro_rules! _handle_group_reqs{
($me:ident, $arg:ident) => ({
use args::AnyArg;
debugln!("_handle_group_reqs!;");
for grp in $me.groups.values() {
for grp in $me.groups.iter() {
let found = if grp.args.contains(&$arg.name()) {
vec_remove!($me.required, &$arg.name());
// vec_remove!($me.required, &$arg.name());
if let Some(ref reqs) = grp.requires {
debugln!("_handle_group_reqs!: Adding {:?} to the required list", reqs);
$me.required.extend(reqs);
@ -126,18 +128,6 @@ macro_rules! _handle_group_reqs{
})
}
macro_rules! validate_multiples {
($_self:ident, $a:ident, $m:ident) => {
debugln!("validate_multiples!;");
if $m.contains(&$a.b.name) && !$a.b.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, None),
$_self.color()))
}
};
}
macro_rules! parse_positional {
(
$_self:ident,
@ -147,12 +137,11 @@ macro_rules! parse_positional {
$matcher:ident
) => {
debugln!("parse_positional!;");
validate_multiples!($_self, $p, $matcher);
if !$_self.is_set(TrailingValues) &&
($_self.is_set(TrailingVarArg) &&
if !$_self.is_set(AS::TrailingValues) &&
($_self.is_set(AS::TrailingVarArg) &&
$pos_counter == $_self.positionals.len()) {
$_self.settings.set(TrailingValues);
$_self.settings.set(AS::TrailingValues);
}
let _ = try!($_self.add_val_to_arg($p, &$arg_os, $matcher));
@ -166,89 +155,3 @@ macro_rules! parse_positional {
}
};
}
macro_rules! find_from {
($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
if let Some(ref v) = f.$from() {
if v.contains($arg_name) {
ret = Some(f.to_string());
}
}
}
if let Some(o) = find_by_name!($_self, &k, opts, iter) {
if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) {
ret = Some(o.to_string());
}
}
}
if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
if let Some(ref v) = pos.$from() {
if v.contains($arg_name) {
ret = Some(pos.b.name.to_owned());
}
}
}
}
ret
}};
}
macro_rules! find_name_from {
($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
if let Some(ref v) = f.$from() {
if v.contains($arg_name) {
ret = Some(f.b.name);
}
}
}
if let Some(o) = find_by_name!($_self, &k, opts, iter) {
if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) {
ret = Some(o.b.name);
}
}
}
if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
if let Some(ref v) = pos.$from() {
if v.contains($arg_name) {
ret = Some(pos.b.name);
}
}
}
}
ret
}};
}
// Finds an arg by name
macro_rules! find_by_name {
($_self:ident, $name:expr, $what:ident, $how:ident) => {
$_self.$what.$how().find(|o| &o.b.name == $name)
}
}
// Finds an option including if it's aliasesed
macro_rules! find_by_long {
($_self:ident, $long:expr, $what:ident) => {
$_self.$what
.iter()
.filter(|o| o.s.long.is_some())
.find(|o| {
&&o.s.long.unwrap() == &$long ||
(o.s.aliases.is_some() &&
o.s
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(alias, _)| &&alias == &$long))
})
}
}

File diff suppressed because it is too large Load diff

View file

@ -2965,12 +2965,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_if(self,
arg: &'a str,
val: Option<&'b str>,
default: &'b str)
-> Self {
self.default_value_if_os(arg, val.map(str::as_bytes).map(OsStr::from_bytes), OsStr::from_bytes(default.as_bytes()))
pub fn default_value_if(self, arg: &'a str, val: Option<&'b str>, default: &'b str) -> Self {
self.default_value_if_os(arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()))
}
/// Provides a conditional default value in the exact same manner as [`Arg::default_value_if`]
@ -2978,10 +2976,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_if_os(mut self,
arg: &'a str,
val: Option<&'b OsStr>,
default: &'b OsStr)
-> Self {
arg: &'a str,
val: Option<&'b OsStr>,
default: &'b OsStr)
-> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.v.default_vals_ifs {
let l = vm.len();
@ -3080,7 +3078,9 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_ifs(mut self, ifs: &[(&'a str, Option<&'b str>, &'b str)]) -> Self {
for &(arg, val, default) in ifs {
self = self.default_value_if_os(arg, val.map(str::as_bytes).map(OsStr::from_bytes), OsStr::from_bytes(default.as_bytes()));
self = self.default_value_if_os(arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()));
}
self
}

View file

@ -22,9 +22,7 @@ impl<'e> Default for Switched<'e> {
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Switched<'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self {
a.s.clone()
}
fn from(a: &'z Arg<'n, 'e>) -> Self { a.s.clone() }
}
impl<'e> Clone for Switched<'e> {

View file

@ -125,21 +125,7 @@ complete -F _{name} -o bashdefault -o default {name}
let mut p = self.p;
for sc in path.split("__").skip(1) {
debugln!("BashGen::option_details_for_path:iter: sc={}", sc);
p = &p.subcommands
.iter()
.find(|s| {
s.p.meta.name == sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == sc))
})
.unwrap()
.p;
p = &find_subcmd!(p, sc).unwrap().p;
}
let mut opts = String::new();
for o in p.opts() {
@ -214,28 +200,12 @@ complete -F _{name} -o bashdefault -o default {name}
let mut p = self.p;
for sc in path.split("__").skip(1) {
debugln!("BashGen::all_options_for_path:iter: sc={}", sc);
p = &p.subcommands
.iter()
.find(|s| {
s.p.meta.name == sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == sc))
})
.unwrap()
.p;
p = &find_subcmd!(p, sc).unwrap().p;
}
let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s));
opts = format!("{} {}",
opts,
p.long_list
.iter()
.fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
opts = format!("{} {}",
opts,
p.positionals

View file

@ -19,10 +19,7 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
let (subcommands_detection_cases, subcommands_cases) = generate_inner(self.p, "");
let mut bin_names = vec![
bin_name.to_string(),
format!("./{0}", bin_name),
];
let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)];
if cfg!(windows) {
bin_names.push(format!("{0}.exe", bin_name));
bin_names.push(format!(r".\{0}", bin_name));
@ -92,10 +89,10 @@ fn generate_inner<'a, 'b>(p: &Parser<'a, 'b>, previous_command_name: &str) -> (S
for subcommand in &p.subcommands {
completions.push_str(&format!("'{}', ", &subcommand.p.meta.name));
}
for short in &p.short_list {
for short in shorts!(p) {
completions.push_str(&format!("'-{}', ", short));
}
for long in &p.long_list {
for long in longs!(p) {
completions.push_str(&format!("'--{}', ", long));
}

View file

@ -846,3 +846,201 @@ macro_rules! vec_remove_all {
}
};
}
macro_rules! find_from {
($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
if let Some(ref v) = f.$from() {
if v.contains($arg_name) {
ret = Some(f.to_string());
}
}
}
if let Some(o) = find_by_name!($_self, &k, opts, iter) {
if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) {
ret = Some(o.to_string());
}
}
}
if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
if let Some(ref v) = pos.$from() {
if v.contains($arg_name) {
ret = Some(pos.b.name.to_owned());
}
}
}
}
ret
}};
}
macro_rules! find_name_from {
($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, &k, flags, iter) {
if let Some(ref v) = f.$from() {
if v.contains($arg_name) {
ret = Some(f.b.name);
}
}
}
if let Some(o) = find_by_name!($_self, &k, opts, iter) {
if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) {
ret = Some(o.b.name);
}
}
}
if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
if let Some(ref v) = pos.$from() {
if v.contains($arg_name) {
ret = Some(pos.b.name);
}
}
}
}
ret
}};
}
// Finds an arg by name
macro_rules! find_by_name {
($_self:ident, $name:expr, $what:ident, $how:ident) => {
$_self.$what.$how().find(|o| &o.b.name == $name)
}
}
// Finds an option including if it's aliasesed
macro_rules! find_opt_by_long {
(@os $_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, opts)
}};
($_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, opts)
}};
}
macro_rules! find_flag_by_long {
(@os $_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, flags)
}};
($_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, flags)
}};
}
macro_rules! find_any_by_long {
($_self:ident, $long:expr, $what:ident) => {
_find_flag_by_long!($_self, $long).or(_find_opt_by_long!($_self, $long))
}
}
macro_rules! _find_by_long {
($_self:ident, $long:expr, $what:ident) => {{
$_self.$what
.iter()
.filter(|a| a.s.long.is_some())
.find(|a| {
&&a.s.long.unwrap() == &$long ||
(a.s.aliases.is_some() &&
a.s
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(alias, _)| &&alias == &$long))
})
}}
}
// Finds an option
macro_rules! find_opt_by_short {
($_self:ident, $short:expr) => {{
_find_by_short!($_self, $short, opts)
}}
}
macro_rules! find_flag_by_short {
($_self:ident, $short:expr) => {{
_find_by_short!($_self, $short, flags)
}}
}
macro_rules! find_any_by_short {
($_self:ident, $short:expr, $what:ident) => {
_find_flag_by_short!($_self, $short).or(_find_opt_by_short!($_self, $short))
}
}
macro_rules! _find_by_short {
($_self:ident, $short:expr, $what:ident) => {{
$_self.$what
.iter()
.filter(|a| a.s.short.is_some())
.find(|a| a.s.short.unwrap() == $short)
}}
}
macro_rules! find_subcmd {
($_self:expr, $sc:expr) => {{
$_self.subcommands
.iter()
.find(|s| {
s.p.meta.name == $sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == $sc))
})
}};
}
macro_rules! shorts {
($_self:ident) => {{
_shorts_longs!($_self, short)
}};
}
macro_rules! longs {
($_self:ident) => {{
_shorts_longs!($_self, long)
}};
}
macro_rules! _shorts_longs {
($_self:ident, $what:ident) => {{
$_self.flags
.iter()
.filter(|f| f.s.$what.is_some())
.map(|f| f.s.$what.as_ref().unwrap())
.chain($_self.opts.iter()
.filter(|o| o.s.$what.is_some())
.map(|o| o.s.$what.as_ref().unwrap()))
}};
}
macro_rules! arg_names {
($_self:ident) => {{
_names!($_self)
}};
}
macro_rules! _names {
($_self:ident) => {{
$_self.flags
.iter()
.map(|f| &*f.b.name)
.chain($_self.opts.iter()
.map(|o| &*o.b.name)
.chain($_self.positionals.values()
.map(|p| &*p.b.name)))
}};
}

View file

@ -63,7 +63,7 @@ static BASH: &'static str = r#"_myapp() {
return 0
;;
myapp__test)
opts=" -h -V --case --help --version "
opts=" -h -V --help --version --case "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
@ -550,7 +550,7 @@ static BASH_WUS: &'static str = r#"_my_app() {
return 0
;;
my_app__some_cmd)
opts=" -h -V --config --help --version "
opts=" -h -V --help --version --config "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
@ -569,7 +569,7 @@ static BASH_WUS: &'static str = r#"_my_app() {
return 0
;;
my_app__test)
opts=" -h -V --case --help --version "
opts=" -h -V --help --version --case "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
@ -609,15 +609,12 @@ fn compare(left: &str, right: &str) -> bool {
b
}
fn build_app() -> App<'static, 'static> {
build_app_with_name("myapp")
}
fn build_app() -> App<'static, 'static> { build_app_with_name("myapp") }
fn build_app_with_name(s: &'static str) -> App<'static, 'static> {
App::new(s)
App::new(s)
.about("Tests completions")
.arg(Arg::with_name("file")
.help("some input file"))
.arg(Arg::with_name("file").help("some input file"))
.subcommand(SubCommand::with_name("test")
.about("tests things")
.arg(Arg::with_name("case")
@ -627,13 +624,12 @@ fn build_app_with_name(s: &'static str) -> App<'static, 'static> {
}
fn build_app_with_underscore() -> App<'static, 'static> {
build_app_with_name("my_app")
.subcommand(SubCommand::with_name("some_cmd")
.about("tests other things")
.arg(Arg::with_name("config")
.long("--config")
.takes_value(true)
.help("the other case to test")))
build_app_with_name("my_app").subcommand(SubCommand::with_name("some_cmd")
.about("tests other things")
.arg(Arg::with_name("config")
.long("--config")
.takes_value(true)
.help("the other case to test")))
}
#[test]
@ -668,25 +664,25 @@ fn fish() {
// Disabled until I figure out this windows line ending and AppVeyor issues
//#[test]
fn powershell() {
let mut app = build_app();
let mut buf = vec![];
app.gen_completions_to("myapp", Shell::PowerShell, &mut buf);
let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, POWERSHELL));
}
// fn powershell() {
// let mut app = build_app();
// let mut buf = vec![];
// app.gen_completions_to("myapp", Shell::PowerShell, &mut buf);
// let string = String::from_utf8(buf).unwrap();
//
// assert!(compare(&*string, POWERSHELL));
// }
// Disabled until I figure out this windows line ending and AppVeyor issues
//#[test]
fn powershell_with_underscore() {
let mut app = build_app_with_underscore();
let mut buf = vec![];
app.gen_completions_to("my_app", Shell::PowerShell, &mut buf);
let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, POWERSHELL_WUS));
}
// fn powershell_with_underscore() {
// let mut app = build_app_with_underscore();
// let mut buf = vec![];
// app.gen_completions_to("my_app", Shell::PowerShell, &mut buf);
// let string = String::from_utf8(buf).unwrap();
//
// assert!(compare(&*string, POWERSHELL_WUS));
// }
#[test]
fn bash_with_underscore() {

View file

@ -278,8 +278,7 @@ fn help_subcommand() {
#[test]
fn subcommand_short_help() {
let m = test::complex_app()
.get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);
let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
@ -287,8 +286,7 @@ fn subcommand_short_help() {
#[test]
fn subcommand_long_help() {
let m = test::complex_app()
.get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);
let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
@ -296,8 +294,7 @@ fn subcommand_long_help() {
#[test]
fn subcommand_help_rev() {
let m = test::complex_app()
.get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);
let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
@ -321,12 +318,11 @@ fn after_and_before_help_output() {
#[test]
fn multi_level_sc_help() {
let app = App::new("ctest")
.subcommand(SubCommand::with_name("subcmd")
.subcommand(SubCommand::with_name("multi")
.about("tests subcommands")
.author("Kevin K. <kbknapp@gmail.com>")
.version("0.1")
.args_from_usage("
.subcommand(SubCommand::with_name("subcmd").subcommand(SubCommand::with_name("multi")
.about("tests subcommands")
.author("Kevin K. <kbknapp@gmail.com>")
.version("0.1")
.args_from_usage("
-f, --flag 'tests flags'
-o, --option [scoption]... 'tests options'
")));
@ -354,16 +350,16 @@ fn issue_626_unicode_cutoff() {
.version("0.1")
.set_term_width(70)
.arg(Arg::with_name("cafe")
.short("c")
.long("cafe")
.value_name("FILE")
.help("A coffeehouse, coffee shop, or café is an establishment \
.short("c")
.long("cafe")
.value_name("FILE")
.help("A coffeehouse, coffee shop, or café is an establishment \
which primarily serves hot coffee, related coffee beverages \
(e.g., café latte, cappuccino, espresso), tea, and other hot \
beverages. Some coffeehouses also serve cold beverages such as \
iced coffee and iced tea. Many cafés also serve some type of \
food, such as light snacks, muffins, or pastries.")
.takes_value(true));
.takes_value(true));
assert!(test::compare_output(app, "ctest --help", ISSUE_626_CUTOFF, false));
}
@ -372,20 +368,20 @@ fn hide_possible_vals() {
let app = App::new("ctest")
.version("0.1")
.arg(Arg::with_name("pos")
.short("p")
.long("pos")
.value_name("VAL")
.possible_values(&["fast", "slow"])
.help("Some vals")
.takes_value(true))
.short("p")
.long("pos")
.value_name("VAL")
.possible_values(&["fast", "slow"])
.help("Some vals")
.takes_value(true))
.arg(Arg::with_name("cafe")
.short("c")
.long("cafe")
.value_name("FILE")
.hide_possible_values(true)
.possible_values(&["fast", "slow"])
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true));
.short("c")
.long("cafe")
.value_name("FILE")
.hide_possible_values(true)
.possible_values(&["fast", "slow"])
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true));
assert!(test::compare_output(app, "ctest --help", HIDE_POS_VALS, false));
}
@ -441,9 +437,9 @@ fn old_newline_chars() {
#[test]
fn issue_688_hidden_pos_vals() {
let filter_values = ["Nearest", "Linear", "Cubic", "Gaussian", "Lanczos3"];
let filter_values = ["Nearest", "Linear", "Cubic", "Gaussian", "Lanczos3"];
let app1 = App::new("ctest")
let app1 = App::new("ctest")
.version("0.1")
.set_term_width(120)
.setting(AppSettings::HidePossibleValuesInHelp)
@ -455,7 +451,7 @@ fn issue_688_hidden_pos_vals() {
.takes_value(true));
assert!(test::compare_output(app1, "ctest --help", ISSUE_688, false));
let app2 = App::new("ctest")
let app2 = App::new("ctest")
.version("0.1")
.set_term_width(120)
.arg(Arg::with_name("filter")
@ -466,7 +462,7 @@ fn issue_688_hidden_pos_vals() {
.takes_value(true));
assert!(test::compare_output(app2, "ctest --help", ISSUE_688, false));
let app3 = App::new("ctest")
let app3 = App::new("ctest")
.version("0.1")
.set_term_width(120)
.arg(Arg::with_name("filter")
@ -483,27 +479,26 @@ fn issue_702_multiple_values() {
.version("1.0")
.author("foo")
.about("bar")
.arg(Arg::with_name("arg1")
.help("some option"))
.arg(Arg::with_name("arg1").help("some option"))
.arg(Arg::with_name("arg2")
.multiple(true)
.help("some option"))
.multiple(true)
.help("some option"))
.arg(Arg::with_name("some")
.help("some option")
.short("s")
.long("some")
.takes_value(true))
.help("some option")
.short("s")
.long("some")
.takes_value(true))
.arg(Arg::with_name("other")
.help("some other option")
.short("o")
.long("other")
.takes_value(true))
.help("some other option")
.short("o")
.long("other")
.takes_value(true))
.arg(Arg::with_name("label")
.help("a label")
.short("l")
.long("label")
.multiple(true)
.takes_value(true));
.help("a label")
.short("l")
.long("label")
.multiple(true)
.takes_value(true));
assert!(test::compare_output(app, "myapp --help", ISSUE_702, false));
}
@ -512,17 +507,17 @@ fn issue_760() {
let app = App::new("ctest")
.version("0.1")
.arg(Arg::with_name("option")
.help("tests options")
.short("o")
.long("option")
.takes_value(true)
.multiple(true)
.number_of_values(1))
.help("tests options")
.short("o")
.long("option")
.takes_value(true)
.multiple(true)
.number_of_values(1))
.arg(Arg::with_name("opt")
.help("tests options")
.short("O")
.long("opt")
.takes_value(true));
.help("tests options")
.short("O")
.long("opt")
.takes_value(true));
assert!(test::compare_output(app, "ctest --help", ISSUE_760, false));
}
#[test]

View file

@ -106,8 +106,7 @@ fn quoted_arg_long_name() {
(@arg scpositional: index(1) "tests positionals"))
);
assert_eq!(app.p.long_list[2], "long-option-2");
let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"]).expect("Expected to successfully match the given args.");
let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
.expect("Expected to successfully match the given args.");
assert!(matches.is_present("option2"));
}

View file

@ -18,7 +18,7 @@ static COND_REQ_IN_USAGE: &'static str = "error: The following required argument
--output <output>
USAGE:
test --target <target> --input <input> --output <output>
test --input <input> --output <output> --target <target>
For more information try --help";
@ -46,7 +46,7 @@ fn flag_required_2() {
#[test]
fn option_required() {
let result = App::new("option_required")
.arg(Arg::from_usage("-f [flag] 'some flag'").requires("color"))
.arg(Arg::from_usage("-f [flag] 'some flag'").requires("c"))
.arg(Arg::from_usage("-c [color] 'third flag'"))
.get_matches_from_safe(vec!["", "-f", "val"]);
assert!(result.is_err());

View file

@ -2,30 +2,21 @@ extern crate clap;
use clap::{App, Arg};
#[test]
#[should_panic]
fn unique_arg_names() {
App::new("some").args(&[
Arg::with_name("arg").short("a"),
Arg::with_name("arg").short("b")
]);
App::new("some").args(&[Arg::with_name("arg").short("a"), Arg::with_name("arg").short("b")]);
}
#[test]
#[should_panic]
fn unique_arg_shorts() {
App::new("some").args(&[
Arg::with_name("arg1").short("a"),
Arg::with_name("arg2").short("a")
]);
App::new("some").args(&[Arg::with_name("arg1").short("a"), Arg::with_name("arg2").short("a")]);
}
#[test]
#[should_panic]
fn unique_arg_longs() {
App::new("some").args(&[
Arg::with_name("arg1").long("long"),
Arg::with_name("arg2").long("long")
]);
App::new("some")
.args(&[Arg::with_name("arg1").long("long"), Arg::with_name("arg2").long("long")]);
}