1 // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use structopt::StructOpt;
10 
11 #[derive(StructOpt, PartialEq, Debug)]
12 struct Opt {
13     #[structopt(short, long)]
14     force: bool,
15     #[structopt(short, long, parse(from_occurrences))]
16     verbose: u64,
17     #[structopt(subcommand)]
18     cmd: Sub,
19 }
20 
21 #[derive(StructOpt, PartialEq, Debug)]
22 enum Sub {
23     Fetch {},
24     Add {},
25 }
26 
27 #[derive(StructOpt, PartialEq, Debug)]
28 struct Opt2 {
29     #[structopt(short, long)]
30     force: bool,
31     #[structopt(short, long, parse(from_occurrences))]
32     verbose: u64,
33     #[structopt(subcommand)]
34     cmd: Option<Sub>,
35 }
36 
37 #[test]
test_no_cmd()38 fn test_no_cmd() {
39     let result = Opt::clap().get_matches_from_safe(&["test"]);
40     assert!(result.is_err());
41 
42     assert_eq!(
43         Opt2 {
44             force: false,
45             verbose: 0,
46             cmd: None
47         },
48         Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"]))
49     );
50 }
51 
52 #[test]
test_fetch()53 fn test_fetch() {
54     assert_eq!(
55         Opt {
56             force: false,
57             verbose: 3,
58             cmd: Sub::Fetch {}
59         },
60         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"]))
61     );
62     assert_eq!(
63         Opt {
64             force: true,
65             verbose: 0,
66             cmd: Sub::Fetch {}
67         },
68         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"]))
69     );
70 }
71 
72 #[test]
test_add()73 fn test_add() {
74     assert_eq!(
75         Opt {
76             force: false,
77             verbose: 0,
78             cmd: Sub::Add {}
79         },
80         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
81     );
82     assert_eq!(
83         Opt {
84             force: false,
85             verbose: 2,
86             cmd: Sub::Add {}
87         },
88         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"]))
89     );
90 }
91 
92 #[test]
test_badinput()93 fn test_badinput() {
94     let result = Opt::clap().get_matches_from_safe(&["test", "badcmd"]);
95     assert!(result.is_err());
96     let result = Opt::clap().get_matches_from_safe(&["test", "add", "--verbose"]);
97     assert!(result.is_err());
98     let result = Opt::clap().get_matches_from_safe(&["test", "--badopt", "add"]);
99     assert!(result.is_err());
100     let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badopt"]);
101     assert!(result.is_err());
102 }
103 
104 #[derive(StructOpt, PartialEq, Debug)]
105 struct Opt3 {
106     #[structopt(short, long)]
107     all: bool,
108     #[structopt(subcommand)]
109     cmd: Sub2,
110 }
111 
112 #[derive(StructOpt, PartialEq, Debug)]
113 enum Sub2 {
114     Foo {
115         file: String,
116         #[structopt(subcommand)]
117         cmd: Sub3,
118     },
119     Bar {},
120 }
121 
122 #[derive(StructOpt, PartialEq, Debug)]
123 enum Sub3 {
124     Baz {},
125     Quux {},
126 }
127 
128 #[test]
test_subsubcommand()129 fn test_subsubcommand() {
130     assert_eq!(
131         Opt3 {
132             all: true,
133             cmd: Sub2::Foo {
134                 file: "lib.rs".to_string(),
135                 cmd: Sub3::Quux {}
136             }
137         },
138         Opt3::from_clap(
139             &Opt3::clap().get_matches_from(&["test", "--all", "foo", "lib.rs", "quux"])
140         )
141     );
142 }
143 
144 #[derive(StructOpt, PartialEq, Debug)]
145 enum SubSubCmdWithOption {
146     Remote {
147         #[structopt(subcommand)]
148         cmd: Option<Remote>,
149     },
150     Stash {
151         #[structopt(subcommand)]
152         cmd: Stash,
153     },
154 }
155 #[derive(StructOpt, PartialEq, Debug)]
156 enum Remote {
157     Add { name: String, url: String },
158     Remove { name: String },
159 }
160 
161 #[derive(StructOpt, PartialEq, Debug)]
162 enum Stash {
163     Save,
164     Pop,
165 }
166 
167 #[test]
sub_sub_cmd_with_option()168 fn sub_sub_cmd_with_option() {
169     fn make(args: &[&str]) -> Option<SubSubCmdWithOption> {
170         SubSubCmdWithOption::clap()
171             .get_matches_from_safe(args)
172             .ok()
173             .map(|m| SubSubCmdWithOption::from_clap(&m))
174     }
175     assert_eq!(
176         Some(SubSubCmdWithOption::Remote { cmd: None }),
177         make(&["", "remote"])
178     );
179     assert_eq!(
180         Some(SubSubCmdWithOption::Remote {
181             cmd: Some(Remote::Add {
182                 name: "origin".into(),
183                 url: "http".into()
184             })
185         }),
186         make(&["", "remote", "add", "origin", "http"])
187     );
188     assert_eq!(
189         Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }),
190         make(&["", "stash", "save"])
191     );
192     assert_eq!(None, make(&["", "stash"]));
193 }
194