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
17use crate::utils;
18
19use clap::{Parser, Subcommand};
20
21#[test]
22fn 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]
49fn 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]
68fn 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]
87fn 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]
113fn 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]
142fn 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]
169fn 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]
188fn 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]
228fn 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]
249fn 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]
277fn 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]
290fn 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]
345fn 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]
364fn 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]
383fn 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]
402fn 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]
423fn 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]
446fn 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]
474fn 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]
516fn 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]
530fn 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