]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
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 | mod utils; | |
10 | ||
11 | use structopt::StructOpt; | |
12 | use utils::*; | |
13 | ||
14 | #[derive(StructOpt, PartialEq, Debug)] | |
15 | enum Opt { | |
16 | /// Fetch stuff from GitHub | |
17 | Fetch { | |
18 | #[structopt(long)] | |
19 | all: bool, | |
20 | #[structopt(short, long)] | |
21 | /// Overwrite local branches. | |
22 | force: bool, | |
23 | repo: String, | |
24 | }, | |
25 | ||
26 | Add { | |
27 | #[structopt(short, long)] | |
28 | interactive: bool, | |
29 | #[structopt(short, long)] | |
30 | verbose: bool, | |
31 | }, | |
32 | } | |
33 | ||
34 | #[test] | |
35 | fn test_fetch() { | |
36 | assert_eq!( | |
37 | Opt::Fetch { | |
38 | all: true, | |
39 | force: false, | |
40 | repo: "origin".to_string() | |
41 | }, | |
42 | Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"])) | |
43 | ); | |
44 | assert_eq!( | |
45 | Opt::Fetch { | |
46 | all: false, | |
47 | force: true, | |
48 | repo: "origin".to_string() | |
49 | }, | |
50 | Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"])) | |
51 | ); | |
52 | } | |
53 | ||
54 | #[test] | |
55 | fn test_add() { | |
56 | assert_eq!( | |
57 | Opt::Add { | |
58 | interactive: false, | |
59 | verbose: false | |
60 | }, | |
61 | Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"])) | |
62 | ); | |
63 | assert_eq!( | |
64 | Opt::Add { | |
65 | interactive: true, | |
66 | verbose: true | |
67 | }, | |
68 | Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"])) | |
69 | ); | |
70 | } | |
71 | ||
72 | #[test] | |
73 | fn test_no_parse() { | |
74 | let result = Opt::clap().get_matches_from_safe(&["test", "badcmd", "-i", "-v"]); | |
75 | assert!(result.is_err()); | |
76 | ||
77 | let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badoption"]); | |
78 | assert!(result.is_err()); | |
79 | ||
80 | let result = Opt::clap().get_matches_from_safe(&["test"]); | |
81 | assert!(result.is_err()); | |
82 | } | |
83 | ||
84 | #[derive(StructOpt, PartialEq, Debug)] | |
85 | enum Opt2 { | |
86 | DoSomething { arg: String }, | |
87 | } | |
88 | ||
89 | #[test] | |
90 | /// This test is specifically to make sure that hyphenated subcommands get | |
91 | /// processed correctly. | |
92 | fn test_hyphenated_subcommands() { | |
93 | assert_eq!( | |
94 | Opt2::DoSomething { | |
95 | arg: "blah".to_string() | |
96 | }, | |
97 | Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"])) | |
98 | ); | |
99 | } | |
100 | ||
101 | #[derive(StructOpt, PartialEq, Debug)] | |
102 | enum Opt3 { | |
103 | Add, | |
104 | Init, | |
105 | Fetch, | |
106 | } | |
107 | ||
108 | #[test] | |
109 | fn test_null_commands() { | |
110 | assert_eq!( | |
111 | Opt3::Add, | |
112 | Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"])) | |
113 | ); | |
114 | assert_eq!( | |
115 | Opt3::Init, | |
116 | Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"])) | |
117 | ); | |
118 | assert_eq!( | |
119 | Opt3::Fetch, | |
120 | Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"])) | |
121 | ); | |
122 | } | |
123 | ||
124 | #[derive(StructOpt, PartialEq, Debug)] | |
125 | #[structopt(about = "Not shown")] | |
126 | struct Add { | |
127 | file: String, | |
128 | } | |
129 | /// Not shown | |
130 | #[derive(StructOpt, PartialEq, Debug)] | |
131 | struct Fetch { | |
132 | remote: String, | |
133 | } | |
134 | #[derive(StructOpt, PartialEq, Debug)] | |
135 | enum Opt4 { | |
136 | // Not shown | |
137 | /// Add a file | |
138 | Add(Add), | |
139 | Init, | |
140 | /// download history from remote | |
141 | Fetch(Fetch), | |
142 | } | |
143 | ||
144 | #[test] | |
145 | fn test_tuple_commands() { | |
146 | assert_eq!( | |
147 | Opt4::Add(Add { | |
148 | file: "f".to_string() | |
149 | }), | |
150 | Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "add", "f"])) | |
151 | ); | |
152 | assert_eq!( | |
153 | Opt4::Init, | |
154 | Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"])) | |
155 | ); | |
156 | assert_eq!( | |
157 | Opt4::Fetch(Fetch { | |
158 | remote: "origin".to_string() | |
159 | }), | |
160 | Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "fetch", "origin"])) | |
161 | ); | |
162 | ||
163 | let output = get_long_help::<Opt4>(); | |
164 | ||
165 | assert!(output.contains("download history from remote")); | |
166 | assert!(output.contains("Add a file")); | |
167 | assert!(!output.contains("Not shown")); | |
168 | } | |
169 | ||
170 | #[test] | |
171 | fn enum_in_enum_subsubcommand() { | |
172 | #[derive(StructOpt, Debug, PartialEq)] | |
173 | pub enum Opt { | |
174 | Daemon(DaemonCommand), | |
175 | } | |
176 | ||
177 | #[derive(StructOpt, Debug, PartialEq)] | |
178 | pub enum DaemonCommand { | |
179 | Start, | |
180 | Stop, | |
181 | } | |
182 | ||
183 | let result = Opt::clap().get_matches_from_safe(&["test"]); | |
184 | assert!(result.is_err()); | |
185 | ||
186 | let result = Opt::clap().get_matches_from_safe(&["test", "daemon"]); | |
187 | assert!(result.is_err()); | |
188 | ||
189 | let result = Opt::from_iter(&["test", "daemon", "start"]); | |
190 | assert_eq!(Opt::Daemon(DaemonCommand::Start), result); | |
191 | } | |
192 | ||
193 | #[test] | |
194 | fn flatten_enum() { | |
195 | #[derive(StructOpt, Debug, PartialEq)] | |
196 | struct Opt { | |
197 | #[structopt(flatten)] | |
198 | sub_cmd: SubCmd, | |
199 | } | |
200 | #[derive(StructOpt, Debug, PartialEq)] | |
201 | enum SubCmd { | |
202 | Foo, | |
203 | Bar, | |
204 | } | |
205 | ||
206 | assert!(Opt::from_iter_safe(&["test"]).is_err()); | |
207 | assert_eq!( | |
208 | Opt::from_iter(&["test", "foo"]), | |
209 | Opt { | |
210 | sub_cmd: SubCmd::Foo | |
211 | } | |
212 | ); | |
213 | } | |
214 | ||
215 | #[test] | |
216 | fn external_subcommand() { | |
217 | #[derive(Debug, PartialEq, StructOpt)] | |
218 | struct Opt { | |
219 | #[structopt(subcommand)] | |
220 | sub: Subcommands, | |
221 | } | |
222 | ||
223 | #[derive(Debug, PartialEq, StructOpt)] | |
224 | enum Subcommands { | |
225 | Add, | |
226 | Remove, | |
227 | #[structopt(external_subcommand)] | |
228 | Other(Vec<String>), | |
229 | } | |
230 | ||
231 | assert_eq!( | |
232 | Opt::from_iter(&["test", "add"]), | |
233 | Opt { | |
234 | sub: Subcommands::Add | |
235 | } | |
236 | ); | |
237 | ||
238 | assert_eq!( | |
239 | Opt::from_iter(&["test", "remove"]), | |
240 | Opt { | |
241 | sub: Subcommands::Remove | |
242 | } | |
243 | ); | |
244 | ||
245 | assert_eq!( | |
246 | Opt::from_iter(&["test", "git", "status"]), | |
247 | Opt { | |
248 | sub: Subcommands::Other(vec!["git".into(), "status".into()]) | |
249 | } | |
250 | ); | |
251 | ||
252 | assert!(Opt::from_iter_safe(&["test"]).is_err()); | |
253 | } | |
254 | ||
255 | #[test] | |
256 | fn external_subcommand_os_string() { | |
257 | use std::ffi::OsString; | |
258 | ||
259 | #[derive(Debug, PartialEq, StructOpt)] | |
260 | struct Opt { | |
261 | #[structopt(subcommand)] | |
262 | sub: Subcommands, | |
263 | } | |
264 | ||
265 | #[derive(Debug, PartialEq, StructOpt)] | |
266 | enum Subcommands { | |
267 | #[structopt(external_subcommand)] | |
268 | Other(Vec<OsString>), | |
269 | } | |
270 | ||
271 | assert_eq!( | |
272 | Opt::from_iter(&["test", "git", "status"]), | |
273 | Opt { | |
274 | sub: Subcommands::Other(vec!["git".into(), "status".into()]) | |
275 | } | |
276 | ); | |
277 | ||
278 | assert!(Opt::from_iter_safe(&["test"]).is_err()); | |
279 | } | |
280 | ||
281 | #[test] | |
282 | fn external_subcommand_optional() { | |
283 | #[derive(Debug, PartialEq, StructOpt)] | |
284 | struct Opt { | |
285 | #[structopt(subcommand)] | |
286 | sub: Option<Subcommands>, | |
287 | } | |
288 | ||
289 | #[derive(Debug, PartialEq, StructOpt)] | |
290 | enum Subcommands { | |
291 | #[structopt(external_subcommand)] | |
292 | Other(Vec<String>), | |
293 | } | |
294 | ||
295 | assert_eq!( | |
296 | Opt::from_iter(&["test", "git", "status"]), | |
297 | Opt { | |
298 | sub: Some(Subcommands::Other(vec!["git".into(), "status".into()])) | |
299 | } | |
300 | ); | |
301 | ||
302 | assert_eq!(Opt::from_iter(&["test"]), Opt { sub: None }); | |
303 | } | |
a2a8927a XL |
304 | |
305 | #[test] | |
306 | fn skip_subcommand() { | |
307 | #[derive(Debug, PartialEq, StructOpt)] | |
308 | struct Opt { | |
309 | #[structopt(subcommand)] | |
310 | sub: Subcommands, | |
311 | } | |
312 | ||
313 | #[derive(Debug, PartialEq, StructOpt)] | |
314 | enum Subcommands { | |
315 | Add, | |
316 | Remove, | |
317 | ||
318 | #[allow(dead_code)] | |
319 | #[structopt(skip)] | |
320 | Skip, | |
321 | } | |
322 | ||
323 | assert_eq!( | |
324 | Opt::from_iter(&["test", "add"]), | |
325 | Opt { | |
326 | sub: Subcommands::Add | |
327 | } | |
328 | ); | |
329 | ||
330 | assert_eq!( | |
331 | Opt::from_iter(&["test", "remove"]), | |
332 | Opt { | |
333 | sub: Subcommands::Remove | |
334 | } | |
335 | ); | |
336 | ||
337 | let res = Opt::from_iter_safe(&["test", "skip"]); | |
338 | assert!( | |
339 | matches!( | |
340 | res, | |
341 | Err(clap::Error { | |
342 | kind: clap::ErrorKind::UnknownArgument, | |
343 | .. | |
344 | }) | |
345 | ), | |
346 | "Unexpected result: {:?}", | |
347 | res | |
348 | ); | |
349 | } |