1use std::cell::RefCell;
7use std::collections::{hash_map::Entry, HashMap};
8use std::env;
9use std::fmt;
10use std::io::Write;
11use std::rc::Rc;
12
13use crate::error::{Error, Result};
14
15const OPT_PREFIX: char = '-';
16const HELP_OPTION: &str = "-h";
17
18const REQUIRED_STR: &str = " (required)";
20
21const END_OF_OPTIONS: &str = "--";
27const LONG_OPT_PREFIX: &str = END_OF_OPTIONS;
28
29pub const POSITIONAL_HANDLER_OPT: char = '"';
38
39pub const UNKNOWN_OPTION_HANDLER_OPT: char = '?';
59
60const USAGE_PREFIX_SPACES: &str = " ";
61
62#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
65pub enum Need {
66 Nothing,
68 Argument,
70}
71
72impl Default for Need {
73 fn default() -> Self {
74 Need::Nothing
75 }
76}
77
78impl Need {
79 pub fn new() -> Self {
81 Need::default()
82 }
83}
84
85pub trait Handler {
87 fn handle(&mut self, arg: Arg) -> Result<()>;
109}
110
111impl<'a> fmt::Debug for dyn Handler + 'a {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 write!(f, "Handler: {:p}", self)
114 }
115}
116
117impl<'a> PartialEq for Box<dyn Handler + 'a> {
118 fn eq(&self, other: &Box<dyn Handler + 'a>) -> bool {
119 self == other
120 }
121}
122
123#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
139pub struct Arg {
140 pub option: char,
146 pub needs: Need,
148 pub help: Option<String>,
150 pub required: bool,
152
153 pub value: Option<String>,
164 pub count: usize,
175}
176
177impl Arg {
178 pub fn new(option: char) -> Self {
180 Arg::default().option(option)
181 }
182
183 pub fn option(self, option: char) -> Self {
185 Arg { option, ..self }
186 }
187
188 pub fn needs(self, needs: Need) -> Self {
190 Arg { needs, ..self }
191 }
192
193 pub fn help(self, help: &str) -> Self {
195 Arg {
196 help: Some(help.into()),
197 ..self
198 }
199 }
200
201 pub fn required(self) -> Self {
203 Arg {
204 required: true,
205 ..self
206 }
207 }
208}
209
210impl fmt::Display for Arg {
211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 let value = if self.needs == Need::Argument {
213 " <value>"
214 } else {
215 ""
216 };
217
218 let required = if self.required { REQUIRED_STR } else { "" };
219
220 let help: String = match &self.help {
221 Some(help) => format!(" # {}", help),
222 _ => "".into(),
223 };
224
225 write!(
226 f,
227 "{}{}{}{}{}",
228 OPT_PREFIX, self.option, value, required, help
229 )
230 }
231}
232
233#[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, Default, PartialEq)]
235pub struct Settings {
236 ignore_unknown_options: bool,
239
240 ignore_unknown_posn_args: bool,
243
244 no_strict_options: bool,
251}
252
253impl Settings {
254 pub fn new() -> Self {
256 Settings::default()
257 }
258
259 pub fn ignore_unknown_options(self) -> Self {
262 Settings {
263 ignore_unknown_options: true,
264 ..self
265 }
266 }
267
268 pub fn ignore_unknown_posn_args(self) -> Self {
271 Settings {
272 ignore_unknown_posn_args: true,
273 ..self
274 }
275 }
276
277 pub fn no_strict_options(self) -> Self {
331 Settings {
332 no_strict_options: true,
333 ..self
334 }
335 }
336}
337
338pub fn get_args() -> Vec<String> {
346 let mut args: Vec<String> = env::args().collect();
347
348 let _ = args.remove(0);
350
351 args
352}
353
354#[derive(Clone, Debug, Eq, PartialEq)]
356pub struct Args {
357 entries: HashMap<char, Rc<RefCell<Arg>>>,
362}
363
364impl Args {
365 pub fn new() -> Self {
367 Args {
368 entries: HashMap::<char, Rc<RefCell<Arg>>>::new(),
369 }
370 }
371
372 fn len(&self) -> usize {
374 self.entries.len()
375 }
376
377 #[allow(dead_code)]
383 fn set(&mut self, args: Vec<Arg>) {
384 self.entries.clear();
385
386 for arg in args {
387 self.entries.insert(arg.option, Rc::new(RefCell::new(arg)));
388 }
389 }
390
391 pub fn add(&mut self, arg: Arg) {
393 self.entries.insert(arg.option, Rc::new(RefCell::new(arg)));
394 }
395
396 pub fn exists(&self, option: &char) -> bool {
398 self.entries.get(option).is_some()
399 }
400
401 pub fn get(&self, option: char) -> Option<Arg> {
403 self.entries.get(&option).map(|a| a.borrow().clone())
406 }
407}
408
409impl Default for Args {
410 fn default() -> Self {
412 Self::new()
413 }
414}
415
416#[derive(Clone, Default, Debug, PartialEq)]
421pub struct App<'a> {
422 name: String,
423 version: String,
424 summary: String,
425 help: String,
426 notes: String,
427 settings: Settings,
428 args: Args,
429 handler: Option<Rc<RefCell<Box<dyn Handler + 'a>>>>,
430}
431
432impl<'a> App<'a> {
433 pub fn new(name: &str) -> Self {
435 App::default().name(name)
436 }
437
438 fn name(self, name: &str) -> Self {
440 App {
441 name: name.into(),
442 ..self
443 }
444 }
445
446 pub fn args(self, args: Args) -> Self {
448 App { args, ..self }
449 }
450
451 pub fn version(self, version: &str) -> Self {
453 App {
454 version: version.into(),
455 ..self
456 }
457 }
458
459 pub fn summary(self, summary: &str) -> Self {
461 App {
462 summary: summary.into(),
463 ..self
464 }
465 }
466
467 pub fn help(self, help: &str) -> Self {
469 App {
470 help: help.into(),
471 ..self
472 }
473 }
474
475 pub fn notes(self, notes: &str) -> Self {
477 App {
478 notes: notes.into(),
479 ..self
480 }
481 }
482
483 pub fn settings(self, settings: Settings) -> Self {
485 App { settings, ..self }
486 }
487
488 pub fn ignore_unknown_options(self) -> Self {
495 App {
496 settings: Settings {
497 ignore_unknown_options: true,
498 ..Default::default()
499 },
500 ..self
501 }
502 }
503
504 pub fn ignore_unknown_posn_args(self) -> Self {
511 App {
512 settings: Settings {
513 ignore_unknown_posn_args: true,
514 ..Default::default()
515 },
516 ..self
517 }
518 }
519
520 pub fn no_strict_options(self) -> Self {
529 App {
530 settings: Settings {
531 no_strict_options: true,
532 ..Default::default()
533 },
534 ..self
535 }
536 }
537
538 pub fn generate_help<W>(&self, writer: &mut W) -> Result<()>
543 where
544 W: Write + Send + Sync + 'static,
545 {
546 let mut lines = Vec::<String>::new();
547 let mut flag_lines = Vec::<String>::new();
548 let mut option_lines = Vec::<String>::new();
549
550 let mut keys: Vec<char> = self
551 .args
552 .entries
553 .iter()
554 .map(|(key, _)| *key)
555 .filter(|k| *k != POSITIONAL_HANDLER_OPT)
556 .collect();
557
558 keys.sort_unstable();
559
560 for key in keys.clone() {
564 let arg_ref = self.args.entries.get(&key).unwrap();
566
567 let arg = arg_ref.borrow();
568
569 if arg.needs == Need::Nothing {
570 let line = format!("{}{}", USAGE_PREFIX_SPACES, arg.to_string());
571 flag_lines.push(line);
572 }
573 }
574
575 for key in keys {
579 let arg_ref = self.args.entries.get(&key).unwrap();
580
581 let arg = arg_ref.borrow();
582
583 if arg.needs != Need::Nothing {
584 let line = format!("{}{}", USAGE_PREFIX_SPACES, arg.to_string());
585 option_lines.push(line);
586 }
587 }
588
589 let line = format!("NAME:\n{}{}\n", USAGE_PREFIX_SPACES, self.name);
592 lines.push(line);
593
594 if !self.version.is_empty() {
595 let line = format!("VERSION:\n{}{}\n", USAGE_PREFIX_SPACES, self.version);
596 lines.push(line);
597 }
598
599 if !self.summary.is_empty() {
600 let line = format!("SUMMARY:\n{}{}\n", USAGE_PREFIX_SPACES, self.summary.trim());
601 lines.push(line);
602 }
603
604 let have_posn_handler = self.args.get(POSITIONAL_HANDLER_OPT).is_some();
605
606 let posn_args = match have_posn_handler {
607 true => " [ARGUMENT]...",
608 false => "",
609 };
610
611 lines.push("USAGE:".into());
612
613 let name: String = if self.name.is_empty() {
614 env::args().collect::<Vec<String>>().pop().unwrap()
615 } else {
616 self.name.clone()
617 };
618
619 let have_flags = !flag_lines.is_empty();
620 let have_options = !option_lines.is_empty();
621
622 let option_types = if have_flags && have_options {
623 "[FLAG/OPTION]..."
624 } else if have_flags {
625 "[FLAG]..."
626 } else if have_options {
627 "[OPTION]..."
628 } else {
629 ""
630 };
631
632 let line = format!(
634 "{}{} {}{}\n",
635 USAGE_PREFIX_SPACES, name, option_types, posn_args
636 );
637
638 lines.push(line);
639
640 if !flag_lines.is_empty() {
643 lines.push("FLAGS:".into());
644
645 lines.extend_from_slice(&flag_lines);
646 }
647
648 if !option_lines.is_empty() {
649 lines.push("\nOPTIONS:".into());
650
651 lines.extend_from_slice(&option_lines);
652 }
653
654 let pos_arg = self.args.entries.get(&POSITIONAL_HANDLER_OPT);
657 if let Some(arg) = pos_arg {
658 lines.push("\nPOSITIONAL ARGUMENTS:\n".into());
659
660 if let Some(help_text) = arg.borrow().help.as_ref() {
664 lines.push(help_text.trim().into());
665 } else {
666 lines.push("Supported.".into());
667 }
668 }
669
670 if !self.help.is_empty() {
673 let line = format!("\nHELP:\n\n{}", self.help.trim());
674 lines.push(line);
675 }
676
677 if !self.notes.is_empty() {
678 let line = format!("\nNOTES:\n\n{}", self.notes.trim());
679 lines.push(line);
680 }
681
682 let mut final_lines = lines.join("\n").trim().to_string();
685 final_lines.push('\n');
686
687 writeln!(writer, "{}", final_lines)?;
688
689 Ok(())
690 }
691
692 pub fn parse_with_args(&mut self, cli_args: Vec<String>) -> Result<()> {
706 let mut need = Need::new();
707 let mut end_of_options = false;
708
709 let mut current_option: Option<char> = None;
716
717 for cli_arg in cli_args.iter() {
719 match cli_arg.as_str() {
720 HELP_OPTION => return self.generate_help(&mut std::io::stdout()),
721 END_OF_OPTIONS => break,
723 _ => (),
724 }
725 }
726
727 if self.handler.is_none() {
728 return Err(Error::NoHandler);
729 }
730
731 if self.args.len() == 0 {
732 return Err(Error::NoArgs);
733 }
734
735 for (_i, cli_arg) in cli_args.iter().enumerate() {
736 if cli_arg.starts_with(OPT_PREFIX) && !end_of_options {
737 if cli_arg == END_OF_OPTIONS {
740 end_of_options = true;
741 continue;
742 }
743
744 if !self.settings.no_strict_options {
747 if let Some(option) = current_option {
748 if need == Need::Argument {
749 if let Entry::Occupied(entry) = self.args.entries.entry(option) {
750 let mut arg = entry.get().borrow_mut();
751
752 arg.value = Some(cli_arg.into());
754
755 if let Some(h) = self.handler.clone() {
756 arg.count += 1;
758 h.borrow_mut().handle(arg.clone())?;
759 }
760
761 need = Need::Nothing;
763 current_option = None;
764 continue;
765 }
766 }
767 }
768 }
769
770 if cli_arg.starts_with(LONG_OPT_PREFIX) {
771 return Err(Error::NoLongOpts);
772 }
773
774 let mut chars = cli_arg.chars();
775
776 if cli_arg.len() > 2 {
777 let option_name = *chars.nth(1).as_ref().unwrap();
778
779 if option_name.is_ascii_whitespace() {
780 return Err(Error::MissingOptName);
781 } else {
782 return Err(Error::NoBundling);
783 }
784 }
785
786 let option = chars.nth(1).ok_or(Error::MissingOptName)?;
787
788 if need == Need::Argument {
789 return Err(Error::MissingOptArg);
790 }
791
792 if let Entry::Occupied(entry) = self.args.entries.entry(option) {
793 let arg_ref = entry.get();
794
795 let mut arg = arg_ref.borrow_mut();
796
797 need = arg.needs;
798
799 if need == Need::Nothing {
800 if let Some(h) = self.handler.clone() {
801 arg.count += 1;
803 h.borrow_mut().handle(arg.clone())?;
804 }
805 } else if need == Need::Argument {
806 current_option = Some(arg.option);
810 }
811 } else if let Entry::Occupied(entry) =
812 self.args.entries.entry(UNKNOWN_OPTION_HANDLER_OPT)
813 {
814 let arg_ref = entry.get();
815
816 let mut arg = arg_ref.borrow_mut();
817
818 if let Some(h) = self.handler.clone() {
819 arg.count += 1;
821
822 let mut option_specific = arg.clone();
834 option_specific.option = option;
835
836 h.borrow_mut().handle(option_specific)?;
837 }
838 } else if self.settings.ignore_unknown_options {
839 continue;
840 } else {
841 return Err(Error::UnknownOpt);
842 }
843 } else if let Some(option) = current_option {
844 if let Entry::Occupied(entry) = self.args.entries.entry(option) {
845 let mut arg = entry.get().borrow_mut();
846
847 arg.value = Some(cli_arg.into());
849
850 if let Some(h) = self.handler.clone() {
851 arg.count += 1;
853 h.borrow_mut().handle(arg.clone())?;
854 }
855 } else {
856 return Err(Error::NoHandler);
859 }
860
861 need = Need::Nothing;
863 current_option = None;
864 } else {
865 if let Entry::Occupied(entry) = self.args.entries.entry(POSITIONAL_HANDLER_OPT) {
867 let arg_ref = entry.get();
868
869 let mut arg = arg_ref.borrow_mut();
870
871 arg.value = Some(cli_arg.into());
873
874 if let Some(h) = self.handler.clone() {
875 arg.count += 1;
877 h.borrow_mut().handle(arg.clone())?;
878 }
879 } else if !self.settings.ignore_unknown_posn_args {
880 if !end_of_options {
883 return Err(Error::NoPosnArgs);
884 }
885 }
886
887 need = Need::Nothing;
889 current_option = None;
890 }
891 }
892
893 for arg_ref in self.args.entries.values() {
895 let arg = arg_ref.borrow();
896
897 if let Some(option) = current_option {
899 if arg.needs == Need::Argument && option == arg.option {
900 return Err(Error::MissingOptArg);
901 }
902 }
903
904 if arg.required && arg.count == 0 {
906 return Err(Error::MissingReqOpt);
907 }
908 }
909
910 Ok(())
911 }
912
913 pub fn handler(self, boxed_handler: Box<dyn Handler + 'a>) -> Self {
921 let boxed = Rc::new(RefCell::new(boxed_handler));
922
923 App {
924 handler: Some(boxed),
925 ..self
926 }
927 }
928
929 pub fn parse(&mut self) -> Result<()> {
931 let args = get_args();
932
933 self.parse_with_args(args)
934 }
935}
936
937#[cfg(test)]
938mod tests {
939 use super::*;
940
941 use regex::Regex;
942 use std::sync::{Arc, Mutex};
943
944 #[derive(Default, Clone)]
946 struct BufWriter(Arc<Mutex<Vec<u8>>>);
947
948 impl std::io::Write for BufWriter {
949 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
950 self.0.lock().unwrap().write(buf)
951 }
952
953 fn flush(&mut self) -> std::io::Result<()> {
954 self.0.lock().unwrap().flush()
955 }
956 }
957
958 #[allow(dead_code)]
959 impl BufWriter {
960 fn new() -> Self {
961 BufWriter::default()
962 }
963
964 fn clear(&mut self) {
965 self.0.lock().unwrap().clear();
966 }
967
968 fn len(&mut self) -> usize {
969 self.0.lock().unwrap().len()
970 }
971
972 fn capacity(&mut self) -> usize {
973 self.0.lock().unwrap().capacity()
974 }
975 }
976
977 impl ToString for BufWriter {
978 fn to_string(&self) -> String {
979 let data_ref = self.0.clone();
980 let output = data_ref.lock().unwrap();
981 let s = (*output).clone();
982 let output = String::from_utf8(s).unwrap();
983
984 output
985 }
986 }
987
988 #[test]
989 fn test_requirement() {
990 let r1 = Need::new();
991 let r2 = Need::default();
992
993 assert_eq!(r1, Need::Nothing);
994 assert_eq!(r1, r2);
995 }
996
997 #[test]
998 fn test_settings() {
999 let new_settings = Settings::new();
1000 let def_settings = Settings::default();
1001
1002 assert_eq!(new_settings.ignore_unknown_options, false);
1003 assert_eq!(new_settings.ignore_unknown_posn_args, false);
1004 assert_eq!(new_settings.no_strict_options, false);
1005 assert_eq!(new_settings, def_settings);
1006
1007 let settings = Settings::new()
1008 .ignore_unknown_options()
1009 .ignore_unknown_posn_args()
1010 .no_strict_options();
1011
1012 assert_eq!(settings.ignore_unknown_options, true);
1013 assert_eq!(settings.ignore_unknown_posn_args, true);
1014 assert_eq!(settings.no_strict_options, true);
1015 }
1016
1017 #[test]
1018 fn test_arg() {
1019 let default_arg = Arg::default();
1021
1022 let expected_default = Arg {
1023 option: '\u{0}',
1024 needs: Need::Nothing,
1025 help: None,
1026 required: false,
1027 value: None,
1028 count: 0,
1029 };
1030
1031 assert_eq!(default_arg, expected_default);
1032
1033 let new_arg = Arg::new('a');
1036
1037 let expected_new = Arg {
1038 option: 'a',
1039 needs: Need::Nothing,
1040 help: None,
1041 required: false,
1042 value: None,
1043 count: 0,
1044 };
1045
1046 assert_eq!(new_arg, expected_new);
1047
1048 let option_arg = Arg::new('a').option('b');
1051
1052 assert_eq!(option_arg.option, 'b');
1053
1054 let def_option_arg = Arg::default().option('a');
1057
1058 assert_eq!(def_option_arg.option, 'a');
1059
1060 let needs_arg = Arg::new('a').needs(Need::Argument);
1063
1064 assert_eq!(needs_arg.needs, Need::Argument);
1065
1066 let help = "some help text\nfoo bar\nthe end";
1069 let help_arg = Arg::new('a').help(help);
1070 assert_eq!(help_arg.help, Some(help.into()));
1071
1072 let required_arg = Arg::new('a').required();
1075 assert_eq!(required_arg.required, true);
1076 }
1077
1078 #[test]
1079 fn test_args() {
1080 let new_args = Args::new();
1081 let def_args = Args::default();
1082
1083 assert_eq!(new_args, def_args);
1084
1085 let mut args = Args::new();
1086
1087 assert_eq!(args.len(), 0);
1088 assert!(!args.exists(&'a'));
1089 assert!(!args.exists(&'b'));
1090 assert_eq!(args.get('a'), None);
1091 assert_eq!(args.get('b'), None);
1092
1093 let arg_1 = Arg::new('a');
1094 let arg_2 = Arg::new('b');
1095
1096 args.add(arg_1);
1097 assert_eq!(args.len(), 1);
1098 assert!(args.exists(&'a'));
1099 assert!(!args.exists(&'b'));
1100 assert!(args.get('a').is_some());
1101 assert_eq!(args.get('a').unwrap().option, 'a');
1102 assert_eq!(args.get('b'), None);
1103
1104 args.add(arg_2);
1105 assert_eq!(args.len(), 2);
1106 assert!(args.exists(&'a'));
1107 assert!(args.exists(&'b'));
1108 assert!(args.get('a').is_some());
1109 assert!(args.get('b').is_some());
1110 assert_eq!(args.get('a').unwrap().option, 'a');
1111 assert_eq!(args.get('b').unwrap().option, 'b');
1112 }
1113
1114 #[derive(Clone, Debug, Default)]
1118 struct OkHandler {}
1119
1120 impl Handler for &OkHandler {
1121 fn handle(&mut self, arg: Arg) -> Result<()> {
1122 assert!(arg.count > 0);
1123
1124 Ok(())
1125 }
1126 }
1127
1128 impl Handler for &mut OkHandler {
1129 fn handle(&mut self, arg: Arg) -> Result<()> {
1130 assert!(arg.count > 0);
1131
1132 Ok(())
1133 }
1134 }
1135
1136 #[derive(Clone, Debug, Default)]
1140 struct ErrHandler {}
1141
1142 const TEST_ERR: &str = "dang";
1143
1144 impl Handler for &ErrHandler {
1145 fn handle(&mut self, arg: Arg) -> Result<()> {
1146 assert!(arg.count > 0);
1147
1148 Err(Error::GenericError(TEST_ERR.into()))
1149 }
1150 }
1151
1152 impl Handler for &mut ErrHandler {
1153 fn handle(&mut self, _arg: Arg) -> Result<()> {
1154 Err(Error::GenericError(TEST_ERR.into()))
1155 }
1156 }
1157
1158 #[derive(Clone, Debug, Default, PartialEq)]
1162 struct ModifyHandler {
1163 i: usize,
1165 v: Vec<String>,
1166 s: String,
1167
1168 count: usize,
1170
1171 a_count: usize,
1172 b_count: usize,
1173 d_count: usize,
1174 e_count: usize,
1175 r_count: usize,
1176 }
1177
1178 const INT_INCREMENT: usize = 17;
1179 const HANDLER_SET_MSG: &str = "set by handler";
1180
1181 impl Handler for &mut ModifyHandler {
1182 fn handle(&mut self, arg: Arg) -> Result<()> {
1183 assert!(arg.count > 0);
1184
1185 self.count += arg.count;
1186
1187 self.i += INT_INCREMENT;
1188 self.s = HANDLER_SET_MSG.into();
1189
1190 if let Some(value) = arg.value {
1191 self.v.push(value);
1192 }
1193
1194 match arg.option {
1195 'a' => self.a_count += 1,
1196 'b' => self.b_count += 1,
1197 'd' => self.d_count += 1,
1198 'e' => self.e_count += 1,
1199 'r' => self.r_count += 1,
1200 _ => (),
1201 };
1202
1203 Ok(())
1204 }
1205 }
1206
1207 #[test]
1208 fn test_parse_with_args() {
1209 #[derive(Debug)]
1210 struct TestData<'a> {
1211 cli_args: Vec<&'a str>,
1212 args: Option<Vec<Arg>>,
1213 use_handler: bool,
1214 result: Result<()>,
1215 }
1216
1217 let mut ok_handler = OkHandler::default();
1218
1219 let need_arg_opt_1 = Arg::new('a').needs(Need::Argument);
1220 let need_arg_opt_2 = Arg::new('b').needs(Need::Argument);
1221 let need_arg_opt_3 = Arg::new('3').needs(Need::Argument);
1222
1223 let flag_opt = Arg::new('d').needs(Need::Nothing);
1224 let flag_opt_2 = Arg::new('人').needs(Need::Nothing);
1225 let flag_opt_3 = Arg::new('0').needs(Need::Nothing);
1226
1227 let required_flag_opt = Arg::new('e').needs(Need::Nothing).required();
1228 let required_need_arg_opt = Arg::new('r').needs(Need::Argument).required();
1229
1230 let tests = &[
1231 TestData {
1232 cli_args: vec![],
1233 args: None,
1234 use_handler: false,
1235 result: Err(Error::NoHandler),
1236 },
1237 TestData {
1238 cli_args: vec![],
1239 args: None,
1240 use_handler: true,
1241 result: Err(Error::NoArgs),
1242 },
1243 TestData {
1244 cli_args: vec![],
1245 args: Some(vec![need_arg_opt_1.clone()]),
1246 use_handler: true,
1247 result: Ok(()),
1248 },
1249 TestData {
1250 cli_args: vec![],
1251 args: Some(vec![need_arg_opt_1.clone(), need_arg_opt_2.clone()]),
1252 use_handler: true,
1253 result: Ok(()),
1254 },
1255 TestData {
1256 cli_args: vec![],
1257 args: Some(vec![required_flag_opt.clone()]),
1258 use_handler: true,
1259 result: Err(Error::MissingReqOpt),
1260 },
1261 TestData {
1262 cli_args: vec![],
1263 args: Some(vec![need_arg_opt_1.clone(), required_flag_opt.clone()]),
1264 use_handler: true,
1265 result: Err(Error::MissingReqOpt),
1266 },
1267 TestData {
1268 cli_args: vec![],
1269 args: Some(vec![required_need_arg_opt.clone()]),
1270 use_handler: true,
1271 result: Err(Error::MissingReqOpt),
1272 },
1273 TestData {
1274 cli_args: vec!["-"],
1275 args: Some(vec![flag_opt.clone()]),
1276 use_handler: true,
1277 result: Err(Error::MissingOptName),
1278 },
1279 TestData {
1280 cli_args: vec!["- -"],
1282 args: Some(vec![flag_opt.clone()]),
1283 use_handler: true,
1284 result: Err(Error::MissingOptName),
1285 },
1286 TestData {
1287 cli_args: vec!["- - "],
1289 args: Some(vec![flag_opt.clone()]),
1290 use_handler: true,
1291 result: Err(Error::MissingOptName),
1292 },
1293 TestData {
1294 cli_args: vec![" - "],
1296 args: Some(vec![flag_opt.clone()]),
1297 use_handler: true,
1298 result: Err(Error::NoPosnArgs),
1299 },
1300 TestData {
1301 cli_args: vec![END_OF_OPTIONS],
1302 args: Some(vec![flag_opt.clone()]),
1303 use_handler: true,
1304 result: Ok(()),
1305 },
1306 TestData {
1307 cli_args: vec![" -"],
1309 args: Some(vec![flag_opt.clone()]),
1310 use_handler: true,
1311 result: Err(Error::NoPosnArgs),
1312 },
1313 TestData {
1314 cli_args: vec![" --"],
1316 args: Some(vec![flag_opt.clone()]),
1317 use_handler: true,
1318 result: Err(Error::NoPosnArgs),
1319 },
1320 TestData {
1321 cli_args: vec![" ---"],
1323 args: Some(vec![flag_opt.clone()]),
1324 use_handler: true,
1325 result: Err(Error::NoPosnArgs),
1326 },
1327 TestData {
1328 cli_args: vec![" --- "],
1330 args: Some(vec![flag_opt.clone()]),
1331 use_handler: true,
1332 result: Err(Error::NoPosnArgs),
1333 },
1334 TestData {
1335 cli_args: vec!["---"],
1337 args: Some(vec![flag_opt.clone()]),
1338 use_handler: true,
1339 result: Err(Error::NoLongOpts),
1340 },
1341 TestData {
1342 cli_args: vec!["--notsupported"],
1343 args: Some(vec![flag_opt.clone()]),
1344 use_handler: true,
1345 result: Err(Error::NoLongOpts),
1346 },
1347 TestData {
1348 cli_args: vec!["--not-supported"],
1349 args: Some(vec![flag_opt.clone()]),
1350 use_handler: true,
1351 result: Err(Error::NoLongOpts),
1352 },
1353 TestData {
1354 cli_args: vec![],
1355 args: Some(vec![required_flag_opt.clone()]),
1356 use_handler: true,
1357 result: Err(Error::MissingReqOpt),
1358 },
1359 TestData {
1360 cli_args: vec![],
1361 args: Some(vec![required_need_arg_opt.clone()]),
1362 use_handler: true,
1363 result: Err(Error::MissingReqOpt),
1364 },
1365 TestData {
1366 cli_args: vec!["--", "-r"],
1367 args: Some(vec![required_need_arg_opt.clone()]),
1368 use_handler: true,
1369 result: Err(Error::MissingReqOpt),
1370 },
1371 TestData {
1372 cli_args: vec!["-r"],
1373 args: Some(vec![required_need_arg_opt.clone()]),
1374 use_handler: true,
1375 result: Err(Error::MissingOptArg),
1376 },
1377 TestData {
1378 cli_args: vec!["-r", "--"],
1379 args: Some(vec![required_need_arg_opt.clone()]),
1380 use_handler: true,
1381 result: Err(Error::MissingOptArg),
1382 },
1383 TestData {
1384 cli_args: vec![],
1385 args: Some(vec![required_flag_opt.clone()]),
1386 use_handler: true,
1387 result: Err(Error::MissingReqOpt),
1388 },
1389 TestData {
1390 cli_args: vec!["-r"],
1391 args: Some(vec![required_need_arg_opt.clone()]),
1392 use_handler: true,
1393 result: Err(Error::MissingOptArg),
1394 },
1395 TestData {
1396 cli_args: vec!["-r", "--"],
1397 args: Some(vec![required_need_arg_opt.clone()]),
1398 use_handler: true,
1399 result: Err(Error::MissingOptArg),
1400 },
1401 TestData {
1402 cli_args: vec!["-r"],
1403 args: Some(vec![required_need_arg_opt.clone()]),
1404 use_handler: true,
1405 result: Err(Error::MissingOptArg),
1406 },
1407 TestData {
1408 cli_args: vec!["-r", "foo"],
1409 args: Some(vec![required_need_arg_opt.clone()]),
1410 use_handler: true,
1411 result: Ok(()),
1412 },
1413 TestData {
1414 cli_args: vec!["-3", "three", "-0"],
1415 args: Some(vec![need_arg_opt_3.clone(), flag_opt_3.clone()]),
1416 use_handler: true,
1417 result: Ok(()),
1418 },
1419 TestData {
1420 cli_args: vec!["-人"],
1421 args: Some(vec![flag_opt_2.clone()]),
1422 use_handler: true,
1423 result: Err(Error::NoBundling),
1426 },
1427 TestData {
1428 cli_args: vec!["-ab"],
1429 args: Some(vec![flag_opt.clone()]),
1430 use_handler: true,
1431 result: Err(Error::NoBundling),
1432 },
1433 TestData {
1434 cli_args: vec!["-abc"],
1435 args: Some(vec![flag_opt.clone()]),
1436 use_handler: true,
1437 result: Err(Error::NoBundling),
1438 },
1439 TestData {
1440 cli_args: vec!["--", "-abc"],
1441 args: Some(vec![flag_opt.clone()]),
1442 use_handler: true,
1443 result: Ok(()),
1444 },
1445 TestData {
1446 cli_args: vec!["--", "abc", "def", "hello world", "--wibble", "-abc"],
1447 args: Some(vec![flag_opt.clone()]),
1448 use_handler: true,
1449 result: Ok(()),
1450 },
1451 TestData {
1452 cli_args: vec!["--foo"],
1453 args: Some(vec![flag_opt.clone()]),
1454 use_handler: true,
1455 result: Err(Error::NoLongOpts),
1456 },
1457 TestData {
1458 cli_args: vec!["-y"],
1459 args: Some(vec![flag_opt.clone()]),
1460 use_handler: true,
1461 result: Err(Error::UnknownOpt),
1462 },
1463 ];
1464
1465 for (i, d) in tests.iter().enumerate() {
1466 let msg = format!("test[{}]: {:?}", i, d);
1472
1473 let string_args = d.cli_args.clone().into_iter().map(String::from).collect();
1474
1475 let mut app: App;
1476
1477 if d.use_handler {
1478 app = App::default().handler(Box::new(&mut ok_handler));
1479 } else {
1480 app = App::default();
1481 }
1482
1483 let mut args = Args::default();
1484
1485 if let Some(a) = d.args.clone() {
1486 args.set(a);
1487 }
1488
1489 app = app.args(args);
1490
1491 let result = app.parse_with_args(string_args);
1493
1494 let msg = format!("{}, result: {:?}", msg, result);
1496
1497 if d.result.is_ok() {
1499 assert!(result.is_ok(), "{}", msg);
1500 continue;
1501 }
1502
1503 assert!(result.is_err(), "{}", msg);
1504
1505 let expected_err = format!("{:?}", d.result.as_ref().err());
1506 let actual_err = format!("{:?}", result.as_ref().err());
1507
1508 assert_eq!(actual_err, expected_err, "{}", msg);
1509 }
1510 }
1511
1512 #[test]
1513 fn test_parse_with_handler() {
1514 #[derive(Debug)]
1515 struct TestData<'a> {
1516 cli_args: Vec<&'a str>,
1517 args: Vec<Arg>,
1518 result: Result<()>,
1519 handler_result: ModifyHandler,
1521 }
1522
1523 let need_arg_opt_1 = Arg::new('a').needs(Need::Argument);
1524
1525 let flag_opt = Arg::new('d').needs(Need::Nothing);
1526
1527 let tests = &[
1528 TestData {
1529 cli_args: vec![],
1530 args: vec![flag_opt.clone()],
1531 result: Ok(()),
1532 handler_result: ModifyHandler::default(),
1533 },
1534 TestData {
1535 cli_args: vec!["-d"],
1536 args: vec![flag_opt.clone()],
1537 result: Ok(()),
1538 handler_result: ModifyHandler {
1539 i: INT_INCREMENT,
1540 s: HANDLER_SET_MSG.into(),
1541 count: 1,
1542 d_count: 1,
1543 ..ModifyHandler::default()
1544 },
1545 },
1546 TestData {
1547 cli_args: vec!["-a", "foo"],
1548 args: vec![need_arg_opt_1.clone()],
1549 result: Ok(()),
1550 handler_result: ModifyHandler {
1551 i: INT_INCREMENT,
1552 s: HANDLER_SET_MSG.into(),
1553 v: vec!["foo".into()],
1554 count: 1,
1555 a_count: 1,
1556 ..ModifyHandler::default()
1557 },
1558 },
1559 TestData {
1560 cli_args: vec!["-a", "foo", "-a", "bar", "-a", "baz"],
1561 args: vec![need_arg_opt_1.clone()],
1562 result: Ok(()),
1563 handler_result: ModifyHandler {
1564 i: INT_INCREMENT * 3,
1565 s: HANDLER_SET_MSG.into(),
1566 v: vec!["foo".into(), "bar".into(), "baz".into()],
1567 count: (1 + 2 + 3),
1569 a_count: 3,
1570 ..ModifyHandler::default()
1571 },
1572 },
1573 TestData {
1574 cli_args: vec!["-d", "-a", "foo", "-d", "-a", "bar", "-a", "baz"],
1575 args: vec![flag_opt.clone(), need_arg_opt_1.clone()],
1576 result: Ok(()),
1577 handler_result: ModifyHandler {
1578 i: INT_INCREMENT * 5,
1579 s: HANDLER_SET_MSG.into(),
1580 v: vec!["foo".into(), "bar".into(), "baz".into()],
1581 count: (1 + 2 + 3) + (1 + 2),
1584 a_count: 3,
1585 d_count: 2,
1586 ..ModifyHandler::default()
1587 },
1588 },
1589 ];
1590
1591 for (i, d) in tests.iter().enumerate() {
1592 let msg = format!("test[{}]: {:?}", i, d);
1593 let string_args: Vec<String> =
1594 d.cli_args.clone().into_iter().map(String::from).collect();
1595
1596 let mut args = Args::default();
1597
1598 args.set(d.args.clone());
1599
1600 let mut handler = ModifyHandler::default();
1601 let mut app = App::default().args(args).handler(Box::new(&mut handler));
1602
1603 let result = app.parse_with_args(string_args);
1604
1605 drop(app);
1606
1607 if result.is_err() {
1608 assert!(d.result.is_err(), "{}", msg);
1609
1610 let expected_err = format!("{:?}", d.result.as_ref().err());
1611 let actual_err = format!("{:?}", result.as_ref().err());
1612 assert_eq!(expected_err, actual_err, "{}", msg);
1613
1614 continue;
1615 }
1616
1617 assert!(result.is_ok(), "{}", msg);
1618 assert_eq!(d.handler_result, handler, "{}", msg);
1619 }
1620 }
1621
1622 #[test]
1623 fn test_parse_with_bad_handler() {
1624 let flag_opt = Arg::new('d').needs(Need::Nothing);
1625
1626 let mut args = Args::default();
1627 args.add(flag_opt);
1628
1629 let mut handler = ErrHandler::default();
1631 let mut app = App::default().args(args).handler(Box::new(&mut handler));
1632
1633 let result = app.parse_with_args(vec!["-d".into()]);
1634 assert!(result.is_err());
1635
1636 let expected_err = format!("{:?}", Error::GenericError(TEST_ERR.into()));
1637 let actual_err = format!("{:?}", result.err().unwrap());
1638
1639 assert_eq!(expected_err, actual_err);
1640 }
1641
1642 #[test]
1643 fn test_ensure_handler_not_called_on_parse_fail() {
1644 let mut handler = ModifyHandler::default();
1645 let mut args = Args::default();
1646
1647 let need_arg_opt_1 = Arg::new('a').needs(Need::Argument);
1648 let need_arg_opt_2 = Arg::new('b').needs(Need::Argument);
1649 let flag_opt = Arg::new('d').needs(Need::Nothing);
1650
1651 args.add(flag_opt);
1652 args.add(need_arg_opt_1);
1653 args.add(need_arg_opt_2);
1654
1655 let cli_args = vec!["-d", "-a", "foo bar", "-d", "-a", "hello world", "-b"];
1657
1658 let string_args = cli_args.clone().into_iter().map(String::from).collect();
1659
1660 let mut app = App::default().args(args).handler(Box::new(&mut handler));
1661 let result = app.parse_with_args(string_args);
1662
1663 assert!(result.is_err());
1664
1665 drop(app);
1666
1667 let expected_handler = ModifyHandler {
1668 i: INT_INCREMENT * 4,
1669 s: HANDLER_SET_MSG.into(),
1670 v: vec!["foo bar".into(), "hello world".into()],
1671 count: (1 + 2) + (1 + 2),
1674 a_count: 2,
1675 d_count: 2,
1676 b_count: 0, ..ModifyHandler::default()
1678 };
1679
1680 assert_eq!(expected_handler, handler);
1681 }
1682
1683 #[test]
1684 fn test_parse_positional_args() {
1685 let posn_arg = Arg::new(POSITIONAL_HANDLER_OPT);
1686
1687 #[derive(Debug)]
1688 struct TestData<'a> {
1689 cli_args: Vec<&'a str>,
1690 result: Result<()>,
1691 handler_result: ModifyHandler,
1693 }
1694
1695 let tests = &[
1696 TestData {
1697 cli_args: vec![],
1698 result: Ok(()),
1699 handler_result: ModifyHandler::default(),
1700 },
1701 TestData {
1702 cli_args: vec!["foo"],
1703 result: Ok(()),
1704 handler_result: ModifyHandler {
1705 i: INT_INCREMENT,
1706 v: vec!["foo".into()],
1707 s: HANDLER_SET_MSG.into(),
1708 count: 1,
1709 ..Default::default()
1710 },
1711 },
1712 TestData {
1713 cli_args: vec!["\\- -"],
1714 result: Ok(()),
1715 handler_result: ModifyHandler {
1716 i: INT_INCREMENT,
1717 v: vec!["\\- -".into()],
1718 s: HANDLER_SET_MSG.into(),
1719 count: 1,
1720 ..Default::default()
1721 },
1722 },
1723 TestData {
1724 cli_args: vec!["\\- - "],
1725 result: Ok(()),
1726 handler_result: ModifyHandler {
1727 i: INT_INCREMENT,
1728 v: vec!["\\- - ".into()],
1729 s: HANDLER_SET_MSG.into(),
1730 count: 1,
1731 ..Default::default()
1732 },
1733 },
1734 TestData {
1735 cli_args: vec![" - "],
1736 result: Ok(()),
1737 handler_result: ModifyHandler {
1738 i: INT_INCREMENT,
1739 v: vec![" - ".into()],
1740 s: HANDLER_SET_MSG.into(),
1741 count: 1,
1742 ..Default::default()
1743 },
1744 },
1745 TestData {
1746 cli_args: vec![" - -"],
1747 result: Ok(()),
1748 handler_result: ModifyHandler {
1749 i: INT_INCREMENT,
1750 v: vec![" - -".into()],
1751 s: HANDLER_SET_MSG.into(),
1752 count: 1,
1753 ..Default::default()
1754 },
1755 },
1756 TestData {
1757 cli_args: vec![" - - "],
1758 result: Ok(()),
1759 handler_result: ModifyHandler {
1760 i: INT_INCREMENT,
1761 v: vec![" - - ".into()],
1762 s: HANDLER_SET_MSG.into(),
1763 count: 1,
1764 ..Default::default()
1765 },
1766 },
1767 TestData {
1768 cli_args: vec![" -"],
1769 result: Ok(()),
1770 handler_result: ModifyHandler {
1771 i: INT_INCREMENT,
1772 v: vec![" -".into()],
1773 s: HANDLER_SET_MSG.into(),
1774 count: 1,
1775 ..Default::default()
1776 },
1777 },
1778 TestData {
1779 cli_args: vec![" --"],
1780 result: Ok(()),
1781 handler_result: ModifyHandler {
1782 i: INT_INCREMENT,
1783 v: vec![" --".into()],
1784 s: HANDLER_SET_MSG.into(),
1785 count: 1,
1786 ..Default::default()
1787 },
1788 },
1789 TestData {
1790 cli_args: vec![" ---"],
1791 result: Ok(()),
1792 handler_result: ModifyHandler {
1793 i: INT_INCREMENT,
1794 v: vec![" ---".into()],
1795 s: HANDLER_SET_MSG.into(),
1796 count: 1,
1797 ..Default::default()
1798 },
1799 },
1800 TestData {
1801 cli_args: vec![" --- "],
1802 result: Ok(()),
1803 handler_result: ModifyHandler {
1804 i: INT_INCREMENT,
1805 v: vec![" --- ".into()],
1806 s: HANDLER_SET_MSG.into(),
1807 count: 1,
1808 ..Default::default()
1809 },
1810 },
1811 TestData {
1812 cli_args: vec!["-d", "foo"],
1813 result: Err(Error::UnknownOpt),
1814 handler_result: ModifyHandler::default(),
1815 },
1816 ];
1817
1818 for (i, d) in tests.iter().enumerate() {
1819 let msg = format!("test[{}]: {:?}", i, d);
1820 let string_args: Vec<String> =
1821 d.cli_args.clone().into_iter().map(String::from).collect();
1822
1823 let mut args = Args::default();
1824 args.add(posn_arg.clone());
1825
1826 let mut handler = ModifyHandler::default();
1827 let mut app = App::default().args(args).handler(Box::new(&mut handler));
1828
1829 let result = app.parse_with_args(string_args);
1830
1831 let msg = format!("{}, result: {:?}", msg, result);
1832
1833 drop(app);
1834
1835 if result.is_err() {
1836 assert!(d.result.is_err(), "{}", msg);
1837
1838 let expected_err = format!("{:?}", d.result.as_ref().err());
1839 let actual_err = format!("{:?}", result.as_ref().err());
1840 assert_eq!(expected_err, actual_err, "{}", msg);
1841
1842 continue;
1843 }
1844
1845 assert!(result.is_ok(), "{}", msg);
1846 assert_eq!(d.handler_result, handler, "{}", msg);
1847 }
1848 }
1849
1850 #[test]
1851 fn test_parse_unknown_options() {
1852 let unknown_opts_arg = Arg::new(UNKNOWN_OPTION_HANDLER_OPT);
1853
1854 let mut args = Args::default();
1855 args.add(Arg::new('d'));
1856 args.add(unknown_opts_arg);
1857
1858 let cli_args = vec!["-d", "-a", "-b", "-r", "-d"];
1859
1860 let string_args = cli_args.clone().into_iter().map(String::from).collect();
1861
1862 let mut handler = ModifyHandler::default();
1863 assert_eq!(handler.count, 0);
1864
1865 let mut app = App::default()
1866 .args(args)
1867 .ignore_unknown_options()
1868 .handler(Box::new(&mut handler));
1869
1870 let result = app.parse_with_args(string_args);
1871
1872 assert!(result.is_ok());
1873
1874 drop(app);
1875
1876 let expected_count = (1 + 2) + (1 + 2 + 3);
1878 assert_eq!(handler.count, expected_count);
1879
1880 assert_eq!(handler.a_count, 1);
1881 assert_eq!(handler.b_count, 1);
1882 assert_eq!(handler.d_count, 2);
1883 assert_eq!(handler.r_count, 1);
1884 }
1885
1886 #[test]
1887 fn test_intermingling_arguments() {
1888 let mut handler = ModifyHandler::default();
1889 let mut args = Args::default();
1890
1891 args.add(Arg::new('a').needs(Need::Argument));
1892 args.add(Arg::new('d').needs(Need::Nothing));
1893 args.add(Arg::new(POSITIONAL_HANDLER_OPT));
1894
1895 let mut app = App::default()
1896 .help("some text")
1897 .args(args)
1898 .handler(Box::new(&mut handler));
1899
1900 let cli_args = vec![
1902 "the start",
1903 "-d",
1904 "foo bar",
1905 "-a",
1906 "hello world",
1907 "-d",
1908 "alpha omega",
1909 "one",
1910 "two",
1911 "-d",
1912 "-a",
1913 "moo bar haz",
1914 "the end",
1915 ];
1916
1917 let string_args = cli_args.clone().into_iter().map(String::from).collect();
1918 let result = app.parse_with_args(string_args);
1919
1920 assert!(result.is_ok());
1921
1922 drop(app);
1923
1924 let expected_handler = ModifyHandler {
1925 i: 187,
1926 v: vec![
1927 "the start".into(),
1928 "foo bar".into(),
1929 "hello world".into(),
1930 "alpha omega".into(),
1931 "one".into(),
1932 "two".into(),
1933 "moo bar haz".into(),
1934 "the end".into(),
1935 ],
1936 s: "set by handler".into(),
1937 count: 30,
1938 a_count: 2,
1939 d_count: 3,
1940 ..Default::default()
1941 };
1942
1943 assert_eq!(handler, expected_handler);
1944 }
1945
1946 #[test]
1947 fn test_ignore_unknown_options() {
1948 #[derive(Debug)]
1949 struct TestData<'a> {
1950 cli_args: Vec<&'a str>,
1951 args: Vec<Arg>,
1952 allow_unknown_options: bool,
1953 result: Result<()>,
1954 }
1955
1956 let need_arg_opt = Arg::new('a').needs(Need::Argument);
1957 let flag_opt = Arg::new('d').needs(Need::Nothing);
1958
1959 let tests = &[
1960 TestData {
1961 cli_args: vec!["-z"],
1962 args: vec![need_arg_opt.clone()],
1963 allow_unknown_options: false,
1964 result: Err(Error::UnknownOpt),
1965 },
1966 TestData {
1967 cli_args: vec!["-z"],
1968 args: vec![need_arg_opt.clone()],
1969 allow_unknown_options: true,
1970 result: Ok(()),
1971 },
1972 TestData {
1974 cli_args: vec!["-z"],
1975 args: vec![flag_opt.clone()],
1976 allow_unknown_options: false,
1977 result: Err(Error::UnknownOpt),
1978 },
1979 TestData {
1980 cli_args: vec!["-z"],
1981 args: vec![flag_opt.clone()],
1982 allow_unknown_options: true,
1983 result: Ok(()),
1984 },
1985 TestData {
1987 cli_args: vec!["-z", "-a", "foo"],
1988 args: vec![need_arg_opt.clone()],
1989 allow_unknown_options: false,
1990 result: Err(Error::UnknownOpt),
1991 },
1992 TestData {
1993 cli_args: vec!["-a", "foo", "-z"],
1994 args: vec![need_arg_opt.clone()],
1995 allow_unknown_options: false,
1996 result: Err(Error::UnknownOpt),
1997 },
1998 TestData {
2000 cli_args: vec!["-z", "-a", "foo"],
2001 args: vec![need_arg_opt.clone()],
2002 allow_unknown_options: true,
2003 result: Err(Error::UnknownOpt),
2004 },
2005 TestData {
2006 cli_args: vec!["-a", "foo", "-z"],
2007 args: vec![need_arg_opt.clone()],
2008 allow_unknown_options: true,
2009 result: Ok(()),
2010 },
2011 TestData {
2013 cli_args: vec!["-z", "-d"],
2014 args: vec![flag_opt.clone()],
2015 allow_unknown_options: false,
2016 result: Err(Error::UnknownOpt),
2017 },
2018 TestData {
2019 cli_args: vec!["-d", "-z"],
2020 args: vec![flag_opt.clone()],
2021 allow_unknown_options: false,
2022 result: Err(Error::UnknownOpt),
2023 },
2024 TestData {
2026 cli_args: vec!["-z", "-d"],
2027 args: vec![flag_opt.clone()],
2028 allow_unknown_options: true,
2029 result: Ok(()),
2030 },
2031 TestData {
2032 cli_args: vec!["-d", "-z"],
2033 args: vec![flag_opt.clone()],
2034 allow_unknown_options: true,
2035 result: Ok(()),
2036 },
2037 ];
2038
2039 for (i, d) in tests.iter().enumerate() {
2040 let msg = format!("test[{}]: {:?}", i, d);
2041 let string_args: Vec<String> =
2042 d.cli_args.clone().into_iter().map(String::from).collect();
2043
2044 let mut args = Args::default();
2045 args.set(d.args.clone());
2046
2047 let mut handler = OkHandler::default();
2048 let mut app = App::default().args(args).handler(Box::new(&mut handler));
2049
2050 if d.allow_unknown_options {
2051 app = app.ignore_unknown_options();
2052 }
2053
2054 let result = app.parse_with_args(string_args);
2055
2056 let msg = format!("{}, result: {:?}", msg, result);
2057
2058 if result.is_err() {
2059 assert!(d.result.is_err(), "{}", msg);
2060
2061 let expected_err = format!("{:?}", d.result.as_ref().err());
2062 let actual_err = format!("{:?}", result.as_ref().err());
2063 assert_eq!(expected_err, actual_err, "{}", msg);
2064
2065 continue;
2066 }
2067
2068 assert!(result.is_ok(), "{}", msg);
2069 }
2070 }
2071
2072 #[test]
2073 fn test_ignore_unknown_posn_args() {
2074 #[derive(Debug)]
2075 struct TestData<'a> {
2076 cli_args: Vec<&'a str>,
2077 args: Vec<Arg>,
2078 allow_unknown_posn_args: bool,
2079 result: Result<()>,
2080 }
2081
2082 let need_arg_opt = Arg::new('a').needs(Need::Argument);
2083 let flag_opt = Arg::new('d').needs(Need::Nothing);
2084
2085 let tests = &[
2086 TestData {
2087 cli_args: vec!["foo bar"],
2088 args: vec![need_arg_opt.clone()],
2089 allow_unknown_posn_args: false,
2090 result: Err(Error::NoPosnArgs),
2091 },
2092 TestData {
2093 cli_args: vec!["foo bar"],
2094 args: vec![need_arg_opt.clone()],
2095 allow_unknown_posn_args: true,
2096 result: Ok(()),
2097 },
2098 TestData {
2100 cli_args: vec!["foo bar"],
2101 args: vec![flag_opt.clone()],
2102 allow_unknown_posn_args: false,
2103 result: Err(Error::NoPosnArgs),
2104 },
2105 TestData {
2106 cli_args: vec!["foo bar"],
2107 args: vec![flag_opt.clone()],
2108 allow_unknown_posn_args: true,
2109 result: Ok(()),
2110 },
2111 TestData {
2113 cli_args: vec!["foo bar", "-a", "foo"],
2114 args: vec![need_arg_opt.clone()],
2115 allow_unknown_posn_args: false,
2116 result: Err(Error::NoPosnArgs),
2117 },
2118 TestData {
2119 cli_args: vec!["-a", "foo", "foo bar"],
2120 args: vec![need_arg_opt.clone()],
2121 allow_unknown_posn_args: false,
2122 result: Err(Error::NoPosnArgs),
2123 },
2124 TestData {
2126 cli_args: vec!["foo bar", "-a", "foo"],
2127 args: vec![need_arg_opt.clone()],
2128 allow_unknown_posn_args: true,
2129 result: Err(Error::NoPosnArgs),
2130 },
2131 TestData {
2132 cli_args: vec!["-a", "foo", "foo bar"],
2133 args: vec![need_arg_opt.clone()],
2134 allow_unknown_posn_args: true,
2135 result: Ok(()),
2136 },
2137 TestData {
2139 cli_args: vec!["foo bar", "-d"],
2140 args: vec![flag_opt.clone()],
2141 allow_unknown_posn_args: false,
2142 result: Err(Error::NoPosnArgs),
2143 },
2144 TestData {
2145 cli_args: vec!["-d", "foo bar"],
2146 args: vec![flag_opt.clone()],
2147 allow_unknown_posn_args: false,
2148 result: Err(Error::NoPosnArgs),
2149 },
2150 TestData {
2152 cli_args: vec!["foo bar", "-d"],
2153 args: vec![flag_opt.clone()],
2154 allow_unknown_posn_args: true,
2155 result: Ok(()),
2156 },
2157 TestData {
2158 cli_args: vec!["-d", "foo bar"],
2159 args: vec![flag_opt.clone()],
2160 allow_unknown_posn_args: true,
2161 result: Ok(()),
2162 },
2163 ];
2164
2165 for (i, d) in tests.iter().enumerate() {
2166 let msg = format!("test[{}]: {:?}", i, d);
2167 let string_args: Vec<String> =
2168 d.cli_args.clone().into_iter().map(String::from).collect();
2169
2170 let mut args = Args::default();
2171 args.set(d.args.clone());
2172
2173 let mut handler = OkHandler::default();
2174 let mut app = App::default().args(args).handler(Box::new(&mut handler));
2175
2176 if d.allow_unknown_posn_args {
2177 app = app.ignore_unknown_posn_args();
2178 }
2179
2180 let result = app.parse_with_args(string_args);
2181
2182 let msg = format!("{}, result: {:?}", msg, result);
2183
2184 if result.is_err() {
2185 assert!(d.result.is_err(), "{}", msg);
2186
2187 let expected_err = format!("{:?}", d.result.as_ref().err());
2188 let actual_err = format!("{:?}", result.as_ref().err());
2189 assert_eq!(expected_err, actual_err, "{}", msg);
2190
2191 continue;
2192 }
2193
2194 assert!(result.is_ok(), "{}", msg);
2195 }
2196 }
2197
2198 #[test]
2199 fn test_app_creation() {
2200 let new_app = App::new("foo bar");
2201 let def_app = App::default();
2202
2203 let expected_def_app = App {
2204 name: "".into(),
2205 version: "".into(),
2206 summary: "".into(),
2207 help: "".into(),
2208 notes: "".into(),
2209 settings: Settings::default(),
2210 args: Args::default(),
2211 handler: None,
2212 };
2213
2214 let expected_new_app = App {
2215 name: "foo bar".into(),
2216 ..Default::default()
2217 };
2218
2219 assert_eq!(def_app, expected_def_app);
2220 assert_eq!(new_app, expected_new_app);
2221 }
2222
2223 #[test]
2224 fn test_app() {
2225 let mut app = App::default();
2226
2227 assert_eq!(app.name, "");
2228 let name = "foo bar";
2229 app = app.name(name);
2230 assert_eq!(app.name, name);
2231
2232 let version = "1.2.3-beta5";
2233 assert_eq!(app.version, "");
2234 app = app.version(version);
2235 assert_eq!(app.version, version);
2236
2237 let summary = "my awesome app";
2238 assert_eq!(app.summary, "");
2239 app = app.summary(summary);
2240 assert_eq!(app.summary, summary);
2241
2242 let help = "this app does something\nthe end\n";
2243 assert_eq!(app.help, "");
2244 app = app.help(help);
2245 assert_eq!(app.help, help);
2246
2247 let notes = "a b c d e f# g";
2248 assert_eq!(app.notes, "");
2249 app = app.notes(notes);
2250 assert_eq!(app.notes, notes);
2251
2252 let settings = Settings::new().no_strict_options();
2253 let def_settings = Settings::new();
2254 assert_eq!(app.settings, def_settings);
2255
2256 app = app.settings(settings);
2257 assert_eq!(app.settings, settings);
2258 }
2259
2260 #[test]
2261 fn test_generate_help() {
2262 let mut writer = BufWriter::new();
2263
2264 let mut args = Args::default();
2265
2266 args.add(Arg::new('d').help("enable debug"));
2268 args.add(Arg::new('e').required());
2269 args.add(Arg::new('f').required().help("force mode"));
2270
2271 args.add(Arg::new('n').needs(Need::Argument));
2273 args.add(Arg::new('r').needs(Need::Argument).required());
2274 args.add(
2275 Arg::new('s')
2276 .needs(Need::Argument)
2277 .required()
2278 .help("silly option"),
2279 );
2280
2281 let posn_help = "I am the positional handler \
2282 help text";
2283
2284 args.add(Arg::new(POSITIONAL_HANDLER_OPT).help(posn_help));
2286
2287 let flags_re = concat!(
2288 r#"FLAGS:\n"#,
2289 r#"\s+-d # enable debug\n"#,
2290 r#"\s+-e \(required\)\n"#,
2291 r#"\s+-f \(required\) # force mode\n"#,
2292 );
2293
2294 let options_re = concat!(
2295 r#"OPTIONS:\n"#,
2296 r#"\s+-n <value>\n"#,
2297 r#"\s+-r <value> \(required\)\n"#,
2298 r#"\s+-s <value> \(required\) # silly option\n"#,
2299 );
2300
2301 let pos_handler_re = concat!(
2302 r#"POSITIONAL ARGUMENTS:\n\n"#,
2303 r#"I am the positional handler help text"#
2304 );
2305
2306 let name = "my app";
2309 let name_re = format!(r#"NAME:\n\s+{}\n"#, name);
2310
2311 let version = "1.2.3-alpha4";
2312 let version_re = format!(r"VERSION:\n\s+{}\n", version);
2313
2314 let summary = "This is one awesome app";
2315 let summary_re = format!(r"SUMMARY:\n\s+{}\n", summary);
2316
2317 let help = concat!(
2318 "help line 1\n",
2319 "help line 2\n",
2320 "help line 3\n",
2321 "help last line\n"
2322 );
2323 let help_re = format!(r"HELP:\n\s+{}\n", help);
2324
2325 let notes = concat!(
2326 "notes line 1\n",
2327 "notes line 2\n",
2328 "notes line 3\n",
2329 "notes last line\n"
2330 );
2331
2332 let notes_re = format!(r"NOTES:\n\s+{}\n", notes);
2333
2334 let mut handler = OkHandler::default();
2337
2338 let app = App::new(name)
2339 .summary(summary)
2340 .version(version)
2341 .help(help)
2342 .notes(notes)
2343 .args(args)
2344 .handler(Box::new(&mut handler));
2345
2346 let result = app.generate_help(&mut writer);
2347
2348 drop(app);
2349
2350 assert!(result.is_ok());
2351
2352 let value = writer.to_string();
2353
2354 let re = Regex::new(&name_re).unwrap();
2355 assert!(re.is_match(&value));
2356
2357 let re = Regex::new(&version_re).unwrap();
2358 assert!(re.is_match(&value));
2359
2360 let re = Regex::new(&summary_re).unwrap();
2361 assert!(re.is_match(&value));
2362
2363 let re = Regex::new(&help_re).unwrap();
2364 assert!(re.is_match(&value));
2365
2366 let re = Regex::new(¬es_re).unwrap();
2367 assert!(re.is_match(&value));
2368
2369 let re = Regex::new(&flags_re).unwrap();
2370 assert!(re.is_match(&value));
2371
2372 let re = Regex::new(&options_re).unwrap();
2373 assert!(re.is_match(&value));
2374
2375 let re = Regex::new(&pos_handler_re).unwrap();
2376 assert!(re.is_match(&value));
2377 }
2378
2379 #[test]
2380 fn test_generate_help_usage() {
2381 #[derive(Debug)]
2382 struct TestData<'a> {
2383 args: Vec<Arg>,
2384 usage: &'a str,
2385 }
2386
2387 let tests = &[
2388 TestData {
2389 args: vec![Arg::new(POSITIONAL_HANDLER_OPT)],
2390 usage: r#"\[ARGUMENT\]..."#,
2391 },
2392 TestData {
2394 args: vec![Arg::new('d')],
2395 usage: r#"\[FLAG\]..."#,
2396 },
2397 TestData {
2398 args: vec![Arg::new('d'), Arg::new('e')],
2399 usage: r#"\[FLAG\]..."#,
2400 },
2401 TestData {
2402 args: vec![Arg::new('d').required()],
2403 usage: r#"\[FLAG\]..."#,
2404 },
2405 TestData {
2406 args: vec![Arg::new('d').required().needs(Need::Nothing)],
2407 usage: r#"\[FLAG\]..."#,
2408 },
2409 TestData {
2410 args: vec![Arg::new('d').required().needs(Need::Nothing), Arg::new('e')],
2411 usage: r#"\[FLAG\]..."#,
2412 },
2413 TestData {
2414 args: vec![Arg::new('d').needs(Need::Nothing), Arg::new('e')],
2415 usage: r#"\[FLAG\]..."#,
2416 },
2417 TestData {
2419 args: vec![Arg::new('a').needs(Need::Argument)],
2420 usage: r#"\[OPTION\]..."#,
2421 },
2422 TestData {
2423 args: vec![
2424 Arg::new('d').needs(Need::Argument),
2425 Arg::new('e').needs(Need::Argument),
2426 ],
2427 usage: r#"\[OPTION\]..."#,
2428 },
2429 TestData {
2430 args: vec![Arg::new('d').needs(Need::Argument).required()],
2431 usage: r#"\[OPTION\]..."#,
2432 },
2433 TestData {
2434 args: vec![
2435 Arg::new('d').needs(Need::Argument).required(),
2436 Arg::new('e').needs(Need::Argument),
2437 ],
2438 usage: r#"\[OPTION\]..."#,
2439 },
2440 TestData {
2442 args: vec![
2443 Arg::new('d').needs(Need::Nothing),
2444 Arg::new('e').needs(Need::Argument),
2445 ],
2446 usage: r#"\[FLAG/OPTION\]..."#,
2447 },
2448 TestData {
2449 args: vec![
2450 Arg::new('d').needs(Need::Nothing),
2451 Arg::new(POSITIONAL_HANDLER_OPT),
2452 ],
2453 usage: r#"\[FLAG\]... \[ARGUMENT\]..."#,
2454 },
2455 TestData {
2456 args: vec![
2457 Arg::new(POSITIONAL_HANDLER_OPT),
2458 Arg::new('e').needs(Need::Argument),
2459 ],
2460 usage: r#"\[OPTION\]... \[ARGUMENT\]..."#,
2461 },
2462 TestData {
2463 args: vec![
2464 Arg::new(POSITIONAL_HANDLER_OPT),
2465 Arg::new('d').needs(Need::Nothing),
2466 Arg::new('e').needs(Need::Argument),
2467 ],
2468 usage: r#"\[FLAG/OPTION\]... \[ARGUMENT\]..."#,
2469 },
2470 ];
2472
2473 let mut writer = BufWriter::new();
2474
2475 for (i, d) in tests.iter().enumerate() {
2476 let msg = format!("test[{}]: {:?}", i, d);
2477
2478 let mut handler = OkHandler::default();
2479 let mut args = Args::default();
2480
2481 for arg in d.args.clone() {
2482 args.add(arg);
2483 }
2484
2485 let name = "test";
2486 let app = App::new(name).args(args).handler(Box::new(&mut handler));
2487 let result = app.generate_help(&mut writer);
2488 assert!(result.is_ok(), "{}", msg);
2489
2490 drop(app);
2491
2492 let value = writer.to_string();
2493
2494 let usage_re = format!(r"USAGE:\n\s+{}\s+{}\n", name, d.usage);
2495
2496 let re = Regex::new(&usage_re).unwrap();
2497
2498 assert!(re.is_match(&value), "{}", msg);
2499 }
2500 }
2501
2502 #[test]
2503 fn test_get_args() {
2504 let get_args_result = get_args();
2505
2506 let mut args: Vec<String> = env::args().collect();
2507 args.remove(0);
2508
2509 assert_eq!(get_args_result, args);
2510 }
2511
2512 #[test]
2513 fn test_arg_display() {
2514 #[derive(Debug)]
2515 struct TestData<'a> {
2516 arg: Arg,
2517 display: &'a str,
2518 }
2519
2520 let tests = &[
2521 TestData {
2522 arg: Arg::new('d'),
2523 display: "-d",
2524 },
2525 TestData {
2526 arg: Arg::new('d').required(),
2527 display: "-d (required)",
2528 },
2529 TestData {
2531 arg: Arg::new('d').needs(Need::Nothing),
2532 display: "-d",
2533 },
2534 TestData {
2535 arg: Arg::new('d').required().needs(Need::Nothing),
2536 display: "-d (required)",
2537 },
2538 TestData {
2540 arg: Arg::new('r').needs(Need::Argument),
2541 display: "-r <value>",
2542 },
2543 TestData {
2544 arg: Arg::new('r').needs(Need::Argument).required(),
2545 display: "-r <value> (required)",
2546 },
2547 TestData {
2549 arg: Arg::new('r').needs(Need::Argument),
2550 display: "-r <value>",
2551 },
2552 TestData {
2553 arg: Arg::new('r').needs(Need::Argument).required(),
2554 display: "-r <value> (required)",
2555 },
2556 TestData {
2558 arg: Arg::new('d').help("some help text"),
2559 display: "-d # some help text",
2560 },
2561 TestData {
2562 arg: Arg::new('d').required().help("some help text"),
2563 display: "-d (required) # some help text",
2564 },
2565 ];
2567
2568 for (i, d) in tests.iter().enumerate() {
2569 let value = format!("{:}", d.arg);
2570
2571 let msg = format!("test[{}]: {:?}, value: {:?}", i, d, value);
2572
2573 assert_eq!(value, d.display, "{}", msg);
2574 }
2575 }
2576
2577 #[test]
2578 fn test_handler_display() {
2579 let mut ok_handler = OkHandler::default();
2580 let mut mod_handler = ModifyHandler::default();
2581 let mut err_handler = ErrHandler::default();
2582
2583 let mut handlers: Vec<Box<dyn Handler>> = Vec::new();
2584 handlers.push(Box::new(&mut ok_handler));
2585 handlers.push(Box::new(&mut err_handler));
2586 handlers.push(Box::new(&mut mod_handler));
2587
2588 for (i, handler) in handlers.iter().enumerate() {
2589 let p = handler;
2590
2591 let value = format!("{:?}", p);
2592
2593 let msg = format!("test[{}]: value: {:?}", i, value);
2594
2595 assert!(value.starts_with("Handler: "), "{}", msg);
2596 }
2597 }
2598
2599 #[test]
2600 fn test_no_strict_options() {
2601 #[derive(Debug)]
2602 struct TestData<'a> {
2603 cli_args: Vec<&'a str>,
2604 args: Vec<Arg>,
2605 no_strict_options: bool,
2606 result: Result<()>,
2607 r_count: usize,
2608 d_count: usize,
2609 values: Vec<&'a str>,
2610 }
2611
2612 let flag_opt = Arg::new('d').needs(Need::Nothing);
2613 let need_arg_opt = Arg::new('r').needs(Need::Argument);
2614
2615 let tests = &[
2616 TestData {
2617 cli_args: vec!["-r", "foo", "-d"],
2618 args: vec![flag_opt.clone(), need_arg_opt.clone()],
2619 no_strict_options: false,
2620 result: Ok(()),
2621 r_count: 1,
2622 d_count: 1,
2623 values: vec!["foo"],
2624 },
2625 TestData {
2626 cli_args: vec!["-r", "foo", "-d"],
2627 args: vec![flag_opt.clone(), need_arg_opt.clone()],
2628 no_strict_options: true,
2629 result: Ok(()),
2630 r_count: 1,
2631 d_count: 1,
2632 values: vec!["foo"],
2633 },
2634 TestData {
2636 cli_args: vec!["-r", "-d"],
2637 args: vec![flag_opt.clone(), need_arg_opt.clone()],
2638 no_strict_options: false,
2639 result: Ok(()),
2640 r_count: 1,
2641 d_count: 0,
2642 values: vec!["-d"],
2643 },
2644 TestData {
2645 cli_args: vec!["-r", "-d"],
2646 args: vec![flag_opt.clone(), need_arg_opt.clone()],
2647 no_strict_options: true,
2648 result: Err(Error::MissingOptArg),
2649 r_count: 0,
2650 d_count: 0,
2651 values: vec![],
2652 },
2653 TestData {
2655 cli_args: vec!["-r", "--"],
2656 args: vec![need_arg_opt.clone()],
2657 no_strict_options: false,
2658 result: Err(Error::MissingOptArg),
2659 r_count: 0,
2660 d_count: 0,
2661 values: vec![],
2662 },
2663 TestData {
2664 cli_args: vec!["-r", "--"],
2665 args: vec![need_arg_opt.clone()],
2666 no_strict_options: true,
2667 result: Err(Error::MissingOptArg),
2668 r_count: 0,
2669 d_count: 0,
2670 values: vec![],
2671 },
2672 TestData {
2674 cli_args: vec!["-r", "-d", "--"],
2675 args: vec![need_arg_opt.clone()],
2676 no_strict_options: false,
2677 result: Ok(()),
2678 r_count: 1,
2679 d_count: 0,
2680 values: vec!["-d"],
2681 },
2682 TestData {
2683 cli_args: vec!["-r", "-d", "--"],
2684 args: vec![need_arg_opt.clone()],
2685 no_strict_options: true,
2686 result: Err(Error::MissingOptArg),
2687 r_count: 0,
2688 d_count: 0,
2689 values: vec![],
2690 },
2691 ];
2692
2693 for (i, d) in tests.iter().enumerate() {
2694 let msg = format!("test[{}]: {:?}", i, d);
2695 let string_args: Vec<String> =
2696 d.cli_args.clone().into_iter().map(String::from).collect();
2697
2698 let mut args = Args::default();
2699 args.set(d.args.clone());
2700
2701 let mut handler = ModifyHandler::default();
2702 let mut app = App::default().args(args).handler(Box::new(&mut handler));
2703
2704 if d.no_strict_options {
2705 app = app.no_strict_options();
2706 }
2707
2708 let result = app.parse_with_args(string_args);
2709
2710 let msg = format!("{}, result: {:?}", msg, result);
2711
2712 if result.is_err() {
2713 assert!(d.result.is_err(), "{}", msg);
2714
2715 let expected_err = format!("{:?}", d.result.as_ref().err());
2716 let actual_err = format!("{:?}", result.as_ref().err());
2717 assert_eq!(expected_err, actual_err, "{}", msg);
2718
2719 continue;
2720 }
2721
2722 assert!(result.is_ok(), "{}", msg);
2723
2724 drop(app);
2725
2726 assert_eq!(d.r_count, handler.r_count);
2727 assert_eq!(d.d_count, handler.d_count);
2728
2729 let v: Vec<String> = d.values.clone().into_iter().map(String::from).collect();
2730 assert_eq!(v, handler.v);
2731 }
2732 }
2733}