1 use std::str::FromStr;
2 
3 use assert_matches::assert_matches;
4 
5 use gumdrop::Options;
6 
7 const EMPTY: &'static [&'static str] = &[];
8 
9 #[derive(Debug, Options)]
10 struct NoOpts { }
11 
12 macro_rules! is_err {
13     ( $e:expr , |$ident:ident| $expr:expr ) => {
14         let $ident = $e.map(|_| ()).unwrap_err().to_string();
15         assert!($expr,
16             "error {:?} does not match `{}`", $ident, stringify!($expr));
17     };
18     ( $e:expr , $str:expr ) => {
19         assert_eq!($e.map(|_| ()).unwrap_err().to_string(), $str)
20     };
21 }
22 
23 #[test]
test_hygiene()24 fn test_hygiene() {
25     // Define these aliases in local scope to ensure that generated code
26     // is using absolute paths, i.e. `::std::result::Result`
27     #[allow(dead_code)] struct AsRef;
28     #[allow(dead_code)] struct Default;
29     #[allow(dead_code)] struct FromStr;
30     #[allow(dead_code)] struct Option;
31     #[allow(dead_code)] struct Some;
32     #[allow(dead_code)] struct None;
33     #[allow(dead_code)] struct Options;
34     #[allow(dead_code)] struct Result;
35     #[allow(dead_code)] struct Ok;
36     #[allow(dead_code)] struct Err;
37     #[allow(dead_code)] struct String;
38     #[allow(dead_code)] struct ToString;
39     #[allow(dead_code)] struct Vec;
40 
41     #[derive(Options)]
42     struct Opts {
43         a: i32,
44         b: ::std::string::String,
45         c: ::std::option::Option<::std::string::String>,
46         d: ::std::option::Option<i32>,
47         e: ::std::vec::Vec<i32>,
48         f: ::std::vec::Vec<::std::string::String>,
49         g: ::std::option::Option<(i32, i32)>,
50 
51         #[options(command)]
52         cmd: ::std::option::Option<Cmd>,
53     }
54 
55     #[derive(Options)]
56     enum Cmd {
57         Foo(FooOpts),
58         Bar(BarOpts),
59     }
60 
61     #[derive(Options)]
62     struct FooOpts {
63         #[options(free)]
64         free: ::std::vec::Vec<::std::string::String>,
65         a: i32,
66     }
67 
68     #[derive(Options)]
69     struct BarOpts {
70         #[options(free)]
71         first: ::std::option::Option<::std::string::String>,
72         #[options(free)]
73         rest: ::std::vec::Vec<::std::string::String>,
74         a: i32,
75     }
76 
77     // This is basically just a compile-pass test, so whatever.
78 }
79 
80 #[test]
test_command()81 fn test_command() {
82     #[derive(Options)]
83     struct Opts {
84         help: bool,
85 
86         #[options(command)]
87         command: Option<Command>,
88     }
89 
90     #[derive(Debug, Options)]
91     enum Command {
92         Foo(FooOpts),
93         Bar(BarOpts),
94         #[options(name = "bzzz")]
95         Baz(NoOpts),
96         FooBar(NoOpts),
97         FooXYZ(NoOpts),
98     }
99 
100     #[derive(Debug, Options)]
101     struct FooOpts {
102         foo: Option<String>,
103     }
104 
105     #[derive(Debug, Options)]
106     struct BarOpts {
107         #[options(free)]
108         free: Vec<String>,
109     }
110 
111     let opts = Opts::parse_args_default(EMPTY).unwrap();
112     assert_eq!(opts.command.is_none(), true);
113 
114     let opts = Opts::parse_args_default(&["-h"]).unwrap();
115     assert_eq!(opts.help, true);
116     assert_eq!(opts.command.is_none(), true);
117 
118     let opts = Opts::parse_args_default(&["-h", "foo", "--foo", "x"]).unwrap();
119     assert_eq!(opts.help, true);
120     let cmd = opts.command.unwrap();
121     assert_matches!(cmd, Command::Foo(FooOpts{foo: Some(ref foo)}) if foo == "x");
122 
123     let opts = Opts::parse_args_default(&["--", "foo"]).unwrap();
124     assert_eq!(opts.help, false);
125     let cmd = opts.command.unwrap();
126     assert_matches!(cmd, Command::Foo(_));
127 
128     let opts = Opts::parse_args_default(&["bar", "free"]).unwrap();
129     let cmd = opts.command.unwrap();
130     assert_matches!(cmd, Command::Bar(ref bar) if bar.free == ["free"]);
131 
132     let opts = Opts::parse_args_default(&["bzzz"]).unwrap();
133     let cmd = opts.command.unwrap();
134     assert_matches!(cmd, Command::Baz(_));
135 
136     let opts = Opts::parse_args_default(&["foo-bar"]).unwrap();
137     let cmd = opts.command.unwrap();
138     assert_matches!(cmd, Command::FooBar(_));
139 
140     let opts = Opts::parse_args_default(&["foo-x-y-z"]).unwrap();
141     let cmd = opts.command.unwrap();
142     assert_matches!(cmd, Command::FooXYZ(_));
143 
144     is_err!(Opts::parse_args_default(&["foo", "-h"]),
145         "unrecognized option `-h`");
146     is_err!(Opts::parse_args_default(&["baz"]),
147         "unrecognized command `baz`");
148 }
149 
150 #[test]
test_command_name()151 fn test_command_name() {
152     #[derive(Options)]
153     struct Opts {
154         help: bool,
155 
156         #[options(command)]
157         command: Option<Command>,
158     }
159 
160     #[derive(Debug, Options)]
161     enum Command {
162         Foo(NoOpts),
163         Bar(NoOpts),
164         #[options(name = "bzzz")]
165         Baz(NoOpts),
166         BoopyDoop(NoOpts),
167     }
168 
169 
170     let opts = Opts::parse_args_default(&["foo"]).unwrap();
171     assert_matches!(opts.command_name(), Some("foo"));
172 
173     let opts = Opts::parse_args_default(&["bar"]).unwrap();
174     assert_matches!(opts.command_name(), Some("bar"));
175 
176     let opts = Opts::parse_args_default(&["bzzz"]).unwrap();
177     assert_matches!(opts.command_name(), Some("bzzz"));
178 
179     let opts = Opts::parse_args_default(&["boopy-doop"]).unwrap();
180     assert_matches!(opts.command_name(), Some("boopy-doop"));
181 }
182 
183 #[test]
test_command_usage()184 fn test_command_usage() {
185     #[derive(Options)]
186     struct Opts {
187         #[options(help = "help me!")]
188         help: bool,
189 
190         #[options(command)]
191         command: Option<Command>,
192     }
193 
194     #[derive(Options)]
195     enum Command {
196         #[options(help = "foo help")]
197         Foo(NoOpts),
198         #[options(help = "bar help")]
199         Bar(NoOpts),
200         #[options(help = "baz help")]
201         #[options(name = "bzzz")]
202         Baz(NoOpts),
203     }
204 
205     assert_eq!(Command::usage(), &"
206   foo   foo help
207   bar   bar help
208   bzzz  baz help"
209         // Skip leading newline
210         [1..]);
211 
212     assert_eq!(Command::command_list(), Some(Command::usage()));
213     assert_eq!(Opts::command_list(), Some(Command::usage()));
214 }
215 
216 #[test]
test_opt_bool()217 fn test_opt_bool() {
218     #[derive(Options)]
219     struct Opts {
220         switch: bool,
221     }
222 
223     let opts = Opts::parse_args_default(&["--switch"]).unwrap();
224     assert_eq!(opts.switch, true);
225 
226     let opts = Opts::parse_args_default(&["-s"]).unwrap();
227     assert_eq!(opts.switch, true);
228 
229     is_err!(Opts::parse_args_default(&["--switch=x"]),
230         "option `--switch` does not accept an argument");
231 }
232 
233 #[test]
test_opt_string()234 fn test_opt_string() {
235     #[derive(Options)]
236     struct Opts {
237         foo: String,
238     }
239 
240     let opts = Opts::parse_args_default(&["--foo", "value"]).unwrap();
241     assert_eq!(opts.foo, "value");
242 
243     let opts = Opts::parse_args_default(&["-f", "value"]).unwrap();
244     assert_eq!(opts.foo, "value");
245 
246     let opts = Opts::parse_args_default(&["-fvalue"]).unwrap();
247     assert_eq!(opts.foo, "value");
248 }
249 
250 #[test]
test_opt_int()251 fn test_opt_int() {
252     #[derive(Options)]
253     struct Opts {
254         number: i32,
255     }
256 
257     let opts = Opts::parse_args_default(&["--number", "123"]).unwrap();
258     assert_eq!(opts.number, 123);
259 
260     let opts = Opts::parse_args_default(&["-n", "123"]).unwrap();
261     assert_eq!(opts.number, 123);
262 
263     let opts = Opts::parse_args_default(&["-n123"]).unwrap();
264     assert_eq!(opts.number, 123);
265 
266     is_err!(Opts::parse_args_default(&["-nfail"]),
267         |e| e.starts_with("invalid argument to option `-n`: "));
268     is_err!(Opts::parse_args_default(&["--number", "fail"]),
269         |e| e.starts_with("invalid argument to option `--number`: "));
270     is_err!(Opts::parse_args_default(&["--number=fail"]),
271         |e| e.starts_with("invalid argument to option `--number`: "));
272 }
273 
274 #[test]
test_opt_tuple()275 fn test_opt_tuple() {
276     #[derive(Options)]
277     struct Opts {
278         alpha: (i32, i32),
279         bravo: Option<(i32, i32, i32)>,
280         charlie: Vec<(i32, i32, i32, i32)>,
281         #[options(free)]
282         free: Vec<String>,
283     }
284 
285     let opts = Opts::parse_args_default(&[
286         "--alpha", "1", "2",
287         "--bravo", "11", "12", "13",
288         "--charlie", "21", "22", "23", "24",
289         "--charlie", "31", "32", "33", "34",
290         "free",
291     ]).unwrap();
292 
293     assert_eq!(opts.alpha, (1, 2));
294     assert_eq!(opts.bravo, Some((11, 12, 13)));
295     assert_eq!(opts.charlie, vec![
296         (21, 22, 23, 24),
297         (31, 32, 33, 34),
298     ]);
299     assert_eq!(opts.free, vec!["free".to_owned()]);
300 }
301 
302 #[test]
test_opt_tuple_error()303 fn test_opt_tuple_error() {
304     #[derive(Options)]
305     struct Opts {
306         foo: Option<(i32, i32)>,
307     }
308 
309     is_err!(Opts::parse_args_default(&["--foo"]),
310         "insufficient arguments to option `--foo`: expected 2; found 0");
311     is_err!(Opts::parse_args_default(&["--foo=0", "1"]),
312         "option `--foo` expects 2 arguments; found 1");
313     is_err!(Opts::parse_args_default(&["--foo", "0"]),
314         "insufficient arguments to option `--foo`: expected 2; found 1");
315 }
316 
317 #[test]
test_opt_push()318 fn test_opt_push() {
319     #[derive(Options)]
320     struct Opts {
321         thing: Vec<String>,
322     }
323 
324     let opts = Opts::parse_args_default(EMPTY).unwrap();
325     assert!(opts.thing.is_empty());
326 
327     let opts = Opts::parse_args_default(
328         &["-t", "a", "-tb", "--thing=c", "--thing", "d"]).unwrap();
329     assert_eq!(opts.thing, ["a", "b", "c", "d"]);
330 }
331 
332 #[test]
test_opt_count()333 fn test_opt_count() {
334     #[derive(Options)]
335     struct Opts {
336         #[options(count)]
337         number: i32,
338     }
339 
340     let opts = Opts::parse_args_default(EMPTY).unwrap();
341     assert_eq!(opts.number, 0);
342 
343     let opts = Opts::parse_args_default(&["--number"]).unwrap();
344     assert_eq!(opts.number, 1);
345 
346     let opts = Opts::parse_args_default(&["-nnn"]).unwrap();
347     assert_eq!(opts.number, 3);
348 }
349 
350 #[test]
test_opt_long()351 fn test_opt_long() {
352     #[derive(Options)]
353     struct Opts {
354         #[options(long = "thing", no_short)]
355         foo: bool,
356     }
357 
358     let opts = Opts::parse_args_default(&["--thing"]).unwrap();
359     assert_eq!(opts.foo, true);
360 
361     is_err!(Opts::parse_args_default(&["-f"]),
362         "unrecognized option `-f`");
363     is_err!(Opts::parse_args_default(&["--foo"]),
364         "unrecognized option `--foo`");
365 }
366 
367 #[test]
test_opt_short()368 fn test_opt_short() {
369     #[derive(Options)]
370     struct Opts {
371         #[options(short = "x", no_long)]
372         foo: bool,
373     }
374 
375     let opts = Opts::parse_args_default(&["-x"]).unwrap();
376     assert_eq!(opts.foo, true);
377 
378     is_err!(Opts::parse_args_default(&["-f"]),
379         "unrecognized option `-f`");
380     is_err!(Opts::parse_args_default(&["--foo"]),
381         "unrecognized option `--foo`");
382 }
383 
384 #[test]
test_opt_short_override()385 fn test_opt_short_override() {
386     // Ensures that the generated code sees the manual assignment of short
387     // option for `option_1` before generating a short option for `option_0`.
388     // Thus, giving `option_0` an automatic short option of `O`,
389     // rather than causing a collision.
390     #[derive(Options)]
391     struct Opts {
392         #[options(no_long)]
393         option_0: bool,
394         #[options(short = "o", no_long)]
395         option_1: bool,
396     }
397 
398     let opts = Opts::parse_args_default(&["-o"]).unwrap();
399     assert_eq!(opts.option_0, false);
400     assert_eq!(opts.option_1, true);
401 
402     let opts = Opts::parse_args_default(&["-O"]).unwrap();
403     assert_eq!(opts.option_0, true);
404     assert_eq!(opts.option_1, false);
405 }
406 
407 #[test]
test_opt_free()408 fn test_opt_free() {
409     #[derive(Options)]
410     struct Opts {
411         #[options(free)]
412         free: Vec<String>,
413     }
414 
415     let opts = Opts::parse_args_default(&["a", "b", "c"]).unwrap();
416     assert_eq!(opts.free, ["a", "b", "c"]);
417 }
418 
419 #[test]
test_opt_no_free()420 fn test_opt_no_free() {
421     #[derive(Options)]
422     struct Opts {
423     }
424 
425     assert!(Opts::parse_args_default(EMPTY).is_ok());
426     is_err!(Opts::parse_args_default(&["a"]),
427         "unexpected free argument `a`");
428 }
429 
430 #[test]
test_typed_free()431 fn test_typed_free() {
432     #[derive(Options)]
433     struct Opts {
434         #[options(free)]
435         free: Vec<i32>,
436     }
437 
438     let opts = Opts::parse_args_default(&["1", "2", "3"]).unwrap();
439     assert_eq!(opts.free, [1, 2, 3]);
440 }
441 
442 #[test]
test_multi_free()443 fn test_multi_free() {
444     #[derive(Options)]
445     struct Opts {
446         #[options(free, help = "alpha help")]
447         alpha: u32,
448         #[options(free, help = "bravo help")]
449         bravo: Option<String>,
450         #[options(free, help = "charlie help")]
451         charlie: Option<u32>,
452     }
453 
454     let opts = Opts::parse_args_default(EMPTY).unwrap();
455 
456     assert_eq!(opts.alpha, 0);
457     assert_eq!(opts.bravo, None);
458     assert_eq!(opts.charlie, None);
459 
460     let opts = Opts::parse_args_default(&["1"]).unwrap();
461 
462     assert_eq!(opts.alpha, 1);
463     assert_eq!(opts.bravo, None);
464     assert_eq!(opts.charlie, None);
465 
466     let opts = Opts::parse_args_default(&["1", "two", "3"]).unwrap();
467 
468     assert_eq!(opts.alpha, 1);
469     assert_eq!(opts.bravo, Some("two".to_owned()));
470     assert_eq!(opts.charlie, Some(3));
471 
472     is_err!(Opts::parse_args_default(&["1", "two", "3", "4"]),
473         "unexpected free argument `4`");
474 
475     assert_eq!(Opts::usage(), &"
476 Positional arguments:
477   alpha    alpha help
478   bravo    bravo help
479   charlie  charlie help"
480         // Skip leading newline
481         [1..]);
482 
483     #[derive(Options)]
484     struct ManyOpts {
485         #[options(free, help = "alpha help")]
486         alpha: u32,
487         #[options(free, help = "bravo help")]
488         bravo: Option<String>,
489         #[options(free, help = "charlie help")]
490         charlie: Option<u32>,
491         #[options(free)]
492         rest: Vec<String>,
493     }
494 
495     let opts = ManyOpts::parse_args_default(EMPTY).unwrap();
496 
497     assert_eq!(opts.alpha, 0);
498     assert_eq!(opts.bravo, None);
499     assert_eq!(opts.charlie, None);
500     assert_eq!(opts.rest, Vec::<String>::new());
501 
502     let opts = ManyOpts::parse_args_default(&["1", "two", "3", "4", "five", "VI"]).unwrap();
503 
504     assert_eq!(opts.alpha, 1);
505     assert_eq!(opts.bravo, Some("two".to_owned()));
506     assert_eq!(opts.charlie, Some(3));
507     assert_eq!(opts.rest, vec!["4".to_owned(), "five".to_owned(), "VI".to_owned()]);
508 }
509 
510 #[test]
test_usage()511 fn test_usage() {
512     #[derive(Options)]
513     struct Opts {
514         #[options(help = "alpha help")]
515         alpha: bool,
516         #[options(no_short, help = "bravo help")]
517         bravo: String,
518         #[options(no_long, help = "charlie help")]
519         charlie: bool,
520         #[options(help = "delta help", meta = "X")]
521         delta: i32,
522         #[options(help = "echo help", meta = "Y")]
523         echo: Vec<String>,
524         #[options(help = "foxtrot help", meta = "Z", default = "99")]
525         foxtrot: u32,
526         #[options(no_short, help = "long option help")]
527         very_very_long_option_with_very_very_long_name: bool,
528     }
529 
530     assert_eq!(Opts::usage(), &"
531 Optional arguments:
532   -a, --alpha      alpha help
533   --bravo BRAVO    bravo help
534   -c               charlie help
535   -d, --delta X    delta help
536   -e, --echo Y     echo help
537   -f, --foxtrot Z  foxtrot help (default: 99)
538   --very-very-long-option-with-very-very-long-name
539                    long option help"
540         // Skip leading newline
541         [1..]);
542 
543     #[derive(Options)]
544     struct TupleOpts {
545         #[options(help = "alpha help")]
546         alpha: (),
547         #[options(help = "bravo help")]
548         bravo: (i32,),
549         #[options(help = "charlie help")]
550         charlie: (i32, i32),
551         #[options(help = "delta help")]
552         delta: (i32, i32, i32),
553         #[options(help = "echo help")]
554         echo: (i32, i32, i32, i32),
555     }
556 
557     assert_eq!(TupleOpts::usage(), &"
558 Optional arguments:
559   -a, --alpha        alpha help
560   -b, --bravo BRAVO  bravo help
561   -c, --charlie CHARLIE VALUE
562                      charlie help
563   -d, --delta DELTA VALUE0 VALUE1
564                      delta help
565   -e, --echo ECHO VALUE0 VALUE1 VALUE2
566                      echo help"
567         // Skip leading newline
568         [1..]);
569 
570     #[derive(Options)]
571     struct FreeOpts {
572         #[options(free, help = "a help")]
573         a: u32,
574         #[options(free, help = "b help")]
575         b: u32,
576         #[options(free, help = "c help")]
577         c: u32,
578 
579         #[options(help = "option help")]
580         option: bool,
581     }
582 
583     assert_eq!(FreeOpts::usage(), &"
584 Positional arguments:
585   a             a help
586   b             b help
587   c             c help
588 
589 Optional arguments:
590   -o, --option  option help"
591         // Skip leading newline
592         [1..]);
593 }
594 
595 #[test]
test_help_flag()596 fn test_help_flag() {
597     #[derive(Options)]
598     struct Opts {
599         help: bool,
600     }
601 
602     let opts = Opts::parse_args_default(EMPTY).unwrap();
603     assert_eq!(opts.help_requested(), false);
604 
605     let opts = Opts::parse_args_default(&["--help"]).unwrap();
606     assert_eq!(opts.help_requested(), true);
607 }
608 
609 #[test]
test_no_help_flag()610 fn test_no_help_flag() {
611     #[derive(Options)]
612     struct Opts {
613         #[options(no_help_flag)]
614         help: bool,
615     }
616 
617     let opts = Opts::parse_args_default(&["--help"]).unwrap();
618     assert_eq!(opts.help_requested(), false);
619 }
620 
621 #[test]
test_many_help_flags()622 fn test_many_help_flags() {
623     #[derive(Options)]
624     struct Opts {
625         #[options(help_flag)]
626         help: bool,
627         #[options(help_flag)]
628         halp: bool,
629         #[options(help_flag)]
630         help_please: bool,
631     }
632 
633     let opts = Opts::parse_args_default(EMPTY).unwrap();
634     assert_eq!(opts.help_requested(), false);
635 
636     let opts = Opts::parse_args_default(&["--help"]).unwrap();
637     assert_eq!(opts.help_requested(), true);
638 
639     let opts = Opts::parse_args_default(&["--halp"]).unwrap();
640     assert_eq!(opts.help_requested(), true);
641 
642     let opts = Opts::parse_args_default(&["--help-please"]).unwrap();
643     assert_eq!(opts.help_requested(), true);
644 }
645 
646 #[test]
test_help_flag_command()647 fn test_help_flag_command() {
648     #[derive(Options)]
649     struct Opts {
650         help: bool,
651 
652         #[options(command)]
653         cmd: Option<Cmd>,
654     }
655 
656     #[derive(Options)]
657     struct Opts2 {
658         #[options(command)]
659         cmd: Option<Cmd>,
660     }
661 
662     #[derive(Options)]
663     struct Opts3 {
664         help: bool,
665         #[options(help_flag)]
666         help2: bool,
667 
668         #[options(command)]
669         cmd: Option<Cmd>,
670     }
671 
672     #[derive(Options)]
673     enum Cmd {
674         Foo(CmdOpts),
675         Bar(CmdOpts),
676         Baz(CmdOpts),
677     }
678 
679     #[derive(Options)]
680     struct CmdOpts {
681         help: bool,
682     }
683 
684     let opts = Opts::parse_args_default(EMPTY).unwrap();
685     assert_eq!(opts.help_requested(), false);
686 
687     let opts = Opts::parse_args_default(&["-h"]).unwrap();
688     assert_eq!(opts.help_requested(), true);
689 
690     let opts = Opts::parse_args_default(&["foo", "-h"]).unwrap();
691     assert_eq!(opts.help_requested(), true);
692 
693     let opts = Opts::parse_args_default(&["bar", "-h"]).unwrap();
694     assert_eq!(opts.help_requested(), true);
695 
696     let opts = Opts::parse_args_default(&["baz", "-h"]).unwrap();
697     assert_eq!(opts.help_requested(), true);
698 
699     let opts = Opts2::parse_args_default(EMPTY).unwrap();
700     assert_eq!(opts.help_requested(), false);
701 
702     let opts = Opts3::parse_args_default(EMPTY).unwrap();
703     assert_eq!(opts.help_requested(), false);
704 }
705 
706 #[test]
test_type_attrs()707 fn test_type_attrs() {
708     #[derive(Options)]
709     #[options(no_help_flag, no_short, no_long)]
710     struct Opts {
711         #[options(long = "help")]
712         help: bool,
713         #[options(long = "foo")]
714         foo: bool,
715         #[options(short = "b")]
716         bar: bool,
717     }
718 
719     is_err!(Opts::parse_args_default(&["-f"]),
720         "unrecognized option `-f`");
721     is_err!(Opts::parse_args_default(&["--bar"]),
722         "unrecognized option `--bar`");
723     is_err!(Opts::parse_args_default(&["-h"]),
724         "unrecognized option `-h`");
725 
726     let opts = Opts::parse_args_default(&["--help"]).unwrap();
727     assert_eq!(opts.help, true);
728     assert_eq!(opts.help_requested(), false);
729 
730     let opts = Opts::parse_args_default(&["--foo"]).unwrap();
731     assert_eq!(opts.foo, true);
732 
733     let opts = Opts::parse_args_default(&["-b"]).unwrap();
734     assert_eq!(opts.bar, true);
735 
736     #[derive(Options)]
737     #[options(no_short)]
738     struct Opts2 {
739         foo: bool,
740         #[options(short = "b")]
741         bar: bool,
742     }
743 
744     is_err!(Opts2::parse_args_default(&["-f"]),
745         "unrecognized option `-f`");
746 
747     let opts = Opts2::parse_args_default(&["--foo", "-b"]).unwrap();
748     assert_eq!(opts.foo, true);
749     assert_eq!(opts.bar, true);
750 
751     let opts = Opts2::parse_args_default(&["--bar"]).unwrap();
752     assert_eq!(opts.bar, true);
753 
754     #[derive(Options)]
755     #[options(no_long)]
756     struct Opts3 {
757         foo: bool,
758         #[options(long = "bar")]
759         bar: bool,
760     }
761 
762     is_err!(Opts3::parse_args_default(&["--foo"]),
763         "unrecognized option `--foo`");
764 
765     let opts = Opts3::parse_args_default(&["--bar"]).unwrap();
766     assert_eq!(opts.bar, true);
767 
768     let opts = Opts3::parse_args_default(&["-f", "-b"]).unwrap();
769     assert_eq!(opts.foo, true);
770     assert_eq!(opts.bar, true);
771 
772     #[derive(Options)]
773     #[options(no_help_flag)]
774     struct Opts4 {
775         #[options(help_flag)]
776         help: bool,
777     }
778 
779     let opts = Opts4::parse_args_default(&["-h"]).unwrap();
780     assert_eq!(opts.help, true);
781     assert_eq!(opts.help_requested(), true);
782 
783     #[derive(Options)]
784     #[options(required)]
785     struct Opts5 {
786         #[options(no_long)]
787         foo: i32,
788         #[options(not_required)]
789         bar: i32,
790     }
791 
792     is_err!(Opts5::parse_args_default(EMPTY),
793         "missing required option `-f`");
794 
795     let opts = Opts5::parse_args_default(&["-f", "1"]).unwrap();
796     assert_eq!(opts.foo, 1);
797     assert_eq!(opts.bar, 0);
798 
799     let opts = Opts5::parse_args_default(&["-f", "1", "--bar", "2"]).unwrap();
800     assert_eq!(opts.foo, 1);
801     assert_eq!(opts.bar, 2);
802 }
803 
804 #[test]
test_required()805 fn test_required() {
806     #[derive(Options)]
807     struct Opts {
808         #[options(required)]
809         foo: i32,
810         optional: i32,
811     }
812 
813     #[derive(Options)]
814     struct Opts2 {
815         #[options(command, required)]
816         command: Option<Cmd>,
817         optional: i32,
818     }
819 
820     #[derive(Options)]
821     enum Cmd {
822         Foo(NoOpts),
823     }
824 
825     #[derive(Options)]
826     struct Opts3 {
827         #[options(free, required)]
828         bar: i32,
829         optional: i32,
830     }
831 
832     is_err!(Opts::parse_args_default(EMPTY),
833         "missing required option `--foo`");
834     is_err!(Opts2::parse_args_default(EMPTY),
835         "missing required command");
836     is_err!(Opts3::parse_args_default(EMPTY),
837         "missing required free argument");
838 
839     let opts = Opts::parse_args_default(&["-f", "1"]).unwrap();
840     assert_eq!(opts.foo, 1);
841     let opts = Opts::parse_args_default(&["-f1"]).unwrap();
842     assert_eq!(opts.foo, 1);
843     let opts = Opts::parse_args_default(&["--foo", "1"]).unwrap();
844     assert_eq!(opts.foo, 1);
845     let opts = Opts::parse_args_default(&["--foo=1"]).unwrap();
846     assert_eq!(opts.foo, 1);
847 
848     let opts = Opts2::parse_args_default(&["foo"]).unwrap();
849     assert!(opts.command.is_some());
850 
851     let opts = Opts3::parse_args_default(&["1"]).unwrap();
852     assert_eq!(opts.bar, 1);
853 }
854 
855 #[test]
test_required_help()856 fn test_required_help() {
857     #[derive(Options)]
858     struct Opts {
859         #[options(required)]
860         thing: Option<String>,
861         help: bool,
862     }
863 
864     #[derive(Options)]
865     struct Opts2 {
866         #[options(required)]
867         thing: Option<String>,
868         help: bool,
869         #[options(help_flag)]
870         secondary_help: bool,
871     }
872 
873     let opts = Opts::parse_args_default(&["-h"]).unwrap();
874     assert_eq!(opts.help, true);
875 
876     let opts = Opts2::parse_args_default(&["--secondary-help"]).unwrap();
877     assert_eq!(opts.secondary_help, true);
878 }
879 
880 #[test]
test_parse()881 fn test_parse() {
882     #[derive(Options)]
883     struct Opts {
884         #[options(help = "foo", parse(from_str = "parse_foo"))]
885         foo: Option<Foo>,
886         #[options(help = "bar", parse(try_from_str = "parse_bar"))]
887         bar: Option<Bar>,
888         #[options(help = "baz", parse(from_str))]
889         baz: Option<Baz>,
890         #[options(help = "quux", parse(try_from_str))]
891         quux: Option<Quux>,
892     }
893 
894     #[derive(Debug)]
895     struct Foo(String);
896     #[derive(Debug)]
897     struct Bar(u32);
898     #[derive(Debug)]
899     struct Baz(String);
900     #[derive(Debug)]
901     struct Quux(u32);
902 
903     fn parse_foo(s: &str) -> Foo { Foo(s.to_owned()) }
904     fn parse_bar(s: &str) -> Result<Bar, <u32 as FromStr>::Err> { s.parse().map(Bar) }
905 
906     impl<'a> From<&'a str> for Baz {
907         fn from(s: &str) -> Baz {
908             Baz(s.to_owned())
909         }
910     }
911 
912     impl FromStr for Quux {
913         type Err = <u32 as FromStr>::Err;
914 
915         fn from_str(s: &str) -> Result<Quux, Self::Err> {
916             s.parse().map(Quux)
917         }
918     }
919 
920     let opts = Opts::parse_args_default(&[
921         "-ffoo", "--bar=123", "--baz", "sup", "-q", "456"]).unwrap();
922     assert_matches!(opts.foo, Some(Foo(ref s)) if s == "foo");
923     assert_matches!(opts.bar, Some(Bar(123)));
924     assert_matches!(opts.baz, Some(Baz(ref s)) if s == "sup");
925     assert_matches!(opts.quux, Some(Quux(456)));
926 
927     is_err!(Opts::parse_args_default(&["--bar", "xyz"]),
928         |e| e.starts_with("invalid argument to option `--bar`: "));
929     is_err!(Opts::parse_args_default(&["--quux", "xyz"]),
930         |e| e.starts_with("invalid argument to option `--quux`: "));
931 }
932 
933 #[test]
test_default()934 fn test_default() {
935     #[derive(Options)]
936     struct Opts {
937         foo: u32,
938         #[options(default = "123")]
939         bar: u32,
940         #[options(default = "456")]
941         baz: Baz,
942         #[options(count, default = "789")]
943         count: u32,
944     }
945 
946     #[derive(Copy, Clone, Debug, Eq, PartialEq)]
947     struct Baz(u32);
948 
949     impl FromStr for Baz {
950         type Err = <u32 as FromStr>::Err;
951 
952         fn from_str(s: &str) -> Result<Self, Self::Err> {
953             s.parse().map(Baz)
954         }
955     }
956 
957     let opts = Opts::parse_args_default(EMPTY).unwrap();
958     assert_eq!(opts.foo, 0);
959     assert_eq!(opts.bar, 123);
960     assert_eq!(opts.baz, Baz(456));
961     assert_eq!(opts.count, 789);
962 
963     let opts = Opts::parse_args_default(&["-b99", "--baz=4387", "-c", "-f1"]).unwrap();
964     assert_eq!(opts.foo, 1);
965     assert_eq!(opts.bar, 99);
966     assert_eq!(opts.baz, Baz(4387));
967     assert_eq!(opts.count, 790);
968 }
969 
970 #[test]
test_failed_default()971 fn test_failed_default() {
972     #[derive(Options)]
973     struct Opts {
974         #[options(default = "lolwut")]
975         foo: u32,
976     }
977 
978     is_err!(Opts::parse_args_default(EMPTY),
979         |e| e.starts_with(r#"invalid default value for `foo` ("lolwut"): "#));
980 }
981 
982 #[test]
test_default_parse()983 fn test_default_parse() {
984     #[derive(Options)]
985     struct Opts {
986         #[options(default = "1", parse(try_from_str = "parse_foo"))]
987         foo: Foo,
988     }
989 
990     #[derive(Debug, Eq, PartialEq)]
991     struct Foo(u32);
992 
993     fn parse_foo(s: &str) -> Result<Foo, <u32 as FromStr>::Err> { s.parse().map(Foo) }
994 
995     let opts = Opts::parse_args_default(EMPTY).unwrap();
996     assert_eq!(opts.foo, Foo(1));
997 }
998 
999 #[test]
test_multi()1000 fn test_multi() {
1001     use std::collections::VecDeque;
1002 
1003     #[derive(Options)]
1004     struct Opts {
1005         #[options(multi = "push_back")]
1006         foo: VecDeque<String>,
1007     }
1008 
1009     #[derive(Options)]
1010     struct Opts2 {
1011         #[options(multi = "push_back")]
1012         foo: VecDeque<(i32, i32)>,
1013     }
1014 
1015     #[derive(Options)]
1016     struct Opts3 {
1017         #[options(free, multi = "push_front")]
1018         free: VecDeque<i32>,
1019     }
1020 
1021     let opts = Opts::parse_args_default(&["-f", "foo", "-f", "bar"]).unwrap();
1022     assert_eq!(opts.foo, ["foo", "bar"]);
1023 
1024     let opts = Opts2::parse_args_default(&["-f", "1", "2", "-f", "3", "4"]).unwrap();
1025     assert_eq!(opts.foo, [(1, 2), (3, 4)]);
1026 
1027     let opts = Opts3::parse_args_default(&["1", "2", "3"]).unwrap();
1028     assert_eq!(opts.free, [3, 2, 1]);
1029 }
1030 
1031 #[test]
test_no_multi()1032 fn test_no_multi() {
1033     #[derive(Options)]
1034     struct Opts {
1035         #[options(no_multi, parse(from_str = "comma_list"))]
1036         list_things: Vec<String>,
1037     }
1038 
1039     #[derive(Options)]
1040     #[options(no_multi)]
1041     struct Opts2 {
1042         #[options(parse(from_str = "comma_list"))]
1043         list_things: Vec<String>,
1044     }
1045 
1046     #[derive(Options)]
1047     struct Opts3 {
1048         #[options(free, no_multi, parse(from_str = "comma_list"))]
1049         list_things: Vec<String>,
1050     }
1051 
1052     fn comma_list(s: &str) -> Vec<String> {
1053         s.split(',').map(|s| s.to_string()).collect()
1054     }
1055 
1056     let opts = Opts::parse_args_default(&["-l", "foo,bar,baz"]).unwrap();
1057     assert_eq!(opts.list_things, ["foo", "bar", "baz"]);
1058 
1059     let opts = Opts2::parse_args_default(&["-l", "foo,bar,baz"]).unwrap();
1060     assert_eq!(opts.list_things, ["foo", "bar", "baz"]);
1061 
1062     let opts = Opts3::parse_args_default(&["foo,bar,baz"]).unwrap();
1063     assert_eq!(opts.list_things, ["foo", "bar", "baz"]);
1064 
1065     is_err!(Opts3::parse_args_default(&["foo,bar,baz", "error"]),
1066         "unexpected free argument `error`");
1067 }
1068 
1069 #[test]
test_doc_help()1070 fn test_doc_help() {
1071     /// type-level help comment
1072     #[derive(Options)]
1073     struct Opts {
1074         /// free help comment
1075         #[options(free)]
1076         free: i32,
1077         /// help comment
1078         foo: i32,
1079         /// help comment
1080         #[options(help = "help attribute")]
1081         bar: i32,
1082     }
1083 
1084     #[derive(Options)]
1085     enum Cmd {
1086         /// help comment
1087         Alpha(NoOpts),
1088         /// help comment
1089         #[options(help = "help attribute")]
1090         Bravo(NoOpts),
1091     }
1092 
1093     assert_eq!(Opts::usage(), &"
1094 type-level help comment
1095 
1096 Positional arguments:
1097   free           free help comment
1098 
1099 Optional arguments:
1100   -f, --foo FOO  help comment
1101   -b, --bar BAR  help attribute"
1102         // Skip leading newline
1103         [1..]);
1104 
1105     assert_eq!(Cmd::usage(), &"
1106   alpha  help comment
1107   bravo  help attribute"
1108         // Skip leading newline
1109         [1..]);
1110 }
1111 
1112 #[test]
test_failed_parse_free()1113 fn test_failed_parse_free() {
1114     #[derive(Options)]
1115     struct Opts {
1116         #[options(free)]
1117         foo: u32,
1118         #[options(free, parse(try_from_str = "parse"))]
1119         bar: u32,
1120         #[options(free)]
1121         baz: Vec<u32>,
1122     }
1123 
1124     fn parse(s: &str) -> Result<u32, <u32 as FromStr>::Err> {
1125         s.parse()
1126     }
1127 
1128     is_err!(Opts::parse_args_default(&["x"]),
1129         |e| e.starts_with("invalid argument to option `foo`: "));
1130 
1131     is_err!(Opts::parse_args_default(&["0", "x"]),
1132         |e| e.starts_with("invalid argument to option `bar`: "));
1133 
1134     is_err!(Opts::parse_args_default(&["0", "0", "x"]),
1135         |e| e.starts_with("invalid argument to option `baz`: "));
1136 }
1137 
1138 #[cfg(feature = "default_expr")]
1139 #[test]
test_default_expr()1140 fn test_default_expr() {
1141     #[derive(Options)]
1142     struct Opts {
1143         #[options(default_expr = "foo()")]
1144         foo: u32,
1145     }
1146 
1147     fn foo() -> u32 { 123 }
1148 
1149     let opts = Opts::parse_args_default(EMPTY).unwrap();
1150     assert_eq!(opts.foo, foo());
1151 }
1152