Skip to content

Commit d20331b

Browse files
committed
fix(Required Unless): fixes a bug where having required_unless set doesn't work when conflicts are also set
Closes #753
1 parent eb51316 commit d20331b

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

src/app/parser.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -1608,13 +1608,10 @@ impl<'a, 'b> Parser<'a, 'b>
16081608
fn validate_num_args(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
16091609
debugln!("fn=validate_num_args;");
16101610
for (name, ma) in matcher.iter() {
1611-
if self.groups.contains_key(&**name) {
1612-
continue;
1613-
} else if let Some(opt) = find_by_name!(self, name, opts, iter) {
1611+
debugln!("iter;name={}", name);
1612+
if let Some(opt) = find_by_name!(self, name, opts, iter) {
16141613
try!(self._validate_num_vals(opt, ma, matcher));
1615-
} else if let Some(pos) = self.positionals
1616-
.values()
1617-
.find(|p| &p.b.name == name) {
1614+
} else if let Some(pos) = find_by_name!(self, name, positionals, values) {
16181615
try!(self._validate_num_vals(pos, ma, matcher));
16191616
}
16201617
}
@@ -1685,7 +1682,9 @@ impl<'a, 'b> Parser<'a, 'b>
16851682
}
16861683

16871684
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
1685+
debugln!("fn=validate_required;required={:?};", self.required);
16881686
'outer: for name in &self.required {
1687+
debugln!("iter;name={}", name);
16891688
if matcher.contains(name) {
16901689
continue 'outer;
16911690
}
@@ -1735,27 +1734,36 @@ impl<'a, 'b> Parser<'a, 'b>
17351734
fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool
17361735
where A: AnyArg<'a, 'b>
17371736
{
1737+
debugln!("fn=is_missing_required_ok;a={}", a.name());
17381738
if let Some(bl) = a.blacklist() {
1739+
debugln!("Conflicts found...{:?}", bl);
17391740
for n in bl.iter() {
1741+
debugln!("iter;conflict={}", n);
17401742
if matcher.contains(n) ||
17411743
self.groups
17421744
.get(n)
17431745
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
17441746
return true;
17451747
}
17461748
}
1747-
} else if let Some(ru) = a.required_unless() {
1749+
}
1750+
if let Some(ru) = a.required_unless() {
1751+
debugln!("Required unless found...{:?}", ru);
17481752
let mut found_any = false;
17491753
for n in ru.iter() {
1754+
debugln!("iter;ru={}", n);
17501755
if matcher.contains(n) ||
17511756
self.groups
17521757
.get(n)
17531758
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
17541759
if !a.is_set(ArgSettings::RequiredUnlessAll) {
1760+
debugln!("Doesn't require all...returning true");
17551761
return true;
17561762
}
1763+
debugln!("Requires all...next");
17571764
found_any = true;
17581765
} else if a.is_set(ArgSettings::RequiredUnlessAll) {
1766+
debugln!("Not in matcher, or group and requires all...returning false");
17591767
return false;
17601768
}
17611769
}

tests/require.rs

+17
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,23 @@ fn arg_require_group_3() {
174174

175175
// REQUIRED_UNLESS
176176

177+
#[test]
178+
fn issue_753() {
179+
let m = App::new("test")
180+
.arg(Arg::from_usage("-l, --list 'List available interfaces (and stop there)'"))
181+
.arg(Arg::from_usage("-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'")
182+
.required_unless("list"))
183+
.arg(Arg::from_usage("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'")
184+
.conflicts_with("iface")
185+
.required_unless("list"))
186+
.arg(Arg::from_usage("-s, --server=[SERVER_IP] 'NTP server IP address'")
187+
.required_unless("list"))
188+
.arg(Arg::from_usage("-p, --port=[SERVER_PORT] 'NTP server port'")
189+
.default_value("123"))
190+
.get_matches_from_safe(vec!["test", "--list"]);
191+
assert!(m.is_ok());
192+
}
193+
177194
#[test]
178195
fn required_unless() {
179196
let res = App::new("unlesstest")

0 commit comments

Comments
 (0)