1 // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
2 // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
3 // Ana Hobden (@hoverbear) <operator@hoverbear.org>
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 //
11 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13 // MIT/Apache 2.0 license.
14
15 #![allow(clippy::option_option)]
16
17 use crate::utils;
18
19 use clap::{Parser, Subcommand};
20
21 #[test]
required_option()22 fn required_option() {
23 #[derive(Parser, PartialEq, Debug)]
24 #[command(args_override_self = true)]
25 struct Opt {
26 #[arg(short, long)]
27 arg: i32,
28 }
29 assert_eq!(
30 Opt { arg: 42 },
31 Opt::try_parse_from(["test", "-a42"]).unwrap()
32 );
33 assert_eq!(
34 Opt { arg: 42 },
35 Opt::try_parse_from(["test", "-a", "42"]).unwrap()
36 );
37 assert_eq!(
38 Opt { arg: 42 },
39 Opt::try_parse_from(["test", "--arg", "42"]).unwrap()
40 );
41 assert_eq!(
42 Opt { arg: 42 },
43 Opt::try_parse_from(["test", "--arg", "24", "--arg", "42"]).unwrap()
44 );
45 assert!(Opt::try_parse_from(["test"]).is_err());
46 }
47
48 #[test]
option_with_default()49 fn option_with_default() {
50 #[derive(Parser, PartialEq, Debug)]
51 #[command(args_override_self = true)]
52 struct Opt {
53 #[arg(short, default_value = "42")]
54 arg: i32,
55 }
56 assert_eq!(
57 Opt { arg: 24 },
58 Opt::try_parse_from(["test", "-a24"]).unwrap()
59 );
60 assert_eq!(
61 Opt { arg: 42 },
62 Opt::try_parse_from(["test", "-a", "24", "-a", "42"]).unwrap()
63 );
64 assert_eq!(Opt { arg: 42 }, Opt::try_parse_from(["test"]).unwrap());
65 }
66
67 #[test]
option_with_raw_default()68 fn option_with_raw_default() {
69 #[derive(Parser, PartialEq, Debug)]
70 #[command(args_override_self = true)]
71 struct Opt {
72 #[arg(short, default_value = "42")]
73 arg: i32,
74 }
75 assert_eq!(
76 Opt { arg: 24 },
77 Opt::try_parse_from(["test", "-a24"]).unwrap()
78 );
79 assert_eq!(
80 Opt { arg: 42 },
81 Opt::try_parse_from(["test", "-a", "24", "-a", "42"]).unwrap()
82 );
83 assert_eq!(Opt { arg: 42 }, Opt::try_parse_from(["test"]).unwrap());
84 }
85
86 #[test]
option_from_str()87 fn option_from_str() {
88 #[derive(Clone, Debug, PartialEq)]
89 struct A;
90
91 impl std::str::FromStr for A {
92 type Err = std::convert::Infallible;
93
94 fn from_str(_: &str) -> Result<A, Self::Err> {
95 Ok(A)
96 }
97 }
98
99 #[derive(Debug, Parser, PartialEq)]
100 #[command(args_override_self = true)]
101 struct Opt {
102 a: Option<A>,
103 }
104
105 assert_eq!(Opt { a: None }, Opt::try_parse_from(["test"]).unwrap());
106 assert_eq!(
107 Opt { a: Some(A) },
108 Opt::try_parse_from(["test", "foo"]).unwrap()
109 );
110 }
111
112 #[test]
vec_from_str()113 fn vec_from_str() {
114 #[derive(Clone, Debug, PartialEq)]
115 struct A;
116
117 impl std::str::FromStr for A {
118 type Err = std::convert::Infallible;
119
120 fn from_str(_: &str) -> Result<A, Self::Err> {
121 Ok(A)
122 }
123 }
124
125 #[derive(Debug, Parser, PartialEq)]
126 #[command(args_override_self = true)]
127 struct Opt {
128 a: Vec<A>,
129 }
130
131 assert_eq!(
132 Opt { a: Vec::new() },
133 Opt::try_parse_from(["test"]).unwrap()
134 );
135 assert_eq!(
136 Opt { a: vec![A] },
137 Opt::try_parse_from(["test", "foo"]).unwrap()
138 );
139 }
140
141 #[test]
option_vec_from_str()142 fn option_vec_from_str() {
143 #[derive(Clone, Debug, PartialEq)]
144 struct A;
145
146 impl std::str::FromStr for A {
147 type Err = std::convert::Infallible;
148
149 fn from_str(_: &str) -> Result<A, Self::Err> {
150 Ok(A)
151 }
152 }
153
154 #[derive(Debug, Parser, PartialEq)]
155 #[command(args_override_self = true)]
156 struct Opt {
157 #[arg(short)]
158 a: Option<Vec<A>>,
159 }
160
161 assert_eq!(Opt { a: None }, Opt::try_parse_from(["test"]).unwrap());
162 assert_eq!(
163 Opt { a: Some(vec![A]) },
164 Opt::try_parse_from(["test", "-a", "foo"]).unwrap()
165 );
166 }
167
168 #[test]
option_type_is_optional()169 fn option_type_is_optional() {
170 #[derive(Parser, PartialEq, Debug)]
171 #[command(args_override_self = true)]
172 struct Opt {
173 #[arg(short)]
174 arg: Option<i32>,
175 }
176 assert_eq!(
177 Opt { arg: Some(42) },
178 Opt::try_parse_from(["test", "-a42"]).unwrap()
179 );
180 assert_eq!(
181 Opt { arg: Some(42) },
182 Opt::try_parse_from(["test", "-a", "24", "-a", "42"]).unwrap()
183 );
184 assert_eq!(Opt { arg: None }, Opt::try_parse_from(["test"]).unwrap());
185 }
186
187 #[test]
required_with_option_type()188 fn required_with_option_type() {
189 #[derive(Debug, PartialEq, Eq, Parser)]
190 #[command(subcommand_negates_reqs = true)]
191 #[command(args_override_self = true)]
192 struct Opt {
193 #[arg(required = true)]
194 req_str: Option<String>,
195
196 #[command(subcommand)]
197 cmd: Option<SubCommands>,
198 }
199
200 #[derive(Debug, PartialEq, Eq, Subcommand)]
201 enum SubCommands {
202 ExSub {
203 #[arg(short, long, action = clap::ArgAction::Count)]
204 verbose: u8,
205 },
206 }
207
208 assert_eq!(
209 Opt {
210 req_str: Some(("arg").into()),
211 cmd: None,
212 },
213 Opt::try_parse_from(["test", "arg"]).unwrap()
214 );
215
216 assert_eq!(
217 Opt {
218 req_str: None,
219 cmd: Some(SubCommands::ExSub { verbose: 1 }),
220 },
221 Opt::try_parse_from(["test", "ex-sub", "-v"]).unwrap()
222 );
223
224 assert!(Opt::try_parse_from(["test"]).is_err());
225 }
226
227 #[test]
ignore_qualified_option_type()228 fn ignore_qualified_option_type() {
229 fn parser(s: &str) -> Result<Option<String>, std::convert::Infallible> {
230 Ok(Some(s.to_string()))
231 }
232
233 #[derive(Parser, PartialEq, Debug)]
234 #[command(args_override_self = true)]
235 struct Opt {
236 #[arg(value_parser = parser)]
237 arg: ::std::option::Option<String>,
238 }
239
240 assert_eq!(
241 Opt {
242 arg: Some("success".into())
243 },
244 Opt::try_parse_from(["test", "success"]).unwrap()
245 );
246 }
247
248 #[test]
option_option_type_is_optional_value()249 fn option_option_type_is_optional_value() {
250 #[derive(Parser, PartialEq, Debug)]
251 #[command(args_override_self = true)]
252 struct Opt {
253 #[arg(short)]
254 #[allow(clippy::option_option)]
255 arg: Option<Option<i32>>,
256 }
257 assert_eq!(
258 Opt {
259 arg: Some(Some(42))
260 },
261 Opt::try_parse_from(["test", "-a42"]).unwrap()
262 );
263 assert_eq!(
264 Opt { arg: Some(None) },
265 Opt::try_parse_from(["test", "-a"]).unwrap()
266 );
267 assert_eq!(
268 Opt {
269 arg: Some(Some(42))
270 },
271 Opt::try_parse_from(["test", "-a", "24", "-a", "42"]).unwrap()
272 );
273 assert_eq!(Opt { arg: None }, Opt::try_parse_from(["test"]).unwrap());
274 }
275
276 #[test]
option_option_type_help()277 fn option_option_type_help() {
278 #[derive(Parser, Debug)]
279 #[command(args_override_self = true)]
280 struct Opt {
281 #[arg(long, value_name = "val")]
282 arg: Option<Option<i32>>,
283 }
284 let help = utils::get_help::<Opt>();
285 assert!(help.contains("--arg [<val>]"));
286 assert!(!help.contains("--arg [<val>...]"));
287 }
288
289 #[test]
two_option_option_types()290 fn two_option_option_types() {
291 #[derive(Parser, PartialEq, Debug)]
292 #[command(args_override_self = true)]
293 struct Opt {
294 #[arg(short)]
295 arg: Option<Option<i32>>,
296
297 #[arg(long)]
298 field: Option<Option<String>>,
299 }
300 assert_eq!(
301 Opt {
302 arg: Some(Some(42)),
303 field: Some(Some("f".into()))
304 },
305 Opt::try_parse_from(["test", "-a42", "--field", "f"]).unwrap()
306 );
307 assert_eq!(
308 Opt {
309 arg: Some(Some(42)),
310 field: Some(None)
311 },
312 Opt::try_parse_from(["test", "-a42", "--field"]).unwrap()
313 );
314 assert_eq!(
315 Opt {
316 arg: Some(None),
317 field: Some(None)
318 },
319 Opt::try_parse_from(["test", "-a", "--field"]).unwrap()
320 );
321 assert_eq!(
322 Opt {
323 arg: Some(None),
324 field: Some(Some("f".into()))
325 },
326 Opt::try_parse_from(["test", "-a", "--field", "f"]).unwrap()
327 );
328 assert_eq!(
329 Opt {
330 arg: None,
331 field: Some(None)
332 },
333 Opt::try_parse_from(["test", "--field"]).unwrap()
334 );
335 assert_eq!(
336 Opt {
337 arg: None,
338 field: None
339 },
340 Opt::try_parse_from(["test"]).unwrap()
341 );
342 }
343
344 #[test]
vec_type_is_multiple_occurrences()345 fn vec_type_is_multiple_occurrences() {
346 #[derive(Parser, PartialEq, Debug)]
347 #[command(args_override_self = true)]
348 struct Opt {
349 #[arg(short, long)]
350 arg: Vec<i32>,
351 }
352 assert_eq!(
353 Opt { arg: vec![24] },
354 Opt::try_parse_from(["test", "-a24"]).unwrap()
355 );
356 assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(["test"]).unwrap());
357 assert_eq!(
358 Opt { arg: vec![24, 42] },
359 Opt::try_parse_from(["test", "-a", "24", "-a", "42"]).unwrap()
360 );
361 }
362
363 #[test]
vec_type_with_required()364 fn vec_type_with_required() {
365 #[derive(Parser, PartialEq, Debug)]
366 #[command(args_override_self = true)]
367 struct Opt {
368 #[arg(short, long, required = true)]
369 arg: Vec<i32>,
370 }
371 assert_eq!(
372 Opt { arg: vec![24] },
373 Opt::try_parse_from(["test", "-a24"]).unwrap()
374 );
375 assert!(Opt::try_parse_from(["test"]).is_err());
376 assert_eq!(
377 Opt { arg: vec![24, 42] },
378 Opt::try_parse_from(["test", "-a", "24", "-a", "42"]).unwrap()
379 );
380 }
381
382 #[test]
vec_type_with_multiple_values_only()383 fn vec_type_with_multiple_values_only() {
384 #[derive(Parser, PartialEq, Debug)]
385 #[command(args_override_self = true)]
386 struct Opt {
387 #[arg(short, long, num_args(1..))]
388 arg: Vec<i32>,
389 }
390 assert_eq!(
391 Opt { arg: vec![24] },
392 Opt::try_parse_from(["test", "-a24"]).unwrap()
393 );
394 assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(["test"]).unwrap());
395 assert_eq!(
396 Opt { arg: vec![24, 42] },
397 Opt::try_parse_from(["test", "-a", "24", "42"]).unwrap()
398 );
399 }
400
401 #[test]
ignore_qualified_vec_type()402 fn ignore_qualified_vec_type() {
403 fn parser(s: &str) -> Result<Vec<String>, std::convert::Infallible> {
404 Ok(vec![s.to_string()])
405 }
406
407 #[derive(Parser, PartialEq, Debug)]
408 #[command(args_override_self = true)]
409 struct Opt {
410 #[arg(value_parser = parser)]
411 arg: ::std::vec::Vec<String>,
412 }
413
414 assert_eq!(
415 Opt {
416 arg: vec!["success".into()]
417 },
418 Opt::try_parse_from(["test", "success"]).unwrap()
419 );
420 }
421
422 #[test]
option_vec_type()423 fn option_vec_type() {
424 #[derive(Parser, PartialEq, Debug)]
425 #[command(args_override_self = true)]
426 struct Opt {
427 #[arg(short)]
428 arg: Option<Vec<i32>>,
429 }
430 assert_eq!(
431 Opt { arg: Some(vec![1]) },
432 Opt::try_parse_from(["test", "-a", "1"]).unwrap()
433 );
434
435 assert_eq!(
436 Opt {
437 arg: Some(vec![1, 2])
438 },
439 Opt::try_parse_from(["test", "-a", "1", "-a", "2"]).unwrap()
440 );
441
442 assert_eq!(Opt { arg: None }, Opt::try_parse_from(["test"]).unwrap());
443 }
444
445 #[test]
option_vec_type_structopt_behavior()446 fn option_vec_type_structopt_behavior() {
447 #[derive(Parser, PartialEq, Debug)]
448 #[command(args_override_self = true)]
449 struct Opt {
450 #[arg(short, long, num_args(0..))]
451 arg: Option<Vec<i32>>,
452 }
453 assert_eq!(
454 Opt { arg: Some(vec![1]) },
455 Opt::try_parse_from(["test", "-a", "1"]).unwrap()
456 );
457
458 assert_eq!(
459 Opt {
460 arg: Some(vec![1, 2])
461 },
462 Opt::try_parse_from(["test", "-a", "1", "2"]).unwrap()
463 );
464
465 assert_eq!(
466 Opt { arg: Some(vec![]) },
467 Opt::try_parse_from(["test", "-a"]).unwrap()
468 );
469
470 assert_eq!(Opt { arg: None }, Opt::try_parse_from(["test"]).unwrap());
471 }
472
473 #[test]
two_option_vec_types()474 fn two_option_vec_types() {
475 #[derive(Parser, PartialEq, Debug)]
476 #[command(args_override_self = true)]
477 struct Opt {
478 #[arg(short)]
479 arg: Option<Vec<i32>>,
480
481 #[arg(short)]
482 b: Option<Vec<i32>>,
483 }
484
485 assert_eq!(
486 Opt {
487 arg: Some(vec![1]),
488 b: None,
489 },
490 Opt::try_parse_from(["test", "-a", "1"]).unwrap()
491 );
492
493 assert_eq!(
494 Opt {
495 arg: Some(vec![1]),
496 b: Some(vec![1])
497 },
498 Opt::try_parse_from(["test", "-a", "1", "-b", "1"]).unwrap()
499 );
500
501 assert_eq!(
502 Opt {
503 arg: Some(vec![1, 2]),
504 b: Some(vec![1, 2])
505 },
506 Opt::try_parse_from(["test", "-a", "1", "-a", "2", "-b", "1", "-b", "2"]).unwrap()
507 );
508
509 assert_eq!(
510 Opt { arg: None, b: None },
511 Opt::try_parse_from(["test"]).unwrap()
512 );
513 }
514
515 #[test]
explicit_value_parser()516 fn explicit_value_parser() {
517 #[derive(Parser, PartialEq, Debug)]
518 #[command(args_override_self = true)]
519 struct Opt {
520 #[arg(long, value_parser = clap::value_parser!(i32))]
521 arg: i32,
522 }
523 assert_eq!(
524 Opt { arg: 42 },
525 Opt::try_parse_from(["test", "--arg", "42"]).unwrap()
526 );
527 }
528
529 #[test]
implicit_value_parser()530 fn implicit_value_parser() {
531 #[derive(Parser, PartialEq, Debug)]
532 #[command(args_override_self = true)]
533 struct Opt {
534 #[arg(long)]
535 arg: i32,
536 }
537 assert_eq!(
538 Opt { arg: 42 },
539 Opt::try_parse_from(["test", "--arg", "42"]).unwrap()
540 );
541 }
542