1use clap::builder::ArgPredicate;
2use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
3
4#[cfg(feature = "error-context")]
5use super::utils;
6
7#[test]
8fn 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]
19fn 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]
34fn 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]
45fn 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]
61fn 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]
71fn 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")]
85fn positional_required_with_requires() {
86    static POSITIONAL_REQ: &str = "\
87error: the following required arguments were not provided:
88  <flag>
89  <opt>
90
91Usage: clap-test <flag> <opt> [bar]
92
93For 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")]
106fn positional_required_with_requires_if_no_value() {
107    static POSITIONAL_REQ_IF_NO_VAL: &str = "\
108error: the following required arguments were not provided:
109  <flag>
110
111Usage: clap-test <flag> [opt] [bar]
112
113For 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")]
126fn positional_required_with_requires_if_value() {
127    static POSITIONAL_REQ_IF_VAL: &str = "\
128error: the following required arguments were not provided:
129  <foo>
130  <opt>
131
132Usage: clap-test <flag> <foo> <opt> [bar]
133
134For 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]
147fn 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]
160fn 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]
174fn 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]
188fn 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]
201fn 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]
220fn 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]
241fn 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]
264fn 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]
282fn 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]
298fn 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]
317fn 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]
337fn 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]
356fn 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]
375fn 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]
396fn 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]
418fn 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]
439fn 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]
455fn 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]
476fn 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]
496fn 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")]
514fn missing_required_output() {
515    static MISSING_REQ: &str = "\
516error: the following required arguments were not provided:
517  --long-option-2 <option2>
518  <positional>
519  <positional2>
520
521Usage: clap-test --long-option-2 <option2> -F <positional> <positional2> [positional3]...
522
523For 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]
532fn 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]
548fn 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]
565fn 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]
581fn 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]
598fn 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]
613fn 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]
629fn 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]
649fn 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]
670fn 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]
688fn 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]
704fn 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]
721fn 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]
740fn 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")]
759fn list_correct_required_args() {
760    static COND_REQ_IN_USAGE: &str = "\
761error: the following required arguments were not provided:
762  --output <output>
763
764Usage: test --target <target> --input <input> --output <output>
765
766For 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")]
803fn required_if_val_present_fail_error_output() {
804    static COND_REQ_IN_USAGE: &str = "\
805error: the following required arguments were not provided:
806  --output <output>
807
808Usage: test --target <target> --input <input> --output <output>
809
810For 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]
846fn 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]
861fn 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]
877fn 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]
894fn 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]
910fn 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")]
928fn require_eq() {
929    static REQUIRE_EQUALS: &str = "\
930error: the following required arguments were not provided:
931  --opt=<FILE>
932
933Usage: clap-test --opt=<FILE>
934
935For 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")]
952fn require_eq_filtered() {
953    static REQUIRE_EQUALS_FILTERED: &str = "\
954error: the following required arguments were not provided:
955  --opt=<FILE>
956
957Usage: clap-test --opt=<FILE> --foo=<FILE>
958
959For 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")]
987fn require_eq_filtered_group() {
988    static REQUIRE_EQUALS_FILTERED_GROUP: &str = "\
989error: the following required arguments were not provided:
990  --opt=<FILE>
991
992Usage: clap-test --opt=<FILE> --foo=<FILE> <--g1=<FILE>|--g2=<FILE>>
993
994For 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
1042fn 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")]
1066fn multiple_required_unless_usage_printing() {
1067    static MULTIPLE_REQUIRED_UNLESS_USAGE: &str = "\
1068error: the following required arguments were not provided:
1069  --a <a>
1070  --b <b>
1071
1072Usage: test --c <c> --a <a> --b <b>
1073
1074For 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")]
1110fn issue_1158_conflicting_requirements() {
1111    static ISSUE_1158: &str = "\
1112error: the following required arguments were not provided:
1113  -x <X>
1114  -y <Y>
1115  -z <Z>
1116
1117Usage: example -x <X> -y <Y> -z <Z> <ID>
1118
1119For 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]
1128fn 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]
1135fn 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]
1161fn 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]
1177fn 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]
1202fn 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"]
1237fn 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"]
1246fn 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"]
1259fn 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"]
1272fn 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]
1283fn 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]
1309fn 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]
1335fn 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]
1357fn 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]
1383fn 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]
1409fn 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]
1419fn 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")]
1434fn 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 = "\
1450error: the argument '-b <b>' cannot be used with '-c <c>'
1451
1452Usage: clap-test -b <b> <a>
1453
1454For 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")]
1461fn 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 = "\
1472error: the following required arguments were not provided:
1473  --first
1474
1475Usage: test --require-first <--first|--second>
1476
1477For more information, try '--help'.
1478";
1479    utils::assert_output(cmd, "test --require-first --second", EXPECTED, true);
1480}
1481