Repository: kbknapp/clap-rs (rust)

Issue:
Appsetting::InferSubcommands can't match a command whose name is a substring of another
### Rust Version
1.25.0

### Affected Version of clap
2.31.2

### Expected Behavior Summary
Assuming I have subcommands "foo", "foobar", and "football" with Appsetting::InferSubcommands, I should be able to give "foo", "foob", or "foot" parameters (it's ok to fail if I give "f" or "fo").

### Actual Behavior Summary
```
$ ./inferbug.crs foo
error: The subcommand 'foo' wasn't recognized
        Did you mean 'foo'?
```

### Sample Code or Link to Sample Code
```rust
#!/usr/bin/env run-cargo-script
//! ```cargo                                                                                                                                                                                                                                 
//! [dependencies]                                                                                                                                                                                                                           
//! clap = "2.31.2"                                                                                                                                                                                                                          
//! ```                                                                                                                                                                                                                                      
extern crate clap;
use clap::{App, AppSettings, SubCommand};
fn main() {
    let cli = App::new("clap-infer-bug")
        .setting(AppSettings::InferSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("foo"))
        .subcommand(SubCommand::with_name("foobar"))
        .subcommand(SubCommand::with_name("football"))
        .get_matches();
    println!("{:?}", cli.subcommand().0);
}
```



Pull request:
exactly match a subcommand when using the infersubcommands
Closes #1254.

<!-- 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/1298)
<!-- Reviewable:end -->


Patch:
diff --git a/src/app/parser.rs b/src/app/parser.rs
index 672ef8c5..f9c04227 100644
--- a/src/app/parser.rs
+++ b/src/app/parser.rs
@@ -656,13 +656,12 @@ where
 
     // Checks if the arg matches a subcommand name, or any of it's aliases (if defined)
     fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
+        #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
+        use std::os::unix::ffi::OsStrExt;
+        #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+        use osstringext::OsStrExt3;
         debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
         fn starts(h: &str, n: &OsStr) -> bool {
-            #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
-            use std::os::unix::ffi::OsStrExt;
-            #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
-            use osstringext::OsStrExt3;
-
             let n_bytes = n.as_bytes();
             let h_bytes = OsStr::new(h).as_bytes();
 
@@ -694,6 +693,12 @@ where
                 .map(|sc| &sc.p.meta.name)
                 .collect::<Vec<_>>();
 
+            for sc in &v {
+                if OsStr::new(sc) == arg_os {
+                    return (true, Some(sc));
+                }
+            }
+
             if v.len() == 1 {
                 return (true, Some(v[0]));
             }


Test patch:
diff --git a/tests/app_settings.rs b/tests/app_settings.rs
index c9b0198f..7f2c06ec 100644
--- a/tests/app_settings.rs
+++ b/tests/app_settings.rs
@@ -222,6 +222,19 @@ fn infer_subcommands_pass_close() {
     assert_eq!(m.subcommand_name(), Some("test"));
 }
 
+#[test]
+fn infer_subcommands_pass_exact_match() {
+    let m = App::new("prog")
+        .setting(AppSettings::InferSubcommands)
+        .subcommand(SubCommand::with_name("test"))
+        .subcommand(SubCommand::with_name("testa"))
+        .subcommand(SubCommand::with_name("testb"))
+        .get_matches_from(vec![
+            "prog", "test"
+        ]);
+    assert_eq!(m.subcommand_name(), Some("test"));
+}
+
 #[cfg(feature = "suggestions")]
 #[test]
 fn infer_subcommands_fail_suggestions() {