clapi/
parse_result.rs

1use crate::args::ArgumentList;
2use crate::command::Command;
3use crate::option::OptionList;
4use crate::Argument;
5use std::fmt::Display;
6use std::slice::Iter;
7use std::str::FromStr;
8
9/// Represents the result of a parse operation
10/// and provides a set of methods to query over the values.
11#[derive(Debug, Clone)]
12pub struct ParseResult {
13    command: Command,
14    options: OptionList,
15    args: ArgumentList,
16}
17
18impl ParseResult {
19    /// Constructs a new `ParseResult`.
20    pub fn new(command: Command, options: OptionList, args: ArgumentList) -> Self {
21        ParseResult {
22            command,
23            options,
24            args,
25        }
26    }
27
28    // Returns the executing command.
29    #[doc(hidden)]
30    pub fn executing_command(&self) -> &Command {
31        &self.command
32    }
33
34    /// Returns the name of the executing command.
35    pub fn command_name(&self) -> &str {
36        self.command.get_name()
37    }
38
39    /// Returns the version of the executing command or `None`.
40    pub fn command_version(&self) -> Option<&str> {
41        self.command.get_version()
42    }
43
44    /// Returns the help message of the executing command or `None`.
45    pub fn command_help(&self) -> Option<&str> {
46        self.command.get_help()
47    }
48
49    /// Returns the usage message of the executing command or `None`.
50    pub fn command_usage(&self) -> Option<&str> {
51        self.command.get_usage()
52    }
53
54    /// Returns the `Options` passed to the executing command.
55    pub fn options(&self) -> &OptionList {
56        &self.options
57    }
58
59    /// Returns the `Argument` passed to the executing command or `None` is there is more than 1 argument.
60    pub fn arg(&self) -> Option<&Argument> {
61        if self.args.len() == 1 {
62            Some(&self.args[0])
63        } else {
64            None
65        }
66    }
67
68    /// Returns the `Argument`s passed to the executing command.
69    pub fn args(&self) -> &ArgumentList {
70        &self.args
71    }
72
73    /// Gets the value of the argument with the given name.
74    pub fn value_of(&self, arg_name: &str) -> Option<&str> {
75        self.args
76            .get(arg_name)
77            .map(|arg| arg.get_values())
78            .filter(|values| values.len() == 1)
79            .map(|values| values[0].as_str())
80    }
81
82    /// Gets an iterator over the values of the argument with the given name.
83    pub fn values_of(&self, arg_name: &str) -> Option<Values<'_>> {
84        if let Some(arg) = self.args.get(arg_name) {
85            Some(Values {
86                values: arg.get_values(),
87            })
88        } else {
89            None
90        }
91    }
92
93    /// Gets the value of the argument of the given option.
94    pub fn value_of_option(&self, option_name: &str) -> Option<&str> {
95        self.options
96            .get(option_name)
97            .map(|opt| opt.get_arg())
98            .flatten()
99            .map(|arg| arg.get_values())
100            .filter(|values| values.len() == 1)
101            .map(|values| values[0].as_str())
102    }
103
104    /// Gets an iterator over the values of the arguments of the given option.
105    pub fn values_of_option(&self, option_name: &str) -> Option<Values<'_>> {
106        if let Some(option) = self.options.get(option_name) {
107            let arg = option.get_arg()?;
108            Some(Values {
109                values: arg.get_values(),
110            })
111        } else {
112            None
113        }
114    }
115
116    /// Gets the value of the argument with the given name as a type `T`.
117    pub fn value_of_as<T>(&self, arg_name: &str) -> Option<T>
118    where
119        T: FromStr + 'static,
120        <T as FromStr>::Err: Display,
121    {
122        self.args().convert::<T>(arg_name).ok()
123    }
124
125    /// Gets the values of the argument as a `Vec<T>`.
126    pub fn values_of_as<T>(&self, arg_name: &str) -> Option<Vec<T>>
127    where
128        T: FromStr + 'static,
129        <T as FromStr>::Err: Display,
130    {
131        self.args().convert_all(arg_name).ok()
132    }
133
134    /// Gets the value of the argument of the given option as a type `T`.
135    pub fn value_of_option_as<T>(&self, option_name: &str) -> Option<T>
136    where
137        T: FromStr + 'static,
138        <T as FromStr>::Err: Display,
139    {
140        self.options().convert::<T>(option_name).ok()
141    }
142
143    /// Gets the values of the given option as a type `T`.
144    pub fn values_of_option_as<T>(&self, option_name: &str) -> Option<Vec<T>>
145    where
146        T: FromStr + 'static,
147        <T as FromStr>::Err: Display,
148    {
149        self.options().convert_all(option_name).ok()
150    }
151}
152
153/// An iterator over the values of an argument or option.
154#[derive(Debug, Clone)]
155pub struct Values<'a> {
156    values: &'a [String],
157}
158
159impl<'a> Values<'a> {
160    /// Returns an iterator over the argument valeus.
161    pub fn iter(&self) -> Iter<'_, String> {
162        self.values.iter()
163    }
164
165    /// Returns the number of values.
166    #[inline]
167    pub fn len(&self) -> usize {
168        self.values.len()
169    }
170
171    #[inline]
172    pub fn is_empty(&self) -> bool {
173        self.values.is_empty()
174    }
175
176    /// Returns `true` if contains the value.
177    #[inline]
178    pub fn contains<S: AsRef<str>>(&self, value: S) -> bool {
179        self.values.iter().any(|s| s == value.as_ref())
180    }
181
182    /// Returns an slice to the inner values.
183    #[inline]
184    pub fn inner(&self) -> &'a [String] {
185        self.values
186    }
187}
188
189impl<'a> IntoIterator for Values<'a> {
190    type Item = &'a String;
191    type IntoIter = Iter<'a, String>;
192
193    fn into_iter(self) -> Self::IntoIter {
194        self.values.into_iter()
195    }
196}
197
198impl<'a> IntoIterator for &'a Values<'a> {
199    type Item = &'a String;
200    type IntoIter = Iter<'a, String>;
201
202    fn into_iter(self) -> Self::IntoIter {
203        self.values.into_iter()
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210    use crate::validator::validate_type;
211    use crate::{split_into_args, CommandOption, Context, ErrorKind, Parser};
212
213    fn parse_with(value: &str, command: Command) -> crate::Result<ParseResult> {
214        let context = Context::new(command);
215        Parser::new(&context).parse(split_into_args(value))
216    }
217
218    #[test]
219    fn parse_result_command_test() {
220        let command = Command::new("MyApp")
221            .arg(Argument::one_or_more("values"))
222            .option(
223                CommandOption::new("repeat").alias("r").arg(
224                    Argument::with_name("times")
225                        .validator(validate_type::<u64>())
226                        .default(1),
227                ),
228            )
229            .option(
230                CommandOption::new("color")
231                    .alias("c")
232                    .arg(Argument::with_name("color").valid_values(&["red", "blue", "green"])),
233            );
234
235        let result = parse_with("--repeat 2 -c red hello world!", command.clone()).unwrap();
236        assert!(result.options().contains("repeat"));
237        assert!(result.options().contains("r"));
238        assert!(result.options().contains("color"));
239        assert!(result.options().contains("c"));
240        assert_eq!(
241            result
242                .options()
243                .get("repeat")
244                .unwrap()
245                .get_arg()
246                .unwrap()
247                .convert::<u64>()
248                .ok(),
249            Some(2)
250        );
251        assert!(result
252            .options()
253            .get("color")
254            .unwrap()
255            .get_arg()
256            .unwrap()
257            .contains("red"));
258        assert_eq!(result.arg().unwrap().get_values(), &["hello", "world!"]);
259
260        // Whitespace test
261        assert!(parse_with("\" \"", command.clone())
262            .unwrap()
263            .arg()
264            .unwrap()
265            .contains(" "));
266
267        // Ok
268        assert!(parse_with("Hola Mundo!", command.clone()).is_ok());
269        assert!(parse_with("--repeat 10 Hola Mundo!", command.clone()).is_ok());
270        assert!(parse_with("--color green Hola Mundo!", command.clone()).is_ok());
271        assert!(parse_with("-c blue -- Hola Mundo!", command.clone()).is_ok());
272        assert!(parse_with("\" \"", command.clone()).is_ok());
273
274        // Err
275        assert!(parse_with("--repeat -2 Hola Mundo!", command.clone()).is_err());
276        assert!(parse_with("", command.clone()).is_err());
277        assert!(parse_with("--repeat 2 -c:red", command.clone()).is_err());
278        assert!(parse_with("-r a Hello World", command.clone()).is_err());
279        assert!(parse_with("-c yellow Hello World", command.clone()).is_err());
280    }
281
282    #[test]
283    fn parse_result_subcommand_test() {
284        let command = Command::new("MyApp")
285            .subcommand(Command::new("version"))
286            .subcommand(
287                Command::new("set")
288                    .arg(Argument::one_or_more("value"))
289                    .option(CommandOption::new("repeat").arg(Argument::with_name("count"))),
290            )
291            .subcommand(Command::new("get"));
292
293        let result = parse_with("set --repeat 1 1 2 3 4", command.clone()).unwrap();
294        assert_eq!(result.executing_command().get_name(), "set");
295        assert!(result
296            .options()
297            .get("repeat")
298            .unwrap()
299            .get_arg()
300            .unwrap()
301            .contains("1"));
302        assert_eq!(
303            result.arg().unwrap().get_values(),
304            &[
305                "1".to_owned(),
306                "2".to_owned(),
307                "3".to_owned(),
308                "4".to_owned()
309            ]
310        );
311
312        // Ok
313        assert!(parse_with("version", command.clone()).is_ok());
314        assert!(parse_with("set 1 2 3", command.clone()).is_ok());
315        assert!(parse_with("get", command.clone()).is_ok());
316        assert!(parse_with("", command.clone()).is_ok());
317
318        // Err
319        assert!(parse_with("Hello", command.clone()).is_err());
320        assert!(parse_with("version hello", command.clone()).is_err());
321        assert!(parse_with("version set 1 2 3", command.clone()).is_err());
322        assert!(parse_with("version hello", command.clone()).is_err());
323    }
324
325    #[test]
326    fn parse_result_required_option_test() {
327        let command = Command::new("MyApp")
328            .option(CommandOption::new("enable"))
329            .option(
330                CommandOption::new("times")
331                    .alias("t")
332                    .required(true)
333                    .arg(Argument::with_name("times").validator(validate_type::<u64>())),
334            )
335            .arg(Argument::zero_or_more("values"));
336
337        let result = parse_with("--times 1 -- one two three", command.clone()).unwrap();
338        assert!(result.options().contains("times"));
339        assert!(result
340            .options()
341            .get("times")
342            .unwrap()
343            .get_arg()
344            .unwrap()
345            .contains("1"));
346        assert!(result.arg().unwrap().contains("one"));
347        assert!(result.arg().unwrap().contains("two"));
348        assert!(result.arg().unwrap().contains("three"));
349
350        // Ok
351        assert!(parse_with("--times 1", command.clone()).is_ok());
352        assert!(parse_with("--times 1 1 2 3", command.clone()).is_ok());
353        assert!(parse_with("--times 1 --enable", command.clone()).is_ok());
354
355        // This is `Ok` because `--enable` takes not arguments
356        // so the value `false` is passed as command argument
357        assert!(parse_with("--times 1 --enable false", command.clone()).is_ok());
358
359        // Err
360
361        // Unlike above here is an error due `false` is being passed to `--enable` as argument
362        // but it takes not arguments
363        // Any tokens before `--` are considered arguments to the previous option
364        // and the values following `--` are considered arguments to the command
365        assert!(parse_with("--times 1 --enable false --", command.clone()).is_err());
366
367        assert!(parse_with(" ", command.clone()).is_err());
368        assert!(parse_with("--times", command.clone()).is_err());
369    }
370
371    #[test]
372    fn parse_result_options_test() {
373        let command = Command::new("MyApp")
374            .option(CommandOption::new("hour").alias("h"))
375            .option(CommandOption::new("minute").alias("m"))
376            .option(CommandOption::new("second").alias("s"))
377            .option(
378                CommandOption::new("enable").arg(
379                    Argument::with_name("value")
380                        .validator(validate_type::<bool>())
381                        .values_count(0..=1),
382                ),
383            );
384
385        let result = parse_with("--hour -m -s --enable false", command.clone()).unwrap();
386        assert_eq!(result.args().len(), 0);
387        assert!(result.options().contains("hour"));
388        assert!(result.options().contains("minute"));
389        assert!(result.options().contains("second"));
390        assert!(result
391            .options()
392            .get("enable")
393            .unwrap()
394            .get_arg()
395            .unwrap()
396            .contains("false"));
397    }
398
399    #[test]
400    fn parse_result_multiple_args_test() {
401        let command = Command::new("MyApp")
402            .arg(Argument::with_name("min").validator(validate_type::<i64>()))
403            .arg(Argument::with_name("max").validator(validate_type::<i64>()))
404            .option(
405                CommandOption::new("replace")
406                    .alias("r")
407                    .arg(Argument::with_name("from"))
408                    .arg(Argument::with_name("to")),
409            );
410
411        let result = parse_with("--replace a A -- 2 10", command.clone()).unwrap();
412        assert!(result
413            .options()
414            .get("replace")
415            .unwrap()
416            .get_args()
417            .get("from")
418            .unwrap()
419            .contains("a"));
420        assert!(result
421            .options()
422            .get("replace")
423            .unwrap()
424            .get_args()
425            .get("to")
426            .unwrap()
427            .contains("A"));
428        assert_eq!(
429            result.args().get("min").unwrap().convert::<i64>().ok(),
430            Some(2)
431        );
432        assert_eq!(
433            result.args().get("max").unwrap().convert::<i64>().ok(),
434            Some(10)
435        );
436
437        // Ok
438        assert!(parse_with("2 10", command.clone()).is_ok());
439
440        // Err
441        assert!(parse_with("--replace hello HELLO", command.clone()).is_err());
442        assert!(parse_with("25", command.clone()).is_err());
443    }
444
445    #[test]
446    fn parse_result_eoa_test() {
447        let command = Command::new("MyApp")
448            .arg(Argument::one_or_more("args"))
449            .option(CommandOption::new("A").alias("a"))
450            .option(CommandOption::new("B").alias("b"))
451            .option(CommandOption::new("C").alias("c"))
452            .option(
453                CommandOption::new("D")
454                    .alias("d")
455                    .arg(Argument::one_or_more("d")),
456            );
457
458        let result1 = parse_with("--A --B -- --C", command.clone()).unwrap();
459        assert_eq!(result1.options().len(), 2);
460        assert_eq!(result1.arg().unwrap().get_values().len(), 1);
461        assert!(result1.options().contains("A"));
462        assert!(result1.options().contains("B"));
463        assert!(result1.arg().unwrap().contains("--C"));
464
465        let result2 = parse_with("-- --A -b --C", command.clone()).unwrap();
466        assert_eq!(result2.options().len(), 0);
467        assert_eq!(result2.arg().unwrap().get_values().len(), 3);
468        assert!(result2.arg().unwrap().contains("--A"));
469        assert!(result2.arg().unwrap().contains("-b"));
470        assert!(result2.arg().unwrap().contains("--C"));
471
472        let result3 = parse_with("-- -- -a -b -c", command.clone()).unwrap();
473        assert_eq!(result3.options().len(), 0);
474        assert_eq!(result3.arg().unwrap().get_values().len(), 4);
475        assert!(result3.arg().unwrap().contains("--"));
476        assert!(result3.arg().unwrap().contains("-a"));
477        assert!(result3.arg().unwrap().contains("-b"));
478        assert!(result3.arg().unwrap().contains("-c"));
479
480        let result4 = parse_with("--D 1 2 3 -- hello world", command.clone()).unwrap();
481        assert_eq!(result4.options().len(), 1);
482        assert!(result4.options().get_arg("D").unwrap().contains("1"));
483        assert!(result4.options().get_arg("D").unwrap().contains("2"));
484        assert!(result4.options().get_arg("D").unwrap().contains("3"));
485        assert!(result4.arg().unwrap().contains("hello"));
486        assert!(result4.arg().unwrap().contains("world"));
487
488        let result5 = parse_with("1 2 3 -- hello world", command.clone());
489        assert!(result5.is_err());
490    }
491
492    #[test]
493    fn parse_result_variable_arg_count_test1() {
494        let command = Command::new("MyApp")
495            .arg(Argument::with_name("values").values_count(0..=3))
496            .option(
497                CommandOption::new("letters").arg(
498                    Argument::with_name("letters")
499                        .values_count(1..)
500                        .validator(validate_type::<char>()),
501                ),
502            )
503            .option(
504                CommandOption::new("numbers").arg(
505                    Argument::with_name("numbers")
506                        .values_count(1..=2)
507                        .validator(validate_type::<i64>()),
508                ),
509            );
510
511        let result = parse_with(
512            "--letters a b c d e --numbers 1 -- one two three",
513            command.clone(),
514        )
515        .unwrap();
516
517        assert_eq!(
518            result
519                .options()
520                .get("letters")
521                .unwrap()
522                .get_arg()
523                .unwrap()
524                .get_values()
525                .len(),
526            5
527        );
528        assert!(result
529            .options()
530            .get("letters")
531            .unwrap()
532            .get_arg()
533            .unwrap()
534            .contains("a"));
535        assert!(result
536            .options()
537            .get("letters")
538            .unwrap()
539            .get_arg()
540            .unwrap()
541            .contains("b"));
542        assert!(result
543            .options()
544            .get("letters")
545            .unwrap()
546            .get_arg()
547            .unwrap()
548            .contains("c"));
549        assert!(result
550            .options()
551            .get("letters")
552            .unwrap()
553            .get_arg()
554            .unwrap()
555            .contains("d"));
556        assert!(result
557            .options()
558            .get("letters")
559            .unwrap()
560            .get_arg()
561            .unwrap()
562            .contains("e"));
563        assert!(result
564            .options()
565            .get("numbers")
566            .unwrap()
567            .get_arg()
568            .unwrap()
569            .contains("1"));
570        assert!(result.arg().unwrap().contains("one"));
571        assert!(result.arg().unwrap().contains("two"));
572        assert!(result.arg().unwrap().contains("three"));
573
574        // --numbers only accepts 2 arguments but was 3
575        assert_eq!(
576            parse_with(
577                "--letters a b c d e --numbers 1 2 3 -- one two three",
578                command.clone()
579            )
580            .err()
581            .unwrap()
582            .kind(),
583            &ErrorKind::InvalidArgumentCount
584        );
585    }
586
587    #[test]
588    fn parse_result_error_kind_test() {
589        let command = Command::new("MyApp")
590            .arg(Argument::with_name("values").values_count(0..5))
591            .subcommand(Command::new("version"))
592            .option(
593                CommandOption::new("range")
594                    .alias("r")
595                    .arg(Argument::with_name("min").validator(validate_type::<i64>()))
596                    .arg(Argument::with_name("max").validator(validate_type::<i64>())),
597            )
598            .option(CommandOption::new("A").alias("a"))
599            .option(CommandOption::new("B").alias("b"))
600            .subcommand(
601                Command::new("read").option(
602                    CommandOption::new("mode")
603                        .required(true)
604                        .arg(Argument::with_name("mode").valid_values(&["low", "mid", "high"])),
605                ),
606            )
607            .subcommand(
608                Command::new("data")
609                    .subcommand(Command::new("set").arg(Argument::with_name("value")))
610                    .subcommand(Command::new("get")),
611            );
612
613        let err_kind = move |value: &str| -> ErrorKind {
614            parse_with(value, command.clone())
615                .err()
616                .unwrap_or_else(|| panic!("{}", value))
617                .kind()
618                .clone()
619        };
620
621        assert!(matches!(
622            err_kind("version 1 2 3"),
623            ErrorKind::InvalidArgumentCount
624        ));
625        assert!(matches!(
626            err_kind("-- 1 2 3 4 5"),
627            ErrorKind::InvalidArgumentCount
628        ));
629        assert!(matches!(
630            err_kind("--range 0"),
631            ErrorKind::InvalidArgumentCount
632        ));
633        assert!(matches!(
634            err_kind("--range 1 2 3 -- "),
635            ErrorKind::InvalidArgumentCount
636        ));
637        assert!(matches!(err_kind("-r=0=1"), ErrorKind::InvalidExpression));
638        assert!(
639            matches!(err_kind("--range 10 b"), ErrorKind::InvalidArgument(arg) if arg == "max")
640        );
641        assert!(matches!(err_kind("--C"), ErrorKind::UnexpectedOption(o) if o == "--C"));
642        assert!(matches!(err_kind("data write"), ErrorKind::UnexpectedCommand(x) if x == "write"));
643        assert!(matches!(err_kind("read"), ErrorKind::MissingOption(x) if x == "mode"));
644        assert!(
645            matches!(err_kind("read --mode lo"), ErrorKind::InvalidArgument(arg) if arg == "mode")
646        );
647        assert!(matches!(
648            err_kind("read --mode low mid"),
649            ErrorKind::InvalidArgumentCount
650        ));
651        assert!(matches!(err_kind("data clear"), ErrorKind::UnexpectedCommand(x) if x == "clear"));
652        assert!(matches!(
653            err_kind("data get 0"),
654            ErrorKind::InvalidArgumentCount
655        ));
656        assert!(matches!(
657            err_kind("data set \"Hello World\" Bye"),
658            ErrorKind::InvalidArgumentCount
659        ));
660    }
661
662    #[test]
663    fn parse_result_option_bool_flag_test() {
664        let command = Command::new("MyApp").option(
665            CommandOption::new("enable").arg(
666                Argument::with_name("enable")
667                    .values_count(0..=1)
668                    .validator(validate_type::<bool>()),
669            ),
670        );
671
672        let res1 = parse_with("--enable true", command.clone()).unwrap();
673        assert_eq!(
674            res1.options()
675                .get("enable")
676                .unwrap()
677                .get_arg()
678                .unwrap()
679                .get_values()[0],
680            "true".to_owned()
681        );
682
683        let res2 = parse_with("--enable false", command.clone()).unwrap();
684        assert_eq!(
685            res2.options()
686                .get("enable")
687                .unwrap()
688                .get_arg()
689                .unwrap()
690                .get_values()[0],
691            "false".to_owned()
692        );
693
694        let res3 = parse_with("--enable", command.clone()).unwrap();
695        assert!(res3.options().contains("enable"));
696
697        let res4 = parse_with("", command.clone()).unwrap();
698        assert!(!res4.options().contains("enable"));
699    }
700
701    #[test]
702    fn parse_result_arg_default_values_test1() {
703        let command = Command::new("MyApp")
704            .arg(Argument::with_name("min").default(1))
705            .arg(Argument::with_name("max"));
706
707        let result1 = parse_with("10", command.clone()).unwrap();
708        assert!(result1.args.get("min").unwrap().contains("1"));
709        assert!(result1.args.get("max").unwrap().contains("10"));
710
711        let result2 = parse_with("5 12", command.clone()).unwrap();
712        assert!(result2.args.get("min").unwrap().contains("5"));
713        assert!(result2.args.get("max").unwrap().contains("12"));
714    }
715
716    #[test]
717    #[should_panic]
718    fn parse_result_arg_default_values_test2() {
719        let _command = Command::new("MyApp")
720            .arg(Argument::with_name("min").default(1))
721            .arg(Argument::with_name("max").default(10));
722    }
723
724    #[test]
725    fn parse_result_option_default_values_test1() {
726        let command = Command::new("MyApp").option(
727            CommandOption::new("range")
728                .arg(Argument::with_name("start").default(1))
729                .arg(Argument::with_name("end")),
730        );
731
732        let result1 = parse_with("--range 22", command.clone()).unwrap();
733        assert!(result1
734            .options()
735            .get_args("range")
736            .unwrap()
737            .get("start")
738            .unwrap()
739            .contains("1"));
740        assert!(result1
741            .options()
742            .get_args("range")
743            .unwrap()
744            .get("end")
745            .unwrap()
746            .contains("22"));
747
748        let result2 = parse_with("--range 10 25", command.clone()).unwrap();
749        assert!(result2
750            .options()
751            .get_args("range")
752            .unwrap()
753            .get("start")
754            .unwrap()
755            .contains("10"));
756        assert!(result2
757            .options()
758            .get_args("range")
759            .unwrap()
760            .get("end")
761            .unwrap()
762            .contains("25"));
763    }
764
765    #[test]
766    #[should_panic]
767    fn parse_result_option_default_values_test2() {
768        let _command = Command::new("MyApp").option(
769            CommandOption::new("range")
770                .arg(Argument::with_name("start").default(1))
771                .arg(Argument::with_name("end").default(20)),
772        );
773    }
774
775    #[test]
776    fn parse_result_allow_multiple_test() {
777        let command = Command::new("MyApp").option(
778            CommandOption::new("values")
779                .multiple(true)
780                .arg(Argument::one_or_more("values")),
781        );
782
783        let result1 = parse_with("--values 5 6", command.clone()).unwrap();
784        assert!(result1.options().get_arg("values").unwrap().contains("5"));
785        assert!(result1.options().get_arg("values").unwrap().contains("6"));
786
787        let result2 = parse_with("--values 1 2 --values 3 4", command.clone()).unwrap();
788        assert!(result2.options().get_arg("values").unwrap().contains("1"));
789        assert!(result2.options().get_arg("values").unwrap().contains("2"));
790        assert!(result2.options().get_arg("values").unwrap().contains("3"));
791        assert!(result2.options().get_arg("values").unwrap().contains("4"));
792    }
793
794    #[test]
795    fn parse_global_option_test() {
796        let command = Command::new("MyApp")
797            .option(
798                CommandOption::new("color")
799                    .global(true)
800                    .arg(Argument::new().valid_values(vec!["red", "green", "blue"])),
801            )
802            .subcommand(Command::new("echo").arg(Argument::one_or_more("values")));
803
804        let result = parse_with("echo --color red -- hello world", command.clone()).unwrap();
805        assert_eq!(result.command_name(), "echo");
806        assert!(result.options().get_arg("color").unwrap().contains("red"));
807        assert!(result.args().get("values").unwrap().contains("hello"));
808        assert!(result.args().get("values").unwrap().contains("world"));
809    }
810
811    #[test]
812    fn parse_required_global_option_test() {
813        let command = Command::new("MyApp")
814            .option(CommandOption::new("flag").required(true).global(true))
815            .subcommand(Command::new("echo").arg(Argument::one_or_more("values")));
816
817        let result = parse_with("echo hello world", command.clone());
818        assert!(result.is_err());
819        assert_eq!(
820            result.unwrap_err().kind(),
821            &ErrorKind::MissingOption("flag".to_owned())
822        );
823
824        assert!(parse_with("echo --flag hello world", command.clone()).is_ok())
825    }
826
827    #[test]
828    fn value_of_test() {
829        let command = Command::new("MyApp").arg(Argument::with_name("color"));
830
831        let result = parse_with("red", command.clone()).unwrap();
832        assert_eq!("red", result.value_of("color").unwrap());
833    }
834
835    #[test]
836    fn values_of_test() {
837        let command = Command::new("MyApp").arg(Argument::one_or_more("colors"));
838
839        let result = parse_with("red blue green", command.clone()).unwrap();
840        assert_eq!(
841            vec!["red".to_owned(), "blue".to_owned(), "green".to_owned()],
842            result
843                .values_of("colors")
844                .unwrap()
845                .iter()
846                .cloned()
847                .collect::<Vec<String>>()
848        );
849    }
850
851    #[test]
852    fn value_of_option_test() {
853        let command = Command::new("MyApp")
854            .option(CommandOption::new("size").arg(Argument::with_name("size")));
855
856        let result = parse_with("--size sm", command.clone()).unwrap();
857        assert_eq!("sm", result.value_of_option("size").unwrap());
858    }
859
860    #[test]
861    fn values_of_option_test() {
862        let command = Command::new("MyApp")
863            .option(CommandOption::new("sizes").arg(Argument::one_or_more("sizes")));
864
865        let result = parse_with("--sizes sm md lg", command.clone()).unwrap();
866        assert_eq!(
867            vec!["sm".to_owned(), "md".to_owned(), "lg".to_owned()],
868            result
869                .values_of_option("sizes")
870                .unwrap()
871                .iter()
872                .cloned()
873                .collect::<Vec<String>>()
874        );
875    }
876
877    #[test]
878    fn value_of_as_test() {
879        let command = Command::new("MyApp").arg(Argument::with_name("numbers"));
880        let result = parse_with("65", command.clone()).unwrap();
881
882        assert_eq!(65, result.value_of_as::<i32>("numbers").unwrap());
883    }
884
885    #[test]
886    fn values_of_as_test() {
887        let command = Command::new("MyApp").arg(Argument::one_or_more("numbers"));
888        let result = parse_with("2 4 6", command.clone()).unwrap();
889
890        assert_eq!(
891            vec![2_i32, 4_i32, 6_i32],
892            result
893                .values_of_as::<i32>("numbers")
894                .unwrap()
895                .iter()
896                .cloned()
897                .collect::<Vec<i32>>()
898        );
899    }
900
901    #[test]
902    fn value_of_option_as_test() {
903        let command = Command::new("MyApp")
904            .option(CommandOption::new("size").arg(Argument::with_name("size")));
905        let result = parse_with("--size 202", command.clone()).unwrap();
906
907        assert_eq!(202_i64, result.value_of_option_as::<i64>("size").unwrap());
908    }
909
910    #[test]
911    fn values_of_option_as_test() {
912        let command = Command::new("MyApp")
913            .option(CommandOption::new("sizes").arg(Argument::one_or_more("sizes")));
914        let result = parse_with("--sizes 202 304", command.clone()).unwrap();
915
916        assert_eq!(
917            vec![202_i64, 304_i64],
918            result
919                .values_of_option_as::<i64>("sizes")
920                .unwrap()
921                .iter()
922                .cloned()
923                .collect::<Vec<i64>>()
924        );
925    }
926}