1 use clap::builder::ArgPredicate;
2 use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
3
4 #[cfg(feature = "error-context")]
5 use super::utils;
6
7 #[test]
flag_required()8 fn flag_required() {
9 let result = Command::new("flag_required")
10 .arg(arg!(-f --flag "some flag").requires("color"))
11 .arg(arg!(-c --color "third flag"))
12 .try_get_matches_from(vec!["", "-f"]);
13 assert!(result.is_err());
14 let err = result.err().unwrap();
15 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
16 }
17
18 #[test]
flag_required_2()19 fn flag_required_2() {
20 let m = Command::new("flag_required")
21 .arg(
22 arg!(-f --flag "some flag")
23 .requires("color")
24 .action(ArgAction::SetTrue),
25 )
26 .arg(arg!(-c --color "third flag").action(ArgAction::SetTrue))
27 .try_get_matches_from(vec!["", "-f", "-c"])
28 .unwrap();
29 assert!(*m.get_one::<bool>("color").expect("defaulted by clap"));
30 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
31 }
32
33 #[test]
option_required()34 fn option_required() {
35 let result = Command::new("option_required")
36 .arg(arg!(f: -f <flag> "some flag").requires("c"))
37 .arg(arg!(c: -c <color> "third flag"))
38 .try_get_matches_from(vec!["", "-f", "val"]);
39 assert!(result.is_err());
40 let err = result.err().unwrap();
41 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
42 }
43
44 #[test]
option_required_2()45 fn option_required_2() {
46 let m = Command::new("option_required")
47 .arg(arg!(f: -f <flag> "some flag").requires("c"))
48 .arg(arg!(c: -c <color> "third flag"))
49 .try_get_matches_from(vec!["", "-f", "val", "-c", "other_val"])
50 .unwrap();
51 assert!(m.contains_id("c"));
52 assert_eq!(
53 m.get_one::<String>("c").map(|v| v.as_str()).unwrap(),
54 "other_val"
55 );
56 assert!(m.contains_id("f"));
57 assert_eq!(m.get_one::<String>("f").map(|v| v.as_str()).unwrap(), "val");
58 }
59
60 #[test]
positional_required()61 fn positional_required() {
62 let result = Command::new("positional_required")
63 .arg(Arg::new("flag").index(1).required(true))
64 .try_get_matches_from(vec![""]);
65 assert!(result.is_err());
66 let err = result.err().unwrap();
67 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
68 }
69
70 #[test]
positional_required_2()71 fn positional_required_2() {
72 let m = Command::new("positional_required")
73 .arg(Arg::new("flag").index(1).required(true))
74 .try_get_matches_from(vec!["", "someval"])
75 .unwrap();
76 assert!(m.contains_id("flag"));
77 assert_eq!(
78 m.get_one::<String>("flag").map(|v| v.as_str()).unwrap(),
79 "someval"
80 );
81 }
82
83 #[test]
84 #[cfg(feature = "error-context")]
positional_required_with_requires()85 fn positional_required_with_requires() {
86 static POSITIONAL_REQ: &str = "\
87 error: the following required arguments were not provided:
88 <flag>
89 <opt>
90
91 Usage: clap-test <flag> <opt> [bar]
92
93 For more information, try '--help'.
94 ";
95
96 let cmd = Command::new("positional_required")
97 .arg(Arg::new("flag").required(true).requires("opt"))
98 .arg(Arg::new("opt"))
99 .arg(Arg::new("bar"));
100
101 utils::assert_output(cmd, "clap-test", POSITIONAL_REQ, true);
102 }
103
104 #[test]
105 #[cfg(feature = "error-context")]
positional_required_with_requires_if_no_value()106 fn positional_required_with_requires_if_no_value() {
107 static POSITIONAL_REQ_IF_NO_VAL: &str = "\
108 error: the following required arguments were not provided:
109 <flag>
110
111 Usage: clap-test <flag> [opt] [bar]
112
113 For more information, try '--help'.
114 ";
115
116 let cmd = Command::new("positional_required")
117 .arg(Arg::new("flag").required(true).requires_if("val", "opt"))
118 .arg(Arg::new("opt"))
119 .arg(Arg::new("bar"));
120
121 utils::assert_output(cmd, "clap-test", POSITIONAL_REQ_IF_NO_VAL, true);
122 }
123
124 #[test]
125 #[cfg(feature = "error-context")]
positional_required_with_requires_if_value()126 fn positional_required_with_requires_if_value() {
127 static POSITIONAL_REQ_IF_VAL: &str = "\
128 error: the following required arguments were not provided:
129 <foo>
130 <opt>
131
132 Usage: clap-test <flag> <foo> <opt> [bar]
133
134 For more information, try '--help'.
135 ";
136
137 let cmd = Command::new("positional_required")
138 .arg(Arg::new("flag").required(true).requires_if("val", "opt"))
139 .arg(Arg::new("foo").required(true))
140 .arg(Arg::new("opt"))
141 .arg(Arg::new("bar"));
142
143 utils::assert_output(cmd, "clap-test val", POSITIONAL_REQ_IF_VAL, true);
144 }
145
146 #[test]
group_required()147 fn group_required() {
148 let result = Command::new("group_required")
149 .arg(arg!(-f --flag "some flag"))
150 .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
151 .arg(arg!(--some "some arg"))
152 .arg(arg!(--other "other arg"))
153 .try_get_matches_from(vec!["", "-f"]);
154 assert!(result.is_err());
155 let err = result.err().unwrap();
156 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
157 }
158
159 #[test]
group_required_2()160 fn group_required_2() {
161 let m = Command::new("group_required")
162 .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue))
163 .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
164 .arg(arg!(--some "some arg").action(ArgAction::SetTrue))
165 .arg(arg!(--other "other arg").action(ArgAction::SetTrue))
166 .try_get_matches_from(vec!["", "-f", "--some"])
167 .unwrap();
168 assert!(*m.get_one::<bool>("some").expect("defaulted by clap"));
169 assert!(!*m.get_one::<bool>("other").expect("defaulted by clap"));
170 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
171 }
172
173 #[test]
group_required_3()174 fn group_required_3() {
175 let m = Command::new("group_required")
176 .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue))
177 .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
178 .arg(arg!(--some "some arg").action(ArgAction::SetTrue))
179 .arg(arg!(--other "other arg").action(ArgAction::SetTrue))
180 .try_get_matches_from(vec!["", "-f", "--other"])
181 .unwrap();
182 assert!(!*m.get_one::<bool>("some").expect("defaulted by clap"));
183 assert!(*m.get_one::<bool>("other").expect("defaulted by clap"));
184 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
185 }
186
187 #[test]
arg_require_group()188 fn arg_require_group() {
189 let result = Command::new("arg_require_group")
190 .arg(arg!(-f --flag "some flag").requires("gr"))
191 .group(ArgGroup::new("gr").arg("some").arg("other"))
192 .arg(arg!(--some "some arg"))
193 .arg(arg!(--other "other arg"))
194 .try_get_matches_from(vec!["", "-f"]);
195 assert!(result.is_err());
196 let err = result.err().unwrap();
197 assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
198 }
199
200 #[test]
arg_require_group_2()201 fn arg_require_group_2() {
202 let res = Command::new("arg_require_group")
203 .arg(
204 arg!(-f --flag "some flag")
205 .requires("gr")
206 .action(ArgAction::SetTrue),
207 )
208 .group(ArgGroup::new("gr").arg("some").arg("other"))
209 .arg(arg!(--some "some arg").action(ArgAction::SetTrue))
210 .arg(arg!(--other "other arg").action(ArgAction::SetTrue))
211 .try_get_matches_from(vec!["", "-f", "--some"]);
212 assert!(res.is_ok(), "{}", res.unwrap_err());
213 let m = res.unwrap();
214 assert!(*m.get_one::<bool>("some").expect("defaulted by clap"));
215 assert!(!*m.get_one::<bool>("other").expect("defaulted by clap"));
216 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
217 }
218
219 #[test]
arg_require_group_3()220 fn arg_require_group_3() {
221 let res = Command::new("arg_require_group")
222 .arg(
223 arg!(-f --flag "some flag")
224 .requires("gr")
225 .action(ArgAction::SetTrue),
226 )
227 .group(ArgGroup::new("gr").arg("some").arg("other"))
228 .arg(arg!(--some "some arg").action(ArgAction::SetTrue))
229 .arg(arg!(--other "other arg").action(ArgAction::SetTrue))
230 .try_get_matches_from(vec!["", "-f", "--other"]);
231 assert!(res.is_ok(), "{}", res.unwrap_err());
232 let m = res.unwrap();
233 assert!(!*m.get_one::<bool>("some").expect("defaulted by clap"));
234 assert!(*m.get_one::<bool>("other").expect("defaulted by clap"));
235 assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
236 }
237
238 // REQUIRED_UNLESS
239
240 #[test]
issue_753()241 fn issue_753() {
242 let m = Command::new("test")
243 .arg(arg!(
244 -l --list "List available interfaces (and stop there)"
245 ))
246 .arg(
247 arg!(
248 -i --iface <INTERFACE> "Ethernet interface for fetching NTP packets"
249 )
250 .required(false)
251 .required_unless_present("list"),
252 )
253 .arg(
254 arg!(-f --file <TESTFILE> "Fetch NTP packets from pcap file")
255 .conflicts_with("iface")
256 .required_unless_present("list"),
257 )
258 .arg(arg!(-s --server <SERVER_IP> "NTP server IP address").required_unless_present("list"))
259 .try_get_matches_from(vec!["test", "--list"]);
260 assert!(m.is_ok(), "{}", m.unwrap_err());
261 }
262
263 #[test]
required_unless_present()264 fn required_unless_present() {
265 let res = Command::new("unlesstest")
266 .arg(
267 Arg::new("cfg")
268 .required_unless_present("dbg")
269 .action(ArgAction::Set)
270 .long("config"),
271 )
272 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
273 .try_get_matches_from(vec!["unlesstest", "--debug"]);
274
275 assert!(res.is_ok(), "{}", res.unwrap_err());
276 let m = res.unwrap();
277 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap"));
278 assert!(!m.contains_id("cfg"));
279 }
280
281 #[test]
required_unless_present_err()282 fn required_unless_present_err() {
283 let res = Command::new("unlesstest")
284 .arg(
285 Arg::new("cfg")
286 .required_unless_present("dbg")
287 .action(ArgAction::Set)
288 .long("config"),
289 )
290 .arg(Arg::new("dbg").long("debug"))
291 .try_get_matches_from(vec!["unlesstest"]);
292
293 assert!(res.is_err());
294 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
295 }
296
297 #[test]
required_unless_present_with_optional_value()298 fn required_unless_present_with_optional_value() {
299 let res = Command::new("unlesstest")
300 .arg(Arg::new("opt").long("opt").num_args(0..=1))
301 .arg(
302 Arg::new("cfg")
303 .required_unless_present("dbg")
304 .action(ArgAction::Set)
305 .long("config"),
306 )
307 .arg(Arg::new("dbg").long("debug"))
308 .try_get_matches_from(vec!["unlesstest", "--opt"]);
309
310 assert!(res.is_err());
311 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
312 }
313
314 // REQUIRED_UNLESS_ALL
315
316 #[test]
required_unless_present_all()317 fn required_unless_present_all() {
318 let res = Command::new("unlessall")
319 .arg(
320 Arg::new("cfg")
321 .required_unless_present_all(["dbg", "infile"])
322 .action(ArgAction::Set)
323 .long("config"),
324 )
325 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
326 .arg(Arg::new("infile").short('i').action(ArgAction::Set))
327 .try_get_matches_from(vec!["unlessall", "--debug", "-i", "file"]);
328
329 assert!(res.is_ok(), "{}", res.unwrap_err());
330 let m = res.unwrap();
331 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap"));
332 assert!(m.contains_id("infile"));
333 assert!(!m.contains_id("cfg"));
334 }
335
336 #[test]
required_unless_all_err()337 fn required_unless_all_err() {
338 let res = Command::new("unlessall")
339 .arg(
340 Arg::new("cfg")
341 .required_unless_present_all(["dbg", "infile"])
342 .action(ArgAction::Set)
343 .long("config"),
344 )
345 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
346 .arg(Arg::new("infile").short('i').action(ArgAction::Set))
347 .try_get_matches_from(vec!["unlessall", "--debug"]);
348
349 assert!(res.is_err());
350 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
351 }
352
353 // REQUIRED_UNLESS_ONE
354
355 #[test]
required_unless_present_any()356 fn required_unless_present_any() {
357 let res = Command::new("unlessone")
358 .arg(
359 Arg::new("cfg")
360 .required_unless_present_any(["dbg", "infile"])
361 .action(ArgAction::Set)
362 .long("config"),
363 )
364 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
365 .arg(Arg::new("infile").short('i').action(ArgAction::Set))
366 .try_get_matches_from(vec!["unlessone", "--debug"]);
367
368 assert!(res.is_ok(), "{}", res.unwrap_err());
369 let m = res.unwrap();
370 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap"));
371 assert!(!m.contains_id("cfg"));
372 }
373
374 #[test]
required_unless_any_2()375 fn required_unless_any_2() {
376 // This tests that the required_unless_present_any works when the second arg in the array is used
377 // instead of the first.
378 let res = Command::new("unlessone")
379 .arg(
380 Arg::new("cfg")
381 .required_unless_present_any(["dbg", "infile"])
382 .action(ArgAction::Set)
383 .long("config"),
384 )
385 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
386 .arg(Arg::new("infile").short('i').action(ArgAction::Set))
387 .try_get_matches_from(vec!["unlessone", "-i", "file"]);
388
389 assert!(res.is_ok(), "{}", res.unwrap_err());
390 let m = res.unwrap();
391 assert!(m.contains_id("infile"));
392 assert!(!m.contains_id("cfg"));
393 }
394
395 #[test]
required_unless_any_works_with_short()396 fn required_unless_any_works_with_short() {
397 // GitHub issue: https://github.com/clap-rs/clap/issues/1135
398 let res = Command::new("unlessone")
399 .arg(
400 Arg::new("a")
401 .conflicts_with("b")
402 .short('a')
403 .action(ArgAction::SetTrue),
404 )
405 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue))
406 .arg(
407 Arg::new("x")
408 .short('x')
409 .action(ArgAction::SetTrue)
410 .required_unless_present_any(["a", "b"]),
411 )
412 .try_get_matches_from(vec!["unlessone", "-a"]);
413
414 assert!(res.is_ok(), "{}", res.unwrap_err());
415 }
416
417 #[test]
required_unless_any_works_with_short_err()418 fn required_unless_any_works_with_short_err() {
419 let res = Command::new("unlessone")
420 .arg(
421 Arg::new("a")
422 .conflicts_with("b")
423 .short('a')
424 .action(ArgAction::SetTrue),
425 )
426 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue))
427 .arg(
428 Arg::new("x")
429 .short('x')
430 .action(ArgAction::SetTrue)
431 .required_unless_present_any(["a", "b"]),
432 )
433 .try_get_matches_from(vec!["unlessone"]);
434
435 assert!(res.is_err());
436 }
437
438 #[test]
required_unless_any_works_without()439 fn required_unless_any_works_without() {
440 let res = Command::new("unlessone")
441 .arg(
442 Arg::new("a")
443 .conflicts_with("b")
444 .short('a')
445 .action(ArgAction::SetTrue),
446 )
447 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue))
448 .arg(Arg::new("x").required_unless_present_any(["a", "b"]))
449 .try_get_matches_from(vec!["unlessone", "-a"]);
450
451 assert!(res.is_ok(), "{}", res.unwrap_err());
452 }
453
454 #[test]
required_unless_any_works_with_long()455 fn required_unless_any_works_with_long() {
456 let res = Command::new("unlessone")
457 .arg(
458 Arg::new("a")
459 .conflicts_with("b")
460 .short('a')
461 .action(ArgAction::SetTrue),
462 )
463 .arg(Arg::new("b").short('b').action(ArgAction::SetTrue))
464 .arg(
465 Arg::new("x")
466 .long("x_is_the_option")
467 .action(ArgAction::SetTrue)
468 .required_unless_present_any(["a", "b"]),
469 )
470 .try_get_matches_from(vec!["unlessone", "-a"]);
471
472 assert!(res.is_ok(), "{}", res.unwrap_err());
473 }
474
475 #[test]
required_unless_any_1()476 fn required_unless_any_1() {
477 let res = Command::new("unlessone")
478 .arg(
479 Arg::new("cfg")
480 .required_unless_present_any(["dbg", "infile"])
481 .action(ArgAction::Set)
482 .long("config"),
483 )
484 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
485 .arg(Arg::new("infile").short('i').action(ArgAction::Set))
486 .try_get_matches_from(vec!["unlessone", "--debug"]);
487
488 assert!(res.is_ok(), "{}", res.unwrap_err());
489 let m = res.unwrap();
490 assert!(!m.contains_id("infile"));
491 assert!(!m.contains_id("cfg"));
492 assert!(*m.get_one::<bool>("dbg").expect("defaulted by clap"));
493 }
494
495 #[test]
required_unless_any_err()496 fn required_unless_any_err() {
497 let res = Command::new("unlessone")
498 .arg(
499 Arg::new("cfg")
500 .required_unless_present_any(["dbg", "infile"])
501 .action(ArgAction::Set)
502 .long("config"),
503 )
504 .arg(Arg::new("dbg").long("debug").action(ArgAction::SetTrue))
505 .arg(Arg::new("infile").short('i').action(ArgAction::Set))
506 .try_get_matches_from(vec!["unlessone"]);
507
508 assert!(res.is_err());
509 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
510 }
511
512 #[test]
513 #[cfg(feature = "error-context")]
missing_required_output()514 fn missing_required_output() {
515 static MISSING_REQ: &str = "\
516 error: the following required arguments were not provided:
517 --long-option-2 <option2>
518 <positional>
519 <positional2>
520
521 Usage: clap-test --long-option-2 <option2> -F <positional> <positional2> [positional3]...
522
523 For more information, try '--help'.
524 ";
525
526 utils::assert_output(utils::complex_app(), "clap-test -F", MISSING_REQ, true);
527 }
528
529 // Conditional external requirements
530
531 #[test]
requires_if_present_val()532 fn requires_if_present_val() {
533 let res = Command::new("unlessone")
534 .arg(
535 Arg::new("cfg")
536 .requires_if("my.cfg", "extra")
537 .action(ArgAction::Set)
538 .long("config"),
539 )
540 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue))
541 .try_get_matches_from(vec!["unlessone", "--config=my.cfg"]);
542
543 assert!(res.is_err());
544 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
545 }
546
547 #[test]
requires_if_present_mult()548 fn requires_if_present_mult() {
549 let res = Command::new("unlessone")
550 .arg(
551 Arg::new("cfg")
552 .requires_ifs([("my.cfg", "extra"), ("other.cfg", "other")])
553 .action(ArgAction::Set)
554 .long("config"),
555 )
556 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue))
557 .arg(Arg::new("other").long("other").action(ArgAction::SetTrue))
558 .try_get_matches_from(vec!["unlessone", "--config=other.cfg"]);
559
560 assert!(res.is_err());
561 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
562 }
563
564 #[test]
requires_if_present_mult_pass()565 fn requires_if_present_mult_pass() {
566 let res = Command::new("unlessone")
567 .arg(
568 Arg::new("cfg")
569 .requires_ifs([("my.cfg", "extra"), ("other.cfg", "other")])
570 .action(ArgAction::Set)
571 .long("config"),
572 )
573 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue))
574 .arg(Arg::new("other").long("other").action(ArgAction::SetTrue))
575 .try_get_matches_from(vec!["unlessone", "--config=some.cfg"]);
576
577 assert!(res.is_ok(), "{}", res.unwrap_err());
578 }
579
580 #[test]
requires_if_present_val_no_present_pass()581 fn requires_if_present_val_no_present_pass() {
582 let res = Command::new("unlessone")
583 .arg(
584 Arg::new("cfg")
585 .requires_if("my.cfg", "extra")
586 .action(ArgAction::Set)
587 .long("config"),
588 )
589 .arg(Arg::new("extra").long("extra").action(ArgAction::SetTrue))
590 .try_get_matches_from(vec!["unlessone"]);
591
592 assert!(res.is_ok(), "{}", res.unwrap_err());
593 }
594
595 // Conditionally required
596
597 #[test]
required_if_val_present_pass()598 fn required_if_val_present_pass() {
599 let res = Command::new("ri")
600 .arg(
601 Arg::new("cfg")
602 .required_if_eq("extra", "val")
603 .action(ArgAction::Set)
604 .long("config"),
605 )
606 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
607 .try_get_matches_from(vec!["ri", "--extra", "val", "--config", "my.cfg"]);
608
609 assert!(res.is_ok(), "{}", res.unwrap_err());
610 }
611
612 #[test]
required_if_val_present_fail()613 fn required_if_val_present_fail() {
614 let res = Command::new("ri")
615 .arg(
616 Arg::new("cfg")
617 .required_if_eq("extra", "val")
618 .action(ArgAction::Set)
619 .long("config"),
620 )
621 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
622 .try_get_matches_from(vec!["ri", "--extra", "val"]);
623
624 assert!(res.is_err());
625 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
626 }
627
628 #[test]
required_if_val_present_ignore_case_pass()629 fn required_if_val_present_ignore_case_pass() {
630 let res = Command::new("ri")
631 .arg(
632 Arg::new("cfg")
633 .required_if_eq("extra", "Val")
634 .action(ArgAction::Set)
635 .long("config"),
636 )
637 .arg(
638 Arg::new("extra")
639 .action(ArgAction::Set)
640 .long("extra")
641 .ignore_case(true),
642 )
643 .try_get_matches_from(vec!["ri", "--extra", "vaL", "--config", "my.cfg"]);
644
645 assert!(res.is_ok(), "{}", res.unwrap_err());
646 }
647
648 #[test]
required_if_val_present_ignore_case_fail()649 fn required_if_val_present_ignore_case_fail() {
650 let res = Command::new("ri")
651 .arg(
652 Arg::new("cfg")
653 .required_if_eq("extra", "Val")
654 .action(ArgAction::Set)
655 .long("config"),
656 )
657 .arg(
658 Arg::new("extra")
659 .action(ArgAction::Set)
660 .long("extra")
661 .ignore_case(true),
662 )
663 .try_get_matches_from(vec!["ri", "--extra", "vaL"]);
664
665 assert!(res.is_err());
666 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
667 }
668
669 #[test]
required_if_all_values_present_pass()670 fn required_if_all_values_present_pass() {
671 let res = Command::new("ri")
672 .arg(
673 Arg::new("cfg")
674 .required_if_eq_all([("extra", "val"), ("option", "spec")])
675 .action(ArgAction::Set)
676 .long("config"),
677 )
678 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
679 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
680 .try_get_matches_from(vec![
681 "ri", "--extra", "val", "--option", "spec", "--config", "my.cfg",
682 ]);
683
684 assert!(res.is_ok(), "{}", res.unwrap_err());
685 }
686
687 #[test]
required_if_some_values_present_pass()688 fn required_if_some_values_present_pass() {
689 let res = Command::new("ri")
690 .arg(
691 Arg::new("cfg")
692 .required_if_eq_all([("extra", "val"), ("option", "spec")])
693 .action(ArgAction::Set)
694 .long("config"),
695 )
696 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
697 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
698 .try_get_matches_from(vec!["ri", "--extra", "val"]);
699
700 assert!(res.is_ok(), "{}", res.unwrap_err());
701 }
702
703 #[test]
required_if_all_values_present_fail()704 fn required_if_all_values_present_fail() {
705 let res = Command::new("ri")
706 .arg(
707 Arg::new("cfg")
708 .required_if_eq_all([("extra", "val"), ("option", "spec")])
709 .action(ArgAction::Set)
710 .long("config"),
711 )
712 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
713 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
714 .try_get_matches_from(vec!["ri", "--extra", "val", "--option", "spec"]);
715
716 assert!(res.is_err());
717 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
718 }
719
720 #[test]
required_if_any_all_values_present_pass()721 fn required_if_any_all_values_present_pass() {
722 let res = Command::new("ri")
723 .arg(
724 Arg::new("cfg")
725 .required_if_eq_all([("extra", "val"), ("option", "spec")])
726 .required_if_eq_any([("extra", "val2"), ("option", "spec2")])
727 .action(ArgAction::Set)
728 .long("config"),
729 )
730 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
731 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
732 .try_get_matches_from(vec![
733 "ri", "--extra", "val", "--option", "spec", "--config", "my.cfg",
734 ]);
735
736 assert!(res.is_ok(), "{}", res.unwrap_err());
737 }
738
739 #[test]
required_if_any_all_values_present_fail()740 fn required_if_any_all_values_present_fail() {
741 let res = Command::new("ri")
742 .arg(
743 Arg::new("cfg")
744 .required_if_eq_all([("extra", "val"), ("option", "spec")])
745 .required_if_eq_any([("extra", "val2"), ("option", "spec2")])
746 .action(ArgAction::Set)
747 .long("config"),
748 )
749 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
750 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
751 .try_get_matches_from(vec!["ri", "--extra", "val", "--option", "spec"]);
752
753 assert!(res.is_err());
754 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
755 }
756
757 #[test]
758 #[cfg(feature = "error-context")]
list_correct_required_args()759 fn list_correct_required_args() {
760 static COND_REQ_IN_USAGE: &str = "\
761 error: the following required arguments were not provided:
762 --output <output>
763
764 Usage: test --target <target> --input <input> --output <output>
765
766 For more information, try '--help'.
767 ";
768
769 let cmd = Command::new("Test cmd")
770 .version("1.0")
771 .author("F0x06")
772 .about("Arg test")
773 .arg(
774 Arg::new("target")
775 .action(ArgAction::Set)
776 .required(true)
777 .value_parser(["file", "stdout"])
778 .long("target"),
779 )
780 .arg(
781 Arg::new("input")
782 .action(ArgAction::Set)
783 .required(true)
784 .long("input"),
785 )
786 .arg(
787 Arg::new("output")
788 .action(ArgAction::Set)
789 .required(true)
790 .long("output"),
791 );
792
793 utils::assert_output(
794 cmd,
795 "test --input somepath --target file",
796 COND_REQ_IN_USAGE,
797 true,
798 );
799 }
800
801 #[test]
802 #[cfg(feature = "error-context")]
required_if_val_present_fail_error_output()803 fn required_if_val_present_fail_error_output() {
804 static COND_REQ_IN_USAGE: &str = "\
805 error: the following required arguments were not provided:
806 --output <output>
807
808 Usage: test --target <target> --input <input> --output <output>
809
810 For more information, try '--help'.
811 ";
812
813 let cmd = Command::new("Test cmd")
814 .version("1.0")
815 .author("F0x06")
816 .about("Arg test")
817 .arg(
818 Arg::new("target")
819 .action(ArgAction::Set)
820 .required(true)
821 .value_parser(["file", "stdout"])
822 .long("target"),
823 )
824 .arg(
825 Arg::new("input")
826 .action(ArgAction::Set)
827 .required(true)
828 .long("input"),
829 )
830 .arg(
831 Arg::new("output")
832 .action(ArgAction::Set)
833 .required_if_eq("target", "file")
834 .long("output"),
835 );
836
837 utils::assert_output(
838 cmd,
839 "test --input somepath --target file",
840 COND_REQ_IN_USAGE,
841 true,
842 );
843 }
844
845 #[test]
required_if_wrong_val()846 fn required_if_wrong_val() {
847 let res = Command::new("ri")
848 .arg(
849 Arg::new("cfg")
850 .required_if_eq("extra", "val")
851 .action(ArgAction::Set)
852 .long("config"),
853 )
854 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
855 .try_get_matches_from(vec!["ri", "--extra", "other"]);
856
857 assert!(res.is_ok(), "{}", res.unwrap_err());
858 }
859
860 #[test]
required_ifs_val_present_pass()861 fn required_ifs_val_present_pass() {
862 let res = Command::new("ri")
863 .arg(
864 Arg::new("cfg")
865 .required_if_eq_any([("extra", "val"), ("option", "spec")])
866 .action(ArgAction::Set)
867 .long("config"),
868 )
869 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
870 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
871 .try_get_matches_from(vec!["ri", "--option", "spec", "--config", "my.cfg"]);
872
873 assert!(res.is_ok(), "{}", res.unwrap_err());
874 }
875
876 #[test]
required_ifs_val_present_fail()877 fn required_ifs_val_present_fail() {
878 let res = Command::new("ri")
879 .arg(
880 Arg::new("cfg")
881 .required_if_eq_any([("extra", "val"), ("option", "spec")])
882 .action(ArgAction::Set)
883 .long("config"),
884 )
885 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
886 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
887 .try_get_matches_from(vec!["ri", "--option", "spec"]);
888
889 assert!(res.is_err());
890 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
891 }
892
893 #[test]
required_ifs_wrong_val()894 fn required_ifs_wrong_val() {
895 let res = Command::new("ri")
896 .arg(
897 Arg::new("cfg")
898 .required_if_eq_any([("extra", "val"), ("option", "spec")])
899 .action(ArgAction::Set)
900 .long("config"),
901 )
902 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
903 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
904 .try_get_matches_from(vec!["ri", "--option", "other"]);
905
906 assert!(res.is_ok(), "{}", res.unwrap_err());
907 }
908
909 #[test]
required_ifs_wrong_val_mult_fail()910 fn required_ifs_wrong_val_mult_fail() {
911 let res = Command::new("ri")
912 .arg(
913 Arg::new("cfg")
914 .required_if_eq_any([("extra", "val"), ("option", "spec")])
915 .action(ArgAction::Set)
916 .long("config"),
917 )
918 .arg(Arg::new("extra").action(ArgAction::Set).long("extra"))
919 .arg(Arg::new("option").action(ArgAction::Set).long("option"))
920 .try_get_matches_from(vec!["ri", "--extra", "other", "--option", "spec"]);
921
922 assert!(res.is_err());
923 assert_eq!(res.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
924 }
925
926 #[test]
927 #[cfg(feature = "error-context")]
require_eq()928 fn require_eq() {
929 static REQUIRE_EQUALS: &str = "\
930 error: the following required arguments were not provided:
931 --opt=<FILE>
932
933 Usage: clap-test --opt=<FILE>
934
935 For more information, try '--help'.
936 ";
937
938 let cmd = Command::new("clap-test").version("v1.4.8").arg(
939 Arg::new("opt")
940 .long("opt")
941 .short('o')
942 .required(true)
943 .require_equals(true)
944 .value_name("FILE")
945 .help("some"),
946 );
947 utils::assert_output(cmd, "clap-test", REQUIRE_EQUALS, true);
948 }
949
950 #[test]
951 #[cfg(feature = "error-context")]
require_eq_filtered()952 fn require_eq_filtered() {
953 static REQUIRE_EQUALS_FILTERED: &str = "\
954 error: the following required arguments were not provided:
955 --opt=<FILE>
956
957 Usage: clap-test --opt=<FILE> --foo=<FILE>
958
959 For more information, try '--help'.
960 ";
961
962 let cmd = Command::new("clap-test")
963 .version("v1.4.8")
964 .arg(
965 Arg::new("opt")
966 .long("opt")
967 .short('o')
968 .required(true)
969 .require_equals(true)
970 .value_name("FILE")
971 .help("some"),
972 )
973 .arg(
974 Arg::new("foo")
975 .long("foo")
976 .short('f')
977 .required(true)
978 .require_equals(true)
979 .value_name("FILE")
980 .help("some other arg"),
981 );
982 utils::assert_output(cmd, "clap-test -f=blah", REQUIRE_EQUALS_FILTERED, true);
983 }
984
985 #[test]
986 #[cfg(feature = "error-context")]
require_eq_filtered_group()987 fn require_eq_filtered_group() {
988 static REQUIRE_EQUALS_FILTERED_GROUP: &str = "\
989 error: the following required arguments were not provided:
990 --opt=<FILE>
991
992 Usage: clap-test --opt=<FILE> --foo=<FILE> <--g1=<FILE>|--g2=<FILE>>
993
994 For more information, try '--help'.
995 ";
996
997 let cmd = Command::new("clap-test")
998 .version("v1.4.8")
999 .arg(
1000 Arg::new("opt")
1001 .long("opt")
1002 .short('o')
1003 .required(true)
1004 .require_equals(true)
1005 .value_name("FILE")
1006 .help("some"),
1007 )
1008 .arg(
1009 Arg::new("foo")
1010 .long("foo")
1011 .short('f')
1012 .required(true)
1013 .require_equals(true)
1014 .value_name("FILE")
1015 .help("some other arg"),
1016 )
1017 .arg(
1018 Arg::new("g1")
1019 .long("g1")
1020 .require_equals(true)
1021 .value_name("FILE"),
1022 )
1023 .arg(
1024 Arg::new("g2")
1025 .long("g2")
1026 .require_equals(true)
1027 .value_name("FILE"),
1028 )
1029 .group(
1030 ArgGroup::new("test_group")
1031 .args(["g1", "g2"])
1032 .required(true),
1033 );
1034 utils::assert_output(
1035 cmd,
1036 "clap-test -f=blah --g1=blah",
1037 REQUIRE_EQUALS_FILTERED_GROUP,
1038 true,
1039 );
1040 }
1041
issue_1158_app() -> Command1042 fn issue_1158_app() -> Command {
1043 Command::new("example")
1044 .arg(
1045 arg!(-c --config <FILE> "Custom config file.")
1046 .required_unless_present("ID")
1047 .conflicts_with("ID"),
1048 )
1049 .arg(
1050 arg!([ID] "ID")
1051 .required_unless_present("config")
1052 .conflicts_with("config")
1053 .requires_ifs([
1054 (ArgPredicate::IsPresent, "x"),
1055 (ArgPredicate::IsPresent, "y"),
1056 (ArgPredicate::IsPresent, "z"),
1057 ]),
1058 )
1059 .arg(arg!(x: -x <X> "X"))
1060 .arg(arg!(y: -y <Y> "Y"))
1061 .arg(arg!(z: -z <Z> "Z"))
1062 }
1063
1064 #[test]
1065 #[cfg(feature = "error-context")]
multiple_required_unless_usage_printing()1066 fn multiple_required_unless_usage_printing() {
1067 static MULTIPLE_REQUIRED_UNLESS_USAGE: &str = "\
1068 error: the following required arguments were not provided:
1069 --a <a>
1070 --b <b>
1071
1072 Usage: test --c <c> --a <a> --b <b>
1073
1074 For more information, try '--help'.
1075 ";
1076 let cmd = Command::new("test")
1077 .arg(
1078 Arg::new("a")
1079 .long("a")
1080 .action(ArgAction::Set)
1081 .required_unless_present("b")
1082 .conflicts_with("b"),
1083 )
1084 .arg(
1085 Arg::new("b")
1086 .long("b")
1087 .action(ArgAction::Set)
1088 .required_unless_present("a")
1089 .conflicts_with("a"),
1090 )
1091 .arg(
1092 Arg::new("c")
1093 .long("c")
1094 .action(ArgAction::Set)
1095 .required_unless_present("d")
1096 .conflicts_with("d"),
1097 )
1098 .arg(
1099 Arg::new("d")
1100 .long("d")
1101 .action(ArgAction::Set)
1102 .required_unless_present("c")
1103 .conflicts_with("c"),
1104 );
1105 utils::assert_output(cmd, "test --c asd", MULTIPLE_REQUIRED_UNLESS_USAGE, true);
1106 }
1107
1108 #[test]
1109 #[cfg(feature = "error-context")]
issue_1158_conflicting_requirements()1110 fn issue_1158_conflicting_requirements() {
1111 static ISSUE_1158: &str = "\
1112 error: the following required arguments were not provided:
1113 -x <X>
1114 -y <Y>
1115 -z <Z>
1116
1117 Usage: example -x <X> -y <Y> -z <Z> <ID>
1118
1119 For more information, try '--help'.
1120 ";
1121
1122 let cmd = issue_1158_app();
1123
1124 utils::assert_output(cmd, "example id", ISSUE_1158, true);
1125 }
1126
1127 #[test]
issue_1158_conflicting_requirements_rev()1128 fn issue_1158_conflicting_requirements_rev() {
1129 let res = issue_1158_app().try_get_matches_from(["", "--config", "some.conf"]);
1130
1131 assert!(res.is_ok(), "{}", res.unwrap_err());
1132 }
1133
1134 #[test]
issue_1643_args_mutually_require_each_other()1135 fn issue_1643_args_mutually_require_each_other() {
1136 use clap::*;
1137
1138 let cmd = Command::new("test")
1139 .arg(
1140 Arg::new("relation_id")
1141 .help("The relation id to get the data from")
1142 .long("relation-id")
1143 .short('r')
1144 .action(ArgAction::Set)
1145 .requires("remote_unit_name"),
1146 )
1147 .arg(
1148 Arg::new("remote_unit_name")
1149 .help("The name of the remote unit to get data from")
1150 .long("remote-unit")
1151 .short('u')
1152 .action(ArgAction::Set)
1153 .requires("relation_id"),
1154 );
1155
1156 cmd.try_get_matches_from(["test", "-u", "hello", "-r", "farewell"])
1157 .unwrap();
1158 }
1159
1160 #[test]
short_flag_require_equals_with_minvals_zero()1161 fn short_flag_require_equals_with_minvals_zero() {
1162 let m = Command::new("foo")
1163 .arg(
1164 Arg::new("check")
1165 .short('c')
1166 .num_args(0..)
1167 .require_equals(true),
1168 )
1169 .arg(Arg::new("unique").short('u').action(ArgAction::SetTrue))
1170 .try_get_matches_from(["foo", "-cu"])
1171 .unwrap();
1172 assert!(m.contains_id("check"));
1173 assert!(*m.get_one::<bool>("unique").expect("defaulted by clap"));
1174 }
1175
1176 #[test]
issue_2624()1177 fn issue_2624() {
1178 let matches = Command::new("foo")
1179 .arg(
1180 Arg::new("check")
1181 .short('c')
1182 .long("check")
1183 .require_equals(true)
1184 .num_args(0..)
1185 .value_parser(["silent", "quiet", "diagnose-first"]),
1186 )
1187 .arg(
1188 Arg::new("unique")
1189 .short('u')
1190 .long("unique")
1191 .action(ArgAction::SetTrue),
1192 )
1193 .try_get_matches_from(["foo", "-cu"])
1194 .unwrap();
1195 assert!(matches.contains_id("check"));
1196 assert!(*matches
1197 .get_one::<bool>("unique")
1198 .expect("defaulted by clap"));
1199 }
1200
1201 #[test]
required_unless_all_with_any()1202 fn required_unless_all_with_any() {
1203 let cmd = Command::new("prog")
1204 .arg(Arg::new("foo").long("foo").action(ArgAction::SetTrue))
1205 .arg(Arg::new("bar").long("bar").action(ArgAction::SetTrue))
1206 .arg(Arg::new("baz").long("baz").action(ArgAction::SetTrue))
1207 .arg(
1208 Arg::new("flag")
1209 .long("flag")
1210 .action(ArgAction::SetTrue)
1211 .required_unless_present_any(["foo"])
1212 .required_unless_present_all(["bar", "baz"]),
1213 );
1214
1215 let result = cmd.clone().try_get_matches_from(vec!["myprog"]);
1216 assert!(result.is_err(), "{:?}", result.unwrap());
1217
1218 let result = cmd.clone().try_get_matches_from(vec!["myprog", "--foo"]);
1219 assert!(result.is_ok(), "{:?}", result.unwrap_err());
1220 let matches = result.unwrap();
1221 assert!(!*matches.get_one::<bool>("flag").expect("defaulted by clap"));
1222
1223 let result = cmd
1224 .clone()
1225 .try_get_matches_from(vec!["myprog", "--bar", "--baz"]);
1226 assert!(result.is_ok(), "{:?}", result.unwrap_err());
1227 let matches = result.unwrap();
1228 assert!(!*matches.get_one::<bool>("flag").expect("defaulted by clap"));
1229
1230 let result = cmd.try_get_matches_from(vec!["myprog", "--bar"]);
1231 assert!(result.is_err(), "{:?}", result.unwrap());
1232 }
1233
1234 #[cfg(debug_assertions)]
1235 #[test]
1236 #[should_panic = "Command prog: Argument or group 'extra' specified in 'requires*' for 'config' does not exist"]
requires_invalid_arg()1237 fn requires_invalid_arg() {
1238 let _ = Command::new("prog")
1239 .arg(Arg::new("config").requires("extra").long("config"))
1240 .try_get_matches_from(vec!["", "--config"]);
1241 }
1242
1243 #[cfg(debug_assertions)]
1244 #[test]
1245 #[should_panic = "Command prog: Argument or group 'extra' specified in 'requires*' for 'config' does not exist"]
requires_if_invalid_arg()1246 fn requires_if_invalid_arg() {
1247 let _ = Command::new("prog")
1248 .arg(
1249 Arg::new("config")
1250 .requires_if("val", "extra")
1251 .long("config"),
1252 )
1253 .try_get_matches_from(vec!["", "--config"]);
1254 }
1255
1256 #[cfg(debug_assertions)]
1257 #[test]
1258 #[should_panic = "Command prog: Argument or group 'extra' specified in 'required_if_eq*' for 'config' does not exist"]
required_if_invalid_arg()1259 fn required_if_invalid_arg() {
1260 let _ = Command::new("prog")
1261 .arg(
1262 Arg::new("config")
1263 .required_if_eq("extra", "val")
1264 .long("config"),
1265 )
1266 .try_get_matches_from(vec!["", "--config"]);
1267 }
1268
1269 #[cfg(debug_assertions)]
1270 #[test]
1271 #[should_panic = "Command prog: Argument or group 'extra' specified in 'required_unless*' for 'config' does not exist"]
required_unless_invalid_arg()1272 fn required_unless_invalid_arg() {
1273 let _ = Command::new("prog")
1274 .arg(
1275 Arg::new("config")
1276 .required_unless_present("extra")
1277 .long("config"),
1278 )
1279 .try_get_matches_from(vec![""]);
1280 }
1281
1282 #[test]
requires_with_default_value()1283 fn requires_with_default_value() {
1284 let result = Command::new("prog")
1285 .arg(
1286 Arg::new("opt")
1287 .long("opt")
1288 .default_value("default")
1289 .requires("flag"),
1290 )
1291 .arg(Arg::new("flag").long("flag").action(ArgAction::SetTrue))
1292 .try_get_matches_from(vec!["myprog"]);
1293
1294 assert!(
1295 result.is_ok(),
1296 "requires should ignore default_value: {:?}",
1297 result.unwrap_err()
1298 );
1299 let m = result.unwrap();
1300
1301 assert_eq!(
1302 m.get_one::<String>("opt").map(|v| v.as_str()),
1303 Some("default")
1304 );
1305 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap"));
1306 }
1307
1308 #[test]
requires_if_with_default_value()1309 fn requires_if_with_default_value() {
1310 let result = Command::new("prog")
1311 .arg(
1312 Arg::new("opt")
1313 .long("opt")
1314 .default_value("default")
1315 .requires_if("default", "flag"),
1316 )
1317 .arg(Arg::new("flag").long("flag").action(ArgAction::SetTrue))
1318 .try_get_matches_from(vec!["myprog"]);
1319
1320 assert!(
1321 result.is_ok(),
1322 "requires_if should ignore default_value: {:?}",
1323 result.unwrap_err()
1324 );
1325 let m = result.unwrap();
1326
1327 assert_eq!(
1328 m.get_one::<String>("opt").map(|v| v.as_str()),
1329 Some("default")
1330 );
1331 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap"));
1332 }
1333
1334 #[test]
group_requires_with_default_value()1335 fn group_requires_with_default_value() {
1336 let result = Command::new("prog")
1337 .arg(Arg::new("opt").long("opt").default_value("default"))
1338 .arg(Arg::new("flag").long("flag").action(ArgAction::SetTrue))
1339 .group(ArgGroup::new("one").arg("opt").requires("flag"))
1340 .try_get_matches_from(vec!["myprog"]);
1341
1342 assert!(
1343 result.is_ok(),
1344 "arg group requires should ignore default_value: {:?}",
1345 result.unwrap_err()
1346 );
1347 let m = result.unwrap();
1348
1349 assert_eq!(
1350 m.get_one::<String>("opt").map(|v| v.as_str()),
1351 Some("default")
1352 );
1353 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap"));
1354 }
1355
1356 #[test]
required_if_eq_on_default_value()1357 fn required_if_eq_on_default_value() {
1358 let result = Command::new("prog")
1359 .arg(Arg::new("opt").long("opt").default_value("default"))
1360 .arg(
1361 Arg::new("flag")
1362 .long("flag")
1363 .action(ArgAction::SetTrue)
1364 .required_if_eq("opt", "default"),
1365 )
1366 .try_get_matches_from(vec!["myprog"]);
1367
1368 assert!(
1369 result.is_ok(),
1370 "required_if_eq should ignore default_value: {:?}",
1371 result.unwrap_err()
1372 );
1373 let m = result.unwrap();
1374
1375 assert_eq!(
1376 m.get_one::<String>("opt").map(|v| v.as_str()),
1377 Some("default")
1378 );
1379 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap"));
1380 }
1381
1382 #[test]
required_if_eq_all_on_default_value()1383 fn required_if_eq_all_on_default_value() {
1384 let result = Command::new("prog")
1385 .arg(Arg::new("opt").long("opt").default_value("default"))
1386 .arg(
1387 Arg::new("flag")
1388 .long("flag")
1389 .action(ArgAction::SetTrue)
1390 .required_if_eq_all([("opt", "default")]),
1391 )
1392 .try_get_matches_from(vec!["myprog"]);
1393
1394 assert!(
1395 result.is_ok(),
1396 "required_if_eq_all should ignore default_value: {:?}",
1397 result.unwrap_err()
1398 );
1399 let m = result.unwrap();
1400
1401 assert_eq!(
1402 m.get_one::<String>("opt").map(|v| v.as_str()),
1403 Some("default")
1404 );
1405 assert!(!*m.get_one::<bool>("flag").expect("defaulted by clap"));
1406 }
1407
1408 #[test]
required_unless_on_default_value()1409 fn required_unless_on_default_value() {
1410 let result = Command::new("prog")
1411 .arg(Arg::new("opt").long("opt").default_value("default"))
1412 .arg(Arg::new("flag").long("flag").required_unless_present("opt"))
1413 .try_get_matches_from(vec!["myprog"]);
1414
1415 assert!(result.is_err(), "{:?}", result.unwrap());
1416 }
1417
1418 #[test]
required_unless_all_on_default_value()1419 fn required_unless_all_on_default_value() {
1420 let result = Command::new("prog")
1421 .arg(Arg::new("opt").long("opt").default_value("default"))
1422 .arg(
1423 Arg::new("flag")
1424 .long("flag")
1425 .required_unless_present_all(["opt"]),
1426 )
1427 .try_get_matches_from(vec!["myprog"]);
1428
1429 assert!(result.is_err(), "{:?}", result.unwrap());
1430 }
1431
1432 #[test]
1433 #[cfg(feature = "error-context")]
required_error_doesnt_duplicate()1434 fn required_error_doesnt_duplicate() {
1435 let cmd = Command::new("Clap-created-USAGE-string-bug")
1436 .arg(Arg::new("a").required(true))
1437 .arg(
1438 Arg::new("b")
1439 .short('b')
1440 .action(ArgAction::Set)
1441 .conflicts_with("c"),
1442 )
1443 .arg(
1444 Arg::new("c")
1445 .short('c')
1446 .action(ArgAction::Set)
1447 .conflicts_with("b"),
1448 );
1449 const EXPECTED: &str = "\
1450 error: the argument '-b <b>' cannot be used with '-c <c>'
1451
1452 Usage: clap-test -b <b> <a>
1453
1454 For more information, try '--help'.
1455 ";
1456 utils::assert_output(cmd, "clap-test aaa -b bbb -c ccc", EXPECTED, true);
1457 }
1458
1459 #[test]
1460 #[cfg(feature = "error-context")]
required_require_with_group_shows_flag()1461 fn required_require_with_group_shows_flag() {
1462 let cmd = Command::new("test")
1463 .arg(arg!(--"require-first").requires("first"))
1464 .arg(arg!(--first).group("either_or_both"))
1465 .arg(arg!(--second).group("either_or_both"))
1466 .group(
1467 ArgGroup::new("either_or_both")
1468 .multiple(true)
1469 .required(true),
1470 );
1471 const EXPECTED: &str = "\
1472 error: the following required arguments were not provided:
1473 --first
1474
1475 Usage: test --require-first <--first|--second>
1476
1477 For more information, try '--help'.
1478 ";
1479 utils::assert_output(cmd, "test --require-first --second", EXPECTED, true);
1480 }
1481