1#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
96 html_favicon_url = "https://www.rust-lang.org/favicon.ico",
97 html_root_url = "https://docs.rs/getopts/0.2.18")]
98#![deny(missing_docs)]
99#![cfg_attr(test, deny(warnings))]
100#![cfg_attr(rust_build, feature(staged_api))]
101#![cfg_attr(rust_build, staged_api)]
102#![cfg_attr(rust_build,
103 unstable(feature = "rustc_private",
104 reason = "use the crates.io `getopts` library instead"))]
105
106#[cfg(test)] #[macro_use] extern crate log;
107extern crate unicode_width;
108
109
110use self::Name::*;
111use self::HasArg::*;
112use self::Occur::*;
113use self::Fail::*;
114use self::Optval::*;
115
116use std::error::Error;
117use std::ffi::OsStr;
118use std::fmt;
119use std::iter::{repeat, IntoIterator};
120use std::result;
121use std::str::FromStr;
122
123use unicode_width::UnicodeWidthStr;
124
125pub struct Options {
127 grps: Vec<OptGroup>,
128 parsing_style : ParsingStyle,
129 long_only: bool
130}
131
132impl Options {
133 pub fn new() -> Options {
135 Options {
136 grps: Vec::new(),
137 parsing_style: ParsingStyle::FloatingFrees,
138 long_only: false
139 }
140 }
141
142 pub fn parsing_style(&mut self, style: ParsingStyle) -> &mut Options {
144 self.parsing_style = style;
145 self
146 }
147
148 pub fn long_only(&mut self, long_only: bool) -> &mut Options {
157 self.long_only = long_only;
158 self
159 }
160
161 pub fn opt(&mut self, short_name: &str, long_name: &str, desc: &str,
163 hint: &str, hasarg: HasArg, occur: Occur) -> &mut Options {
164 validate_names(short_name, long_name);
165 self.grps.push(OptGroup {
166 short_name: short_name.to_string(),
167 long_name: long_name.to_string(),
168 hint: hint.to_string(),
169 desc: desc.to_string(),
170 hasarg: hasarg,
171 occur: occur
172 });
173 self
174 }
175
176 pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str)
182 -> &mut Options {
183 validate_names(short_name, long_name);
184 self.grps.push(OptGroup {
185 short_name: short_name.to_string(),
186 long_name: long_name.to_string(),
187 hint: "".to_string(),
188 desc: desc.to_string(),
189 hasarg: No,
190 occur: Optional
191 });
192 self
193 }
194
195 pub fn optflagmulti(&mut self, short_name: &str, long_name: &str, desc: &str)
202 -> &mut Options {
203 validate_names(short_name, long_name);
204 self.grps.push(OptGroup {
205 short_name: short_name.to_string(),
206 long_name: long_name.to_string(),
207 hint: "".to_string(),
208 desc: desc.to_string(),
209 hasarg: No,
210 occur: Multi
211 });
212 self
213 }
214
215 pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str,
223 hint: &str) -> &mut Options {
224 validate_names(short_name, long_name);
225 self.grps.push(OptGroup {
226 short_name: short_name.to_string(),
227 long_name: long_name.to_string(),
228 hint: hint.to_string(),
229 desc: desc.to_string(),
230 hasarg: Maybe,
231 occur: Optional
232 });
233 self
234 }
235
236 pub fn optmulti(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str)
245 -> &mut Options {
246 validate_names(short_name, long_name);
247 self.grps.push(OptGroup {
248 short_name: short_name.to_string(),
249 long_name: long_name.to_string(),
250 hint: hint.to_string(),
251 desc: desc.to_string(),
252 hasarg: Yes,
253 occur: Multi
254 });
255 self
256 }
257
258 pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str)
266 -> &mut Options {
267 validate_names(short_name, long_name);
268 self.grps.push(OptGroup {
269 short_name: short_name.to_string(),
270 long_name: long_name.to_string(),
271 hint: hint.to_string(),
272 desc: desc.to_string(),
273 hasarg: Yes,
274 occur: Optional
275 });
276 self
277 }
278
279 pub fn reqopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str)
287 -> &mut Options {
288 validate_names(short_name, long_name);
289 self.grps.push(OptGroup {
290 short_name: short_name.to_string(),
291 long_name: long_name.to_string(),
292 hint: hint.to_string(),
293 desc: desc.to_string(),
294 hasarg: Yes,
295 occur: Req
296 });
297 self
298 }
299
300 pub fn parse<C: IntoIterator>(&self, args: C) -> Result
309 where C::Item: AsRef<OsStr>
310 {
311 let opts: Vec<Opt> = self.grps.iter().map(|x| x.long_to_short()).collect();
312
313 let mut vals = (0 .. opts.len()).map(|_| Vec::new()).collect::<Vec<Vec<Optval>>>();
314 let mut free: Vec<String> = Vec::new();
315 let args = args.into_iter().map(|i| {
316 i.as_ref().to_str().ok_or_else(|| {
317 Fail::UnrecognizedOption(format!("{:?}", i.as_ref()))
318 }).map(|s| s.to_owned())
319 }).collect::<::std::result::Result<Vec<_>,_>>()?;
320 let mut args = args.into_iter().peekable();
321 while let Some(cur) = args.next() {
322 if !is_arg(&cur) {
323 free.push(cur);
324 match self.parsing_style {
325 ParsingStyle::FloatingFrees => {},
326 ParsingStyle::StopAtFirstFree => {
327 free.extend(args);
328 break;
329 }
330 }
331 } else if cur == "--" {
332 free.extend(args);
333 break;
334 } else {
335 let mut names;
336 let mut i_arg = None;
337 let mut was_long = true;
338 if cur.as_bytes()[1] == b'-' || self.long_only {
339 let tail = if cur.as_bytes()[1] == b'-' {
340 &cur[2..]
341 } else {
342 assert!(self.long_only);
343 &cur[1..]
344 };
345 let mut parts = tail.splitn(2, '=');
346 names = vec![Name::from_str(parts.next().unwrap())];
347 if let Some(rest) = parts.next() {
348 i_arg = Some(rest.to_string());
349 }
350 } else {
351 was_long = false;
352 names = Vec::new();
353 for (j, ch) in cur.char_indices().skip(1) {
354 let opt = Short(ch);
355
356 let opt_id = match find_opt(&opts, &opt) {
364 Some(id) => id,
365 None => return Err(UnrecognizedOption(opt.to_string()))
366 };
367
368 names.push(opt);
369
370 let arg_follows = match opts[opt_id].hasarg {
371 Yes | Maybe => true,
372 No => false
373 };
374
375 if arg_follows {
376 let next = j + ch.len_utf8();
377 if next < cur.len() {
378 i_arg = Some(cur[next..].to_string());
379 break;
380 }
381 }
382 }
383 }
384 let mut name_pos = 0;
385 for nm in names.iter() {
386 name_pos += 1;
387 let optid = match find_opt(&opts, &nm) {
388 Some(id) => id,
389 None => return Err(UnrecognizedOption(nm.to_string()))
390 };
391 match opts[optid].hasarg {
392 No => {
393 if name_pos == names.len() && !i_arg.is_none() {
394 return Err(UnexpectedArgument(nm.to_string()));
395 }
396 vals[optid].push(Given);
397 }
398 Maybe => {
399 if let Some(i_arg) = i_arg.take() {
406 vals[optid].push(Val(i_arg));
407 } else if was_long || name_pos < names.len() || args.peek().map_or(true, |n| is_arg(&n)) {
408 vals[optid].push(Given);
409 } else {
410 vals[optid].push(Val(args.next().unwrap()));
411 }
412 }
413 Yes => {
414 if let Some(i_arg) = i_arg.take() {
415 vals[optid].push(Val(i_arg));
416 } else if let Some(n) = args.next() {
417 vals[optid].push(Val(n));
418 } else {
419 return Err(ArgumentMissing(nm.to_string()));
420 }
421 }
422 }
423 }
424 }
425 }
426 debug_assert_eq!(vals.len(), opts.len());
427 for (vals, opt) in vals.iter().zip(opts.iter()) {
428 if opt.occur == Req && vals.is_empty() {
429 return Err(OptionMissing(opt.name.to_string()));
430 }
431 if opt.occur != Multi && vals.len() > 1 {
432 return Err(OptionDuplicated(opt.name.to_string()));
433 }
434 }
435 Ok(Matches {
436 opts: opts,
437 vals: vals,
438 free: free
439 })
440 }
441
442 pub fn short_usage(&self, program_name: &str) -> String {
444 let mut line = format!("Usage: {} ", program_name);
445 line.push_str(&self.grps.iter()
446 .map(format_option)
447 .collect::<Vec<String>>()
448 .join(" "));
449 line
450 }
451
452
453 pub fn usage(&self, brief: &str) -> String {
455 self.usage_with_format(|opts|
456 format!("{}\n\nOptions:\n{}\n", brief, opts.collect::<Vec<String>>().join("\n")))
457 }
458
459 pub fn usage_with_format<F: FnMut(&mut Iterator<Item=String>) -> String>(&self, mut formatter: F) -> String {
462 formatter(&mut self.usage_items())
463 }
464
465 fn usage_items<'a>(&'a self) -> Box<Iterator<Item=String> + 'a> {
467 let desc_sep = format!("\n{}", repeat(" ").take(24).collect::<String>());
468
469 let any_short = self.grps.iter().any(|optref| {
470 optref.short_name.len() > 0
471 });
472
473 let rows = self.grps.iter().map(move |optref| {
474 let OptGroup{short_name,
475 long_name,
476 hint,
477 desc,
478 hasarg,
479 ..} = (*optref).clone();
480
481 let mut row = " ".to_string();
482
483 match short_name.width() {
485 0 => {
486 if any_short {
487 row.push_str(" ");
488 }
489 }
490 1 => {
491 row.push('-');
492 row.push_str(&short_name);
493 if long_name.width() > 0 {
494 row.push_str(", ");
495 } else {
496 row.push(' ');
499 }
500 }
501 _ => panic!("the short name should only be 1 ascii char long"),
503 }
504
505 match long_name.width() {
507 0 => {}
508 _ => {
509 row.push_str(if self.long_only { "-" } else { "--" });
510 row.push_str(&long_name);
511 row.push(' ');
512 }
513 }
514
515 match hasarg {
517 No => {}
518 Yes => row.push_str(&hint),
519 Maybe => {
520 row.push('[');
521 row.push_str(&hint);
522 row.push(']');
523 }
524 }
525
526 let rowlen = row.width();
527 if rowlen < 24 {
528 for _ in 0 .. 24 - rowlen {
529 row.push(' ');
530 }
531 } else {
532 row.push_str(&desc_sep)
533 }
534
535 let desc_rows = each_split_within(&desc, 54);
536 row.push_str(&desc_rows.join(&desc_sep));
537
538 row
539 });
540
541 Box::new(rows)
542 }
543}
544
545fn validate_names(short_name: &str, long_name: &str) {
546 let len = short_name.len();
547 assert!(len == 1 || len == 0,
548 "the short_name (first argument) should be a single character, \
549 or an empty string for none");
550 let len = long_name.len();
551 assert!(len == 0 || len > 1,
552 "the long_name (second argument) should be longer than a single \
553 character, or an empty string for none");
554}
555
556#[derive(Clone, Copy, PartialEq, Eq)]
558pub enum ParsingStyle {
559 FloatingFrees,
561 StopAtFirstFree
564}
565
566#[derive(Clone, PartialEq, Eq)]
568enum Name {
569 Long(String),
572 Short(char),
575}
576
577#[derive(Clone, Copy, PartialEq, Eq)]
579pub enum HasArg {
580 Yes,
582 No,
584 Maybe,
586}
587
588#[derive(Clone, Copy, PartialEq, Eq)]
590pub enum Occur {
591 Req,
593 Optional,
595 Multi,
597}
598
599#[derive(Clone, PartialEq, Eq)]
601struct Opt {
602 name: Name,
604 hasarg: HasArg,
606 occur: Occur,
608 aliases: Vec<Opt>,
610}
611
612#[derive(Clone, PartialEq, Eq)]
615struct OptGroup {
616 short_name: String,
618 long_name: String,
620 hint: String,
622 desc: String,
624 hasarg: HasArg,
626 occur: Occur
628}
629
630#[derive(Clone, PartialEq, Eq)]
632enum Optval {
633 Val(String),
634 Given,
635}
636
637#[derive(Clone, PartialEq, Eq)]
640pub struct Matches {
641 opts: Vec<Opt>,
643 vals: Vec<Vec<Optval>>,
645 pub free: Vec<String>,
647}
648
649#[derive(Clone, Debug, PartialEq, Eq)]
653pub enum Fail {
654 ArgumentMissing(String),
656 UnrecognizedOption(String),
658 OptionMissing(String),
660 OptionDuplicated(String),
662 UnexpectedArgument(String),
664}
665
666impl Error for Fail {
667 fn description(&self) -> &str {
668 match *self {
669 ArgumentMissing(_) => "missing argument",
670 UnrecognizedOption(_) => "unrecognized option",
671 OptionMissing(_) => "missing option",
672 OptionDuplicated(_) => "duplicated option",
673 UnexpectedArgument(_) => "unexpected argument",
674 }
675 }
676}
677
678pub type Result = result::Result<Matches, Fail>;
680
681impl Name {
682 fn from_str(nm: &str) -> Name {
683 if nm.len() == 1 {
684 Short(nm.as_bytes()[0] as char)
685 } else {
686 Long(nm.to_string())
687 }
688 }
689
690 fn to_string(&self) -> String {
691 match *self {
692 Short(ch) => ch.to_string(),
693 Long(ref s) => s.to_string()
694 }
695 }
696}
697
698impl OptGroup {
699 fn long_to_short(&self) -> Opt {
702 let OptGroup {
703 short_name,
704 long_name,
705 hasarg,
706 occur,
707 ..
708 } = (*self).clone();
709
710 match (short_name.len(), long_name.len()) {
711 (0,0) => panic!("this long-format option was given no name"),
712 (0,_) => Opt {
713 name: Long(long_name),
714 hasarg: hasarg,
715 occur: occur,
716 aliases: Vec::new()
717 },
718 (1,0) => Opt {
719 name: Short(short_name.as_bytes()[0] as char),
720 hasarg: hasarg,
721 occur: occur,
722 aliases: Vec::new()
723 },
724 (1,_) => Opt {
725 name: Long(long_name),
726 hasarg: hasarg,
727 occur: occur,
728 aliases: vec!(
729 Opt {
730 name: Short(short_name.as_bytes()[0] as char),
731 hasarg: hasarg,
732 occur: occur,
733 aliases: Vec::new()
734 }
735 )
736 },
737 (_,_) => panic!("something is wrong with the long-form opt")
738 }
739 }
740}
741
742impl Matches {
743 fn opt_vals(&self, nm: &str) -> Vec<Optval> {
744 match find_opt(&self.opts, &Name::from_str(nm)) {
745 Some(id) => self.vals[id].clone(),
746 None => panic!("No option '{}' defined", nm)
747 }
748 }
749
750 fn opt_val(&self, nm: &str) -> Option<Optval> {
751 self.opt_vals(nm).into_iter().next()
752 }
753 pub fn opt_defined(&self, nm: &str) -> bool {
755 find_opt(&self.opts, &Name::from_str(nm)).is_some()
756 }
757
758 pub fn opt_present(&self, nm: &str) -> bool {
760 !self.opt_vals(nm).is_empty()
761 }
762
763 pub fn opt_count(&self, nm: &str) -> usize {
765 self.opt_vals(nm).len()
766 }
767
768 pub fn opts_present(&self, names: &[String]) -> bool {
770 names.iter().any(|nm| {
771 match find_opt(&self.opts, &Name::from_str(&nm)) {
772 Some(id) if !self.vals[id].is_empty() => true,
773 _ => false,
774 }
775 })
776 }
777
778 pub fn opts_str(&self, names: &[String]) -> Option<String> {
780 names.iter().filter_map(|nm| {
781 match self.opt_val(&nm) {
782 Some(Val(s)) => Some(s),
783 _ => None,
784 }
785 }).next()
786 }
787
788 pub fn opt_strs(&self, nm: &str) -> Vec<String> {
793 self.opt_vals(nm).into_iter().filter_map(|v| {
794 match v {
795 Val(s) => Some(s),
796 _ => None,
797 }
798 }).collect()
799 }
800
801 pub fn opt_str(&self, nm: &str) -> Option<String> {
803 match self.opt_val(nm) {
804 Some(Val(s)) => Some(s),
805 _ => None,
806 }
807 }
808
809
810 pub fn opt_default(&self, nm: &str, def: &str) -> Option<String> {
816 match self.opt_val(nm) {
817 Some(Val(s)) => Some(s),
818 Some(_) => Some(def.to_string()),
819 None => None,
820 }
821 }
822
823 pub fn opt_get<T>(&self, nm: &str) -> result::Result<Option<T>, T::Err>
827 where T: FromStr
828 {
829 match self.opt_val(nm) {
830 Some(Val(s)) => Ok(Some(s.parse()?)),
831 Some(Given) => Ok(None),
832 None => Ok(None),
833 }
834 }
835
836 pub fn opt_get_default<T>(&self, nm: &str, def: T)
842 -> result::Result<T, T::Err> where T: FromStr
843 {
844 match self.opt_val(nm) {
845 Some(Val(s)) => s.parse(),
846 Some(Given) => Ok(def),
847 None => Ok(def),
848 }
849 }
850}
851
852fn is_arg(arg: &str) -> bool {
853 arg.as_bytes().get(0) == Some(&b'-') && arg.len() > 1
854}
855
856fn find_opt(opts: &[Opt], nm: &Name) -> Option<usize> {
857 let pos = opts.iter().position(|opt| &opt.name == nm);
859 if pos.is_some() {
860 return pos
861 }
862
863 for candidate in opts.iter() {
865 if candidate.aliases.iter().position(|opt| &opt.name == nm).is_some() {
866 return opts.iter().position(|opt| opt.name == candidate.name);
867 }
868 }
869
870 None
871}
872
873impl fmt::Display for Fail {
874 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
875 match *self {
876 ArgumentMissing(ref nm) => {
877 write!(f, "Argument to option '{}' missing", *nm)
878 }
879 UnrecognizedOption(ref nm) => {
880 write!(f, "Unrecognized option: '{}'", *nm)
881 }
882 OptionMissing(ref nm) => {
883 write!(f, "Required option '{}' missing", *nm)
884 }
885 OptionDuplicated(ref nm) => {
886 write!(f, "Option '{}' given more than once", *nm)
887 }
888 UnexpectedArgument(ref nm) => {
889 write!(f, "Option '{}' does not take an argument", *nm)
890 }
891 }
892 }
893}
894
895fn format_option(opt: &OptGroup) -> String {
896 let mut line = String::new();
897
898 if opt.occur != Req {
899 line.push('[');
900 }
901
902 if opt.short_name.len() > 0 {
904 line.push('-');
905 line.push_str(&opt.short_name);
906 } else {
907 line.push_str("--");
908 line.push_str(&opt.long_name);
909 }
910
911 if opt.hasarg != No {
912 line.push(' ');
913 if opt.hasarg == Maybe {
914 line.push('[');
915 }
916 line.push_str(&opt.hint);
917 if opt.hasarg == Maybe {
918 line.push(']');
919 }
920 }
921
922 if opt.occur != Req {
923 line.push(']');
924 }
925 if opt.occur == Multi {
926 line.push_str("..");
927 }
928
929 line
930}
931
932fn each_split_within(desc: &str, lim: usize) -> Vec<String> {
937 let mut rows = Vec::new();
938 for line in desc.trim().lines() {
939 let line_chars = line.chars().chain(Some(' '));
940 let words = line_chars.fold( (Vec::new(), 0, 0), |(mut words, a, z), c | {
941 let idx = z + c.len_utf8(); if c.is_whitespace() {
945 if a != z {
946 words.push(&line[a..z]);
947 }
948 (words, idx, idx)
949 }
950 else {
952 (words, a, idx)
953 }
954 }).0;
955
956 let mut row = String::new();
957 for word in words.iter() {
958 let sep = if row.len() > 0 { Some(" ") } else { None };
959 let width = row.width()
960 + word.width()
961 + sep.map(UnicodeWidthStr::width).unwrap_or(0);
962
963 if width <= lim {
964 if let Some(sep) = sep { row.push_str(sep) }
965 row.push_str(word);
966 continue
967 }
968 if row.len() > 0 {
969 rows.push(row.clone());
970 row.clear();
971 }
972 row.push_str(word);
973 }
974 if row.len() > 0 {
975 rows.push(row);
976 }
977 }
978 rows
979}
980
981#[test]
982fn test_split_within() {
983 fn t(s: &str, i: usize, u: &[String]) {
984 let v = each_split_within(&(s.to_string()), i);
985 assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b));
986 }
987 t("", 0, &[]);
988 t("", 15, &[]);
989 t("hello", 15, &["hello".to_string()]);
990 t("\nMary had a little lamb\nLittle lamb\n", 15, &[
991 "Mary had a".to_string(),
992 "little lamb".to_string(),
993 "Little lamb".to_string()
994 ]);
995 t("\nMary had a little lamb\nLittle lamb\n", ::std::usize::MAX,
996 &["Mary had a little lamb".to_string(),
997 "Little lamb".to_string()
998 ]);
999}
1000
1001#[cfg(test)]
1002mod tests {
1003 use super::{HasArg, Name, Occur, Opt, Options, ParsingStyle};
1004 use super::Fail::*;
1005
1006 #[test]
1008 fn test_reqopt() {
1009 let long_args = vec!("--test=20".to_string());
1010 let mut opts = Options::new();
1011 opts.reqopt("t", "test", "testing", "TEST");
1012 match opts.parse(&long_args) {
1013 Ok(ref m) => {
1014 assert!(m.opt_present("test"));
1015 assert_eq!(m.opt_str("test").unwrap(), "20");
1016 assert!(m.opt_present("t"));
1017 assert_eq!(m.opt_str("t").unwrap(), "20");
1018 }
1019 _ => { panic!("test_reqopt failed (long arg)"); }
1020 }
1021 let short_args = vec!("-t".to_string(), "20".to_string());
1022 match opts.parse(&short_args) {
1023 Ok(ref m) => {
1024 assert!((m.opt_present("test")));
1025 assert_eq!(m.opt_str("test").unwrap(), "20");
1026 assert!((m.opt_present("t")));
1027 assert_eq!(m.opt_str("t").unwrap(), "20");
1028 }
1029 _ => { panic!("test_reqopt failed (short arg)"); }
1030 }
1031 }
1032
1033 #[test]
1034 fn test_reqopt_missing() {
1035 let args = vec!("blah".to_string());
1036 match Options::new()
1037 .reqopt("t", "test", "testing", "TEST")
1038 .parse(&args) {
1039 Err(OptionMissing(_)) => {},
1040 _ => panic!()
1041 }
1042 }
1043
1044 #[test]
1045 fn test_reqopt_no_arg() {
1046 let long_args = vec!("--test".to_string());
1047 let mut opts = Options::new();
1048 opts.reqopt("t", "test", "testing", "TEST");
1049 match opts.parse(&long_args) {
1050 Err(ArgumentMissing(_)) => {},
1051 _ => panic!()
1052 }
1053 let short_args = vec!("-t".to_string());
1054 match opts.parse(&short_args) {
1055 Err(ArgumentMissing(_)) => {},
1056 _ => panic!()
1057 }
1058 }
1059
1060 #[test]
1061 fn test_reqopt_multi() {
1062 let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string());
1063 match Options::new()
1064 .reqopt("t", "test", "testing", "TEST")
1065 .parse(&args) {
1066 Err(OptionDuplicated(_)) => {},
1067 _ => panic!()
1068 }
1069 }
1070
1071 #[test]
1073 fn test_optopt() {
1074 let long_args = vec!("--test=20".to_string());
1075 let mut opts = Options::new();
1076 opts.optopt("t", "test", "testing", "TEST");
1077 match opts.parse(&long_args) {
1078 Ok(ref m) => {
1079 assert!(m.opt_present("test"));
1080 assert_eq!(m.opt_str("test").unwrap(), "20");
1081 assert!((m.opt_present("t")));
1082 assert_eq!(m.opt_str("t").unwrap(), "20");
1083 }
1084 _ => panic!()
1085 }
1086 let short_args = vec!("-t".to_string(), "20".to_string());
1087 match opts.parse(&short_args) {
1088 Ok(ref m) => {
1089 assert!((m.opt_present("test")));
1090 assert_eq!(m.opt_str("test").unwrap(), "20");
1091 assert!((m.opt_present("t")));
1092 assert_eq!(m.opt_str("t").unwrap(), "20");
1093 }
1094 _ => panic!()
1095 }
1096 }
1097
1098 #[test]
1099 fn test_optopt_missing() {
1100 let args = vec!("blah".to_string());
1101 match Options::new()
1102 .optopt("t", "test", "testing", "TEST")
1103 .parse(&args) {
1104 Ok(ref m) => {
1105 assert!(!m.opt_present("test"));
1106 assert!(!m.opt_present("t"));
1107 }
1108 _ => panic!()
1109 }
1110 }
1111
1112 #[test]
1113 fn test_optopt_no_arg() {
1114 let long_args = vec!("--test".to_string());
1115 let mut opts = Options::new();
1116 opts.optopt("t", "test", "testing", "TEST");
1117 match opts.parse(&long_args) {
1118 Err(ArgumentMissing(_)) => {},
1119 _ => panic!()
1120 }
1121 let short_args = vec!("-t".to_string());
1122 match opts.parse(&short_args) {
1123 Err(ArgumentMissing(_)) => {},
1124 _ => panic!()
1125 }
1126 }
1127
1128 #[test]
1129 fn test_optopt_multi() {
1130 let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string());
1131 match Options::new()
1132 .optopt("t", "test", "testing", "TEST")
1133 .parse(&args) {
1134 Err(OptionDuplicated(_)) => {},
1135 _ => panic!()
1136 }
1137 }
1138
1139 #[test]
1141 fn test_optflag() {
1142 let long_args = vec!("--test".to_string());
1143 let mut opts = Options::new();
1144 opts.optflag("t", "test", "testing");
1145 match opts.parse(&long_args) {
1146 Ok(ref m) => {
1147 assert!(m.opt_present("test"));
1148 assert!(m.opt_present("t"));
1149 }
1150 _ => panic!()
1151 }
1152 let short_args = vec!("-t".to_string());
1153 match opts.parse(&short_args) {
1154 Ok(ref m) => {
1155 assert!(m.opt_present("test"));
1156 assert!(m.opt_present("t"));
1157 }
1158 _ => panic!()
1159 }
1160 }
1161
1162 #[test]
1163 fn test_optflag_missing() {
1164 let args = vec!("blah".to_string());
1165 match Options::new()
1166 .optflag("t", "test", "testing")
1167 .parse(&args) {
1168 Ok(ref m) => {
1169 assert!(!m.opt_present("test"));
1170 assert!(!m.opt_present("t"));
1171 }
1172 _ => panic!()
1173 }
1174 }
1175
1176 #[test]
1177 fn test_opt_end() {
1178 let args = vec!["--".to_owned(), "-t".to_owned()];
1179 match Options::new()
1180 .optflag("t", "test", "testing")
1181 .parse(&args) {
1182 Ok(ref m) => {
1183 assert!(!m.opt_present("test"));
1184 assert!(!m.opt_present("t"));
1185 assert_eq!(m.free.len(), 1);
1186 assert_eq!(m.free[0], "-t");
1187 }
1188 _ => panic!()
1189 }
1190 }
1191
1192 #[test]
1193 fn test_opt_only_end() {
1194 let args = vec!["--".to_owned()];
1195 match Options::new()
1196 .optflag("t", "test", "testing")
1197 .parse(&args) {
1198 Ok(ref m) => {
1199 assert!(!m.opt_present("test"));
1200 assert!(!m.opt_present("t"));
1201 assert_eq!(m.free.len(), 0);
1202 }
1203 _ => panic!()
1204 }
1205 }
1206
1207 #[test]
1208 fn test_optflag_long_arg() {
1209 let args = vec!("--test=20".to_string());
1210 match Options::new()
1211 .optflag("t", "test", "testing")
1212 .parse(&args) {
1213 Err(UnexpectedArgument(_)) => {},
1214 _ => panic!()
1215 }
1216 }
1217
1218 #[test]
1219 fn test_optflag_multi() {
1220 let args = vec!("--test".to_string(), "-t".to_string());
1221 match Options::new()
1222 .optflag("t", "test", "testing")
1223 .parse(&args) {
1224 Err(OptionDuplicated(_)) => {},
1225 _ => panic!()
1226 }
1227 }
1228
1229 #[test]
1230 fn test_optflag_short_arg() {
1231 let args = vec!("-t".to_string(), "20".to_string());
1232 match Options::new()
1233 .optflag("t", "test", "testing")
1234 .parse(&args) {
1235 Ok(ref m) => {
1236 assert!(m.free[0] == "20");
1239 }
1240 _ => panic!()
1241 }
1242 }
1243
1244 #[test]
1246 fn test_optflagmulti_short1() {
1247 let args = vec!("-v".to_string());
1248 match Options::new()
1249 .optflagmulti("v", "verbose", "verbosity")
1250 .parse(&args) {
1251 Ok(ref m) => {
1252 assert_eq!(m.opt_count("v"), 1);
1253 }
1254 _ => panic!()
1255 }
1256 }
1257
1258 #[test]
1259 fn test_optflagmulti_short2a() {
1260 let args = vec!("-v".to_string(), "-v".to_string());
1261 match Options::new()
1262 .optflagmulti("v", "verbose", "verbosity")
1263 .parse(&args) {
1264 Ok(ref m) => {
1265 assert_eq!(m.opt_count("v"), 2);
1266 }
1267 _ => panic!()
1268 }
1269 }
1270
1271 #[test]
1272 fn test_optflagmulti_short2b() {
1273 let args = vec!("-vv".to_string());
1274 match Options::new()
1275 .optflagmulti("v", "verbose", "verbosity")
1276 .parse(&args) {
1277 Ok(ref m) => {
1278 assert_eq!(m.opt_count("v"), 2);
1279 }
1280 _ => panic!()
1281 }
1282 }
1283
1284 #[test]
1285 fn test_optflagmulti_long1() {
1286 let args = vec!("--verbose".to_string());
1287 match Options::new()
1288 .optflagmulti("v", "verbose", "verbosity")
1289 .parse(&args) {
1290 Ok(ref m) => {
1291 assert_eq!(m.opt_count("verbose"), 1);
1292 }
1293 _ => panic!()
1294 }
1295 }
1296
1297 #[test]
1298 fn test_optflagmulti_long2() {
1299 let args = vec!("--verbose".to_string(), "--verbose".to_string());
1300 match Options::new()
1301 .optflagmulti("v", "verbose", "verbosity")
1302 .parse(&args) {
1303 Ok(ref m) => {
1304 assert_eq!(m.opt_count("verbose"), 2);
1305 }
1306 _ => panic!()
1307 }
1308 }
1309
1310 #[test]
1311 fn test_optflagmulti_mix() {
1312 let args = vec!("--verbose".to_string(), "-v".to_string(),
1313 "-vv".to_string(), "verbose".to_string());
1314 match Options::new()
1315 .optflagmulti("v", "verbose", "verbosity")
1316 .parse(&args) {
1317 Ok(ref m) => {
1318 assert_eq!(m.opt_count("verbose"), 4);
1319 assert_eq!(m.opt_count("v"), 4);
1320 }
1321 _ => panic!()
1322 }
1323 }
1324
1325 #[test]
1327 fn test_optflagopt() {
1328 let long_args = vec!("--test".to_string());
1329 let mut opts = Options::new();
1330 opts.optflagopt("t", "test", "testing", "ARG");
1331 match opts.parse(&long_args) {
1332 Ok(ref m) => {
1333 assert!(m.opt_present("test"));
1334 assert!(m.opt_present("t"));
1335 }
1336 _ => panic!()
1337 }
1338 let short_args = vec!("-t".to_string());
1339 match opts.parse(&short_args) {
1340 Ok(ref m) => {
1341 assert!(m.opt_present("test"));
1342 assert!(m.opt_present("t"));
1343 }
1344 _ => panic!()
1345 }
1346 let short_args = vec!("-t".to_string(), "x".to_string());
1347 match opts.parse(&short_args) {
1348 Ok(ref m) => {
1349 assert_eq!(m.opt_str("t").unwrap(), "x");
1350 assert_eq!(m.opt_str("test").unwrap(), "x");
1351 }
1352 _ => panic!()
1353 }
1354 let long_args = vec!("--test=x".to_string());
1355 match opts.parse(&long_args) {
1356 Ok(ref m) => {
1357 assert_eq!(m.opt_str("t").unwrap(), "x");
1358 assert_eq!(m.opt_str("test").unwrap(), "x");
1359 }
1360 _ => panic!()
1361 }
1362 let long_args = vec!("--test".to_string(), "x".to_string());
1363 match opts.parse(&long_args) {
1364 Ok(ref m) => {
1365 assert_eq!(m.opt_str("t"), None);
1366 assert_eq!(m.opt_str("test"), None);
1367 }
1368 _ => panic!()
1369 }
1370 let no_args: Vec<String> = vec!();
1371 match opts.parse(&no_args) {
1372 Ok(ref m) => {
1373 assert!(!m.opt_present("test"));
1374 assert!(!m.opt_present("t"));
1375 }
1376 _ => panic!()
1377 }
1378 }
1379
1380 #[test]
1382 fn test_optmulti() {
1383 let long_args = vec!("--test=20".to_string());
1384 let mut opts = Options::new();
1385 opts.optmulti("t", "test", "testing", "TEST");
1386 match opts.parse(&long_args) {
1387 Ok(ref m) => {
1388 assert!((m.opt_present("test")));
1389 assert_eq!(m.opt_str("test").unwrap(), "20");
1390 assert!((m.opt_present("t")));
1391 assert_eq!(m.opt_str("t").unwrap(), "20");
1392 }
1393 _ => panic!()
1394 }
1395 let short_args = vec!("-t".to_string(), "20".to_string());
1396 match opts.parse(&short_args) {
1397 Ok(ref m) => {
1398 assert!((m.opt_present("test")));
1399 assert_eq!(m.opt_str("test").unwrap(), "20");
1400 assert!((m.opt_present("t")));
1401 assert_eq!(m.opt_str("t").unwrap(), "20");
1402 }
1403 _ => panic!()
1404 }
1405 }
1406
1407 #[test]
1408 fn test_optmulti_missing() {
1409 let args = vec!("blah".to_string());
1410 match Options::new()
1411 .optmulti("t", "test", "testing", "TEST")
1412 .parse(&args) {
1413 Ok(ref m) => {
1414 assert!(!m.opt_present("test"));
1415 assert!(!m.opt_present("t"));
1416 }
1417 _ => panic!()
1418 }
1419 }
1420
1421 #[test]
1422 fn test_optmulti_no_arg() {
1423 let long_args = vec!("--test".to_string());
1424 let mut opts = Options::new();
1425 opts.optmulti("t", "test", "testing", "TEST");
1426 match opts.parse(&long_args) {
1427 Err(ArgumentMissing(_)) => {},
1428 _ => panic!()
1429 }
1430 let short_args = vec!("-t".to_string());
1431 match opts.parse(&short_args) {
1432 Err(ArgumentMissing(_)) => {},
1433 _ => panic!()
1434 }
1435 }
1436
1437 #[test]
1438 fn test_optmulti_multi() {
1439 let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string());
1440 match Options::new()
1441 .optmulti("t", "test", "testing", "TEST")
1442 .parse(&args) {
1443 Ok(ref m) => {
1444 assert!(m.opt_present("test"));
1445 assert_eq!(m.opt_str("test").unwrap(), "20");
1446 assert!(m.opt_present("t"));
1447 assert_eq!(m.opt_str("t").unwrap(), "20");
1448 let pair = m.opt_strs("test");
1449 assert!(pair[0] == "20");
1450 assert!(pair[1] == "30");
1451 }
1452 _ => panic!()
1453 }
1454 }
1455
1456 #[test]
1457 fn test_free_argument_is_hyphen() {
1458 let args = vec!("-".to_string());
1459 match Options::new().parse(&args) {
1460 Ok(ref m) => {
1461 assert_eq!(m.free.len(), 1);
1462 assert_eq!(m.free[0], "-");
1463 }
1464 _ => panic!()
1465 }
1466 }
1467
1468 #[test]
1469 fn test_unrecognized_option() {
1470 let long_args = vec!("--untest".to_string());
1471 let mut opts = Options::new();
1472 opts.optmulti("t", "test", "testing", "TEST");
1473 match opts.parse(&long_args) {
1474 Err(UnrecognizedOption(_)) => {},
1475 _ => panic!()
1476 }
1477 let short_args = vec!("-u".to_string());
1478 match opts.parse(&short_args) {
1479 Err(UnrecognizedOption(_)) => {},
1480 _ => panic!()
1481 }
1482 }
1483
1484 #[test]
1485 fn test_combined() {
1486 let args =
1487 vec!("prog".to_string(),
1488 "free1".to_string(),
1489 "-s".to_string(),
1490 "20".to_string(),
1491 "free2".to_string(),
1492 "--flag".to_string(),
1493 "--long=30".to_string(),
1494 "-f".to_string(),
1495 "-m".to_string(),
1496 "40".to_string(),
1497 "-m".to_string(),
1498 "50".to_string(),
1499 "-n".to_string(),
1500 "-A B".to_string(),
1501 "-n".to_string(),
1502 "-60 70".to_string());
1503 match Options::new()
1504 .optopt("s", "something", "something", "SOMETHING")
1505 .optflag("", "flag", "a flag")
1506 .reqopt("", "long", "hi", "LONG")
1507 .optflag("f", "", "another flag")
1508 .optmulti("m", "", "mmmmmm", "YUM")
1509 .optmulti("n", "", "nothing", "NOTHING")
1510 .optopt("", "notpresent", "nothing to see here", "NOPE")
1511 .parse(&args) {
1512 Ok(ref m) => {
1513 assert!(m.free[0] == "prog");
1514 assert!(m.free[1] == "free1");
1515 assert_eq!(m.opt_str("s").unwrap(), "20");
1516 assert!(m.free[2] == "free2");
1517 assert!((m.opt_present("flag")));
1518 assert_eq!(m.opt_str("long").unwrap(), "30");
1519 assert!((m.opt_present("f")));
1520 let pair = m.opt_strs("m");
1521 assert!(pair[0] == "40");
1522 assert!(pair[1] == "50");
1523 let pair = m.opt_strs("n");
1524 assert!(pair[0] == "-A B");
1525 assert!(pair[1] == "-60 70");
1526 assert!((!m.opt_present("notpresent")));
1527 }
1528 _ => panic!()
1529 }
1530 }
1531
1532 #[test]
1533 fn test_mixed_stop() {
1534 let args =
1535 vec!("-a".to_string(),
1536 "b".to_string(),
1537 "-c".to_string(),
1538 "d".to_string());
1539 match Options::new()
1540 .parsing_style(ParsingStyle::StopAtFirstFree)
1541 .optflag("a", "", "")
1542 .optopt("c", "", "", "")
1543 .parse(&args) {
1544 Ok(ref m) => {
1545 println!("{}", m.opt_present("c"));
1546 assert!(m.opt_present("a"));
1547 assert!(!m.opt_present("c"));
1548 assert_eq!(m.free.len(), 3);
1549 assert_eq!(m.free[0], "b");
1550 assert_eq!(m.free[1], "-c");
1551 assert_eq!(m.free[2], "d");
1552 }
1553 _ => panic!()
1554 }
1555 }
1556
1557 #[test]
1558 fn test_mixed_stop_hyphen() {
1559 let args =
1560 vec!("-a".to_string(),
1561 "-".to_string(),
1562 "-c".to_string(),
1563 "d".to_string());
1564 match Options::new()
1565 .parsing_style(ParsingStyle::StopAtFirstFree)
1566 .optflag("a", "", "")
1567 .optopt("c", "", "", "")
1568 .parse(&args) {
1569 Ok(ref m) => {
1570 println!("{}", m.opt_present("c"));
1571 assert!(m.opt_present("a"));
1572 assert!(!m.opt_present("c"));
1573 assert_eq!(m.free.len(), 3);
1574 assert_eq!(m.free[0], "-");
1575 assert_eq!(m.free[1], "-c");
1576 assert_eq!(m.free[2], "d");
1577 }
1578 _ => panic!()
1579 }
1580 }
1581
1582 #[test]
1583 fn test_multi() {
1584 let mut opts = Options::new();
1585 opts.optopt("e", "", "encrypt", "ENCRYPT");
1586 opts.optopt("", "encrypt", "encrypt", "ENCRYPT");
1587 opts.optopt("f", "", "flag", "FLAG");
1588
1589 let args_single = vec!("-e".to_string(), "foo".to_string());
1590 let matches_single = &match opts.parse(&args_single) {
1591 Ok(m) => m,
1592 Err(_) => panic!()
1593 };
1594 assert!(matches_single.opts_present(&["e".to_string()]));
1595 assert!(matches_single.opts_present(&["encrypt".to_string(), "e".to_string()]));
1596 assert!(matches_single.opts_present(&["e".to_string(), "encrypt".to_string()]));
1597 assert!(!matches_single.opts_present(&["encrypt".to_string()]));
1598 assert!(!matches_single.opts_present(&["thing".to_string()]));
1599 assert!(!matches_single.opts_present(&[]));
1600
1601 assert_eq!(matches_single.opts_str(&["e".to_string()]).unwrap(), "foo");
1602 assert_eq!(matches_single.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(),
1603 "foo");
1604 assert_eq!(matches_single.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(),
1605 "foo");
1606
1607 let args_both = vec!("-e".to_string(), "foo".to_string(), "--encrypt".to_string(),
1608 "foo".to_string());
1609 let matches_both = &match opts.parse(&args_both) {
1610 Ok(m) => m,
1611 Err(_) => panic!()
1612 };
1613 assert!(matches_both.opts_present(&["e".to_string()]));
1614 assert!(matches_both.opts_present(&["encrypt".to_string()]));
1615 assert!(matches_both.opts_present(&["encrypt".to_string(), "e".to_string()]));
1616 assert!(matches_both.opts_present(&["e".to_string(), "encrypt".to_string()]));
1617 assert!(!matches_both.opts_present(&["f".to_string()]));
1618 assert!(!matches_both.opts_present(&["thing".to_string()]));
1619 assert!(!matches_both.opts_present(&[]));
1620
1621 assert_eq!(matches_both.opts_str(&["e".to_string()]).unwrap(), "foo");
1622 assert_eq!(matches_both.opts_str(&["encrypt".to_string()]).unwrap(), "foo");
1623 assert_eq!(matches_both.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(),
1624 "foo");
1625 assert_eq!(matches_both.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(),
1626 "foo");
1627 }
1628
1629 #[test]
1630 fn test_nospace() {
1631 let args = vec!("-Lfoo".to_string(), "-M.".to_string());
1632 let matches = &match Options::new()
1633 .optmulti("L", "", "library directory", "LIB")
1634 .optmulti("M", "", "something", "MMMM")
1635 .parse(&args) {
1636 Ok(m) => m,
1637 Err(_) => panic!()
1638 };
1639 assert!(matches.opts_present(&["L".to_string()]));
1640 assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "foo");
1641 assert!(matches.opts_present(&["M".to_string()]));
1642 assert_eq!(matches.opts_str(&["M".to_string()]).unwrap(), ".");
1643
1644 }
1645
1646 #[test]
1647 fn test_nospace_conflict() {
1648 let args = vec!("-vvLverbose".to_string(), "-v".to_string() );
1649 let matches = &match Options::new()
1650 .optmulti("L", "", "library directory", "LIB")
1651 .optflagmulti("v", "verbose", "Verbose")
1652 .parse(&args) {
1653 Ok(m) => m,
1654 Err(e) => panic!( "{}", e )
1655 };
1656 assert!(matches.opts_present(&["L".to_string()]));
1657 assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "verbose");
1658 assert!(matches.opts_present(&["v".to_string()]));
1659 assert_eq!(3, matches.opt_count("v"));
1660 }
1661
1662 #[test]
1663 fn test_long_to_short() {
1664 let mut short = Opt {
1665 name: Name::Long("banana".to_string()),
1666 hasarg: HasArg::Yes,
1667 occur: Occur::Req,
1668 aliases: Vec::new(),
1669 };
1670 short.aliases = vec!(Opt { name: Name::Short('b'),
1671 hasarg: HasArg::Yes,
1672 occur: Occur::Req,
1673 aliases: Vec::new() });
1674 let mut opts = Options::new();
1675 opts.reqopt("b", "banana", "some bananas", "VAL");
1676 let ref verbose = opts.grps[0];
1677 assert!(verbose.long_to_short() == short);
1678 }
1679
1680 #[test]
1681 fn test_aliases_long_and_short() {
1682 let args = vec!("-a".to_string(), "--apple".to_string(), "-a".to_string());
1683
1684 let matches = Options::new()
1685 .optflagmulti("a", "apple", "Desc")
1686 .parse(&args)
1687 .unwrap();
1688 assert_eq!(3, matches.opt_count("a"));
1689 assert_eq!(3, matches.opt_count("apple"));
1690 }
1691
1692 #[test]
1693 fn test_usage() {
1694 let mut opts = Options::new();
1695 opts.reqopt("b", "banana", "Desc", "VAL");
1696 opts.optopt("a", "012345678901234567890123456789",
1697 "Desc", "VAL");
1698 opts.optflag("k", "kiwi", "Desc");
1699 opts.optflagopt("p", "", "Desc", "VAL");
1700 opts.optmulti("l", "", "Desc", "VAL");
1701 opts.optflag("", "starfruit", "Starfruit");
1702
1703 let expected =
1704"Usage: fruits
1705
1706Options:
1707 -b, --banana VAL Desc
1708 -a, --012345678901234567890123456789 VAL
1709 Desc
1710 -k, --kiwi Desc
1711 -p [VAL] Desc
1712 -l VAL Desc
1713 --starfruit Starfruit
1714";
1715
1716 let generated_usage = opts.usage("Usage: fruits");
1717
1718 debug!("expected: <<{}>>", expected);
1719 debug!("generated: <<{}>>", generated_usage);
1720 assert_eq!(generated_usage, expected);
1721 }
1722
1723 #[test]
1724 fn test_usage_description_wrapping() {
1725 let mut opts = Options::new();
1729 opts.optflag("k", "kiwi",
1730 "This is a long description which won't be wrapped..+.."); opts.optflag("a", "apple",
1732 "This is a long description which _will_ be wrapped..+..");
1733 opts.optflag("b", "banana",
1734 "HereWeNeedOneSingleWordThatIsLongerThanTheWrappingLengthAndThisIsIt");
1735
1736 let expected =
1737"Usage: fruits
1738
1739Options:
1740 -k, --kiwi This is a long description which won't be wrapped..+..
1741 -a, --apple This is a long description which _will_ be
1742 wrapped..+..
1743 -b, --banana HereWeNeedOneSingleWordThatIsLongerThanTheWrappingLengthAndThisIsIt
1744";
1745
1746 let usage = opts.usage("Usage: fruits");
1747
1748 debug!("expected: <<{}>>", expected);
1749 debug!("generated: <<{}>>", usage);
1750 assert!(usage == expected)
1751 }
1752
1753 #[test]
1754 fn test_usage_description_multibyte_handling() {
1755 let mut opts = Options::new();
1756 opts.optflag("k", "k\u{2013}w\u{2013}",
1757 "The word kiwi is normally spelled with two i's");
1758 opts.optflag("a", "apple",
1759 "This \u{201C}description\u{201D} has some characters that could \
1760confuse the line wrapping; an apple costs 0.51€ in some parts of Europe.");
1761
1762 let expected =
1763"Usage: fruits
1764
1765Options:
1766 -k, --k–w– The word kiwi is normally spelled with two i's
1767 -a, --apple This “description” has some characters that could
1768 confuse the line wrapping; an apple costs 0.51€ in
1769 some parts of Europe.
1770";
1771
1772 let usage = opts.usage("Usage: fruits");
1773
1774 debug!("expected: <<{}>>", expected);
1775 debug!("generated: <<{}>>", usage);
1776 assert!(usage == expected)
1777 }
1778
1779 #[test]
1780 fn test_usage_description_newline_handling() {
1781 let mut opts = Options::new();
1782 opts.optflag("k", "k\u{2013}w\u{2013}",
1783 "The word kiwi is normally spelled with two i's");
1784 opts.optflag("a", "apple",
1785 "This description forces a new line.\n Here is a premature\n\
1786 newline");
1787
1788 let expected =
1789"Usage: fruits
1790
1791Options:
1792 -k, --k–w– The word kiwi is normally spelled with two i's
1793 -a, --apple This description forces a new line.
1794 Here is a premature
1795 newline
1796";
1797
1798 let usage = opts.usage("Usage: fruits");
1799
1800 debug!("expected: <<{}>>", expected);
1801 debug!("generated: <<{}>>", usage);
1802 assert!(usage == expected)
1803 }
1804
1805 #[test]
1806 fn test_usage_multiwidth() {
1807 let mut opts = Options::new();
1808 opts.optflag("a", "apple", "apple description");
1809 opts.optflag("b", "banana\u{00AB}", "banana description");
1810 opts.optflag("c", "brûlée", "brûlée quite long description");
1811 opts.optflag("k", "kiwi\u{20AC}", "kiwi description");
1812 opts.optflag("o", "orange\u{2039}", "orange description");
1813 opts.optflag("r", "raspberry-but-making-this-option-way-too-long",
1814 "raspberry description is also quite long indeed longer than \
1815 every other piece of text we might encounter here and thus will \
1816 be automatically broken up"
1817 );
1818
1819 let expected =
1820"Usage: fruits
1821
1822Options:
1823 -a, --apple apple description
1824 -b, --banana« banana description
1825 -c, --brûlée brûlée quite long description
1826 -k, --kiwi€ kiwi description
1827 -o, --orange‹ orange description
1828 -r, --raspberry-but-making-this-option-way-too-long
1829 raspberry description is also quite long indeed longer
1830 than every other piece of text we might encounter here
1831 and thus will be automatically broken up
1832";
1833
1834 let usage = opts.usage("Usage: fruits");
1835
1836 debug!("expected: <<{}>>", expected);
1837 debug!("generated: <<{}>>", usage);
1838 assert!(usage == expected)
1839 }
1840
1841
1842 #[test]
1843 fn test_usage_short_only() {
1844 let mut opts = Options::new();
1845 opts.optopt("k", "", "Kiwi", "VAL");
1846 opts.optflag("s", "", "Starfruit");
1847 opts.optflagopt("a", "", "Apple", "TYPE");
1848
1849 let expected =
1850"Usage: fruits
1851
1852Options:
1853 -k VAL Kiwi
1854 -s Starfruit
1855 -a [TYPE] Apple
1856";
1857
1858 let usage = opts.usage("Usage: fruits");
1859 debug!("expected: <<{}>>", expected);
1860 debug!("generated: <<{}>>", usage);
1861 assert!(usage == expected)
1862 }
1863
1864 #[test]
1865 fn test_usage_long_only() {
1866 let mut opts = Options::new();
1867 opts.optopt("", "kiwi", "Kiwi", "VAL");
1868 opts.optflag("", "starfruit", "Starfruit");
1869 opts.optflagopt("", "apple", "Apple", "TYPE");
1870
1871 let expected =
1872"Usage: fruits
1873
1874Options:
1875 --kiwi VAL Kiwi
1876 --starfruit Starfruit
1877 --apple [TYPE] Apple
1878";
1879
1880 let usage = opts.usage("Usage: fruits");
1881 debug!("expected: <<{}>>", expected);
1882 debug!("generated: <<{}>>", usage);
1883 assert!(usage == expected)
1884 }
1885
1886 #[test]
1887 fn test_short_usage() {
1888 let mut opts = Options::new();
1889 opts.reqopt("b", "banana", "Desc", "VAL");
1890 opts.optopt("a", "012345678901234567890123456789",
1891 "Desc", "VAL");
1892 opts.optflag("k", "kiwi", "Desc");
1893 opts.optflagopt("p", "", "Desc", "VAL");
1894 opts.optmulti("l", "", "Desc", "VAL");
1895
1896 let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string();
1897 let generated_usage = opts.short_usage("fruits");
1898
1899 debug!("expected: <<{}>>", expected);
1900 debug!("generated: <<{}>>", generated_usage);
1901 assert_eq!(generated_usage, expected);
1902 }
1903 #[test]
1904 fn test_nonexistant_opt() {
1905 let mut opts = Options::new();
1906 opts.optflag("b", "bar", "Desc");
1907 let args: Vec<String> = Vec::new();
1908 let matches = opts.parse(&args).unwrap();
1909 assert_eq!(matches.opt_defined("foo"), false);
1910 assert_eq!(matches.opt_defined("bar"), true);
1911 }
1912 #[test]
1913 fn test_args_with_equals() {
1914 let mut opts = Options::new();
1915 opts.optopt("o", "one", "One", "INFO");
1916 opts.optopt("t", "two", "Two", "INFO");
1917
1918 let args = vec!("--one".to_string(), "A=B".to_string(),
1919 "--two=C=D".to_string());
1920 let matches = &match opts.parse(&args) {
1921 Ok(m) => m,
1922 Err(e) => panic!("{}", e)
1923 };
1924 assert_eq!(matches.opts_str(&["o".to_string()]).unwrap(), "A=B");
1925 assert_eq!(matches.opts_str(&["t".to_string()]).unwrap(), "C=D");
1926 }
1927
1928 #[test]
1929 fn test_long_only_usage() {
1930 let mut opts = Options::new();
1931 opts.long_only(true);
1932 opts.optflag("k", "kiwi", "Description");
1933 opts.optflag("a", "apple", "Description");
1934
1935 let expected =
1936"Usage: fruits
1937
1938Options:
1939 -k, -kiwi Description
1940 -a, -apple Description
1941";
1942
1943 let usage = opts.usage("Usage: fruits");
1944
1945 debug!("expected: <<{}>>", expected);
1946 debug!("generated: <<{}>>", usage);
1947 assert!(usage == expected)
1948 }
1949
1950 #[test]
1951 fn test_long_only_mode() {
1952 let mut opts = Options::new();
1953 opts.long_only(true);
1954 opts.optopt("a", "apple", "Description", "X");
1955 opts.optopt("b", "banana", "Description", "X");
1956 opts.optopt("c", "currant", "Description", "X");
1957 opts.optopt("", "durian", "Description", "X");
1958 opts.optopt("e", "", "Description", "X");
1959 opts.optopt("", "fruit", "Description", "X");
1960
1961 let args = vec!("-a", "A", "-b=B", "--c=C", "-durian", "D", "--e", "E",
1962 "-fruit=any");
1963 let matches = &match opts.parse(&args) {
1964 Ok(m) => m,
1965 Err(e) => panic!("{}", e)
1966 };
1967 assert_eq!(matches.opts_str(&["a".to_string()]).unwrap(), "A");
1968 assert_eq!(matches.opts_str(&["b".to_string()]).unwrap(), "B");
1969 assert_eq!(matches.opts_str(&["c".to_string()]).unwrap(), "C");
1970 assert_eq!(matches.opts_str(&["durian".to_string()]).unwrap(), "D");
1971 assert_eq!(matches.opts_str(&["e".to_string()]).unwrap(), "E");
1972 assert_eq!(matches.opts_str(&["fruit".to_string()]).unwrap(), "any");
1973 }
1974
1975 #[test]
1976 fn test_long_only_mode_no_short_parse() {
1977 let mut opts = Options::new();
1978 opts.long_only(true);
1979 opts.optflag("h", "help", "Description");
1980 opts.optflag("i", "ignore", "Description");
1981 opts.optflag("", "hi", "Description");
1982
1983 let args = vec!("-hi");
1984 let matches = &match opts.parse(&args) {
1985 Ok(m) => m,
1986 Err(e) => panic!("{}", e)
1987 };
1988 assert!(matches.opt_present("hi"));
1989 assert!(!matches.opt_present("h"));
1990 assert!(!matches.opt_present("i"));
1991 }
1992
1993 #[test]
1994 fn test_normal_mode_no_long_parse() {
1995 let mut opts = Options::new();
1999 opts.long_only(true);
2000 opts.optflag("h", "help", "Description");
2001 opts.optflag("i", "ignore", "Description");
2002 opts.optflag("", "hi", "Description");
2003 opts.long_only(false);
2004
2005 let args = vec!("-hi");
2006 let matches = &match opts.parse(&args) {
2007 Ok(m) => m,
2008 Err(e) => panic!("{}", e)
2009 };
2010 assert!(!matches.opt_present("hi"));
2011 assert!(matches.opt_present("h"));
2012 assert!(matches.opt_present("i"));
2013 }
2014
2015 #[test]
2016 #[should_panic]
2017 fn test_long_name_too_short() {
2018 let mut opts = Options::new();
2019 opts.optflag("", "a", "Oops, long option too short");
2020 }
2021
2022 #[test]
2023 #[should_panic]
2024 fn test_undefined_opt_present() {
2025 let mut opts = Options::new();
2026 opts.optflag("h", "help", "Description");
2027 let args = vec!["-h"];
2028 match opts.parse(args) {
2029 Ok(matches) => assert!(!matches.opt_present("undefined")),
2030 Err(e) => panic!("{}", e)
2031 }
2032 }
2033
2034 #[test]
2035 fn test_opt_default() {
2036 let mut opts = Options::new();
2037 opts.optflag("h", "help", "Description");
2038 opts.optflag("i", "ignore", "Description");
2039 opts.optflag("r", "run", "Description");
2040 opts.long_only(false);
2041
2042 let args: Vec<String> = ["-i", "-r", "10"]
2043 .iter().map(|x| x.to_string()).collect();
2044 let matches = &match opts.parse(&args) {
2045 Ok(m) => m,
2046 Err(e) => panic!("{}", e)
2047 };
2048 assert_eq!(matches.opt_default("help", ""), None);
2049 assert_eq!(matches.opt_default("i", "def"), Some("def".to_string()));
2050 }
2051
2052 #[test]
2053 fn test_opt_get() {
2054 let mut opts = Options::new();
2055 opts.optflag("h", "help", "Description");
2056 opts.optflagopt("i", "ignore", "Description", "true | false");
2057 opts.optflagopt("r", "run", "Description", "0 .. 10");
2058 opts.optflagopt("p", "percent", "Description", "0.0 .. 10.0");
2059 opts.long_only(false);
2060
2061 let args: Vec<String> = [
2062 "-i", "true", "-p", "1.1"
2063 ].iter().map(|x| x.to_string()).collect();
2064 let matches = &match opts.parse(&args) {
2065 Ok(m) => m,
2066 Err(e) => panic!("{}", e)
2067 };
2068 let h_arg = matches.opt_get::<i32>("help");
2069 assert_eq!(h_arg, Ok(None));
2070 let i_arg = matches.opt_get("i");
2071 assert_eq!(i_arg, Ok(Some(true)));
2072 let p_arg = matches.opt_get("p");
2073 assert_eq!(p_arg, Ok(Some(1.1)));
2074 }
2075
2076 #[test]
2077 fn test_opt_get_default() {
2078 let mut opts = Options::new();
2079 opts.optflag("h", "help", "Description");
2080 opts.optflagopt("i", "ignore", "Description", "true | false");
2081 opts.optflagopt("r", "run", "Description", "0 .. 10");
2082 opts.optflagopt("p", "percent", "Description", "0.0 .. 10.0");
2083 opts.long_only(false);
2084
2085 let args: Vec<String> = [
2086 "-i", "true", "-p", "1.1"
2087 ].iter().map(|x| x.to_string()).collect();
2088 let matches = &match opts.parse(&args) {
2089 Ok(m) => m,
2090 Err(e) => panic!("{}", e)
2091 };
2092 let h_arg =matches.opt_get_default("help", 10);
2093 assert_eq!(h_arg, Ok(10));
2094 let i_arg = matches.opt_get_default("i", false);
2095 assert_eq!(i_arg, Ok(true));
2096 let p_arg = matches.opt_get_default("p", 10.2);
2097 assert_eq!(p_arg, Ok(1.1));
2098 }
2099}