• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::ffi::OsString;
2 
3 use super::utils;
4 
5 use clap::{arg, error::ErrorKind, Arg, ArgAction, Command};
6 
7 static ALLOW_EXT_SC: &str = "\
8 Usage: clap-test [COMMAND]
9 
10 Options:
11   -h, --help     Print help
12   -V, --version  Print version
13 ";
14 
15 static DONT_COLLAPSE_ARGS: &str = "\
16 Usage: clap-test [arg1] [arg2] [arg3]
17 
18 Arguments:
19   [arg1]  some
20   [arg2]  some
21   [arg3]  some
22 
23 Options:
24   -h, --help     Print help
25   -V, --version  Print version
26 ";
27 
28 #[test]
sub_command_negate_required()29 fn sub_command_negate_required() {
30     Command::new("sub_command_negate")
31         .subcommand_negates_reqs(true)
32         .arg(Arg::new("test").required(true).index(1))
33         .subcommand(Command::new("sub1"))
34         .try_get_matches_from(vec!["myprog", "sub1"])
35         .unwrap();
36 }
37 
38 #[test]
sub_command_negate_required_2()39 fn sub_command_negate_required_2() {
40     let result = Command::new("sub_command_negate")
41         .subcommand_negates_reqs(true)
42         .arg(Arg::new("test").required(true).index(1))
43         .subcommand(Command::new("sub1"))
44         .try_get_matches_from(vec![""]);
45     assert!(result.is_err());
46     let err = result.err().unwrap();
47     assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
48 }
49 
50 #[test]
sub_command_required()51 fn sub_command_required() {
52     let result = Command::new("sc_required")
53         .subcommand_required(true)
54         .subcommand(Command::new("sub1"))
55         .try_get_matches_from(vec![""]);
56     assert!(result.is_err());
57     let err = result.err().unwrap();
58     assert_eq!(err.kind(), ErrorKind::MissingSubcommand);
59 }
60 
61 #[test]
62 #[cfg(feature = "error-context")]
sub_command_required_error()63 fn sub_command_required_error() {
64     static ERROR: &str = "\
65 error: 'sc_required' requires a subcommand but one was not provided
66   [subcommands: sub1, help]
67 
68 Usage: sc_required <COMMAND>
69 
70 For more information, try '--help'.
71 ";
72 
73     let cmd = Command::new("sc_required")
74         .subcommand_required(true)
75         .subcommand(Command::new("sub1"));
76     utils::assert_output(cmd, "sc_required", ERROR, true);
77 }
78 
79 #[test]
arg_required_else_help()80 fn arg_required_else_help() {
81     let result = Command::new("arg_required")
82         .arg_required_else_help(true)
83         .arg(Arg::new("test").index(1))
84         .try_get_matches_from(vec![""]);
85 
86     assert!(result.is_err());
87     let err = result.err().unwrap();
88     assert_eq!(
89         err.kind(),
90         ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
91     );
92 }
93 
94 #[test]
arg_required_else_help_over_req_arg()95 fn arg_required_else_help_over_req_arg() {
96     let result = Command::new("arg_required")
97         .arg_required_else_help(true)
98         .arg(Arg::new("test").index(1).required(true))
99         .try_get_matches_from(vec![""]);
100 
101     assert!(result.is_err());
102     let err = result.err().unwrap();
103     assert_eq!(
104         err.kind(),
105         ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
106     );
107 }
108 
109 #[test]
arg_required_else_help_over_req_subcommand()110 fn arg_required_else_help_over_req_subcommand() {
111     let result = Command::new("sub_required")
112         .arg_required_else_help(true)
113         .subcommand_required(true)
114         .subcommand(Command::new("sub1"))
115         .try_get_matches_from(vec![""]);
116 
117     assert!(result.is_err());
118     let err = result.err().unwrap();
119     assert_eq!(
120         err.kind(),
121         ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
122     );
123 }
124 
125 #[test]
arg_required_else_help_with_default()126 fn arg_required_else_help_with_default() {
127     let result = Command::new("arg_required")
128         .arg_required_else_help(true)
129         .arg(arg!(--input <PATH>).default_value("-"))
130         .try_get_matches_from(vec![""]);
131 
132     assert!(result.is_err());
133     let err = result.err().unwrap();
134     assert_eq!(
135         err.kind(),
136         ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
137     );
138 }
139 
140 #[test]
arg_required_else_help_error_message()141 fn arg_required_else_help_error_message() {
142     static ARG_REQUIRED_ELSE_HELP: &str = "\
143 Usage: test [OPTIONS]
144 
145 Options:
146   -i, --info     Provides more info
147   -h, --help     Print help
148   -V, --version  Print version
149 ";
150 
151     let cmd = Command::new("test")
152         .arg_required_else_help(true)
153         .version("1.0")
154         .arg(
155             Arg::new("info")
156                 .help("Provides more info")
157                 .short('i')
158                 .long("info")
159                 .action(ArgAction::SetTrue),
160         );
161     utils::assert_output(
162         cmd,
163         "test",
164         ARG_REQUIRED_ELSE_HELP,
165         true, // Unlike normal displaying of help, we should provide a fatal exit code
166     );
167 }
168 
169 #[cfg(not(feature = "suggestions"))]
170 #[test]
infer_subcommands_fail_no_args()171 fn infer_subcommands_fail_no_args() {
172     let m = Command::new("prog")
173         .infer_subcommands(true)
174         .subcommand(Command::new("test"))
175         .subcommand(Command::new("temp"))
176         .try_get_matches_from(vec!["prog", "te"]);
177     assert!(m.is_err(), "{:#?}", m.unwrap());
178     assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
179 }
180 
181 #[cfg(feature = "suggestions")]
182 #[test]
infer_subcommands_fail_no_args()183 fn infer_subcommands_fail_no_args() {
184     let m = Command::new("prog")
185         .infer_subcommands(true)
186         .subcommand(Command::new("test"))
187         .subcommand(Command::new("temp"))
188         .try_get_matches_from(vec!["prog", "te"]);
189     assert!(m.is_err(), "{:#?}", m.unwrap());
190     assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
191 }
192 
193 #[test]
infer_subcommands_fail_with_args()194 fn infer_subcommands_fail_with_args() {
195     let m = Command::new("prog")
196         .infer_subcommands(true)
197         .arg(Arg::new("some"))
198         .subcommand(Command::new("test"))
199         .subcommand(Command::new("temp"))
200         .try_get_matches_from(vec!["prog", "t"]);
201     assert!(m.is_ok(), "{:?}", m.unwrap_err().kind());
202     assert_eq!(
203         m.unwrap().get_one::<String>("some").map(|v| v.as_str()),
204         Some("t")
205     );
206 }
207 
208 #[test]
infer_subcommands_fail_with_args2()209 fn infer_subcommands_fail_with_args2() {
210     let m = Command::new("prog")
211         .infer_subcommands(true)
212         .arg(Arg::new("some"))
213         .subcommand(Command::new("test"))
214         .subcommand(Command::new("temp"))
215         .try_get_matches_from(vec!["prog", "te"]);
216     assert!(m.is_ok(), "{:?}", m.unwrap_err().kind());
217     assert_eq!(
218         m.unwrap().get_one::<String>("some").map(|v| v.as_str()),
219         Some("te")
220     );
221 }
222 
223 #[test]
infer_subcommands_pass()224 fn infer_subcommands_pass() {
225     let m = Command::new("prog")
226         .infer_subcommands(true)
227         .subcommand(Command::new("test"))
228         .try_get_matches_from(vec!["prog", "te"])
229         .unwrap();
230     assert_eq!(m.subcommand_name(), Some("test"));
231 }
232 
233 #[test]
infer_subcommands_pass_close()234 fn infer_subcommands_pass_close() {
235     let m = Command::new("prog")
236         .infer_subcommands(true)
237         .subcommand(Command::new("test"))
238         .subcommand(Command::new("temp"))
239         .try_get_matches_from(vec!["prog", "tes"])
240         .unwrap();
241     assert_eq!(m.subcommand_name(), Some("test"));
242 }
243 
244 #[test]
infer_subcommands_pass_exact_match()245 fn infer_subcommands_pass_exact_match() {
246     let m = Command::new("prog")
247         .infer_subcommands(true)
248         .subcommand(Command::new("test"))
249         .subcommand(Command::new("testa"))
250         .subcommand(Command::new("testb"))
251         .try_get_matches_from(vec!["prog", "test"])
252         .unwrap();
253     assert_eq!(m.subcommand_name(), Some("test"));
254 }
255 
256 #[cfg(feature = "suggestions")]
257 #[test]
infer_subcommands_fail_suggestions()258 fn infer_subcommands_fail_suggestions() {
259     let m = Command::new("prog")
260         .infer_subcommands(true)
261         .subcommand(Command::new("test"))
262         .subcommand(Command::new("temp"))
263         .try_get_matches_from(vec!["prog", "temps"]);
264     assert!(m.is_err(), "{:#?}", m.unwrap());
265     assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
266 }
267 
268 #[cfg(not(feature = "suggestions"))]
269 #[test]
infer_subcommands_fail_suggestions()270 fn infer_subcommands_fail_suggestions() {
271     let m = Command::new("prog")
272         .infer_subcommands(true)
273         .subcommand(Command::new("test"))
274         .subcommand(Command::new("temp"))
275         .try_get_matches_from(vec!["prog", "temps"]);
276     assert!(m.is_err(), "{:#?}", m.unwrap());
277     assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
278 }
279 
280 #[test]
no_bin_name()281 fn no_bin_name() {
282     let result = Command::new("arg_required")
283         .no_binary_name(true)
284         .arg(Arg::new("test").required(true).index(1))
285         .try_get_matches_from(vec!["testing"]);
286     assert!(result.is_ok(), "{}", result.unwrap_err());
287     let matches = result.unwrap();
288     assert_eq!(
289         matches
290             .get_one::<String>("test")
291             .map(|v| v.as_str())
292             .unwrap(),
293         "testing"
294     );
295 }
296 
297 #[test]
skip_possible_values()298 fn skip_possible_values() {
299     static SKIP_POS_VALS: &str = "\
300 tests stuff
301 
302 Usage: test [OPTIONS] [arg1]
303 
304 Arguments:
305   [arg1]  some pos arg
306 
307 Options:
308   -o, --opt <opt>  some option
309   -h, --help       Print help
310   -V, --version    Print version
311 ";
312 
313     let cmd = Command::new("test")
314         .author("Kevin K.")
315         .about("tests stuff")
316         .version("1.3")
317         .hide_possible_values(true)
318         .args([
319             arg!(-o --opt <opt> "some option").value_parser(["one", "two"]),
320             arg!([arg1] "some pos arg").value_parser(["three", "four"]),
321         ]);
322 
323     utils::assert_output(cmd, "test --help", SKIP_POS_VALS, false);
324 }
325 
326 #[test]
stop_delim_values_only_pos_follows()327 fn stop_delim_values_only_pos_follows() {
328     let r = Command::new("onlypos")
329         .dont_delimit_trailing_values(true)
330         .args([arg!(f: -f <flag> "some opt"), arg!([arg] ... "some arg")])
331         .try_get_matches_from(vec!["", "--", "-f", "-g,x"]);
332     assert!(r.is_ok(), "{}", r.unwrap_err());
333     let m = r.unwrap();
334     assert!(m.contains_id("arg"));
335     assert!(!m.contains_id("f"));
336     assert_eq!(
337         m.get_many::<String>("arg")
338             .unwrap()
339             .map(|v| v.as_str())
340             .collect::<Vec<_>>(),
341         ["-f", "-g,x"]
342     );
343 }
344 
345 #[test]
dont_delim_values_trailingvararg()346 fn dont_delim_values_trailingvararg() {
347     let m = Command::new("positional")
348         .dont_delimit_trailing_values(true)
349         .arg(arg!([opt] ... "some pos").trailing_var_arg(true))
350         .try_get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"])
351         .unwrap();
352     assert!(m.contains_id("opt"));
353     assert_eq!(
354         m.get_many::<String>("opt")
355             .unwrap()
356             .map(|v| v.as_str())
357             .collect::<Vec<_>>(),
358         ["test", "--foo", "-Wl,-bar"]
359     );
360 }
361 
362 #[test]
delim_values_only_pos_follows()363 fn delim_values_only_pos_follows() {
364     let r = Command::new("onlypos")
365         .args([arg!(f: -f [flag] "some opt"), arg!([arg] ... "some arg")])
366         .try_get_matches_from(vec!["", "--", "-f", "-g,x"]);
367     assert!(r.is_ok(), "{}", r.unwrap_err());
368     let m = r.unwrap();
369     assert!(m.contains_id("arg"));
370     assert!(!m.contains_id("f"));
371     assert_eq!(
372         m.get_many::<String>("arg")
373             .unwrap()
374             .map(|v| v.as_str())
375             .collect::<Vec<_>>(),
376         ["-f", "-g,x"]
377     );
378 }
379 
380 #[test]
delim_values_trailingvararg()381 fn delim_values_trailingvararg() {
382     let m = Command::new("positional")
383         .arg(arg!([opt] ... "some pos").trailing_var_arg(true))
384         .try_get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"])
385         .unwrap();
386     assert!(m.contains_id("opt"));
387     assert_eq!(
388         m.get_many::<String>("opt")
389             .unwrap()
390             .map(|v| v.as_str())
391             .collect::<Vec<_>>(),
392         ["test", "--foo", "-Wl,-bar"]
393     );
394 }
395 
396 #[test]
delim_values_only_pos_follows_with_delim()397 fn delim_values_only_pos_follows_with_delim() {
398     let r = Command::new("onlypos")
399         .args([
400             arg!(f: -f [flag] "some opt"),
401             arg!([arg] ... "some arg").value_delimiter(','),
402         ])
403         .try_get_matches_from(vec!["", "--", "-f", "-g,x"]);
404     assert!(r.is_ok(), "{}", r.unwrap_err());
405     let m = r.unwrap();
406     assert!(m.contains_id("arg"));
407     assert!(!m.contains_id("f"));
408     assert_eq!(
409         m.get_many::<String>("arg")
410             .unwrap()
411             .map(|v| v.as_str())
412             .collect::<Vec<_>>(),
413         ["-f", "-g", "x"]
414     );
415 }
416 
417 #[test]
delim_values_trailingvararg_with_delim()418 fn delim_values_trailingvararg_with_delim() {
419     let m = Command::new("positional")
420         .arg(
421             arg!([opt] ... "some pos")
422                 .value_delimiter(',')
423                 .trailing_var_arg(true),
424         )
425         .try_get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"])
426         .unwrap();
427     assert!(m.contains_id("opt"));
428     assert_eq!(
429         m.get_many::<String>("opt")
430             .unwrap()
431             .map(|v| v.as_str())
432             .collect::<Vec<_>>(),
433         ["test", "--foo", "-Wl", "-bar"]
434     );
435 }
436 
437 #[test]
leading_hyphen_short()438 fn leading_hyphen_short() {
439     let res = Command::new("leadhy")
440         .arg(Arg::new("some").allow_hyphen_values(true))
441         .arg(Arg::new("other").short('o').action(ArgAction::SetTrue))
442         .try_get_matches_from(vec!["", "-bar", "-o"]);
443     assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind());
444     let m = res.unwrap();
445     assert!(m.contains_id("some"));
446     assert!(m.contains_id("other"));
447     assert_eq!(
448         m.get_one::<String>("some").map(|v| v.as_str()).unwrap(),
449         "-bar"
450     );
451     assert_eq!(
452         *m.get_one::<bool>("other").expect("defaulted by clap"),
453         true
454     );
455 }
456 
457 #[test]
leading_hyphen_long()458 fn leading_hyphen_long() {
459     let res = Command::new("leadhy")
460         .arg(Arg::new("some").allow_hyphen_values(true))
461         .arg(Arg::new("other").short('o').action(ArgAction::SetTrue))
462         .try_get_matches_from(vec!["", "--bar", "-o"]);
463     assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind());
464     let m = res.unwrap();
465     assert!(m.contains_id("some"));
466     assert!(m.contains_id("other"));
467     assert_eq!(
468         m.get_one::<String>("some").map(|v| v.as_str()).unwrap(),
469         "--bar"
470     );
471     assert_eq!(
472         *m.get_one::<bool>("other").expect("defaulted by clap"),
473         true
474     );
475 }
476 
477 #[test]
leading_hyphen_opt()478 fn leading_hyphen_opt() {
479     let res = Command::new("leadhy")
480         .arg(
481             Arg::new("some")
482                 .action(ArgAction::Set)
483                 .long("opt")
484                 .allow_hyphen_values(true),
485         )
486         .arg(Arg::new("other").short('o').action(ArgAction::SetTrue))
487         .try_get_matches_from(vec!["", "--opt", "--bar", "-o"]);
488     assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind());
489     let m = res.unwrap();
490     assert!(m.contains_id("some"));
491     assert!(m.contains_id("other"));
492     assert_eq!(
493         m.get_one::<String>("some").map(|v| v.as_str()).unwrap(),
494         "--bar"
495     );
496     assert_eq!(
497         *m.get_one::<bool>("other").expect("defaulted by clap"),
498         true
499     );
500 }
501 
502 #[test]
allow_negative_numbers_success()503 fn allow_negative_numbers_success() {
504     let res = Command::new("negnum")
505         .arg(Arg::new("panum").allow_negative_numbers(true))
506         .arg(
507             Arg::new("onum")
508                 .short('o')
509                 .action(ArgAction::Set)
510                 .allow_negative_numbers(true),
511         )
512         .try_get_matches_from(vec!["negnum", "-20", "-o", "-1.2"]);
513     assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind());
514     let m = res.unwrap();
515     assert_eq!(
516         m.get_one::<String>("panum").map(|v| v.as_str()).unwrap(),
517         "-20"
518     );
519     assert_eq!(
520         m.get_one::<String>("onum").map(|v| v.as_str()).unwrap(),
521         "-1.2"
522     );
523 }
524 
525 #[test]
allow_negative_numbers_fail()526 fn allow_negative_numbers_fail() {
527     let res = Command::new("negnum")
528         .arg(Arg::new("panum").allow_negative_numbers(true))
529         .arg(
530             Arg::new("onum")
531                 .short('o')
532                 .action(ArgAction::Set)
533                 .allow_negative_numbers(true),
534         )
535         .try_get_matches_from(vec!["negnum", "--foo", "-o", "-1.2"]);
536     assert!(res.is_err());
537     assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument)
538 }
539 
540 #[test]
trailing_var_arg_with_hyphen_values_escape_first()541 fn trailing_var_arg_with_hyphen_values_escape_first() {
542     assert_trailing_var_args(&["test", "--", "foo", "bar"], Some(&["foo", "bar"]), false);
543 }
544 
545 #[test]
trailing_var_arg_with_hyphen_values_escape_middle()546 fn trailing_var_arg_with_hyphen_values_escape_middle() {
547     assert_trailing_var_args(
548         &["test", "foo", "--", "bar"],
549         Some(&["foo", "--", "bar"]),
550         false,
551     );
552 }
553 
554 #[test]
trailing_var_arg_with_hyphen_values_short_first()555 fn trailing_var_arg_with_hyphen_values_short_first() {
556     assert_trailing_var_args(&["test", "-p", "foo", "bar"], Some(&["foo", "bar"]), true);
557 }
558 
559 #[test]
trailing_var_arg_with_hyphen_values_short_middle()560 fn trailing_var_arg_with_hyphen_values_short_middle() {
561     assert_trailing_var_args(
562         &["test", "foo", "-p", "bar"],
563         Some(&["foo", "-p", "bar"]),
564         false,
565     );
566 }
567 
568 #[test]
trailing_var_arg_with_hyphen_values_long_first()569 fn trailing_var_arg_with_hyphen_values_long_first() {
570     assert_trailing_var_args(
571         &["test", "--prog", "foo", "bar"],
572         Some(&["foo", "bar"]),
573         true,
574     );
575 }
576 
577 #[test]
trailing_var_arg_with_hyphen_values_long_middle()578 fn trailing_var_arg_with_hyphen_values_long_middle() {
579     assert_trailing_var_args(
580         &["test", "foo", "--prog", "bar"],
581         Some(&["foo", "--prog", "bar"]),
582         false,
583     );
584 }
585 
586 #[track_caller]
assert_trailing_var_args( input: &[&str], expected_var_arg: Option<&[&str]>, expected_flag: bool, )587 fn assert_trailing_var_args(
588     input: &[&str],
589     expected_var_arg: Option<&[&str]>,
590     expected_flag: bool,
591 ) {
592     let cmd = Command::new("test").arg(arg!(-p - -prog)).arg(
593         arg!([opt] ... "some pos")
594             .trailing_var_arg(true)
595             .allow_hyphen_values(true),
596     );
597     let m = cmd.try_get_matches_from(input);
598     assert!(
599         m.is_ok(),
600         "failed with args {:?}: {}",
601         input,
602         m.unwrap_err()
603     );
604     let m = m.unwrap();
605 
606     let actual_var_args = m
607         .get_many::<String>("opt")
608         .map(|v| v.map(|s| s.as_str()).collect::<Vec<_>>());
609     assert_eq!(actual_var_args.as_deref(), expected_var_arg);
610     assert_eq!(m.get_flag("prog"), expected_flag);
611 }
612 
613 #[test]
disable_help_subcommand()614 fn disable_help_subcommand() {
615     let result = Command::new("disablehelp")
616         .disable_help_subcommand(true)
617         .subcommand(Command::new("sub1"))
618         .try_get_matches_from(vec!["", "help"]);
619     assert!(result.is_err());
620     let err = result.err().unwrap();
621     assert_eq!(err.kind(), ErrorKind::InvalidSubcommand);
622 }
623 
624 #[test]
dont_collapse_args()625 fn dont_collapse_args() {
626     let cmd = Command::new("clap-test").version("v1.4.8").args([
627         Arg::new("arg1").help("some"),
628         Arg::new("arg2").help("some"),
629         Arg::new("arg3").help("some"),
630     ]);
631     utils::assert_output(cmd, "clap-test --help", DONT_COLLAPSE_ARGS, false);
632 }
633 
634 #[test]
require_eq()635 fn require_eq() {
636     static REQUIRE_EQUALS: &str = "\
637 Usage: clap-test --opt=<FILE>
638 
639 Options:
640   -o, --opt=<FILE>  some
641   -h, --help        Print help
642   -V, --version     Print version
643 ";
644 
645     let cmd = Command::new("clap-test").version("v1.4.8").arg(
646         Arg::new("opt")
647             .long("opt")
648             .short('o')
649             .required(true)
650             .require_equals(true)
651             .value_name("FILE")
652             .help("some"),
653     );
654     utils::assert_output(cmd, "clap-test --help", REQUIRE_EQUALS, false);
655 }
656 
657 #[test]
propagate_vals_down()658 fn propagate_vals_down() {
659     let m = Command::new("myprog")
660         .arg(arg!([cmd] "command to run").global(true))
661         .subcommand(Command::new("foo"))
662         .try_get_matches_from(vec!["myprog", "set", "foo"]);
663     assert!(m.is_ok(), "{:?}", m.unwrap_err().kind());
664     let m = m.unwrap();
665     assert_eq!(m.get_one::<String>("cmd").map(|v| v.as_str()), Some("set"));
666     let sub_m = m.subcommand_matches("foo").unwrap();
667     assert_eq!(
668         sub_m.get_one::<String>("cmd").map(|v| v.as_str()),
669         Some("set")
670     );
671 }
672 
673 #[test]
allow_missing_positional()674 fn allow_missing_positional() {
675     let m = Command::new("test")
676         .allow_missing_positional(true)
677         .arg(arg!([src] "some file").default_value("src"))
678         .arg(arg!(<dest> "some file"))
679         .try_get_matches_from(vec!["test", "file"]);
680     assert!(m.is_ok(), "{:?}", m.unwrap_err().kind());
681     let m = m.unwrap();
682     assert_eq!(m.get_one::<String>("src").map(|v| v.as_str()), Some("src"));
683     assert_eq!(
684         m.get_one::<String>("dest").map(|v| v.as_str()),
685         Some("file")
686     );
687 }
688 
689 #[test]
allow_missing_positional_no_default()690 fn allow_missing_positional_no_default() {
691     let m = Command::new("test")
692         .allow_missing_positional(true)
693         .arg(arg!([src] "some file"))
694         .arg(arg!(<dest> "some file"))
695         .try_get_matches_from(vec!["test", "file"]);
696     assert!(m.is_ok(), "{:?}", m.unwrap_err().kind());
697     let m = m.unwrap();
698     assert_eq!(m.get_one::<String>("src").map(|v| v.as_str()), None);
699     assert_eq!(
700         m.get_one::<String>("dest").map(|v| v.as_str()),
701         Some("file")
702     );
703 }
704 
705 #[test]
missing_positional_no_hyphen()706 fn missing_positional_no_hyphen() {
707     let r = Command::new("bench")
708         .allow_missing_positional(true)
709         .arg(arg!([BENCH] "some bench"))
710         .arg(arg!([ARGS] ... "some args"))
711         .try_get_matches_from(vec!["bench", "foo", "arg1", "arg2", "arg3"]);
712     assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
713 
714     let m = r.unwrap();
715 
716     let expected_bench = Some("foo");
717     let expected_args = vec!["arg1", "arg2", "arg3"];
718 
719     assert_eq!(
720         m.get_one::<String>("BENCH").map(|v| v.as_str()),
721         expected_bench
722     );
723     assert_eq!(
724         m.get_many::<String>("ARGS")
725             .unwrap()
726             .map(|v| v.as_str())
727             .collect::<Vec<_>>(),
728         &*expected_args
729     );
730 }
731 
732 #[test]
missing_positional_hyphen()733 fn missing_positional_hyphen() {
734     let r = Command::new("bench")
735         .allow_missing_positional(true)
736         .arg(arg!([BENCH] "some bench"))
737         .arg(arg!([ARGS] ... "some args"))
738         .try_get_matches_from(vec!["bench", "--", "arg1", "arg2", "arg3"]);
739     assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
740 
741     let m = r.unwrap();
742 
743     let expected_bench = None;
744     let expected_args = vec!["arg1", "arg2", "arg3"];
745 
746     assert_eq!(
747         m.get_one::<String>("BENCH").map(|v| v.as_str()),
748         expected_bench
749     );
750     assert_eq!(
751         m.get_many::<String>("ARGS")
752             .unwrap()
753             .map(|v| v.as_str())
754             .collect::<Vec<_>>(),
755         &*expected_args
756     );
757 }
758 
759 #[test]
missing_positional_hyphen_far_back()760 fn missing_positional_hyphen_far_back() {
761     let r = Command::new("bench")
762         .allow_missing_positional(true)
763         .arg(arg!([BENCH1] "some bench"))
764         .arg(arg!([BENCH2] "some bench"))
765         .arg(arg!([BENCH3] "some bench"))
766         .arg(arg!([ARGS] ... "some args"))
767         .try_get_matches_from(vec!["bench", "foo", "--", "arg1", "arg2", "arg3"]);
768     assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
769 
770     let m = r.unwrap();
771 
772     let expected_bench1 = Some("foo");
773     let expected_bench2 = None;
774     let expected_bench3 = None;
775     let expected_args = vec!["arg1", "arg2", "arg3"];
776 
777     assert_eq!(
778         m.get_one::<String>("BENCH1").map(|v| v.as_str()),
779         expected_bench1
780     );
781     assert_eq!(
782         m.get_one::<String>("BENCH2").map(|v| v.as_str()),
783         expected_bench2
784     );
785     assert_eq!(
786         m.get_one::<String>("BENCH3").map(|v| v.as_str()),
787         expected_bench3
788     );
789     assert_eq!(
790         m.get_many::<String>("ARGS")
791             .unwrap()
792             .map(|v| v.as_str())
793             .collect::<Vec<_>>(),
794         &*expected_args
795     );
796 }
797 
798 #[test]
missing_positional_hyphen_req_error()799 fn missing_positional_hyphen_req_error() {
800     let r = Command::new("bench")
801         .allow_missing_positional(true)
802         .arg(arg!([BENCH1] "some bench"))
803         .arg(arg!(<BENCH2> "some bench"))
804         .arg(arg!([ARGS] ... "some args"))
805         .try_get_matches_from(vec!["bench", "foo", "--", "arg1", "arg2", "arg3"]);
806     assert!(r.is_err());
807     assert_eq!(r.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
808 }
809 
810 #[test]
issue_1066_allow_leading_hyphen_and_unknown_args_option()811 fn issue_1066_allow_leading_hyphen_and_unknown_args_option() {
812     let res = Command::new("prog")
813         .arg(
814             arg!(--"some-argument" <val>)
815                 .required(true)
816                 .allow_hyphen_values(true),
817         )
818         .try_get_matches_from(vec!["prog", "-fish"]);
819 
820     assert!(res.is_err());
821     assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument);
822 }
823 
824 #[test]
issue_1437_allow_hyphen_values_for_positional_arg()825 fn issue_1437_allow_hyphen_values_for_positional_arg() {
826     let m = Command::new("tmp")
827         .arg(
828             Arg::new("pat")
829                 .allow_hyphen_values(true)
830                 .required(true)
831                 .action(ArgAction::Set),
832         )
833         .try_get_matches_from(["tmp", "-file"])
834         .unwrap();
835     assert_eq!(
836         m.get_one::<String>("pat").map(|v| v.as_str()),
837         Some("-file")
838     );
839 }
840 
841 #[test]
issue_3880_allow_long_flag_hyphen_value_for_positional_arg()842 fn issue_3880_allow_long_flag_hyphen_value_for_positional_arg() {
843     let m = Command::new("prog")
844         .arg(
845             Arg::new("pat")
846                 .allow_hyphen_values(true)
847                 .required(true)
848                 .action(ArgAction::Set),
849         )
850         .try_get_matches_from(["", "--file"])
851         .unwrap();
852 
853     assert_eq!(
854         m.get_one::<String>("pat").map(|v| v.as_str()),
855         Some("--file")
856     );
857 }
858 
859 #[test]
issue_1093_allow_ext_sc()860 fn issue_1093_allow_ext_sc() {
861     let cmd = Command::new("clap-test")
862         .version("v1.4.8")
863         .allow_external_subcommands(true);
864     utils::assert_output(cmd, "clap-test --help", ALLOW_EXT_SC, false);
865 }
866 
867 #[test]
allow_ext_sc_empty_args()868 fn allow_ext_sc_empty_args() {
869     let res = Command::new("clap-test")
870         .version("v1.4.8")
871         .allow_external_subcommands(true)
872         .try_get_matches_from(vec!["clap-test", "external-cmd"]);
873 
874     assert!(res.is_ok(), "{}", res.unwrap_err());
875 
876     match res.unwrap().subcommand() {
877         Some((name, args)) => {
878             assert_eq!(name, "external-cmd");
879             assert_eq!(
880                 args.get_many::<OsString>("").unwrap().collect::<Vec<_>>(),
881                 Vec::<&OsString>::new(),
882             );
883         }
884         _ => unreachable!(),
885     }
886 }
887 
888 #[test]
allow_ext_sc_when_sc_required()889 fn allow_ext_sc_when_sc_required() {
890     let res = Command::new("clap-test")
891         .version("v1.4.8")
892         .allow_external_subcommands(true)
893         .subcommand_required(true)
894         .try_get_matches_from(vec!["clap-test", "external-cmd", "foo"]);
895 
896     assert!(res.is_ok(), "{}", res.unwrap_err());
897 
898     match res.unwrap().subcommand() {
899         Some((name, args)) => {
900             assert_eq!(name, "external-cmd");
901             assert_eq!(
902                 args.get_many::<OsString>("")
903                     .unwrap()
904                     .cloned()
905                     .collect::<Vec<_>>(),
906                 vec![OsString::from("foo")]
907             );
908         }
909         _ => unreachable!(),
910     }
911 }
912 
913 #[test]
external_subcommand_looks_like_built_in()914 fn external_subcommand_looks_like_built_in() {
915     let res = Command::new("cargo")
916         .version("1.26.0")
917         .allow_external_subcommands(true)
918         .subcommand(Command::new("install"))
919         .try_get_matches_from(vec!["cargo", "install-update", "foo"]);
920     assert!(res.is_ok(), "{}", res.unwrap_err());
921     let m = res.unwrap();
922     match m.subcommand() {
923         Some((name, args)) => {
924             assert_eq!(name, "install-update");
925             assert_eq!(
926                 args.get_many::<OsString>("")
927                     .unwrap()
928                     .cloned()
929                     .collect::<Vec<_>>(),
930                 vec![OsString::from("foo")]
931             );
932         }
933         _ => panic!("external_subcommand didn't work"),
934     }
935 }
936 
937 #[test]
built_in_subcommand_escaped()938 fn built_in_subcommand_escaped() {
939     let res = Command::new("cargo")
940         .version("1.26.0")
941         .allow_external_subcommands(true)
942         .subcommand(Command::new("install"))
943         .try_get_matches_from(vec!["cargo", "--", "install", "foo"]);
944     assert!(res.is_ok(), "{}", res.unwrap_err());
945     let m = res.unwrap();
946     match m.subcommand() {
947         Some((name, args)) => {
948             assert_eq!(name, "install");
949             assert_eq!(
950                 args.get_many::<OsString>("")
951                     .unwrap()
952                     .cloned()
953                     .collect::<Vec<_>>(),
954                 vec![OsString::from("foo")]
955             );
956         }
957         _ => panic!("external_subcommand didn't work"),
958     }
959 }
960 
961 #[test]
aaos_opts_w_other_overrides()962 fn aaos_opts_w_other_overrides() {
963     // opts with other overrides
964     let res = Command::new("posix")
965         .args_override_self(true)
966         .arg(arg!(--opt <val> "some option").action(ArgAction::Set))
967         .arg(
968             arg!(--other <val> "some other option")
969                 .overrides_with("opt")
970                 .action(ArgAction::Set),
971         )
972         .try_get_matches_from(vec!["", "--opt=some", "--other=test", "--opt=other"]);
973     assert!(res.is_ok(), "{}", res.unwrap_err());
974     let m = res.unwrap();
975     assert!(m.contains_id("opt"));
976     assert!(!m.contains_id("other"));
977     assert_eq!(
978         m.get_one::<String>("opt").map(|v| v.as_str()),
979         Some("other")
980     );
981 }
982 
983 #[test]
aaos_opts_w_other_overrides_rev()984 fn aaos_opts_w_other_overrides_rev() {
985     // opts with other overrides, rev
986     let res = Command::new("posix")
987         .args_override_self(true)
988         .arg(
989             arg!(--opt <val> "some option")
990                 .required(true)
991                 .action(ArgAction::Set),
992         )
993         .arg(
994             arg!(--other <val> "some other option")
995                 .required(true)
996                 .overrides_with("opt")
997                 .action(ArgAction::Set),
998         )
999         .try_get_matches_from(vec!["", "--opt=some", "--opt=other", "--other=val"]);
1000     assert!(res.is_ok(), "{}", res.unwrap_err());
1001     let m = res.unwrap();
1002     assert!(!m.contains_id("opt"));
1003     assert!(m.contains_id("other"));
1004     assert_eq!(
1005         m.get_one::<String>("other").map(|v| v.as_str()),
1006         Some("val")
1007     );
1008 }
1009 
1010 #[test]
aaos_opts_w_other_overrides_2()1011 fn aaos_opts_w_other_overrides_2() {
1012     // opts with other overrides
1013     let res = Command::new("posix")
1014         .args_override_self(true)
1015         .arg(
1016             arg!(--opt <val> "some option")
1017                 .overrides_with("other")
1018                 .action(ArgAction::Set),
1019         )
1020         .arg(arg!(--other <val> "some other option").action(ArgAction::Set))
1021         .try_get_matches_from(vec!["", "--opt=some", "--other=test", "--opt=other"]);
1022     assert!(res.is_ok(), "{}", res.unwrap_err());
1023     let m = res.unwrap();
1024     assert!(m.contains_id("opt"));
1025     assert!(!m.contains_id("other"));
1026     assert_eq!(
1027         m.get_one::<String>("opt").map(|v| v.as_str()),
1028         Some("other")
1029     );
1030 }
1031 
1032 #[test]
aaos_opts_w_other_overrides_rev_2()1033 fn aaos_opts_w_other_overrides_rev_2() {
1034     // opts with other overrides, rev
1035     let res = Command::new("posix")
1036         .args_override_self(true)
1037         .arg(
1038             arg!(--opt <val> "some option")
1039                 .required(true)
1040                 .overrides_with("other")
1041                 .action(ArgAction::Set),
1042         )
1043         .arg(
1044             arg!(--other <val> "some other option")
1045                 .required(true)
1046                 .action(ArgAction::Set),
1047         )
1048         .try_get_matches_from(vec!["", "--opt=some", "--opt=other", "--other=val"]);
1049     assert!(res.is_ok(), "{}", res.unwrap_err());
1050     let m = res.unwrap();
1051     assert!(!m.contains_id("opt"));
1052     assert!(m.contains_id("other"));
1053     assert_eq!(
1054         m.get_one::<String>("other").map(|v| v.as_str()),
1055         Some("val")
1056     );
1057 }
1058 
1059 #[test]
aaos_opts_w_override_as_conflict_1()1060 fn aaos_opts_w_override_as_conflict_1() {
1061     // opts with other overrides, rev
1062     let res = Command::new("posix")
1063         .arg(
1064             arg!(--opt <val> "some option")
1065                 .required(true)
1066                 .overrides_with("other")
1067                 .action(ArgAction::Set),
1068         )
1069         .arg(
1070             arg!(--other <val> "some other option")
1071                 .required(true)
1072                 .action(ArgAction::Set),
1073         )
1074         .try_get_matches_from(vec!["", "--opt=some"]);
1075     assert!(res.is_ok(), "{}", res.unwrap_err());
1076     let m = res.unwrap();
1077     assert!(m.contains_id("opt"));
1078     assert!(!m.contains_id("other"));
1079     assert_eq!(m.get_one::<String>("opt").map(|v| v.as_str()), Some("some"));
1080 }
1081 
1082 #[test]
aaos_opts_w_override_as_conflict_2()1083 fn aaos_opts_w_override_as_conflict_2() {
1084     // opts with other overrides, rev
1085     let res = Command::new("posix")
1086         .arg(
1087             arg!(--opt <val> "some option")
1088                 .required(true)
1089                 .overrides_with("other")
1090                 .action(ArgAction::Set),
1091         )
1092         .arg(
1093             arg!(--other <val> "some other option")
1094                 .required(true)
1095                 .action(ArgAction::Set),
1096         )
1097         .try_get_matches_from(vec!["", "--other=some"]);
1098     assert!(res.is_ok(), "{}", res.unwrap_err());
1099     let m = res.unwrap();
1100     assert!(!m.contains_id("opt"));
1101     assert!(m.contains_id("other"));
1102     assert_eq!(
1103         m.get_one::<String>("other").map(|v| v.as_str()),
1104         Some("some")
1105     );
1106 }
1107 
1108 #[test]
aaos_opts_mult_req_delims()1109 fn aaos_opts_mult_req_delims() {
1110     // opts with multiple and require delims
1111     let res = Command::new("posix")
1112         .arg(
1113             arg!(--opt <val> ... "some option")
1114                 .action(ArgAction::Set)
1115                 .value_delimiter(',')
1116                 .action(ArgAction::Append),
1117         )
1118         .try_get_matches_from(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]);
1119     assert!(res.is_ok(), "{}", res.unwrap_err());
1120     let m = res.unwrap();
1121     assert!(m.contains_id("opt"));
1122     assert_eq!(
1123         m.get_many::<String>("opt")
1124             .unwrap()
1125             .map(|v| v.as_str())
1126             .collect::<Vec<_>>(),
1127         ["some", "other", "one", "two"]
1128     );
1129 }
1130 
1131 #[test]
aaos_opts_mult()1132 fn aaos_opts_mult() {
1133     // opts with multiple
1134     let res = Command::new("posix")
1135         .arg(
1136             arg!(--opt <val> ... "some option")
1137                 .num_args(1..)
1138                 .action(ArgAction::Append),
1139         )
1140         .try_get_matches_from(vec![
1141             "",
1142             "--opt",
1143             "first",
1144             "overrides",
1145             "--opt",
1146             "some",
1147             "other",
1148             "val",
1149         ]);
1150     assert!(res.is_ok(), "{}", res.unwrap_err());
1151     let m = res.unwrap();
1152     assert!(m.contains_id("opt"));
1153     assert_eq!(
1154         m.get_many::<String>("opt")
1155             .unwrap()
1156             .map(|v| v.as_str())
1157             .collect::<Vec<_>>(),
1158         ["first", "overrides", "some", "other", "val"]
1159     );
1160 }
1161 
1162 #[test]
aaos_pos_mult()1163 fn aaos_pos_mult() {
1164     // opts with multiple
1165     let res = Command::new("posix")
1166         .arg(arg!([val] ... "some pos"))
1167         .try_get_matches_from(vec!["", "some", "other", "value"]);
1168     assert!(res.is_ok(), "{}", res.unwrap_err());
1169     let m = res.unwrap();
1170     assert!(m.contains_id("val"));
1171     assert_eq!(
1172         m.get_many::<String>("val")
1173             .unwrap()
1174             .map(|v| v.as_str())
1175             .collect::<Vec<_>>(),
1176         ["some", "other", "value"]
1177     );
1178 }
1179 
1180 #[test]
aaos_option_use_delim_false()1181 fn aaos_option_use_delim_false() {
1182     let m = Command::new("posix")
1183         .args_override_self(true)
1184         .arg(
1185             arg!(--opt <val> "some option")
1186                 .required(true)
1187                 .action(ArgAction::Set),
1188         )
1189         .try_get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"])
1190         .unwrap();
1191     assert!(m.contains_id("opt"));
1192     assert_eq!(
1193         m.get_many::<String>("opt")
1194             .unwrap()
1195             .map(|v| v.as_str())
1196             .collect::<Vec<_>>(),
1197         ["one,two"]
1198     );
1199 }
1200 
1201 #[test]
1202 #[cfg(feature = "color")]
color_is_global()1203 fn color_is_global() {
1204     let mut cmd = Command::new("myprog")
1205         .color(clap::ColorChoice::Never)
1206         .subcommand(Command::new("foo"));
1207     cmd.build();
1208     assert_eq!(cmd.get_color(), clap::ColorChoice::Never);
1209 
1210     let sub = cmd.get_subcommands().collect::<Vec<_>>()[0];
1211     assert_eq!(sub.get_color(), clap::ColorChoice::Never);
1212 }
1213