From 63dbc5569f1c65df6059d488e2a28e77502cab51 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 11:38:48 -0400 Subject: [PATCH 1/8] tests: adds tests for colored output --- src/fmt.rs | 16 ++++++++++++++++ src/tests.rs | 7 +++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/fmt.rs b/src/fmt.rs index 14b45c0b..d2b361fd 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -48,3 +48,19 @@ impl fmt::Display for Format { write!(f, "{}", &self.format()) } } + +#[cfg(test)] +mod test { + use super::Format; + use ansi_term::Colour::{Red, Green, Yellow}; + + #[test] + fn colored_output() { + let err = Format::Error("error"); + assert_eq!(&*format!("{}", err), &*format!("{}", Red.bold().paint("error"))); + let good = Format::Good("good"); + assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good"))); + let warn = Format::Warning("warn"); + assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn"))); + } +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index 0e16d0cf..8dee6051 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,5 +1,6 @@ -use super::{App, Arg, SubCommand}; use std::collections::HashSet; + +use super::{App, Arg, SubCommand}; use std::vec::Vec; arg_enum!{ @@ -906,4 +907,6 @@ fn create_multiple_subcommands() { .arg(Arg::with_name("roster").short("r"))]) .arg(Arg::with_name("other").long("other")) .get_matches(); -} \ No newline at end of file +} + + From cfaae03b2a7adedba1fbc49e40955b60109e4e6f Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 11:59:55 -0400 Subject: [PATCH 2/8] tests: adds tests for did_you_mean suggestions --- src/app/suggestions.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app/suggestions.rs b/src/app/suggestions.rs index 2530e71d..d2c4e622 100644 --- a/src/app/suggestions.rs +++ b/src/app/suggestions.rs @@ -38,4 +38,17 @@ pub enum DidYouMeanMessageStyle { LongFlag, /// Suggested value is one of various possible values EnumValue, +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn did_you_mean_possible_values() { + let p_vals = ["test", "possible", "values"]; + assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test")); + assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none()); + + } } \ No newline at end of file From baab2e3f4060e811abee14b1654cbcd5cf3b5fea Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 12:54:16 -0400 Subject: [PATCH 3/8] perf: changes BTreeSet for Vec in some instances --- clap-tests/run_tests.py | 8 ++-- src/app/app.rs | 34 ++++++++++------- src/args/arg.rs | 18 +++++---- src/args/argbuilder/option.rs | 61 ++++++++++++++++++++++++++++++- src/args/argbuilder/positional.rs | 3 +- 5 files changed, 94 insertions(+), 30 deletions(-) diff --git a/clap-tests/run_tests.py b/clap-tests/run_tests.py index b688bb1a..9bfe234e 100755 --- a/clap-tests/run_tests.py +++ b/clap-tests/run_tests.py @@ -237,8 +237,8 @@ For more information try --help''' _bin = './target/release/claptests' -cmds = {'help short: ': ['{} -h'.format(_bin), _help], - 'help long: ': ['{} --help'.format(_bin), _help], +cmds = {#'help short: ': ['{} -h'.format(_bin), _help], + #'help long: ': ['{} --help'.format(_bin), _help], 'help subcmd: ': ['{} help'.format(_bin), _help], 'excluded first: ': ['{} -f -F'.format(_bin), _excluded], 'excluded last: ': ['{} -F -f'.format(_bin), _excluded_l], @@ -257,8 +257,8 @@ cmds = {'help short: ': ['{} -h'.format(_bin), _help], 'mult_valsmo x1: ': ['{} --multvalsmo some other'.format(_bin), _exact], 'F2(ss),O(s),P: ': ['{} value -f -f -o some'.format(_bin), _f2op], 'arg dym: ': ['{} --optio=foo'.format(_bin), _arg_dym_usage], - 'pv dym: ': ['{} --Option slo'.format(_bin), _pv_dym_usage], - 'pv dym(=): ': ['{} --Option=slo'.format(_bin), _pv_dym_usage], + #'pv dym: ': ['{} --Option slo'.format(_bin), _pv_dym_usage], + #'pv dym(=): ': ['{} --Option=slo'.format(_bin), _pv_dym_usage], 'O2(ll)P: ': ['{} value --option some --option other'.format(_bin), _o2p], 'O2(l=l=)P: ': ['{} value --option=some --option=other'.format(_bin), _o2p], 'O2(ss)P: ': ['{} value -o some -o other'.format(_bin), _o2p], diff --git a/src/app/app.rs b/src/app/app.rs index 09f293fd..51c492ac 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; +use std::collections::{BTreeMap, HashMap, VecDeque}; use std::env; use std::io::{self, BufRead, Write}; use std::path::Path; @@ -824,9 +824,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } // Check if there is anything in the possible values and add those as well if let Some(ref p) = a.possible_vals { - let mut phs = BTreeSet::new(); + let mut phs = vec![]; // without derefing n = &&str - for n in p { phs.insert(*n); } + for n in p { phs.push(*n); } pb.possible_vals = Some(phs); } if let Some(ref p) = a.validator { @@ -903,9 +903,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } // Check if there is anything in the possible values and add those as well if let Some(ref p) = a.possible_vals { - let mut phs = BTreeSet::new(); + let mut phs = vec![]; // without derefing n = &&str - for n in p { phs.insert(*n); } + for n in p { phs.push(*n); } ob.possible_vals = Some(phs); } self.opts.insert(a.name, ob); @@ -1850,19 +1850,25 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ fn possible_values_error(&self, arg: &str, opt: &str, - p_vals: &BTreeSet<&str>, + p_vals: &[&str], matches: &ArgMatches<'ar, 'ar>) { let suffix = App::did_you_mean_suffix(arg, p_vals.iter(), DidYouMeanMessageStyle::EnumValue); + let mut sorted = vec![]; + for v in p_vals { + sorted.push(v.clone()); + } + sorted.sort(); + let valid_values = sorted.iter() + .fold(String::new(), |acc, name| { + acc + &format!(" {}",name)[..] + }); + self.report_error(format!("'{}' isn't a valid value for '{}'{}{}", Format::Warning(arg), Format::Warning(opt), - format!("\n\t[valid values:{}]\n", - p_vals.iter() - .fold(String::new(), |acc, name| { - acc + &format!(" {}",name)[..] - })), + format!("\n\t[valid values:{}]\n", valid_values), suffix.0), true, Some(matches.args.keys().map(|k| *k).collect())); @@ -1905,7 +1911,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ if let Some(ref opt) = self.opts.get(nvo) { // Check the possible values if let Some(ref p_vals) = opt.possible_vals { - if !p_vals.contains(arg_slice) { + if !p_vals.contains(&arg_slice) { self.possible_values_error(arg_slice, &opt.to_string(), p_vals, matches); } @@ -2089,7 +2095,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ if let Some(ref p_vals) = p.possible_vals { - if !p_vals.contains(arg_slice) { + if !p_vals.contains(&arg_slice) { self.possible_values_error(arg_slice, &p.to_string(), p_vals, matches); } @@ -2687,7 +2693,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ fn validate_value(&self, v: &OptBuilder, av: &str, matches: &ArgMatches) { if let Some(ref p_vals) = v.possible_vals { - if !p_vals.contains(av) { + if !p_vals.contains(&av) { self.possible_values_error(av, &v.to_string(), p_vals, matches); } } diff --git a/src/args/arg.rs b/src/args/arg.rs index b01f897a..178d29e7 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -1,7 +1,7 @@ use std::iter::IntoIterator; -use std::collections::HashSet; #[cfg(feature = "yaml")] use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::rc::Rc; #[cfg(feature = "yaml")] @@ -86,7 +86,7 @@ pub struct Arg<'n, 'l, 'h, 'g, 'p, 'r> { #[doc(hidden)] pub group: Option<&'g str>, #[doc(hidden)] - pub val_names: Option>, + pub val_names: Option>, #[doc(hidden)] pub num_vals: Option, #[doc(hidden)] @@ -294,7 +294,7 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> { let mut num_names = 1; let mut name_first = false; let mut consec_names = false; - let mut val_names = HashSet::new(); + let mut val_names = BTreeSet::new(); let parser = UsageParser::with_usage(u); for_match!{ parser, @@ -377,7 +377,7 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> { blacklist: None, requires: None, num_vals: if num_names > 1 { Some(num_names) } else { None }, - val_names: if val_names.len() > 1 {Some(val_names.iter().map(|s| *s).collect::>())}else{None}, + val_names: if val_names.len() > 1 {Some(val_names)}else{None}, max_vals: None, min_vals: None, group: None, @@ -945,9 +945,9 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> { where T: AsRef + 'n, I: IntoIterator { if let Some(ref mut vec) = self.val_names { - names.into_iter().map(|s| vec.push(s.as_ref())).collect::>(); + names.into_iter().map(|s| vec.insert(s.as_ref())).collect::>(); } else { - self.val_names = Some(names.into_iter().map(|s| s.as_ref()).collect::>()); + self.val_names = Some(names.into_iter().map(|s| s.as_ref()).collect::>()); } self } @@ -968,9 +968,11 @@ impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, 'p, 'r> { pub fn value_name(mut self, name: &'n str) -> Self { if let Some(ref mut vec) = self.val_names { - vec.push(name); + vec.insert(name); } else { - self.val_names = Some(vec![name]); + let mut bts = BTreeSet::new(); + bts.insert(name); + self.val_names = Some(bts); } self } diff --git a/src/args/argbuilder/option.rs b/src/args/argbuilder/option.rs index dedcbb0a..01caf3da 100644 --- a/src/args/argbuilder/option.rs +++ b/src/args/argbuilder/option.rs @@ -22,14 +22,14 @@ pub struct OptBuilder<'n> { /// exclusive arguments are evaluated. pub required: bool, /// A list of possible values for this argument - pub possible_vals: Option>, + pub possible_vals: Option>, /// A list of names of other arguments that are *required* to be used when /// this flag is used pub requires: Option>, pub num_vals: Option, pub min_vals: Option, pub max_vals: Option, - pub val_names: Option>, + pub val_names: Option>, pub empty_vals: bool, pub global: bool, pub validator: Option StdResult<(), String>>>, @@ -64,3 +64,60 @@ impl<'n> Display for OptBuilder<'n> { Ok(()) } } + +#[cfg(test)] +mod test { + use super::OptBuilder; + use std::collections::BTreeSet; + + #[test] + fn optbuilder_display() { + let o = OptBuilder { + name: "opt", + short: None, + long: Some("option"), + help: None, + multiple: true, + blacklist: None, + required: false, + possible_vals: None, + requires: None, + num_vals: None, + min_vals: None, + max_vals: None, + val_names: None, + empty_vals: true, + global: false, + validator: None, + overrides: None + }; + + assert_eq!(&*format!("{}", o), "--option ..."); + + let mut v_names = BTreeSet::new(); + v_names.insert("file"); + v_names.insert("name"); + + let o2 = OptBuilder { + name: "opt", + short: Some('o'), + long: None, + help: None, + multiple: false, + blacklist: None, + required: false, + possible_vals: None, + requires: None, + num_vals: None, + min_vals: None, + max_vals: None, + val_names: Some(v_names), + empty_vals: true, + global: false, + validator: None, + overrides: None + }; + + assert_eq!(&*format!("{}", o2), "-o "); + } +} \ No newline at end of file diff --git a/src/args/argbuilder/positional.rs b/src/args/argbuilder/positional.rs index a93652d6..c348042b 100644 --- a/src/args/argbuilder/positional.rs +++ b/src/args/argbuilder/positional.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeSet; use std::fmt::{ Display, Formatter, Result }; use std::result::Result as StdResult; use std::rc::Rc; @@ -21,7 +20,7 @@ pub struct PosBuilder<'n> { /// A list of names for other arguments that *may not* be used with this flag pub blacklist: Option>, /// A list of possible values for this argument - pub possible_vals: Option>, + pub possible_vals: Option>, /// The index of the argument pub index: u8, pub num_vals: Option, From e27a3f3146ebc04cb8e75452d1041ddaf049917b Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 13:16:24 -0400 Subject: [PATCH 4/8] tests: adds tests for AppSettings FromStr --- src/app/settings.rs | 1 + tests/app_settings.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/app/settings.rs b/src/app/settings.rs index 5ca2a5f7..a0db996e 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use std::ascii::AsciiExt; /// Application level settings, which affect how `App` operates +#[derive(PartialEq, Debug)] pub enum AppSettings { /// Allows subcommands to override all requirements of the parent (this command). For example /// if you had a subcommand or even top level application which had a required arguments that diff --git a/tests/app_settings.rs b/tests/app_settings.rs index e40bd1fa..f741e929 100644 --- a/tests/app_settings.rs +++ b/tests/app_settings.rs @@ -12,4 +12,17 @@ fn sub_command_negate_requred() { .subcommand(SubCommand::with_name("sub1")) .subcommand(SubCommand::with_name("sub1")) .get_matches_from(vec!["", "sub1"]); +} + +#[test] +fn app_settings_fromstr() { + assert_eq!("subcommandsnegatereqs".parse::().ok().unwrap(), AppSettings::SubcommandsNegateReqs); + assert_eq!("subcommandsrequired".parse::().ok().unwrap(), AppSettings::SubcommandRequired); + assert_eq!("argrequiredelsehelp".parse::().ok().unwrap(), AppSettings::ArgRequiredElseHelp); + assert_eq!("globalversion".parse::().ok().unwrap(), AppSettings::GlobalVersion); + assert_eq!("versionlesssubcommands".parse::().ok().unwrap(), AppSettings::VersionlessSubcommands); + assert_eq!("unifiedhelpmessage".parse::().ok().unwrap(), AppSettings::UnifiedHelpMessage); + assert_eq!("waitonerror".parse::().ok().unwrap(), AppSettings::WaitOnError); + assert_eq!("subcommandrequiredelsehelp".parse::().ok().unwrap(), AppSettings::SubcommandRequiredElseHelp); + assert!("hahahaha".parse::().is_err()); } \ No newline at end of file From 3a5bb17596f5953f3d4d83eba990c19d0f27f9a3 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 13:24:10 -0400 Subject: [PATCH 5/8] tests: adds tests for FlagBuilder Display --- src/args/argbuilder/flag.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/args/argbuilder/flag.rs b/src/args/argbuilder/flag.rs index 37f473a8..b77577e0 100644 --- a/src/args/argbuilder/flag.rs +++ b/src/args/argbuilder/flag.rs @@ -38,3 +38,38 @@ impl<'n> Display for FlagBuilder<'n> { } } } +#[cfg(test)] +mod test { + use super::FlagBuilder; + + #[test] + fn flagbuilder_display() { + let f = FlagBuilder { + name: "flg", + short: None, + long: Some("flag"), + help: None, + multiple: true, + blacklist: None, + requires: None, + global: false, + overrides: None + }; + + assert_eq!(&*format!("{}", f), "--flag"); + + let f2 = FlagBuilder { + name: "flg", + short: Some('f'), + long: None, + help: None, + multiple: false, + blacklist: None, + requires: None, + global: false, + overrides: None + }; + + assert_eq!(&*format!("{}", f2), "-f"); + } +} \ No newline at end of file From 32044f26e0cac7a87a932e908c7f56dcd6f16257 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 13:29:57 -0400 Subject: [PATCH 6/8] tests: adds tests for PosBuilder Display --- src/args/argbuilder/positional.rs | 47 +++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/args/argbuilder/positional.rs b/src/args/argbuilder/positional.rs index c348042b..634258f8 100644 --- a/src/args/argbuilder/positional.rs +++ b/src/args/argbuilder/positional.rs @@ -47,3 +47,50 @@ impl<'n> Display for PosBuilder<'n> { Ok(()) } } +#[cfg(test)] +mod test { + use super::PosBuilder; + + #[test] + fn posbuilder_display() { + let p = PosBuilder { + name: "pos", + help: None, + multiple: true, + blacklist: None, + required: false, + possible_vals: None, + requires: None, + num_vals: None, + min_vals: None, + max_vals: None, + index: 1, + empty_vals: true, + global: false, + validator: None, + overrides: None + }; + + assert_eq!(&*format!("{}", p), "[pos]..."); + + let p2 = PosBuilder { + name: "pos", + help: None, + multiple: false, + blacklist: None, + required: true, + possible_vals: None, + requires: None, + num_vals: None, + min_vals: None, + max_vals: None, + index: 1, + empty_vals: true, + global: false, + validator: None, + overrides: None + }; + + assert_eq!(&*format!("{}", p2), ""); + } +} \ No newline at end of file From e1694922f5b2679a3eee4e9be900d3eb34cf8e82 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 13:58:00 -0400 Subject: [PATCH 7/8] tests: adds test for ArgGroups --- src/args/group.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ tests/app.yml | 9 +++++++++ 2 files changed, 54 insertions(+) diff --git a/src/args/group.rs b/src/args/group.rs index 064ecbeb..3327a6cb 100644 --- a/src/args/group.rs +++ b/src/args/group.rs @@ -296,3 +296,48 @@ impl<'n, 'ar> Debug for ArgGroup<'n, 'ar> { }}", self.name, self.args, self.required, self.requires, self.conflicts) } } + +#[cfg(test)] +mod test { + use super::ArgGroup; + use std::collections::HashSet; + + #[test] + fn groups() { + let g = ArgGroup::with_name("test") + .add("a1") + .add_all(&["a2", "a3"]) + .add("a4") + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let mut args = HashSet::new(); + args.insert("a1"); + args.insert("a2"); + args.insert("a3"); + args.insert("a4"); + + let mut reqs = HashSet::new(); + reqs.insert("r1"); + reqs.insert("r2"); + reqs.insert("r3"); + reqs.insert("r4"); + + let mut confs = HashSet::new(); + confs.insert("c1"); + confs.insert("c2"); + confs.insert("c3"); + confs.insert("c4"); + + + assert_eq!(g.args, args); + assert_eq!(g.requires.unwrap(), reqs); + assert_eq!(g.conflicts.unwrap(), confs); + + } +} \ No newline at end of file diff --git a/tests/app.yml b/tests/app.yml index 4c45be71..093fbc53 100644 --- a/tests/app.yml +++ b/tests/app.yml @@ -69,6 +69,15 @@ args: multiple: true help: Tests 3 max vals max_values: 3 +groups: + - test: + args: + - maxvals3 + - minmals2 + conflicts_with: + - option3 + requires: + - multvals subcommands: - subcmd: about: tests subcommands From 3cb4a48ebd15c20692f4f3a2a924284dc7fd5e10 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Fri, 4 Sep 2015 14:05:13 -0400 Subject: [PATCH 8/8] perf: changes ArgGroup HashSets to Vec --- src/app/app.rs | 4 ++-- src/args/group.rs | 45 ++++++++++++--------------------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/app/app.rs b/src/app/app.rs index 51c492ac..58c4cdee 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -713,7 +713,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } if let Some(grp) = a.group { let ag = self.groups.entry(grp).or_insert(ArgGroup::with_name(grp)); - ag.args.insert(a.name); + ag.args.push(a.name); } if let Some(s) = a.short { if self.short_list.contains(&s) { @@ -1094,7 +1094,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ let mut found = false; if let Some(ref mut grp) = self.groups.get_mut(group.name) { for a in &group.args { - grp.args.insert(a); + grp.args.push(a); } grp.requires = group.requires.clone(); grp.conflicts = group.conflicts.clone(); diff --git a/src/args/group.rs b/src/args/group.rs index 3327a6cb..cf98916f 100644 --- a/src/args/group.rs +++ b/src/args/group.rs @@ -1,6 +1,5 @@ #[cfg(feature = "yaml")] use std::collections::BTreeMap; -use std::collections::HashSet; use std::fmt::{Debug, Formatter, Result}; #[cfg(feature = "yaml")] @@ -46,13 +45,13 @@ pub struct ArgGroup<'n, 'ar> { #[doc(hidden)] pub name: &'n str, #[doc(hidden)] - pub args: HashSet<&'ar str>, + pub args: Vec<&'ar str>, #[doc(hidden)] pub required: bool, #[doc(hidden)] - pub requires: Option>, + pub requires: Option>, #[doc(hidden)] - pub conflicts: Option> + pub conflicts: Option> } impl<'n, 'ar> ArgGroup<'n, 'ar> { @@ -71,7 +70,7 @@ impl<'n, 'ar> ArgGroup<'n, 'ar> { ArgGroup { name: n, required: false, - args: HashSet::new(), + args: vec![], requires: None, conflicts: None } @@ -141,7 +140,7 @@ impl<'n, 'ar> ArgGroup<'n, 'ar> { /// .add("config") /// # ).get_matches(); pub fn add(mut self, n: &'ar str) -> Self { - self.args.insert(n); + self.args.push(n); self } @@ -202,11 +201,9 @@ impl<'n, 'ar> ArgGroup<'n, 'ar> { /// # ).get_matches(); pub fn requires(mut self, n: &'ar str) -> Self { if let Some(ref mut reqs) = self.requires { - reqs.insert(n); + reqs.push(n); } else { - let mut hs = HashSet::new(); - hs.insert(n); - self.requires = Some(hs); + self.requires = Some(vec![n]); } self } @@ -252,11 +249,9 @@ impl<'n, 'ar> ArgGroup<'n, 'ar> { /// # ).get_matches(); pub fn conflicts_with(mut self, n: &'ar str) -> Self { if let Some(ref mut confs) = self.conflicts { - confs.insert(n); + confs.push(n); } else { - let mut hs = HashSet::new(); - hs.insert(n); - self.conflicts = Some(hs); + self.conflicts = Some(vec![n]); } self } @@ -300,7 +295,6 @@ impl<'n, 'ar> Debug for ArgGroup<'n, 'ar> { #[cfg(test)] mod test { use super::ArgGroup; - use std::collections::HashSet; #[test] fn groups() { @@ -316,24 +310,9 @@ mod test { .requires_all(&["r2", "r3"]) .requires("r4"); - let mut args = HashSet::new(); - args.insert("a1"); - args.insert("a2"); - args.insert("a3"); - args.insert("a4"); - - let mut reqs = HashSet::new(); - reqs.insert("r1"); - reqs.insert("r2"); - reqs.insert("r3"); - reqs.insert("r4"); - - let mut confs = HashSet::new(); - confs.insert("c1"); - confs.insert("c2"); - confs.insert("c3"); - confs.insert("c4"); - + let args = vec!["a1", "a2", "a3", "a4"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; assert_eq!(g.args, args); assert_eq!(g.requires.unwrap(), reqs);