Repository: kbknapp/clap-rs
Pull request #1109 (2017-11-13 22:06:28)

Issue 1105


<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/1109)
<!-- Reviewable:end -->



Patch:
diff --git a/src/app/validator.rs b/src/app/validator.rs
index fd152a83..70eb266b 100644
--- a/src/app/validator.rs
+++ b/src/app/validator.rs
@@ -139,7 +139,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
                 let mut c_with = find_from!($p, &$name, blacklist, &$matcher);
                 c_with = c_with.or(
                     $p.find_any_arg(&$name).map_or(None, |aa| aa.blacklist())
-                                           .map_or(None, 
+                                           .map_or(None,
                                                 |bl| bl.iter().find(|arg| $matcher.contains(arg)))
                                            .map_or(None, |an| $p.find_any_arg(an))
                                            .map_or(None, |aa| Some(format!("{}", aa)))
@@ -312,7 +312,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
             num == 0
         } else { false };
         // Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
-        if a.takes_value() && !(a.is_set(ArgSettings::EmptyValues) || min_vals_zero)  && ma.vals.is_empty() {
+        // Issue 1105 (https://github.com/kbknapp/clap-rs/issues/1105)
+        if a.takes_value() && !min_vals_zero && ma.vals.is_empty() {
             return Err(Error::empty_value(a,
                                           &*usage::create_error_usage(self.0, matcher, None),
                                           self.0.color()));
@@ -410,7 +411,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
                         }
                     })
                 })
-            }}; 
+            }};
         }
         if a.is_set(ArgSettings::RequiredUnlessAll) {
             check!(all, self.0, a, matcher)
diff --git a/src/macros.rs b/src/macros.rs
index 7f530069..ab1357a8 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -308,7 +308,7 @@ macro_rules! arg_enum {
             type Err = String;
 
             fn from_str(s: &str) -> ::std::result::Result<Self,Self::Err> {
-                #[allow(unused_imports)] 
+                #[allow(unused_imports)]
                 use ::std::ascii::AsciiExt;
                 match s {
                     $(stringify!($v) |
@@ -771,6 +771,7 @@ macro_rules! wlnerr(
 
 #[cfg(feature = "debug")]
 #[cfg_attr(feature = "debug", macro_use)]
+#[cfg_attr(feature = "debug", allow(unused_macros))]
 mod debug_macros {
     macro_rules! debugln {
         ($fmt:expr) => (println!(concat!("DEBUG:clap:", $fmt)));
diff --git a/src/osstringext.rs b/src/osstringext.rs
index 303cbcbe..abc222e7 100644
--- a/src/osstringext.rs
+++ b/src/osstringext.rs
@@ -56,11 +56,17 @@ impl OsStrExt2 for OsStr {
     }
 
     fn trim_left_matches(&self, byte: u8) -> &OsStr {
+        let mut found = false;
         for (i, b) in self.as_bytes().iter().enumerate() {
             if b != &byte {
                 return OsStr::from_bytes(&self.as_bytes()[i..]);
+            } else {
+                found = true;
             }
         }
+        if found {
+            return OsStr::from_bytes(&self.as_bytes()[self.len_()..]);
+        }
         &*self
     }
 


Test patch:
diff --git a/tests/opts.rs b/tests/opts.rs
index 8a2deee9..a9029ac9 100644
--- a/tests/opts.rs
+++ b/tests/opts.rs
@@ -3,7 +3,7 @@ extern crate regex;
 
 include!("../clap-test.rs");
 
-use clap::{App, Arg, ErrorKind};
+use clap::{App, ArgMatches, Arg, ErrorKind};
 
 #[cfg(feature = "suggestions")]
 static DYM: &'static str = "error: Found argument '--optio' which wasn't expected, or isn't valid in this context
@@ -194,18 +194,6 @@ fn opts_using_long_space() {
     assert_eq!(m.value_of("color").unwrap(), "other");
 }
 
-#[test]
-fn opts_with_empty_values() {
-    let r = App::new("opts")
-        .arg_from_usage("--flag [flag]... 'some flag'")
-        .get_matches_from_safe(vec!["", "--flag", "", "test"]);
-    assert!(r.is_ok());
-    let m = r.unwrap();
-    assert!(m.is_present("flag"));
-    assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(),
-               ["", "test"]);
-}
-
 #[test]
 fn opts_using_long_equals() {
     let r = App::new("opts")
@@ -409,4 +397,65 @@ fn issue_1047_min_zero_vals_default_val() {
         .get_matches_from(vec!["foo", "-d"]);
     assert_eq!(m.occurrences_of("del"), 1);
     assert_eq!(m.value_of("del"), Some("default"));
-}
\ No newline at end of file
+}
+
+fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches<'static>, clap::Error> {
+    App::new("opts")
+        .arg_from_usage("-o, --option [opt] 'some option'")
+        .arg_from_usage("--flag 'some flag'")
+        .get_matches_from_safe(argv)
+}
+
+#[test]
+fn issue_1105_empty_value_long_fail() {
+    let r = issue_1105_setup(vec!["app",  "--option", "--flag"]);
+    assert!(r.is_err());
+    assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn issue_1105_empty_value_long_explicit() {
+    let r = issue_1105_setup(vec!["app", "--option", ""]);
+    assert!(r.is_ok());
+    let m = r.unwrap();
+    assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_long_equals() {
+    let r = issue_1105_setup(vec!["app",  "--option="]);
+    assert!(r.is_ok());
+    let m = r.unwrap();
+    assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_short_fail() {
+    let r = issue_1105_setup(vec!["app", "-o", "--flag"]);
+    assert!(r.is_err());
+    assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn issue_1105_empty_value_short_explicit() {
+    let r = issue_1105_setup(vec!["app", "-o", ""]);
+    assert!(r.is_ok());
+    let m = r.unwrap();
+    assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_short_equals() {
+    let r = issue_1105_setup(vec!["app", "-o="]);
+    assert!(r.is_ok());
+    let m = r.unwrap();
+    assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_short_explicit_no_space() {
+    let r = issue_1105_setup(vec!["app", "-o", ""]);
+    assert!(r.is_ok());
+    let m = r.unwrap();
+    assert_eq!(m.value_of("option"), Some(""));
+}