Merge pull request #1079 from kbknapp/issues-1031,1050,1056,1066,1071

Issues 1031,1050,1056,1066,1071
This commit is contained in:
Kevin K 2017-10-24 21:49:18 -04:00 committed by GitHub
commit fe814b88e3
12 changed files with 279 additions and 112 deletions

View file

@ -1,3 +1,49 @@
<a name="v2.27.0"></a>
## v2.27.0 (2017-10-24)
** This release raises the minimum required version of Rust to 1.19 **
** This release also contains a very minor breaking change to fix a bug **
The only CLIs affected will be those using unrestrained multiple values and subcommands where the
subcommand name can coincide with one of the multiple values.
See the commit [0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31) for full details.
#### Bug Fixes
* Values from global args are now propagated UP and DOWN!
* fixes a bug where using AppSettings::AllowHyphenValues would allow invalid arguments even when there is no way for them to be valid ([77ed4684](https://github.com/kbknapp/clap-rs/commit/77ed46841fc0263d7aa32fcc5cc49ef703b37c04), closes [#1066](https://github.com/kbknapp/clap-rs/issues/1066))
* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/))
* fixes a bug that prevented number_of_values and default_values to be used together ([5eb342a9](https://github.com/kbknapp/clap-rs/commit/5eb342a99dde07b0f011048efde3e283bc1110fc), closes [#1050](https://github.com/kbknapp/clap-rs/issues/1050), [#1056](https://github.com/kbknapp/clap-rs/issues/1056))
* fixes a bug that didn't allow args with default values to have conflicts ([58b5b4be](https://github.com/kbknapp/clap-rs/commit/58b5b4be315280888d50d9b15119b91a9028f050), closes [#1071](https://github.com/kbknapp/clap-rs/issues/1071))
* fixes a panic when using global args and calling App::get_matches_from_safe_borrow multiple times ([d86ec797](https://github.com/kbknapp/clap-rs/commit/d86ec79742c77eb3f663fb30e225954515cf25bb), closes [#1076](https://github.com/kbknapp/clap-rs/issues/1076))
* fixes issues and potential regressions with global args values not being propagated properly or at all ([a43f9dd4](https://github.com/kbknapp/clap-rs/commit/a43f9dd4aaf1864dd14a3c28dec89ccdd70c61e5), closes [#1010](https://github.com/kbknapp/clap-rs/issues/1010), [#1061](https://github.com/kbknapp/clap-rs/issues/1061), [#978](https://github.com/kbknapp/clap-rs/issues/978))
* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047))
#### Documentation
* adds addtional blurbs about using multiples with subcommands ([03455b77](https://github.com/kbknapp/clap-rs/commit/03455b7751a757e7b2f6ffaf2d16168539c99661))
* updates the docs to reflect changes to global args and that global args values can now be propagated back up the stack ([ead076f0](https://github.com/kbknapp/clap-rs/commit/ead076f03ada4c322bf3e34203925561ec496d87))
* add html_root_url attribute ([e67a061b](https://github.com/kbknapp/clap-rs/commit/e67a061bcf567c6518d6c2f58852e01f02764b22))
* sync README version numbers with crate version ([5536361b](https://github.com/kbknapp/clap-rs/commit/5536361bcda29887ed86bb68e43d0b603cbc423f))
#### Improvements
* args that have require_delimiter(true) is now reflected in help and usage strings ([dce61699](https://github.com/kbknapp/clap-rs/commit/dce616998ed9bd95e8ed3bec1f09a4883da47b85), closes [#1052](https://github.com/kbknapp/clap-rs/issues/1052))
* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046))
#### Breaking Changes
* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/))
#### Deprecations
* **AppSettings::PropagateGlobalValuesDown:** this setting is no longer required to propagate values down or up ([2bb5ddce](https://github.com/kbknapp/clap-rs/commit/2bb5ddcee61c791ca1aaca494fbeb4bd5e277488))
<a name="v2.26.2"></a>
### v2.26.2 (2017-09-14)

View file

@ -1,7 +1,7 @@
[package]
name = "clap"
version = "2.26.2"
version = "2.27.0"
authors = ["Kevin K. <kbknapp@gmail.com>"]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
repository = "https://github.com/kbknapp/clap-rs.git"

View file

@ -45,24 +45,47 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## What's New
Here's what's new in 2.26.2:
Here's whats new in 2.27.0:
* if all subcommands are hidden, the subcommands section of the help message is no longer displayed
* fixes a bug where default values are not applied if the option supports zero values
* fixes using require_equals(true) and min_values(0) together
* escape special characters in zsh and fish completions
* avoid panic generating default help msg if term width set to 0 due to bug in textwrap 0.7.0
** This release also contains a very minor breaking change to fix a bug **
The only CLIs affected will be those using unrestrained multiple values and subcommands where the
subcommand name can coincide with one of the multiple values.
See the commit [0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31) for full details.
* **The minimum required version of Rust is now 1.12.0 (Stable)**
* Values from global args are now propagated UP and DOWN!
* fixes a bug where using AppSettings::AllowHyphenValues would allow invalid arguments even when there is no way for them to be valid
* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value
* fixes a bug that prevented number_of_values and default_values to be used together
* fixes a bug that didn't allow args with default values to have conflicts
* fixes a panic when using global args and calling App::get_matches_from_safe_borrow multiple times
* fixes issues and potential regressions with global args values not being propagated properly or at all
* fixes a bug where default values are not applied if the option supports zero values
* adds addtional blurbs about using multiples with subcommands
* updates the docs to reflect changes to global args and that global args values can now be propagated back up the stack
* add html_root_url attribute
* sync README version numbers with crate version
* args that have require_delimiter(true) is now reflected in help and usage strings
* if all subcommands are hidden, the subcommands section of the help message is no longer displayed
* fixes when an argument requires a value and that value happens to match a subcommand name, its parsed as a value
* **AppSettings::PropagateGlobalValuesDown:** this setting deprecated and is no longer required to propagate values down or up
Here's the highlights for v2.21.0 to v2.26.2
* if all subcommands are hidden, the subcommands section of the help message is no longer displayed
* fixes a bug where default values are not applied if the option supports zero values
* fixes using require_equals(true) and min_values(0) together
* escape special characters in zsh and fish completions
* avoid panic generating default help msg if term width set to 0 due to bug in textwrap 0.7.0
* Change `who's` -> `whose` in documentation
* **Help Message:** fixes `App::long_about` not being displayed
* **Suggestions:** output for flag after subcommand
Here's the highlights for v2.21.0 to v2.26.0
* **Suggestions:** output for flag after subcommand
* **The minimum required version of Rust is now 1.13.0 (Stable)**
* bumps unicode-segmentation to v1.2
* bumps unicode-segmentation to v1.2
* update textwrap to version 0.7.0 which increases the performance of writing help strings
* impl Default for Values + OsValues for any lifetime.
* impl Default for Values + OsValues for any lifetime.
* use textwrap crate for wrapping help texts
* suggests to use flag after subcommand when applicable
* Bumps bitflags crate to v0.9
@ -353,7 +376,7 @@ subcommands:
Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml:
Simply change your `clap = "2.19"` to `clap = {version = "2.19", features = ["yaml"]}`.
Simply change your `clap = "2.27"` to `clap = {version = "2.27", features = ["yaml"]}`.
At last we create our `main.rs` file just like we would have with the previous two examples:
@ -472,7 +495,7 @@ For full usage, add `clap` as a dependency in your `Cargo.toml` () to use from c
```toml
[dependencies]
clap = "~2.26"
clap = "~2.27"
```
(**note**: If you are concerned with supporting a minimum version of Rust that is *older* than the current stable Rust minus 2 stable releases, it's recommended to use the `~major.minor.patch` style versions in your `Cargo.toml` which will only update the patch version automatically. For more information see the [Compatibility Policy](#compatibility-policy))
@ -496,7 +519,7 @@ To disable these, add this to your `Cargo.toml`:
```toml
[dependencies.clap]
version = "2.26"
version = "2.27"
default-features = false
```
@ -504,7 +527,7 @@ You can also selectively enable only the features you'd like to include, by addi
```toml
[dependencies.clap]
version = "2.26"
version = "2.27"
default-features = false
# Cherry-pick the features you'd like to use
@ -630,7 +653,7 @@ In order to keep from being surprised of breaking changes, it is **highly** reco
```toml
[dependencies]
clap = "~2.26"
clap = "~2.27"
```
This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust.
@ -647,11 +670,11 @@ Right now Cargo's version resolution is pretty naive, it's just a brute-force se
# In one Cargo.toml
[dependencies]
clap = "~2.19.0"
clap = "~2.27.0"
# In another Cargo.toml
[dependencies]
clap = "2.22"
clap = "2.27"
```
@ -659,8 +682,9 @@ This is inherently an unresolvable crate graph in Cargo right now. Cargo require
#### Minimum Version of Rust
`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.13.0, meaning `clap` is guaranteed to compile with 1.11.0 and beyond.
At the 1.14.0 release, `clap` will be guaranteed to compile with 1.12.0 and beyond, etc.
`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.21.0, meaning `clap` is guaranteed to compile with 1.19.0 and beyond.
At the 1.22.0 stable release, `clap` will be guaranteed to compile with 1.20.0 and beyond, etc.
Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be clearly annotated in the `CHANGELOG.md`
@ -724,6 +748,6 @@ As of 2.0.0 (From 1.x)
Old method names will be left around for several minor version bumps, or one major version bump.
As of 2.19.0:
As of 2.27.0:
* None!
* **AppSettings::PropagateGlobalValuesDown:** this setting deprecated and is no longer required to propagate values down or up

View file

@ -848,17 +848,22 @@ impl<'a, 'b> Parser<'a, 'b>
if !self.is_set(AS::TrailingValues) {
// Does the arg match a subcommand name, or any of it's aliases (if defined)
{
let (is_match, sc_name) = self.possible_subcommand(&arg_os);
debugln!("Parser::get_matches_with: possible_sc={:?}, sc={:?}",
is_match,
sc_name);
if is_match {
let sc_name = sc_name.expect(INTERNAL_ERROR_MSG);
if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) {
self.parse_help_subcommand(it)?;
match needs_val_of {
ParseResult::Opt(_) | ParseResult::Pos(_) =>(),
_ => {
let (is_match, sc_name) = self.possible_subcommand(&arg_os);
debugln!("Parser::get_matches_with: possible_sc={:?}, sc={:?}",
is_match,
sc_name);
if is_match {
let sc_name = sc_name.expect(INTERNAL_ERROR_MSG);
if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) {
self.parse_help_subcommand(it)?;
}
subcmd_name = Some(sc_name.to_owned());
break;
}
}
subcmd_name = Some(sc_name.to_owned());
break;
}
}
@ -1010,8 +1015,8 @@ impl<'a, 'b> Parser<'a, 'b>
name: sc_name,
matches: sc_m.into(),
});
} else if !(self.is_set(AS::AllowLeadingHyphen) ||
self.is_set(AS::AllowNegativeNumbers)) &&
} else if !((self.is_set(AS::AllowLeadingHyphen) ||
self.is_set(AS::AllowNegativeNumbers)) && arg_os.starts_with(b"-")) &&
!self.is_set(AS::InferSubcommands) {
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
"",
@ -1042,6 +1047,13 @@ impl<'a, 'b> Parser<'a, 'b>
.unwrap_or(&self.meta.name),
self.color()));
}
} else {
return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
"",
&*usage::create_error_usage(self,
matcher,
None),
self.color()));
}
}
@ -1723,17 +1735,24 @@ impl<'a, 'b> Parser<'a, 'b>
}
pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
debugln!("Parser::add_defaults;");
macro_rules! add_val {
(@default $_self:ident, $a:ident, $m:ident) => {
if let Some(ref val) = $a.v.default_val {
debugln!("Parser::add_defaults:iter:{}: has default vals", $a.b.name);
if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.b.name);
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
} else if $m.get($a.b.name).is_some() {
debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.b.name);
} else {
debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.b.name);
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
@ -1741,10 +1760,13 @@ impl<'a, 'b> Parser<'a, 'b>
$_self.cache = Some($a.name());
}
}
} else {
debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.b.name);
}
};
($_self:ident, $a:ident, $m:ident) => {
if let Some(ref vm) = $a.v.default_vals_ifs {
sdebugln!(" has conditional defaults");
let mut done = false;
if $m.get($a.b.name).is_none() {
for &(arg, val, default) in vm.values() {
@ -1772,15 +1794,19 @@ impl<'a, 'b> Parser<'a, 'b>
if done {
continue; // outer loop (outside macro)
}
} else {
sdebugln!(" doesn't have conditional defaults");
}
add_val!(@default $_self, $a, $m)
};
}
for o in &self.opts {
debug!("Parser::add_defaults:iter:{}:", o.b.name);
add_val!(self, o, matcher);
}
for p in self.positionals.values() {
debug!("Parser::add_defaults:iter:{}:", p.b.name);
add_val!(self, p, matcher);
}
Ok(())

View file

@ -166,20 +166,22 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
for name in &self.0.blacklist {
debugln!("Validator::validate_blacklist:iter: Checking blacklisted name: {}",
name);
debugln!("Validator::validate_blacklist:iter:{}: Checking blacklisted arg", name);
let mut should_err = false;
if self.0.groups.iter().any(|g| &g.name == name) {
debugln!("Validator::validate_blacklist:iter: groups contains it...");
debugln!("Validator::validate_blacklist:iter:{}: groups contains it...", name);
for n in self.0.arg_names_in_group(name) {
debugln!("Validator::validate_blacklist:iter:iter: Checking arg '{}' in group...",
n);
debugln!("Validator::validate_blacklist:iter:{}:iter:{}: looking in group...", name, n);
if matcher.contains(n) {
debugln!("Validator::validate_blacklist:iter:iter: matcher contains it...");
debugln!("Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...", name, n);
return Err(build_err!(self.0, n, matcher));
}
}
} else if matcher.contains(name) {
debugln!("Validator::validate_blacklist:iter: matcher contains it...");
} else if let Some(ma) = matcher.get(name) {
debugln!("Validator::validate_blacklist:iter:{}: matcher contains it...", name);
should_err = ma.occurs > 0;
}
if should_err {
return Err(build_err!(self.0, *name, matcher));
}
}

View file

@ -1891,11 +1891,11 @@ impl<'a, 'b> Arg<'a, 'b> {
/// **WARNING:**
///
/// Setting `multiple(true)` for an [option] with no other details, allows multiple values
/// **and** multiple occurrences because it isn't possible to have more occurrences than values for
/// options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly valid,
/// be careful when designing a CLI where positional arguments are expected after a option which
/// accepts multiple values, as `clap` will continue parsing *values* until it reaches the max
/// or specific number of values defined, or another flag or option.
/// **and** multiple occurrences because it isn't possible to have more occurrences than values
/// for options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly
/// valid, be careful when designing a CLI where positional arguments are expected after a
/// option which accepts multiple values, as `clap` will continue parsing *values* until it
/// reaches the max or specific number of values defined, or another flag or option.
///
/// **Pro Tip**:
///
@ -1903,6 +1903,36 @@ impl<'a, 'b> Arg<'a, 'b> {
/// occurrence. To do this use [`Arg::number_of_values(1)`] in coordination with
/// [`Arg::multiple(true)`].
///
/// **WARNING:**
///
/// When using args with `multiple(true)` on [options] or [positionals] (i.e. those args that
/// accept values) and [subcommands], one needs to consider the posibility of an argument value
/// being the same as a valid subcommand. By default `clap` will parse the argument in question
/// as a value *only if* a value is possible at that moment. Otherwise it will be parsed as a
/// subcommand. In effect, this means using `multiple(true)` with no additional parameters and
/// a possible value that coincides with a subcommand name, the subcommand cannot be called
/// unless another argument is passed first.
///
/// As an example, consider a CLI with an option `--ui-paths=<paths>...` and subcommand `signer`
///
/// The following would be parsed as values to `--ui-paths`.
///
/// ```notrust
/// $ program --ui-paths path1 path2 signer
/// ```
///
/// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values
/// until another argument is reached and it knows `--ui-paths` is done.
///
/// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding
/// [`Arg::number_of_values(1)`] as discussed above. The following are all valid, and `signer`
/// is parsed as both a subcommand and a value in the second case.
///
/// ```notrust
/// $ program --ui-paths path1 signer
/// $ program --ui-paths path1 --ui-paths signer signer
/// ```
///
/// # Examples
///
/// ```rust
@ -2036,6 +2066,9 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
/// ```
/// [option]: ./struct.Arg.html#method.takes_value
/// [options]: ./struct.Arg.html#method.takes_value
/// [subcommands]: ./struct.SubCommand.html
/// [positionals]: ./struct.Arg.html#method.index
/// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn multiple(self, multi: bool) -> Self {

View file

@ -180,7 +180,7 @@
//! Since this feature requires additional dependencies that not everyone may want, it is *not*
//! compiled in by default and we need to enable a feature flag in Cargo.toml:
//!
//! Simply change your `clap = "~2.19.0"` to `clap = {version = "~2.19.0", features = ["yaml"]}`.
//! Simply change your `clap = "~2.27.0"` to `clap = {version = "~2.27.0", features = ["yaml"]}`.
//!
//! At last we create our `main.rs` file just like we would have with the previous two examples:
//!
@ -306,7 +306,7 @@
//!
//! ```toml
//! [dependencies]
//! clap = "~2.19.0"
//! clap = "~2.27.0"
//! ```
//!
//! Or get the latest changes from the master branch at github:
@ -337,7 +337,7 @@
//!
//! ```toml
//! [dependencies.clap]
//! version = "~2.19.0"
//! version = "~2.27.0"
//! default-features = false
//! ```
//!
@ -345,7 +345,7 @@
//!
//! ```toml
//! [dependencies.clap]
//! version = "~2.19.0"
//! version = "~2.27.0"
//! default-features = false
//!
//! # Cherry-pick the features you'd like to use
@ -491,7 +491,7 @@
//! the `~major.minor.patch` style in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies] clap = "~2.19.0"
//! [dependencies] clap = "~2.27.0"
//! ```
//!
//! This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore
@ -500,9 +500,9 @@
//! #### Minimum Version of Rust
//!
//! `clap` will officially support current stable Rust, minus two releases, but may work with prior
//! releases as well. For example, current stable Rust at the time of this writing is 1.13.0,
//! meaning `clap` is guaranteed to compile with 1.11.0 and beyond. At the 1.14.0 release, `clap`
//! will be guaranteed to compile with 1.12.0 and beyond, etc.
//! releases as well. For example, current stable Rust at the time of this writing is 1.21.0,
//! meaning `clap` is guaranteed to compile with 1.19.0 and beyond. At the 1.22.0 release, `clap`
//! will be guaranteed to compile with 1.20.0 and beyond, etc.
//!
//! Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be
//! clearly annotated in the `CHANGELOG.md`
@ -513,7 +513,7 @@
//! this repository for more information.
#![crate_type= "lib"]
#![doc(html_root_url = "https://docs.rs/clap/2.26.2")]
#![doc(html_root_url = "https://docs.rs/clap/2.27.0")]
#![deny(
missing_docs,
missing_debug_implementations,

View file

@ -619,3 +619,36 @@ fn allow_missing_positional() {
assert_eq!(m.value_of("src"), Some("src"));
assert_eq!(m.value_of("dest"), Some("file"));
}
#[test]
fn issue_1066_allow_leading_hyphen_and_unknown_args() {
let res = App::new("prog")
.global_setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::from_usage("--some-argument"))
.get_matches_from_safe(vec!["prog", "hello"]);
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
}
#[test]
fn issue_1066_allow_leading_hyphen_and_unknown_args_no_vals() {
let res = App::new("prog")
.global_setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::from_usage("--some-argument"))
.get_matches_from_safe(vec!["prog", "--hello"]);
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
}
#[test]
fn issue_1066_allow_leading_hyphen_and_unknown_args_option() {
let res = App::new("prog")
.global_setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::from_usage("--some-argument=[val]"))
.get_matches_from_safe(vec!["prog", "-hello"]);
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
}

View file

@ -86,3 +86,17 @@ fn conflict_output() {
fn conflict_output_rev() {
test::compare_output(test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true);
}
#[test]
fn conflict_with_unused_default_value() {
let result = App::new("conflict")
.arg(Arg::from_usage("-o, --opt=[opt] 'some opt'")
.default_value("default"))
.arg(Arg::from_usage("-f, --flag 'some flag'")
.conflicts_with("opt"))
.get_matches_from_safe(vec!["myprog", "-f"]);
assert!(result.is_ok());
let m = result.unwrap();
assert_eq!(m.value_of("opt"), Some("default"));
assert!(m.is_present("flag"));
}

View file

@ -479,3 +479,20 @@ fn conditional_reqs_pass() {
assert_eq!(m.value_of("output"), Some("other"));
assert_eq!(m.value_of("input"), Some("some"));
}
#[test]
fn issue_1050_num_vals_and_defaults() {
let res = App::new("hello")
.arg(
Arg::with_name("exit-code")
.long("exit-code")
.required(true)
.takes_value(true)
.number_of_values(1)
.default_value("0"),
)
.get_matches_from_safe(vec!["hello", "--exit-code=1"]);
assert!(res.is_ok());
let m = res.unwrap();
assert_eq!(m.value_of("exit-code"), Some("1"));
}

View file

@ -25,30 +25,6 @@ fn option_long() {
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
}
#[test]
fn with_subcmd() {
let m = App::new("multiple_values")
.arg(Arg::with_name("option")
.long("option")
.help("multiple options")
.takes_value(true)
.multiple(true))
.subcommand(SubCommand::with_name("foo"))
.get_matches_from_safe(vec![
"",
"--option", "val1",
"val2", "foo"
]);
assert!(m.is_ok());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2"]);
assert_eq!(m.subcommand_name(), Some("foo"));
}
#[test]
fn option_short() {
let m = App::new("multiple_values")
@ -985,35 +961,6 @@ fn low_index_positional() {
assert_eq!(m.value_of("target").unwrap(), "target");
}
#[test]
fn low_index_positional_with_subcmd() {
let m = App::new("lip")
.arg(Arg::with_name("files")
.index(1)
.required(true)
.multiple(true))
.arg(Arg::with_name("target")
.index(2)
.required(true))
.subcommand(SubCommand::with_name("test").arg(Arg::with_name("other")))
.get_matches_from_safe(vec![
"lip",
"file1", "file2",
"file3", "target",
"test"
]);
assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
let m = m.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.occurrences_of("files"), 3);
assert!(m.is_present("target"));
assert_eq!(m.occurrences_of("target"), 1);
assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
assert_eq!(m.value_of("target").unwrap(), "target");
}
#[test]
fn low_index_positional_in_subcmd() {
let m = App::new("lip")

View file

@ -164,3 +164,28 @@ fn invisible_aliases_help_output() {
.alias("invisible"));
assert!(test::compare_output(app, "clap-test --help", INVISIBLE_ALIAS_HELP, false));
}
#[test]
fn issue_1031_args_with_same_name() {
let res = App::new("prog")
.arg(Arg::from_usage("--ui-path=<PATH>"))
.subcommand(SubCommand::with_name("signer"))
.get_matches_from_safe(vec!["prog", "--ui-path", "signer"]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
let m = res.unwrap();
assert_eq!(m.value_of("ui-path"), Some("signer"));
}
#[test]
fn issue_1031_args_with_same_name_no_more_vals() {
let res = App::new("prog")
.arg(Arg::from_usage("--ui-path=<PATH>"))
.subcommand(SubCommand::with_name("signer"))
.get_matches_from_safe(vec!["prog", "--ui-path", "value", "signer"]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
let m = res.unwrap();
assert_eq!(m.value_of("ui-path"), Some("value"));
assert_eq!(m.subcommand_name(), Some("signer"));
}