1#![cfg_attr(not(feature = "std"), no_std)]
2extern crate alloc;
3
4#[cfg(not(feature = "std"))]
5mod std;
6
7#[cfg(feature = "derive")]
8use serde::{Deserialize, Serialize};
9
10pub mod value;
11
12use std::iter::Peekable;
13use std::string::String;
14use std::vec::Vec;
15use std::{
16 collections::{
17 hash_map::Entry::{Occupied, Vacant},
18 HashMap,
19 },
20 process::exit,
21};
22
23use crate::value::{cast_type, check_type, Type, Value};
24use unicode_segmentation::UnicodeSegmentation;
25
26#[cfg(feature = "debug")]
27use log::debug;
28
29#[cfg(not(feature = "debug"))]
31macro_rules! debug {
32 ($($arg:tt)+) => {};
33}
34
35#[derive(PartialEq, Debug)]
36pub enum Error<'a> {
37 UnknownArg,
38 InvalidArg,
39 MissingRequiredArgs(Vec<&'a str>),
40 WrongNumValues(&'a str, &'a NumValues, Value),
41 WrongValueType(Value),
42 WrongCastType(String),
43 InvalidValue(String, String),
44 Override(&'a str),
45 UnknownArgs(Vec<String>),
46 BadInput,
47}
48
49#[allow(dead_code)]
54#[derive(PartialEq, Debug)]
55#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
56pub enum NumValues {
57 None,
58 Fixed(usize),
59 AtLeast(usize),
60 Between(usize, usize),
61 Any,
62}
63
64impl Default for NumValues {
65 fn default() -> Self {
66 NumValues::Fixed(1)
67 }
68}
69
70#[cfg_attr(feature = "derive", derive(Deserialize))]
72pub struct Arg<'a> {
73 pub name: &'a str,
75 #[cfg_attr(feature = "derive", serde(default))]
79 pub short: Option<&'a str>,
80 #[cfg_attr(feature = "derive", serde(default))]
82 pub long: Option<&'a str>,
83 #[cfg_attr(feature = "derive", serde(default))]
85 pub about: &'a str,
86 #[cfg_attr(feature = "derive", serde(default))]
88 pub num_values: NumValues,
89 #[cfg_attr(feature = "derive", serde(default))]
91 pub value_name: Option<&'a str>,
92 #[cfg_attr(feature = "derive", serde(skip, default))]
94 pub default: Option<fn() -> Value>,
95 #[cfg_attr(feature = "derive", serde(default))]
97 pub required: bool,
98 #[cfg_attr(feature = "derive", serde(default))]
100 pub value_type: Type,
101 #[cfg_attr(feature = "derive", serde(skip, default = "default_validation"))]
104 pub validation: fn(&Value) -> Result<(), String>,
105}
106
107fn default_validation() -> fn(&Value) -> Result<(), String> {
108 |_| Ok(())
109}
110
111impl<'a> std::default::Default for Arg<'a> {
112 fn default() -> Self {
113 Arg {
114 name: Default::default(),
115 short: Default::default(),
116 long: Default::default(),
117 about: Default::default(),
118 num_values: Default::default(),
119 value_name: Default::default(),
120 default: Default::default(),
121 required: Default::default(),
122 value_type: Default::default(),
123 validation: default_validation(),
124 }
125 }
126}
127
128#[cfg_attr(feature = "debug", derive(Debug))]
132#[cfg_attr(feature = "derive", derive(Deserialize))]
133pub enum FilterType {
134 All,
135 Any,
136}
137
138#[derive(Default)]
141#[cfg_attr(feature = "derive", derive(Deserialize))]
142pub struct Filters<'a> {
143 #[cfg_attr(feature = "derive", serde(default))]
144 pub filter_type: FilterType,
145 #[cfg_attr(feature = "derive", serde(default, borrow))]
146 pub filters: Vec<Filter<'a>>,
147 #[cfg_attr(feature = "derive", serde(default))]
148 pub inverse: bool,
149}
150
151#[cfg_attr(feature = "debug", derive(Debug))]
157#[derive(Default)]
158#[cfg_attr(feature = "derive", derive(Deserialize))]
159pub struct Filter<'a> {
160 #[cfg_attr(feature = "derive", serde(default))]
161 pub inverse: bool,
162 #[cfg_attr(feature = "derive", serde(default))]
163 pub filter_type: FilterType,
164 #[cfg_attr(feature = "derive", serde(default, borrow))]
166 pub args: Vec<&'a str>,
167}
168
169impl<'a> Filter<'a> {
170 fn test(&self, builder: &Builder<'a>) -> usize {
172 debug!("applying filter {:?} to {:?}", self, builder);
173 let res = match self.filter_type {
174 FilterType::All => self.args.iter().all(|p| builder.args.contains_key(p) || builder.flags.contains_key(p)),
175 FilterType::Any => self.args.iter().any(|p| builder.args.contains_key(p) || builder.flags.contains_key(p)),
176 };
177 debug!("filter result: {}, using inverse: {}", res, self.inverse);
178 (res ^ self.inverse) as usize
179 }
180}
181
182impl Default for FilterType {
183 fn default() -> Self {
184 FilterType::Any
185 }
186}
187
188#[cfg_attr(feature = "derive", derive(Deserialize))]
190pub struct Args<'a, T = Results<'a>> {
191 #[cfg_attr(feature = "derive", serde(default = "name_default"))]
194 pub name: &'a str,
195 #[cfg_attr(feature = "derive", serde(default))]
205 pub path: Option<&'a str>,
206 #[cfg_attr(feature = "derive", serde(default = "version_default"))]
209 pub version: &'a str,
210 #[cfg_attr(feature = "derive", serde(default = "about_default"))]
213 pub about: &'a str,
214 #[cfg_attr(feature = "derive", serde(default))]
216 pub args: Vec<Arg<'a>>,
217 #[cfg_attr(feature = "derive", serde(default))]
219 pub disable_overrides: bool,
220 #[cfg_attr(feature = "derive", serde(default))]
222 pub fail_on_unknown_args: bool,
223 #[cfg_attr(feature = "derive", serde(default = "default_vec"))]
225 pub subcommands: Vec<Args<'a, T>>,
226 #[cfg_attr(feature = "derive", serde(skip, bound(deserialize = "T: Handler<'a, T>"), default = "T::handler"))]
229 pub handler: fn(Results<'a>) -> T,
230 #[cfg_attr(feature = "derive", serde(default))]
232 pub filters: Filters<'a>,
233}
234
235fn name_default<'a>() -> &'a str {
236 env!("CARGO_PKG_NAME")
237}
238
239fn version_default<'a>() -> &'a str {
240 env!("CARGO_PKG_VERSION")
241}
242
243fn about_default<'a>() -> &'a str {
244 env!("CARGO_PKG_DESCRIPTION")
245}
246
247#[cfg(feature = "derive")]
248fn default_vec<'a, T>() -> Vec<Args<'a, T>> {
249 vec![]
250}
251
252pub trait Handler<'a, T> {
253 fn handler() -> fn(Results<'a>) -> T;
254}
255
256impl<'a, T: Default> Handler<'a, T> for T {
258 fn handler() -> fn(Results<'a>) -> Self {
259 |_| Default::default()
260 }
261}
262
263impl<'a> Handler<'a, Results<'a>> for Results<'a> {
264 fn handler() -> fn(Results<'a>) -> Self {
265 |results| results
266 }
267}
268
269impl<'a, T: Handler<'a, T>> Default for Args<'a, T> {
270 fn default() -> Self {
271 Args {
272 name: name_default(),
273 path: Default::default(),
274 version: version_default(),
275 about: about_default(),
276 args: Default::default(),
277 disable_overrides: Default::default(),
278 fail_on_unknown_args: Default::default(),
279 subcommands: Default::default(),
280 handler: T::handler(),
281 filters: Default::default(),
282 }
283 }
284}
285
286#[derive(Debug, PartialEq)]
288#[cfg_attr(feature = "derive", derive(Deserialize))]
289pub struct Results<'a> {
290 pub path: &'a str,
292 pub flags: HashMap<&'a str, i32>,
294 pub args: HashMap<&'a str, Value>,
298 pub unknown_args: Vec<String>,
300 pub positional: Vec<String>,
305}
306
307struct Builder<'a> {
309 flags: HashMap<&'a str, i32>,
310 args: HashMap<&'a str, Value>,
311}
312
313pub trait IntoStr {
314 fn into(&self) -> &str;
315}
316
317impl IntoStr for &str {
318 fn into(&self) -> &str {
319 self
320 }
321}
322
323impl IntoStr for String {
324 fn into(&self) -> &str {
325 self.as_str()
326 }
327}
328
329trait ArgsMethods<'a, R, S: IntoStr, T: Iterator<Item = S>> {
332 fn get_values_unbounded(&self, arg: &Arg, args: &mut Peekable<T>, est: usize) -> Result<Vec<Value>, Error>;
334 fn get_values_bounded(&self, arg: &Arg, args: &mut Peekable<T>, est: usize) -> Result<Vec<Value>, Error>;
336 fn update_values(&'a self, arg: &'a Arg, args: &mut Peekable<T>, out: &mut Builder<'a>) -> Result<(), Error>;
339 fn handle_arg(&'a self, arg: &str, args: &mut Peekable<T>, out: &mut Builder<'a>) -> Result<(), Error>;
343 fn apply(&'a self, args: T) -> Result<R, Error>;
345}
346
347impl<'a, R, S: IntoStr, T: Iterator<Item = S>> ArgsMethods<'a, R, S, T> for Args<'a, R> {
348 fn get_values_unbounded(&self, arg: &Arg, args: &mut Peekable<T>, est: usize) -> Result<Vec<Value>, Error> {
349 let mut params = Vec::with_capacity(est);
350 while let Some(param) = args.peek() {
351 let param = param.into();
352 if param.starts_with("-") {
353 break;
354 }
355 let val = cast_type(&arg.value_type, param)?;
356 if let Err(e) = (arg.validation)(&val) {
357 debug!("validation failed, reason: {}", e);
358 return Err(Error::InvalidValue(param.to_string(), e));
359 }
360 params.push(val);
361 args.next();
362 }
363 debug!("found params {:?}", params);
364 Ok(params)
365 }
366
367 fn get_values_bounded(&self, arg: &Arg, args: &mut Peekable<T>, est: usize) -> Result<Vec<Value>, Error> {
368 let mut params = Vec::with_capacity(est);
369 while let Some(param) = args.peek() {
370 let param = param.into();
371 if param.starts_with("-") || params.len() == est {
372 break;
373 }
374 let val = cast_type(&arg.value_type, param)?;
375 if let Err(e) = (arg.validation)(&val) {
376 debug!("validation failed, reason: {}", e);
377 return Err(Error::InvalidValue(param.to_string(), e));
378 }
379 params.push(val);
380 args.next();
381 }
382 debug!("found params {:?}", params);
383 Ok(params)
384 }
385
386 fn update_values(&'a self, arg: &'a Arg, args: &mut Peekable<T>, out: &mut Builder<'a>) -> Result<(), Error> {
387 debug!("getting values for {}", arg.name);
388 let value = match arg.num_values {
389 NumValues::Any => Ok(self.get_values_unbounded(arg, args, 0)?.into()),
390 NumValues::AtLeast(i) => {
391 debug!("looking for at x > {} values", i);
392 let params = self.get_values_unbounded(arg, args, i)?;
393 if params.len() >= i {
394 Ok(params.into())
395 } else {
396 debug!("too few values found, expected {}, got {}: {:?}", i, params.len(), params);
397 Err(Error::WrongNumValues(arg.name, &arg.num_values, Value::from(params)))
398 }
399 }
400 NumValues::Between(low, high) => {
401 debug!("looking for value where {} >= x >= {}", high, low);
402 let params = self.get_values_bounded(arg, args, high)?;
403 if params.len() >= low && params.len() <= high {
404 Ok(params.into())
405 } else {
406 debug!(
407 "wrong number of values found, expected {} >= x >= {}, got {}: {:?}",
408 high,
409 low,
410 params.len(),
411 params
412 );
413 Err(Error::WrongNumValues(arg.name, &arg.num_values, Value::from(params)))
414 }
415 }
416 NumValues::Fixed(i) => {
417 debug!("looking for x = {} values", i);
418 let mut params = self.get_values_bounded(arg, args, i)?;
419 if params.len() != i {
420 debug!("wrong number of found, expected {}, got {}: {:?}", i, params.len(), params);
421 Err(Error::WrongNumValues(arg.name, &arg.num_values, Value::from(params)))
422 } else if params.len() == 1 {
423 debug!("single param found, simplifying vec");
424 Ok(params.pop().unwrap())
425 } else {
426 Ok(params.into())
427 }
428 }
429 NumValues::None => return self.try_insert_flag(arg.name, out),
430 }?;
431 self.try_insert_param(arg.name, value, out)
432 }
433
434 fn handle_arg(&'a self, arg: &str, args: &mut Peekable<T>, out: &mut Builder<'a>) -> Result<(), Error> {
435 if arg.starts_with("--") {
436 let arg = &arg[2..];
437 debug!("handling long {}", arg);
438 for a in &self.args {
439 if let Some(i) = a.long {
440 if i == arg {
441 debug!("found arg {}", a.name);
442 return self.update_values(a, args, out);
443 }
444 }
445 }
446 self.handle_arg_missing(arg, out)
447 } else {
448 let arg = &arg[1..];
449 debug!("handling short(s) {}", arg);
450 let mut matches = arg
451 .graphemes(true)
452 .filter_map(|g| self.args.iter().filter(|a| a.short.is_some()).find(|a| a.short.unwrap() == g));
454 match (matches.next(), matches.next()) {
455 (Some(first), None) => {
456 debug!("single short found {}, trying to expand", arg);
457 self.update_values(first, args, out)
458 }
459 (Some(first), Some(second)) => {
460 debug!("flag combination found {}", arg);
461 self.try_insert_flag(first.name, out)?;
462 self.try_insert_flag(second.name, out)?;
463 for res in matches {
464 self.try_insert_flag(res.name, out)?;
465 }
466 Ok(())
467 }
468 (None, _) => {
469 debug!("no arg found for {}, looking for default", arg);
470 self.handle_arg_missing(arg, out)
471 }
472 }
473 }
474 }
475
476 fn apply(&'a self, args: T) -> Result<R, Error> {
477 debug!("parsing args using command {}", self.name);
478 let mut builder = Builder {
480 args: HashMap::new(),
481 flags: HashMap::new(),
482 };
483 let mut unknown_args = Vec::with_capacity(0);
484 let mut positional = Vec::with_capacity(0);
485 let mut args = args.peekable();
486 while let Some(a) = args.next() {
487 let arg = (&a).into();
488 if arg.starts_with("-") {
490 if arg == "--" {
491 debug!("found --, treating everything after as positional");
492 (&mut args).for_each(|a| positional.push((&a).into().to_string()));
493 } else {
494 debug!("found arg {}", arg);
495 match self.handle_arg(&arg, &mut args, &mut builder) {
496 Err(Error::UnknownArg) => unknown_args.push(arg.to_string()),
497 Err(e) => return Err(e),
498 _ => {}
499 }
500 }
501 } else {
502 debug!("found positional arg {}", arg);
503 positional.push(arg.to_string());
504 }
505 }
506 debug!("finished looping through args, running postprocessing");
507 if self.fail_on_unknown_args && !unknown_args.is_empty() {
508 return Err(Error::UnknownArgs(unknown_args));
509 }
510
511 let mut missing = Vec::with_capacity(0);
513 for param in self.args.iter().filter(|p| p.num_values != NumValues::None) {
514 if param.required && !builder.args.contains_key(param.name) {
515 missing.push(param.name);
516 } else if let Some(default) = ¶m.default {
517 if let Vacant(v) = builder.args.entry(param.name) {
518 debug!("using default value for {}", param.name);
519 let val = v.insert(default());
520 if !check_type(¶m.value_type, val) {
521 return Err(Error::WrongValueType(val.clone()));
522 }
523 }
524 }
525 }
526 if !missing.is_empty() {
527 debug!("missing required args! {:?}", missing);
528 return Err(Error::MissingRequiredArgs(missing));
529 }
530
531 if !self.filters.filters.is_empty() {
532 let is_ok = match self.filters.filter_type {
533 FilterType::All => self.filters.filters.iter().all(|f| f.test(&builder) == 1),
534 FilterType::Any => self.filters.filters.iter().any(|f| f.test(&builder) == 1),
535 };
536 debug!("filter result: {}, using inverse: {}", is_ok, self.filters.inverse);
537 if is_ok == self.filters.inverse {
538 debug!("filtering failed");
539 return Err(Error::BadInput);
540 }
541 }
542
543 Ok((self.handler)(Results {
544 path: self.path.unwrap_or(self.name),
545 flags: builder.flags,
546 args: builder.args,
547 unknown_args,
548 positional,
549 }))
550 }
551}
552
553impl<'a, R> Args<'a, R> {
554 #[allow(dead_code)]
555 pub fn parse<S: IntoStr, T: IntoIterator<Item = S>>(&'a self, args: T) -> Result<R, Error<'a>> {
556 debug!("starting arg parsing");
557 let mut command = self;
558 let mut args = args.into_iter().skip(1).peekable();
559 while let Some(arg) = args.peek() {
560 let arg = arg.into();
561 debug!("checking if {} is a subcommand of {}", arg, command.name);
562 if let Some(arg) = command.subcommands.iter().find(|&i| i.name == arg) {
563 args.next();
565 command = arg;
566 } else if arg == "help" {
567 print!("{}", command.generate_help());
568 exit(0);
569 } else if arg == "version" {
570 println!("{} {}", self.path.unwrap_or(self.name), command.version);
571 exit(0)
572 } else {
573 break;
574 }
575 }
576 debug!("applying command {}", command.name);
577 return command.apply(args);
578 }
579
580 fn generate_help(&self) -> String {
595 let mut help = format!(
596 "{}\nUSAGE:\n\t{} [SUBCOMMAND] [OPTIONS]\nOPTIONS:\n",
597 self.about,
598 self.path.unwrap_or(self.name)
599 );
600 help.push_str("\t-V, --version Print version info and exit\n");
601 if !self.args.is_empty() {
602 help = self.args.iter().fold(help, |mut opt, arg| {
603 let has_comma = if arg.short.is_some() && arg.long.is_some() { 1 } else { 0 };
604 let size = arg.short.map_or(0, |s| s.len() + 2)
605 + arg.long.map_or(0, |s| s.len() + 3)
606 + has_comma
607 + arg.value_name.map_or(0, |s| s.len() + 1)
608 + arg.about.len();
609 opt.reserve(size + 2);
610 opt.push_str("\t");
611 if let Some(s) = arg.short {
612 opt.push('-');
613 opt.push_str(s);
614 if has_comma == 1 {
615 opt.push(',');
616 }
617 opt.push(' ');
618 }
619 if let Some(s) = arg.long {
620 opt.push_str("--");
621 opt.push_str(s);
622 opt.push(' ');
623 }
624 if let Some(s) = arg.value_name {
625 opt.push_str(s);
626 opt.push(' ');
627 }
628 opt.push_str(arg.about);
629 opt.push('\n');
630 opt
631 });
632 }
633 help.push_str("\t-h, --help Prints help information\n");
634 if !self.subcommands.is_empty() {
635 help.push_str("SUBCOMMANDS (use ");
636 help.push_str(self.name);
637 help.push_str(" [SUBCOMMAND] help for more details):\n");
638 help = self.subcommands.iter().fold(help, |mut opt, arg| {
639 let size = arg.name.len() + 1 + arg.about.len();
640 opt.reserve(size + 1);
641 opt.push_str(arg.name);
642 opt.push(' ');
643 opt.push_str(arg.about);
644 opt.push('\n');
645 opt
646 });
647 }
648 help
649 }
650
651 fn try_insert_param(&self, key: &'a str, value: Value, out: &mut Builder<'a>) -> Result<(), Error> {
654 if !self.disable_overrides {
655 out.args.insert(key, value);
656 return Ok(());
657 }
658 match out.args.entry(key) {
659 Occupied(_) => Err(Error::Override(key)),
660 Vacant(e) => {
661 e.insert(value);
662 Ok(())
663 }
664 }
665 }
666
667 fn try_insert_flag(&self, key: &'a str, out: &mut Builder<'a>) -> Result<(), Error> {
669 debug!("inserting flag {}", key);
670 match out.flags.entry(key) {
671 Occupied(mut e) => {
672 if self.disable_overrides {
673 Err(Error::Override(key))
674 } else {
675 debug!("incrementing count {}", e.get());
676 e.insert(e.get() + 1);
677 Ok(())
678 }
679 }
680 Vacant(e) => {
681 debug!("new flag found");
682 e.insert(1);
683 Ok(())
684 }
685 }
686 }
687
688 fn handle_arg_missing(&self, arg: &str, _: &mut Builder<'a>) -> Result<(), Error> {
692 match arg {
693 "help" | "h" => {
694 print!("{}", self.generate_help());
695 exit(0);
696 }
697 "version" | "V" => {
698 println!("{} {}", self.path.unwrap_or(self.name), self.version);
699 exit(0);
700 }
701 _ => Err(Error::UnknownArg),
702 }
703 }
704}
705
706#[cfg(feature = "macros")]
708#[macro_export]
709macro_rules! args {
710 ($($key:ident : $value:expr),* $(,)?) => {
711 Args {
712 $($key: $value),+,
713 ..Default::default()
714 }
715 }
716}
717
718#[cfg(feature = "macros")]
720#[macro_export]
721macro_rules! arg {
722 ($($key:ident : $value:expr),* $(,)?) => {
723 Arg {
724 $($key: $value),+,
725 ..Default::default()
726 }
727 }
728}
729
730#[cfg(test)]
731mod tests {
732 use std::{collections::HashMap, convert::TryInto, sync::Once};
733
734 use crate::{value::Type, Arg, Args, Error, Filter, FilterType, Filters, NumValues, Results, Value};
735 use pretty_assertions::assert_eq;
736 use simple_logger::SimpleLogger;
737
738 static INIT: Once = Once::new();
739
740 macro_rules! test {
741 ($name:ident() $block:block) => {
742 #[test]
743 fn $name() {
744 INIT.call_once(|| {
745 SimpleLogger::new().init().unwrap();
746 });
747 $block
748 }
749 };
750 }
751
752 macro_rules! assert_has {
753 ($expected:expr, $results:ident, $key:literal) => {
754 if let Some(arg) = $results.args.get($key) {
755 assert_eq!(Ok($expected), arg.try_into());
756 1
757 } else {
758 0
759 }
760 };
761 }
762
763 test!(test_returning_results() {
764 let args = args! {
765 subcommands: vec![args! {
766 name: "sub",
767 path: Some("main/sub"),
768 args: vec![arg! {
769 name: "arg",
770 long: Some("arg"),
771 num_values: NumValues::None,
772 }],
773 }],
774 };
775 let mut flags = HashMap::with_capacity(1);
776 flags.insert("arg", 1);
777
778 assert_eq!(Ok(Results {
779 path: "main/sub",
780 flags,
781 args: HashMap::new(),
782 unknown_args: vec!["-u".to_string()],
783 positional: vec!["lol".to_string()],
784 }), args.parse(vec!["prog", "sub", "--arg", "lol", "-u"]));
785 });
786
787 test!(test_flag() {
788 let args = args! {
789 args: vec![arg! {
790 name: "arg",
791 long: Some("arg"),
792 num_values: NumValues::None,
793 }],
794 handler: |r| if r.flags.contains_key("arg") { 1 } else { 0 },
795 };
796 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg"]));
797 });
798
799 test!(test_arg_with_fixed_num_values_fails_on_none() {
800 let args = args! {
801 args: vec![arg! {
802 name: "arg",
803 long: Some("arg"),
804 num_values: NumValues::Fixed(1),
805 }],
806 handler: |r| if r.args.contains_key("arg") { 1 } else { 0 },
807 };
808 assert_eq!(
809 Err(Error::WrongNumValues("arg", &NumValues::Fixed(1), Value::from(vec![]))),
810 args.parse(vec!["prog", "--arg"])
811 );
812 });
813
814 test!(test_arg_with_fixed_num_values() {
815 let args = args! {
816 args: vec![arg! {
817 name: "arg",
818 long: Some("arg"),
819 num_values: NumValues::Fixed(1),
820 }],
821 handler: |r| assert_has!("lol", r, "arg"),
822 };
823 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "lol"]));
824 });
825
826 test!(test_arg_with_any_values_none() {
827 let args = args! {
828 args: vec![arg! {
829 name: "arg",
830 long: Some("arg"),
831 num_values: NumValues::Any,
832 }],
833 handler: |r| assert_has!(&vec![], r, "arg"),
834 };
835 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg"]));
836 });
837
838 test!(test_arg_with_any_values_single() {
839 let args = args! {
840 args: vec![arg! {
841 name: "arg",
842 long: Some("arg"),
843 num_values: NumValues::Any,
844 }],
845 handler: |r| assert_has!(vec!["lol"], r, "arg"),
846 };
847 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "lol"]));
848 });
849
850 test!(test_arg_with_any_values_multiple() {
851 let args = args! {
852 args: vec![arg! {
853 name: "arg",
854 long: Some("arg"),
855 num_values: NumValues::Any,
856 }],
857 handler: |r| assert_has!(vec!["lol", "lol2"], r, "arg"),
858 };
859 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "lol", "lol2"]));
860 });
861
862 test!(test_arg_with_fixed_num_values_too_many_values() {
863 let args = args! {
864 args: vec![arg! {
865 name: "arg",
866 long: Some("arg"),
867 num_values: NumValues::Fixed(1),
868 }],
869 handler: |r| assert_has!("lol", r, "arg") == 1 && r.positional.first().filter(|i| i.as_str() == "no").is_some(),
870 };
871 assert_eq!(Ok(true), args.parse(vec!["prog", "--arg", "lol", "no"]));
872 });
873
874 test!(test_arg_with_fixed_num_values_and_other_args() {
875 let args = args! {
876 args: vec![arg! {
877 name: "arg",
878 long: Some("arg"),
879 num_values: NumValues::Fixed(1),
880 }],
881 handler: |r| assert_has!("lol", r, "arg"),
882 };
883 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "lol", "--arg2"]));
884 });
885
886 test!(test_arg_with_fixed_num_values_and_other_args_double_dash() {
887 let args = args! {
888 args: vec![arg! {
889 name: "arg",
890 long: Some("arg"),
891 num_values: NumValues::Fixed(1),
892 }],
893 handler: |r| assert_has!("lol", r, "arg"),
894 };
895 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "lol", "--arg2"]));
896 });
897
898 test!(test_multiple_args() {
899 let args = args! {
900 args: vec![
901 arg! {
902 name: "arg",
903 long: Some("arg"),
904 num_values: NumValues::Fixed(2),
905 },
906 arg! {
907 name: "arg2",
908 long: Some("arg2"),
909 num_values: NumValues::Any,
910 },
911 ],
912 handler: |r| match assert_has!(vec!["1", "2"], r, "arg") {
913 1 => assert_has!(&vec![], r, "arg2"),
914 _ => 0,
915 },
916 };
917 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "1", "2", "--arg2"]));
918 });
919
920 test!(test_missing_arg() {
921 let args = args! {
922 args: vec![arg! {
923 name: "arg",
924 long: Some("arg"),
925 num_values: NumValues::None,
926 }],
927 handler: |r| if r.args.contains_key("arg") { 1 } else { 0 },
928 };
929 assert_eq!(Ok(0), args.parse(vec!["prog"]));
930 });
931
932 test!(test_sub_command_not_called() {
933 let args = args! {
934 subcommands: vec![args! {
935 name: "sub",
936 }],
937 handler: |_| 1,
938 };
939 assert_eq!(Ok(1), args.parse(vec!["prog"]));
940 });
941
942 test!(test_sub_commands() {
943 let args = args! {
944 subcommands: vec![args! {
945 name: "sub",
946 subcommands: vec![args! {
947 name: "sub",
948 handler: |_| 1,
949 }],
950 }],
951 };
952 assert_eq!(Ok(1), args.parse(vec!["prog", "sub", "sub"]));
953 });
954
955 test!(test_default_arg() {
956 let args = args! {
957 args: vec![arg! {
958 name: "arg",
959 long: Some("arg"),
960 default: Some(|| "lol".into()),
961 }],
962 handler: |r| assert_has!("lol", r, "arg"),
963 };
964 assert_eq!(Ok(1), args.parse(vec!["prog"]));
965 });
966
967 test!(test_required_arg_missing() {
968 let args: Args<()> = args! {
969 args: vec![arg! {
970 name: "arg",
971 long: Some("arg"),
972 required: true,
973 num_values: NumValues::Fixed(1),
974 }],
975 };
976 assert_eq!(Err(Error::MissingRequiredArgs(vec!["arg"])), args.parse(vec!["prog"]));
977 });
978
979 test!(test_required_arg() {
980 let args = args! {
981 args: vec![arg! {
982 name: "arg",
983 long: Some("arg"),
984 required: true,
985 num_values: NumValues::Fixed(1),
986 }],
987 handler: |r| assert_has!("lol", r, "arg"),
988 };
989 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "lol"]));
990 });
991
992 test!(test_wrong_type() {
993 let args = args! {
994 args: vec![arg! {
995 name: "arg",
996 long: Some("arg"),
997 value_type: Type::Bool,
998 num_values: NumValues::Fixed(1),
999 }],
1000 handler: |r| assert_has!("lol", r, "arg"),
1001 };
1002 assert_eq!(Err(Error::WrongCastType("lol".to_owned())), args.parse(vec!["prog", "--arg", "lol"]));
1003 });
1004
1005 test!(test_right_type_bool() {
1006 let args = args! {
1007 args: vec![arg! {
1008 name: "arg",
1009 long: Some("arg"),
1010 value_type: Type::Bool,
1011 num_values: NumValues::Fixed(1),
1012 }],
1013 handler: |r| assert_has!(&true, r, "arg"),
1014 };
1015 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "true"]));
1016 });
1017
1018 test!(test_right_type_int() {
1019 let args = args! {
1020 args: vec![arg! {
1021 name: "arg",
1022 long: Some("arg"),
1023 value_type: Type::Int,
1024 num_values: NumValues::Fixed(1),
1025 }],
1026 handler: |r| assert_has!(&3, r, "arg"),
1027 };
1028 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "3"]));
1029 });
1030
1031 test!(test_right_type_long() {
1032 let args = args! {
1033 args: vec![arg! {
1034 name: "arg",
1035 long: Some("arg"),
1036 value_type: Type::Long,
1037 num_values: NumValues::Fixed(1),
1038 }],
1039 handler: |r| assert_has!(&i64::max_value(), r, "arg"),
1040 };
1041 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", i64::max_value().to_string().as_str()]));
1042 });
1043
1044 test!(test_right_type_float() {
1045 let args = args! {
1046 args: vec![arg! {
1047 name: "arg",
1048 long: Some("arg"),
1049 value_type: Type::Float,
1050 num_values: NumValues::Fixed(1),
1051 }],
1052 handler: |r| assert_has!(&f32::MAX, r, "arg"),
1053 };
1054 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", f32::MAX.to_string().as_str()]));
1055 });
1056
1057 test!(test_right_type_double() {
1058 let args = args! {
1059 args: vec![arg! {
1060 name: "arg",
1061 long: Some("arg"),
1062 value_type: Type::Double,
1063 num_values: NumValues::Fixed(1),
1064 }],
1065 handler: |r| assert_has!(&f64::MAX, r, "arg"),
1066 };
1067 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", f64::MAX.to_string().as_str()]));
1068 });
1069
1070 test!(test_right_type_string() {
1071 let args = args! {
1072 args: vec![arg! {
1073 name: "arg",
1074 long: Some("arg"),
1075 value_type: Type::String,
1076 num_values: NumValues::Fixed(1),
1077 }],
1078 handler: |r| assert_has!("woop", r, "arg"),
1079 };
1080 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "woop"]));
1081 });
1082
1083 test!(test_right_type_array() {
1084 let args = args! {
1085 args: vec![arg! {
1086 name: "arg",
1087 long: Some("arg"),
1088 value_type: Type::Array(Box::from(Type::Int)),
1089 num_values: NumValues::Any
1090 }],
1091 handler: |r| assert_has!(vec![&23, &32], r, "arg"),
1092 };
1093 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "23", "32"]));
1094 });
1095
1096 test!(test_right_type_array_single() {
1097 let args = args! {
1098 args: vec![arg! {
1099 name: "arg",
1100 long: Some("arg"),
1101 value_type: Type::Array(Box::from(Type::Int)),
1102 num_values: NumValues::Any
1103 }],
1104 handler: |r| assert_has!(vec![&23], r, "arg"),
1105 };
1106 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "23"]));
1107 });
1108
1109 test!(test_wrong_type_array() {
1110 let args = args! {
1111 args: vec![arg! {
1112 name: "arg",
1113 long: Some("arg"),
1114 value_type: Type::Array(Box::from(Type::Int)),
1115 }],
1116 handler: |r| assert_has!(vec![&23], r, "arg"),
1117 };
1118 assert_eq!(Err(Error::WrongCastType("true".to_owned())), args.parse(vec!["prog", "--arg", "true"]));
1119 });
1120
1121 test!(test_default_returns_wrong_type() {
1122 let args: Args<()> = args! {
1123 args: vec![arg! {
1124 name: "arg",
1125 long: Some("arg"),
1126 value_type: Type::Int,
1127 default: Some(|| "lol".into()),
1128 }],
1129 };
1130 assert_eq!(Err(Error::WrongValueType("lol".into())), args.parse(vec!["prog"]));
1131 });
1132
1133 test!(test_property() {
1134 let args = args! {
1135 handler: |r| r.positional.first().filter(|i| i.as_str() == "prop").is_some(),
1136 };
1137 assert_eq!(Ok(true), args.parse(vec!["prog", "prop"]));
1138 });
1139
1140 test!(test_property_after_arg() {
1141 let args = args! {
1142 args: vec![arg! {
1143 name: "arg",
1144 long: Some("arg"),
1145 num_values: NumValues::None,
1146 }],
1147 handler: |r| r.positional.first().filter(|i| i.as_str() == "prop").is_some(),
1148 };
1149 assert_eq!(Ok(true), args.parse(vec!["prog", "--arg", "prop"]));
1150 });
1151
1152 test!(test_long_arg_ignores_single_dash() {
1153 let args = args! {
1154 args: vec![arg! {
1155 name: "arg",
1156 long: Some("arg"),
1157 num_values: NumValues::None,
1158 }],
1159 handler: |r| !r.args.contains_key("arg"),
1160 };
1161 assert_eq!(Ok(true), args.parse(vec!["prog", "-arg"]));
1162 });
1163
1164 test!(test_short_arg_ignores_mario_kart_double_dash() {
1165 let args = args! {
1166 args: vec![arg! {
1167 name: "arg",
1168 short: Some("a"),
1169 num_values: NumValues::None,
1170 }],
1171 handler: |r| !r.flags.contains_key("arg"),
1172 };
1173 assert_eq!(Ok(true), args.parse(vec!["prog", "--a"]));
1174 });
1175
1176 test!(test_short_arg() {
1177 let args = args! {
1178 args: vec![arg! {
1179 name: "arg",
1180 short: Some("a"),
1181 num_values: NumValues::None,
1182 }],
1183 handler: |r| r.flags.contains_key("arg"),
1184 };
1185 assert_eq!(Ok(true), args.parse(vec!["prog", "-a"]));
1186 });
1187
1188 test!(test_unicode_short_arg() {
1189 let args = args! {
1190 args: vec![arg! {
1191 name: "arg",
1192 short: Some("Ẩ"),
1193 num_values: NumValues::None,
1194 }],
1195 handler: |r| r.flags.contains_key("arg"),
1196 };
1197 assert_eq!(Ok(true), args.parse(vec!["prog", "-Ẩ"]));
1198 });
1199
1200 test!(test_unicode_short_arg_no_match() {
1201 let args = args! {
1202 args: vec![arg! {
1203 name: "arg",
1204 short: Some("A"),
1205 num_values: NumValues::None,
1206 }],
1207 handler: |r| r.flags.contains_key("arg"),
1208 };
1209 assert_eq!(Ok(false), args.parse(vec!["prog", "-Ẩ"]));
1210 });
1211
1212 test!(test_combinations() {
1213 let args = args! {
1214 args: vec![arg! {
1215 name: "arg",
1216 short: Some("Ẩ"),
1217 num_values: NumValues::None,
1218 }, arg! {
1219 name: "arg2",
1220 short: Some("A"),
1221 num_values: NumValues::None,
1222 }],
1223 handler: |r| r.flags.contains_key("arg") && r.flags.contains_key("arg2"),
1224 };
1225 assert_eq!(Ok(true), args.parse(vec!["prog", "-ẨA"]));
1226 });
1227
1228 test!(test_flag_repeats() {
1229 let args = args! {
1230 args: vec![arg! {
1231 name: "arg",
1232 long: Some("arg"),
1233 short: Some("A"),
1234 num_values: NumValues::None,
1235 }],
1236 handler: |r| r.flags["arg"],
1237 };
1238 assert_eq!(Ok(4), args.parse(vec!["prog", "-AA", "--arg", "-A"]));
1239 });
1240
1241 test!(test_positional_after_double_dash() {
1242 let args = args! {
1243 args: vec![arg! {
1244 name: "arg",
1245 short: Some("a"),
1246 num_values: NumValues::None,
1247 }, arg! {
1248 name: "arg2",
1249 short: Some("b"),
1250 num_values: NumValues::None,
1251 }],
1252 handler: |r| r.flags.contains_key("arg2") && !r.flags.contains_key("arg") && r.positional.first().filter(|f| f.as_str() == "-a").is_some(),
1253 };
1254 assert_eq!(Ok(true), args.parse(vec!["prog", "-b", "--", "-a"]));
1255 });
1256
1257 test!(test_sub_commands_after_arg_is_not_called() {
1258 let args = args! {
1259 subcommands: vec![args! {
1260 name: "sub",
1261 handler: |_| 1,
1262 }],
1263 handler: |_| 0,
1264 };
1265 assert_eq!(Ok(0), args.parse(vec!["prog", "-arg", "sub"]));
1266 });
1267
1268 test!(test_validation() {
1269 let args = args! {
1270 args: vec![arg! {
1271 name: "arg",
1272 short: Some("a"),
1273 num_values: NumValues::Fixed(1),
1274 validation: |v| {
1275 let s: String = v.into();
1276 if "abc" == s.as_str() {
1277 Ok(())
1278 } else {
1279 Err("oh noes".to_string())
1280 }
1281 },
1282 }],
1283 handler: |r| r.args.contains_key("arg"),
1284 };
1285 assert_eq!(Ok(true), args.parse(vec!["prog", "-a", "abc"]));
1286 });
1287
1288 test!(test_validation_vec() {
1289 let args = args! {
1290 args: vec![arg! {
1291 name: "arg",
1292 short: Some("a"),
1293 num_values: NumValues::AtLeast(1),
1294 value_type: Type::Int,
1295 validation: |v| {
1296 let s: &i32 = v.try_into().unwrap();
1297 if 2 >= *s {
1298 Ok(())
1299 } else {
1300 Err("oh noes".to_string())
1301 }
1302 },
1303 }],
1304 handler: |r| assert_has!(vec![&1, &2], r, "arg"),
1305 };
1306 assert_eq!(Ok(1), args.parse(vec!["prog", "-a", "1", "2"]));
1307 });
1308
1309 test!(test_validation_unbounded() {
1310 let args = args! {
1311 args: vec![arg! {
1312 name: "arg",
1313 short: Some("a"),
1314 num_values: NumValues::Any,
1315 validation: |v| {
1316 let s: String = v.into();
1317 if "abc" == s.as_str() {
1318 Ok(())
1319 } else {
1320 Err("oh noes".to_string())
1321 }
1322 },
1323 }],
1324 handler: |r| r.args.contains_key("arg"),
1325 };
1326 assert_eq!(Ok(true), args.parse(vec!["prog", "-a", "abc"]));
1327 });
1328
1329 test!(test_validation_fails() {
1330 let args = args! {
1331 args: vec![arg! {
1332 name: "arg",
1333 short: Some("a"),
1334 num_values: NumValues::Fixed(1),
1335 validation: |v| {
1336 let s: String = v.into();
1337 if "abc" == s.as_str() {
1338 Ok(())
1339 } else {
1340 Err("oh noes".to_string())
1341 }
1342 },
1343 }],
1344 handler: |r| !r.args.contains_key("arg"),
1345 };
1346 assert_eq!(Err(Error::InvalidValue("abcdef".to_string(), "oh noes".to_string())),
1347 args.parse(vec!["prog", "-a", "abcdef"]));
1348 });
1349
1350 test!(test_validation_fails_unbounded() {
1351 let args = args! {
1352 args: vec![arg! {
1353 name: "arg",
1354 short: Some("a"),
1355 num_values: NumValues::Any,
1356 validation: |v| {
1357 let s: String = v.into();
1358 if "abc" == s.as_str() {
1359 Ok(())
1360 } else {
1361 Err("oh noes".to_string())
1362 }
1363 },
1364 }],
1365 handler: |r| !r.args.contains_key("arg"),
1366 };
1367 assert_eq!(Err(Error::InvalidValue("abcdef".to_string(), "oh noes".to_string())),
1368 args.parse(vec!["prog", "-a", "abcdef"]));
1369 });
1370
1371 test!(test_fail_duplicate_arg() {
1372 let args: Args<()> = args! {
1373 args: vec![arg! {
1374 name: "arg",
1375 short: Some("a"),
1376 long: Some("arg"),
1377 num_values: NumValues::None,
1378 }],
1379 disable_overrides: true,
1380 };
1381 assert_eq!(Err(Error::Override("arg")), args.parse(vec!["prog", "-a", "--arg"]));
1382 });
1383
1384 test!(test_simple_and_filter() {
1385 let args: Args<()> = args! {
1386 args: vec![arg! {
1387 name: "arg",
1388 short: Some("a"),
1389 num_values: NumValues::None,
1390 }, arg! {
1391 name: "arg2",
1392 long: Some("arg"),
1393 num_values: NumValues::None,
1394 }],
1395 filters: Filters {
1396 filters: vec![Filter {
1397 filter_type: FilterType::All,
1398 inverse: false,
1399 args: vec!["arg", "arg2"],
1400 }],
1401 ..Default::default()
1402 },
1403 disable_overrides: true,
1404 };
1405 assert_eq!(Ok(()), args.parse(vec!["prog", "-a", "--arg"]));
1406 });
1407
1408 test!(test_simple_and_filter_fails() {
1409 let args: Args<()> = args! {
1410 args: vec![arg! {
1411 name: "arg",
1412 short: Some("a"),
1413 num_values: NumValues::None,
1414 }, arg! {
1415 name: "arg2",
1416 long: Some("arg"),
1417 num_values: NumValues::None,
1418 }],
1419 filters: Filters {
1420 filters: vec![Filter {
1421 filter_type: FilterType::All,
1422 inverse: false,
1423 args: vec!["arg", "arg2"],
1424 }],
1425 ..Default::default()
1426 },
1427 disable_overrides: true,
1428 };
1429 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a"]));
1430 });
1431
1432 test!(test_simple_or_filter() {
1433 let args: Args<()> = args! {
1434 args: vec![arg! {
1435 name: "arg",
1436 short: Some("a"),
1437 num_values: NumValues::None,
1438 }, arg! {
1439 name: "arg2",
1440 long: Some("arg"),
1441 num_values: NumValues::None,
1442 }],
1443 filters: Filters {
1444 filters: vec![Filter {
1445 filter_type: FilterType::All,
1446 inverse: true,
1447 args: vec!["arg", "arg2"],
1448 }],
1449 ..Default::default()
1450 },
1451 disable_overrides: true,
1452 };
1453 assert_eq!(Ok(()), args.parse(vec!["prog", "-a"]));
1454 });
1455
1456 test!(test_simple_or_filter_fails() {
1457 let args: Args<()> = args! {
1458 args: vec![arg! {
1459 name: "arg",
1460 short: Some("a"),
1461 num_values: NumValues::None,
1462 }, arg! {
1463 name: "arg2",
1464 long: Some("arg"),
1465 num_values: NumValues::None,
1466 }],
1467 filters: Filters {
1468 filters: vec![Filter {
1469 filter_type: FilterType::All,
1470 inverse: true,
1471 args: vec!["arg", "arg2"],
1472 }],
1473 ..Default::default()
1474 },
1475 disable_overrides: true,
1476 };
1477 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a", "--arg"]));
1478 });
1479
1480 test!(test_multiple_filters_any() {
1481 let args: Args<()> = args! {
1482 args: vec![arg! {
1483 name: "arg",
1484 short: Some("a"),
1485 num_values: NumValues::None,
1486 }, arg! {
1487 name: "arg2",
1488 long: Some("arg"),
1489 num_values: NumValues::None,
1490 }, arg! {
1491 name: "arg3",
1492 long: Some("arg3"),
1493 num_values: NumValues::None,
1494 }],
1495 filters: Filters {
1496 filters: vec![Filter {
1497 filter_type: FilterType::All,
1498 inverse: false,
1499 args: vec!["arg", "arg2"],
1500 }, Filter {
1501 filter_type: FilterType::All,
1502 inverse: false,
1503 args: vec!["arg", "arg3"],
1504 }],
1505 ..Default::default()
1506 },
1507 disable_overrides: true,
1508 };
1509 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a"]));
1510 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg"]));
1511 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg3"]));
1512 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg", "--arg3"]));
1513 assert_eq!(Ok(()), args.parse(vec!["prog", "-a", "--arg"]));
1514 assert_eq!(Ok(()), args.parse(vec!["prog", "-a", "--arg3"]));
1515 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg", "-a"]));
1516 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg3", "-a"]));
1517 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg3", "-a", "--arg"]));
1518 });
1519
1520 test!(test_multiple_filters_all() {
1521 let args: Args<()> = args! {
1522 args: vec![arg! {
1523 name: "arg",
1524 short: Some("a"),
1525 num_values: NumValues::None,
1526 }, arg! {
1527 name: "arg2",
1528 long: Some("arg"),
1529 num_values: NumValues::None,
1530 }, arg! {
1531 name: "arg3",
1532 long: Some("arg3"),
1533 num_values: NumValues::None,
1534 }],
1535 filters: Filters {
1536 filters: vec![Filter {
1537 filter_type: FilterType::All,
1538 inverse: false,
1539 args: vec!["arg", "arg2"],
1540 }, Filter {
1541 filter_type: FilterType::All,
1542 inverse: false,
1543 args: vec!["arg", "arg3"],
1544 }],
1545 filter_type: FilterType::All,
1546 ..Default::default()
1547 },
1548 disable_overrides: true,
1549 };
1550 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a"]));
1551 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg"]));
1552 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg3"]));
1553 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg", "--arg3"]));
1554 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a", "--arg"]));
1555 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a", "--arg3"]));
1556 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg", "-a"]));
1557 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg3", "-a"]));
1558 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg3", "-a", "--arg"]));
1559 });
1560
1561 test!(test_multiple_filters_all_not() {
1562 let args: Args<()> = args! {
1563 args: vec![arg! {
1564 name: "arg",
1565 short: Some("a"),
1566 num_values: NumValues::None,
1567 }, arg! {
1568 name: "arg2",
1569 long: Some("arg"),
1570 num_values: NumValues::None,
1571 }, arg! {
1572 name: "arg3",
1573 long: Some("arg3"),
1574 num_values: NumValues::None,
1575 }],
1576 filters: Filters {
1577 filters: vec![Filter {
1578 filter_type: FilterType::All,
1579 inverse: false,
1580 args: vec!["arg", "arg2"],
1581 }, Filter {
1582 filter_type: FilterType::All,
1583 inverse: false,
1584 args: vec!["arg", "arg3"],
1585 }],
1586 filter_type: FilterType::All,
1587 inverse: true
1588 },
1589 disable_overrides: true,
1590 };
1591 assert_eq!(Ok(()), args.parse(vec!["prog", "-a"]));
1592 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg"]));
1593 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg3"]));
1594 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg", "--arg3"]));
1595 assert_eq!(Ok(()), args.parse(vec!["prog", "-a", "--arg"]));
1596 assert_eq!(Ok(()), args.parse(vec!["prog", "-a", "--arg3"]));
1597 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg", "-a"]));
1598 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg3", "-a"]));
1599 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg3", "-a", "--arg"]));
1600 });
1601
1602 test!(test_multiple_filters_any_not() {
1603 let args: Args<()> = args! {
1604 args: vec![arg! {
1605 name: "arg",
1606 short: Some("a"),
1607 num_values: NumValues::None,
1608 }, arg! {
1609 name: "arg2",
1610 long: Some("arg"),
1611 num_values: NumValues::None,
1612 }, arg! {
1613 name: "arg3",
1614 long: Some("arg3"),
1615 num_values: NumValues::None,
1616 }],
1617 filters: Filters {
1618 filters: vec![Filter {
1619 filter_type: FilterType::All,
1620 inverse: false,
1621 args: vec!["arg", "arg2"],
1622 }, Filter {
1623 filter_type: FilterType::All,
1624 inverse: false,
1625 args: vec!["arg", "arg3"],
1626 }],
1627 filter_type: FilterType::Any,
1628 inverse: true
1629 },
1630 disable_overrides: true,
1631 };
1632 assert_eq!(Ok(()), args.parse(vec!["prog", "-a"]));
1633 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg"]));
1634 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg3"]));
1635 assert_eq!(Ok(()), args.parse(vec!["prog", "--arg", "--arg3"]));
1636 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a", "--arg"]));
1637 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "-a", "--arg3"]));
1638 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg", "-a"]));
1639 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg3", "-a"]));
1640 assert_eq!(Err(Error::BadInput), args.parse(vec!["prog", "--arg3", "-a", "--arg"]));
1641 });
1642
1643 test!(test_multiple_values_split_unsupported() {
1644 let args = args! {
1645 args: vec![arg! {
1646 name: "arg",
1647 long: Some("arg"),
1648 num_values: NumValues::Fixed(2),
1649 }],
1650 handler: |r| assert_has!(vec!["1", "2"], r, "arg"),
1651 };
1652 assert_eq!(Err(Error::WrongNumValues("arg", &NumValues::Fixed(2), Value::Array(vec![Value::String("1".to_string())]))),
1653 args.parse(vec!["prog", "--arg", "1", "--arg", "2"]));
1654 });
1655
1656 test!(test_fail_on_unknown_args() {
1657 let args = args! {
1658 args: vec![arg! {
1659 name: "arg",
1660 long: Some("arg"),
1661 num_values: NumValues::Fixed(2),
1662 }],
1663 fail_on_unknown_args: true,
1664 handler: |r| assert_has!(vec!["1", "2"], r, "arg"),
1665 };
1666 assert_eq!(Ok(1), args.parse(vec!["prog", "--arg", "1", "2"]));
1667 assert_eq!(Err(Error::UnknownArgs(vec!["-u".to_string()])), args.parse(vec!["prog", "--arg", "1", "2", "-u"]));
1668 assert_eq!(Err(Error::UnknownArgs(vec!["--u".to_string()])), args.parse(vec!["prog", "--arg", "1", "2", "--u"]));
1669 assert_eq!(Err(Error::UnknownArgs(vec!["-u".to_string(), "--u".to_string()])), args.parse(vec!["prog", "-u", "--arg", "1", "2", "--u"]));
1670 });
1671}