From 45dcf0ed222e5fdb023f45b50366cf0e3817c907 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Oct 2022 19:02:39 -0500 Subject: [PATCH] fix(parser): Don't make Args `exclusive` with their ArgGroup This is most obvious with the derive API as it creates `ArgGroup`s all over the place now. Fixes #4396 --- src/parser/validator.rs | 3 +++ tests/builder/conflicts.rs | 23 ++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/parser/validator.rs b/src/parser/validator.rs index 8b6e46c6367..970804bcca7 100644 --- a/src/parser/validator.rs +++ b/src/parser/validator.rs @@ -112,6 +112,9 @@ impl<'cmd> Validator<'cmd> { .arg_ids() .filter(|arg_id| { matcher.check_explicit(arg_id, &crate::builder::ArgPredicate::IsPresent) + // Avoid including our own groups by checking none of them. If a group is present, the + // args for the group will be. + && self.cmd.find(arg_id).is_some() }) .count(); if args_count <= 1 { diff --git a/tests/builder/conflicts.rs b/tests/builder/conflicts.rs index dbee06b16e8..32a3342aa22 100644 --- a/tests/builder/conflicts.rs +++ b/tests/builder/conflicts.rs @@ -38,10 +38,13 @@ fn flag_conflict_with_all() { #[test] fn exclusive_flag() { - let result = Command::new("flag_conflict") + let cmd = Command::new("flag_conflict") .arg(arg!(-f --flag "some flag").exclusive(true)) - .arg(arg!(-o --other "some flag")) - .try_get_matches_from(vec!["myprog", "-o", "-f"]); + .arg(arg!(-o --other "some flag")); + let result = cmd.clone().try_get_matches_from(vec!["myprog", "-f"]); + assert!(result.is_ok(), "{}", result.unwrap_err()); + + let result = cmd.clone().try_get_matches_from(vec!["myprog", "-o", "-f"]); assert!(result.is_err()); let err = result.err().unwrap(); assert_eq!(err.kind(), ErrorKind::ArgumentConflict); @@ -71,6 +74,20 @@ fn not_exclusive_with_defaults() { assert!(result.is_ok(), "{}", result.unwrap_err()); } +#[test] +fn not_exclusive_with_group() { + let cmd = Command::new("test") + .group(clap::ArgGroup::new("test").arg("foo")) + .arg( + clap::Arg::new("foo") + .long("foo") + .exclusive(true) + .action(clap::ArgAction::SetTrue), + ); + let result = cmd.try_get_matches_from(vec!["test", "--foo"]); + assert!(result.is_ok(), "{}", result.unwrap_err()); +} + #[test] fn default_doesnt_activate_exclusive() { let result = Command::new("flag_conflict")