Merge pull request #3797 from epage/deprecate

fix: Deprecate features redundant with Actions
This commit is contained in:
Ed Page 2022-06-08 10:25:11 -05:00 committed by GitHub
commit 3ded927662
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
119 changed files with 18488 additions and 865 deletions

View file

@ -1,4 +1,4 @@
use clap::{arg, Arg, Command};
use clap::{arg, Arg, ArgAction, Command};
use criterion::{criterion_group, criterion_main, Criterion};
static OPT3_VALS: [&str; 2] = ["fast", "slow"];
@ -59,7 +59,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.long("option")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(Arg::new("positional").help("tests positionals").index(1))
.arg(
@ -68,7 +68,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.help("tests flags")
.long("flag")
.global(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(
Arg::new("flag2")
@ -102,7 +102,6 @@ pub fn build_from_builder(c: &mut Criterion) {
Arg::new("positional3")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.help("tests positionals with specific values")
.index(4)
.value_parser(POS3_VALS),
@ -118,7 +117,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.long("multvalsmo")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.help("Tests multiple values, not mult occs")
.value_names(&["one", "two"]),
)
@ -127,7 +126,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.long("minvals2")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.help("Tests 2 min vals")
.min_values(2),
)
@ -136,7 +135,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.long("maxvals3")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.help("Tests 3 max vals")
.max_values(3),
)
@ -151,7 +150,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.long("option")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.help("tests options"),
)
.arg(Arg::new("scpositional").index(1).help("tests positionals")),

View file

@ -1,5 +1,5 @@
use clap::Command;
use clap::{arg, Arg};
use clap::{arg, Arg, ArgAction};
use criterion::{criterion_group, criterion_main, Criterion};
use std::io::Cursor;
@ -95,7 +95,7 @@ fn app_example5<'c>() -> Command<'c> {
.help("turns up the awesome")
.short('a')
.long("awesome")
.multiple_occurrences(true),
.action(ArgAction::Count),
)
}
@ -120,7 +120,7 @@ fn app_example7<'c>() -> Command<'c> {
.help("the input file to use")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.required(true)
.short('i')
.long("input")
@ -138,7 +138,7 @@ fn app_example8<'c>() -> Command<'c> {
.help("the input file to use")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.required(true)
.short('i')
.long("input")

View file

@ -3,7 +3,7 @@
//
// CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a
use clap::{value_parser, Arg, Command};
use clap::{value_parser, Arg, ArgAction, Command};
use criterion::{criterion_group, criterion_main, Criterion};
use std::collections::HashMap;
use std::io::Cursor;
@ -323,17 +323,12 @@ where
"type-list",
"version",
]))
.arg(
arg("path")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.arg(arg("path").takes_value(true).multiple_values(true))
.arg(
flag("regexp")
.short('e')
.allow_hyphen_values(true)
.multiple_occurrences(true)
.action(ArgAction::Append)
.takes_value(true)
.value_name("pattern"),
)
@ -357,14 +352,14 @@ where
.arg(
flag("colors")
.value_name("SPEC")
.multiple_occurrences(true)
.action(ArgAction::Append)
.takes_value(true),
)
.arg(flag("fixed-strings").short('F'))
.arg(
flag("glob")
.short('g')
.multiple_occurrences(true)
.action(ArgAction::Append)
.takes_value(true)
.value_name("GLOB"),
)
@ -375,18 +370,18 @@ where
.arg(
flag("type")
.short('t')
.multiple_occurrences(true)
.action(ArgAction::Append)
.takes_value(true)
.value_name("TYPE"),
)
.arg(
flag("type-not")
.short('T')
.multiple_occurrences(true)
.action(ArgAction::Append)
.takes_value(true)
.value_name("TYPE"),
)
.arg(flag("unrestricted").short('u').multiple_occurrences(true))
.arg(flag("unrestricted").short('u').action(ArgAction::Append))
.arg(flag("invert-match").short('v'))
.arg(flag("word-regexp").short('w'))
// Third, set up less common flags.
@ -415,7 +410,7 @@ where
flag("file")
.short('f')
.value_name("FILE")
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(flag("files-with-matches").short('l'))
.arg(flag("files-without-match"))
@ -427,7 +422,7 @@ where
.arg(
flag("ignore-file")
.value_name("FILE")
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(flag("follow").short('L'))
.arg(
@ -464,12 +459,12 @@ where
.arg(
flag("type-add")
.value_name("TYPE")
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(
flag("type-clear")
.value_name("TYPE")
.multiple_occurrences(true),
.action(ArgAction::Append),
)
}

View file

@ -218,8 +218,7 @@ fn build_cli() -> Command<'static> {
Arg::new("command")
.required(true)
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
.multiple_values(true),
),
)
.subcommand(

View file

@ -22,7 +22,7 @@ pub mod bash {
#[derive(Clone, Debug)]
pub struct CompleteArgs {
/// Path to write completion-registration to
#[clap(long, required = true, parse(from_os_str))]
#[clap(long, required = true, value_parser)]
register: Option<std::path::PathBuf>,
#[clap(
@ -30,34 +30,36 @@ pub mod bash {
required = true,
value_name = "COMP_CWORD",
hide_short_help = true,
group = "complete"
group = "complete",
value_parser
)]
index: Option<usize>,
#[clap(long, hide_short_help = true, group = "complete")]
#[clap(long, hide_short_help = true, group = "complete", value_parser)]
ifs: Option<String>,
#[clap(
long = "type",
required = true,
arg_enum,
hide_short_help = true,
group = "complete"
group = "complete",
value_parser
)]
comp_type: Option<CompType>,
#[clap(long, hide_short_help = true, group = "complete")]
#[clap(long, hide_short_help = true, group = "complete", action)]
space: bool,
#[clap(
long,
conflicts_with = "space",
hide_short_help = true,
group = "complete"
group = "complete",
action
)]
no_space: bool,
#[clap(raw = true, hide_short_help = true, group = "complete")]
#[clap(raw = true, hide_short_help = true, group = "complete", value_parser)]
comp_words: Vec<OsString>,
}

View file

@ -451,6 +451,7 @@ fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String {
let help = o.get_help().map_or(String::new(), escape_help);
let conflicts = arg_conflicts(p, o, p_global);
#[allow(deprecated)]
let multiple = if o.is_multiple_occurrences_set() {
"*"
} else {
@ -554,6 +555,7 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String {
let help = f.get_help().map_or(String::new(), escape_help);
let conflicts = arg_conflicts(p, &f, p_global);
#[allow(deprecated)]
let multiple = if f.is_multiple_occurrences_set() {
"*"
} else {
@ -632,6 +634,7 @@ fn write_positionals_of(p: &Command) -> String {
for arg in p.get_positionals() {
debug!("write_positionals_of:iter: arg={}", arg.get_id());
#[allow(deprecated)]
let cardinality = if arg.is_multiple_values_set() || arg.is_multiple_occurrences_set() {
"*:"
} else if !arg.is_required_set() {

View file

@ -6,7 +6,7 @@ pub fn basic_command(name: &'static str) -> clap::Command<'static> {
clap::Command::new("test").about("Subcommand").arg(
clap::Arg::new("debug")
.short('d')
.multiple_occurrences(true),
.action(clap::ArgAction::Count),
),
)
}
@ -23,7 +23,7 @@ pub fn feature_sample_command(name: &'static str) -> clap::Command<'static> {
)
.arg(
clap::Arg::new("config")
.multiple_occurrences(true)
.action(clap::ArgAction::Count)
.help("some config file")
.short('c')
.visible_short_alias('C')
@ -57,7 +57,7 @@ pub fn special_commands_command(name: &'static str) -> clap::Command<'static> {
.arg(
clap::Arg::new("path")
.takes_value(true)
.multiple_occurrences(true),
.multiple_values(true),
),
)
.subcommand(clap::Command::new("some-cmd-with-hyphens").alias("hyphen"))

View file

@ -216,6 +216,7 @@ fn gen_options(cmd: &Command, indent: usize) -> String {
buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 4));
}
#[allow(deprecated)]
if option.is_multiple_occurrences_set() {
buffer.push_str(&format!(
"{:indent$}isRepeatable: true,\n",
@ -303,6 +304,7 @@ fn gen_options(cmd: &Command, indent: usize) -> String {
buffer.push_str(&format!("{:indent$}],\n", "", indent = indent + 4));
}
#[allow(deprecated)]
if flag.is_multiple_occurrences_set() {
buffer.push_str(&format!(
"{:indent$}isRepeatable: true,\n",

View file

@ -6,7 +6,7 @@ pub fn basic_command(name: &'static str) -> clap::Command<'static> {
clap::Command::new("test").about("Subcommand").arg(
clap::Arg::new("debug")
.short('d')
.multiple_occurrences(true),
.action(clap::ArgAction::Count),
),
)
}
@ -23,7 +23,7 @@ pub fn feature_sample_command(name: &'static str) -> clap::Command<'static> {
)
.arg(
clap::Arg::new("config")
.multiple_occurrences(true)
.action(clap::ArgAction::Count)
.help("some config file")
.short('c')
.visible_short_alias('C')
@ -57,7 +57,7 @@ pub fn special_commands_command(name: &'static str) -> clap::Command<'static> {
.arg(
clap::Arg::new("path")
.takes_value(true)
.multiple_occurrences(true),
.multiple_values(true),
),
)
.subcommand(clap::Command::new("some-cmd-with-hyphens").alias("hyphen"))

View file

@ -49,6 +49,7 @@ const completion: Fig.Spec = {
],
args: {
name: "path",
isVariadic: true,
isOptional: true,
},
},

View file

@ -50,6 +50,7 @@ pub struct Attrs {
next_help_heading: Option<Method>,
help_heading: Option<Method>,
is_enum: bool,
is_positional: bool,
kind: Sp<Kind>,
}
@ -436,6 +437,7 @@ impl Attrs {
next_help_heading: None,
help_heading: None,
is_enum: false,
is_positional: true,
kind: Sp::new(Kind::Arg(Sp::new(Ty::Other, default_span)), default_span),
}
}
@ -448,6 +450,9 @@ impl Attrs {
} else if name == "action" {
self.action = Some(Action::Explicit(Method::new(name, quote!(#arg))));
} else {
if name == "short" || name == "long" {
self.is_positional = false;
}
self.methods.push(Method::new(name, quote!(#arg)));
}
}
@ -810,6 +815,10 @@ impl Attrs {
self.is_enum
}
pub fn is_positional(&self) -> bool {
self.is_positional
}
pub fn ignore_case(&self) -> TokenStream {
let method = self.find_method("ignore_case");
@ -828,12 +837,6 @@ impl Attrs {
self.env_casing.clone()
}
pub fn is_positional(&self) -> bool {
self.methods
.iter()
.all(|m| m.name != "long" && m.name != "short")
}
pub fn has_explicit_methods(&self) -> bool {
self.methods
.iter()

View file

@ -304,25 +304,73 @@ pub fn gen_augment(
#action
},
Ty::OptionVec => quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
.multiple_occurrences(true)
#possible_values
#validator
#value_parser
#action
},
Ty::OptionVec => {
if attrs.ignore_parser() {
if attrs.is_positional() {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
.multiple_values(true) // action won't be sufficient for getting multiple
#possible_values
#validator
#value_parser
#action
}
} else {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
#possible_values
#validator
#value_parser
#action
}
}
} else {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
.multiple_occurrences(true)
#possible_values
#validator
#value_parser
#action
}
}
}
Ty::Vec => {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
.multiple_occurrences(true)
#possible_values
#validator
#value_parser
#action
if attrs.ignore_parser() {
if attrs.is_positional() {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
.multiple_values(true) // action won't be sufficient for getting multiple
#possible_values
#validator
#value_parser
#action
}
} else {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
#possible_values
#validator
#value_parser
#action
}
}
} else {
quote_spanned! { ty.span()=>
.takes_value(true)
.value_name(#value_name)
.multiple_occurrences(true)
#possible_values
#validator
#value_parser
#action
}
}
}

View file

@ -13,7 +13,7 @@ fn main() {
.arg(
// Indicates that `slop` is only accessible after `--`.
arg!(slop: [SLOP])
.multiple_occurrences(true)
.multiple_values(true)
.last(true)
.value_parser(value_parser!(String)),
)

View file

@ -35,7 +35,7 @@ fn main() {
let matches = cmd.get_matches();
let mut subcommand = matches.subcommand();
if let Some(("busybox", cmd)) = subcommand {
if cmd.occurrences_of("install") > 0 {
if cmd.is_present("install") {
unimplemented!("Make hardlinks to the executable here");
}
subcommand = cmd.subcommand();

View file

@ -2,7 +2,7 @@
use std::path::PathBuf;
use clap::{arg, command, value_parser, Command};
use clap::{arg, command, value_parser, ArgAction, Command};
fn main() {
let matches = command!()
@ -15,9 +15,12 @@ fn main() {
.required(false)
.value_parser(value_parser!(PathBuf)),
)
.arg(arg!(
-d --debug ... "Turn debugging information on"
))
.arg(
arg!(
-d --debug "Turn debugging information on"
)
.action(ArgAction::Count),
)
.subcommand(
Command::new("test")
.about("does testing things")
@ -36,7 +39,10 @@ fn main() {
// You can see how many times a particular flag or argument occurred
// Note, only flags can have multiple occurrences
match matches.occurrences_of("debug") {
match matches
.get_one::<u64>("debug")
.expect("Count's are defaulted")
{
0 => println!("Debug mode is off"),
1 => println!("Debug mode is kind of on"),
2 => println!("Debug mode is on"),

View file

@ -1,14 +1,13 @@
// Note: this requires the `cargo` feature
use clap::{arg, command, AppSettings};
use clap::{arg, command, AppSettings, ArgAction};
fn main() {
let matches = command!()
.args_override_self(true)
.global_setting(AppSettings::DeriveDisplayOrder)
.allow_negative_numbers(true)
.arg(arg!(--two <VALUE>))
.arg(arg!(--one <VALUE>))
.arg(arg!(--two <VALUE>).action(ArgAction::Set))
.arg(arg!(--one <VALUE>).action(ArgAction::Set))
.get_matches();
println!(

View file

@ -1,9 +1,16 @@
// Note: this requires the `cargo` feature
use clap::{arg, command};
use clap::{arg, command, ArgAction};
fn main() {
let matches = command!().arg(arg!(-v --verbose ...)).get_matches();
let matches = command!()
.arg(arg!(-v - -verbose).action(ArgAction::Count))
.get_matches();
println!("verbose: {:?}", matches.occurrences_of("verbose"));
println!(
"verbose: {:?}",
matches
.get_one::<u64>("verbose")
.expect("Count always defaulted")
);
}

View file

@ -2,7 +2,6 @@ use clap::{AppSettings, Parser};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(args_override_self = true)]
#[clap(allow_negative_numbers = true)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
struct Cli {

View file

@ -22,7 +22,7 @@ struct Args {
sleep: Option<humantime::Duration>,
/// Hand-written parser for tuples
#[clap(short = 'D', value_parser = parse_key_val::<String, i32>, multiple_occurrences(true))]
#[clap(short = 'D', value_parser = parse_key_val::<String, i32>)]
defines: Vec<(String, i32)>,
}

View file

@ -58,7 +58,6 @@ pub enum ArgAction {
/// .arg(
/// Arg::new("flag")
/// .long("flag")
/// .multiple_occurrences(true)
/// .action(clap::ArgAction::Append)
/// );
///
@ -71,51 +70,17 @@ pub enum ArgAction {
/// );
/// ```
Append,
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
///
/// # Examples
///
/// ```rust
/// # use clap::Command;
/// # use clap::Arg;
/// let cmd = Command::new("mycmd")
/// .arg(
/// Arg::new("flag")
/// .long("flag")
/// .action(clap::ArgAction::StoreValue)
/// );
///
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value"]).unwrap();
/// assert!(matches.is_present("flag"));
/// assert_eq!(matches.occurrences_of("flag"), 1);
/// assert_eq!(
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
/// vec!["value"]
/// );
/// ```
/// Deprecated, replaced with [`ArgAction::Set`] or [`ArgAction::Append`]
#[deprecated(
since = "3.2.0",
note = "Replaced with `ArgAction::Set` or `ArgAction::Append`"
)]
StoreValue,
/// When encountered, increment [`ArgMatches::occurrences_of`][crate::ArgMatches::occurrences_of]
///
/// No value is allowed
///
/// # Examples
///
/// ```rust
/// # use clap::Command;
/// # use clap::Arg;
/// let cmd = Command::new("mycmd")
/// .arg(
/// Arg::new("flag")
/// .long("flag")
/// .multiple_occurrences(true)
/// .action(clap::ArgAction::IncOccurrence)
/// );
///
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
/// assert!(matches.is_present("flag"));
/// assert_eq!(matches.occurrences_of("flag"), 2);
/// assert_eq!(matches.get_many::<String>("flag").unwrap_or_default().count(), 0);
/// ```
/// Deprecated, replaced with [`ArgAction::SetTrue`] or [`ArgAction::Count`]
#[deprecated(
since = "3.2.0",
note = "Replaced with `ArgAction::SetTrue` or `ArgAction::Count`"
)]
IncOccurrence,
/// When encountered, act as if `"true"` was encountered on the command-line
///
@ -284,7 +249,9 @@ impl ArgAction {
match self {
Self::Set => true,
Self::Append => true,
#[allow(deprecated)]
Self::StoreValue => true,
#[allow(deprecated)]
Self::IncOccurrence => false,
Self::SetTrue => false,
Self::SetFalse => false,
@ -298,7 +265,9 @@ impl ArgAction {
match self {
Self::Set => None,
Self::Append => None,
#[allow(deprecated)]
Self::StoreValue => None,
#[allow(deprecated)]
Self::IncOccurrence => None,
Self::SetTrue => Some(std::ffi::OsStr::new("false")),
Self::SetFalse => Some(std::ffi::OsStr::new("true")),
@ -312,11 +281,13 @@ impl ArgAction {
match self {
Self::Set => None,
Self::Append => None,
#[allow(deprecated)]
Self::StoreValue => None,
#[allow(deprecated)]
Self::IncOccurrence => None,
Self::SetTrue => Some(super::ValueParser::bool()),
Self::SetFalse => Some(super::ValueParser::bool()),
Self::Count => Some(crate::value_parser!(u64)),
Self::Count => Some(crate::value_parser!(u64).into()),
Self::Help => None,
Self::Version => None,
}
@ -329,7 +300,9 @@ impl ArgAction {
match self {
Self::Set => None,
Self::Append => None,
#[allow(deprecated)]
Self::StoreValue => None,
#[allow(deprecated)]
Self::IncOccurrence => None,
Self::SetTrue => Some(AnyValueId::of::<bool>()),
Self::SetFalse => Some(AnyValueId::of::<bool>()),

View file

@ -776,53 +776,10 @@ impl<'help> Arg<'help> {
}
}
/// Specifies that the argument may appear more than once.
///
/// For flags, this results in the number of occurrences of the flag being recorded. For
/// example `-ddd` or `-d -d -d` would count as three occurrences. For options or arguments
/// that take a value, this *does not* affect how many values they can accept. (i.e. only one
/// at a time is allowed)
///
/// For example, `--opt val1 --opt val2` is allowed, but `--opt val1 val2` is not.
///
/// # Examples
///
/// An example with flags
///
/// ```rust
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("verbose")
/// .multiple_occurrences(true)
/// .short('v'))
/// .get_matches_from(vec![
/// "prog", "-v", "-v", "-v" // note, -vvv would have same result
/// ]);
///
/// assert!(m.is_present("verbose"));
/// assert_eq!(m.occurrences_of("verbose"), 3);
/// ```
///
/// An example with options
///
/// ```rust
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("file")
/// .multiple_occurrences(true)
/// .takes_value(true)
/// .short('F'))
/// .get_matches_from(vec![
/// "prog", "-F", "file1", "-F", "file2", "-F", "file3"
/// ]);
///
/// assert!(m.is_present("file"));
/// assert_eq!(m.occurrences_of("file"), 3);
/// let files: Vec<_> = m.values_of("file").unwrap().collect();
/// assert_eq!(files, ["file1", "file2", "file3"]);
/// ```
/// Deprecated, replaced with [`Arg::action`] ([Issue #3772](https://github.com/clap-rs/clap/issues/3772))
#[inline]
#[must_use]
#[deprecated(since = "3.2.0", note = "Replaced with `Arg::action` (Issue #3772)")]
pub fn multiple_occurrences(self, yes: bool) -> Self {
if yes {
self.setting(ArgSettings::MultipleOccurrences)
@ -831,57 +788,13 @@ impl<'help> Arg<'help> {
}
}
/// The *maximum* number of occurrences for this argument.
///
/// For example, if you had a
/// `-v` flag and you wanted up to 3 levels of verbosity you would set `.max_occurrences(3)`, and
/// this argument would be satisfied if the user provided it once or twice or thrice.
///
/// **NOTE:** This implicitly sets [`Arg::multiple_occurrences(true)`] if the value is greater than 1.
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg};
/// Arg::new("verbosity")
/// .short('v')
/// .max_occurrences(3);
/// ```
///
/// Supplying less than the maximum number of arguments is allowed
///
/// ```rust
/// # use clap::{Command, Arg};
/// let res = Command::new("prog")
/// .arg(Arg::new("verbosity")
/// .max_occurrences(3)
/// .short('v'))
/// .try_get_matches_from(vec![
/// "prog", "-vvv"
/// ]);
///
/// assert!(res.is_ok());
/// let m = res.unwrap();
/// assert_eq!(m.occurrences_of("verbosity"), 3);
/// ```
///
/// Supplying more than the maximum number of arguments is an error
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let res = Command::new("prog")
/// .arg(Arg::new("verbosity")
/// .max_occurrences(2)
/// .short('v'))
/// .try_get_matches_from(vec![
/// "prog", "-vvv"
/// ]);
///
/// assert!(res.is_err());
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::TooManyOccurrences);
/// ```
/// [`Arg::multiple_occurrences(true)`]: Arg::multiple_occurrences()
/// Deprecated, for flags this is replaced with `action(ArgAction::Count).value_parser(value_parser!(u64).range(..max))`
#[inline]
#[must_use]
#[deprecated(
since = "3.2.0",
note = "For flags, replaced with `action(ArgAction::Count).value_parser(value_parser!(u64).range(..max))`"
)]
pub fn max_occurrences(mut self, qty: usize) -> Self {
self.max_occurs = Some(qty);
if qty > 1 {
@ -1014,12 +927,12 @@ impl<'help> Arg<'help> {
/// .arg(
/// Arg::new("flag")
/// .long("flag")
/// .action(clap::ArgAction::StoreValue)
/// .action(clap::ArgAction::Set)
/// );
///
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value"]).unwrap();
/// assert!(matches.is_present("flag"));
/// assert_eq!(matches.occurrences_of("flag"), 1);
/// assert_eq!(matches.occurrences_of("flag"), 0);
/// assert_eq!(
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
/// vec!["value"]
@ -1041,7 +954,7 @@ impl<'help> Arg<'help> {
/// - [`value_parser!`][crate::value_parser!] for auto-selecting a value parser for a given type
/// - [`BoolishValueParser`][crate::builder::BoolishValueParser], and [`FalseyValueParser`][crate::builder::FalseyValueParser] for alternative `bool` implementations
/// - [`NonEmptyStringValueParser`][crate::builder::NonEmptyStringValueParser] for basic validation for strings
/// - [`RangedI64ValueParser`][crate::builder::RangedI64ValueParser] for numeric ranges
/// - [`RangedI64ValueParser`][crate::builder::RangedI64ValueParser] and [`RangedU64ValueParser`][crate::builder::RangedU64ValueParser] for numeric ranges
/// - [`ArgEnumValueParser`][crate::builder::ArgEnumValueParser] and [`PossibleValuesParser`][crate::builder::PossibleValuesParser] for static enumerated values
/// - or any other [`TypedValueParser`][crate::builder::TypedValueParser] implementation
///
@ -1133,7 +1046,7 @@ impl<'help> Arg<'help> {
/// until another argument is reached and it knows `--ui-paths` is done parsing.
///
/// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding
/// [`Arg::number_of_values(1)`] or using *only* [`Arg::multiple_occurrences`]. The following are all
/// [`Arg::number_of_values(1)`] or using *only* [`ArgAction::Append`]. The following are all
/// valid, and `signer` is parsed as a subcommand in the first case, but a value in the second
/// case.
///
@ -1158,7 +1071,6 @@ impl<'help> Arg<'help> {
/// ]);
///
/// assert!(m.is_present("file"));
/// assert_eq!(m.occurrences_of("file"), 1); // notice only one occurrence
/// let files: Vec<_> = m.values_of("file").unwrap().collect();
/// assert_eq!(files, ["file1", "file2", "file3"]);
/// ```
@ -1206,14 +1118,14 @@ impl<'help> Arg<'help> {
/// appear to only fail sometimes...not good!
///
/// A solution for the example above is to limit how many values with a [maximum], or [specific]
/// number, or to say [`Arg::multiple_occurrences`] is ok, but multiple values is not.
/// number, or to say [`ArgAction::Append`] is ok, but multiple values is not.
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ArgAction};
/// let m = Command::new("prog")
/// .arg(Arg::new("file")
/// .takes_value(true)
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .short('F'))
/// .arg(Arg::new("word"))
/// .get_matches_from(vec![
@ -1230,11 +1142,11 @@ impl<'help> Arg<'help> {
/// As a final example, let's fix the above error and get a pretty message to the user :)
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// # use clap::{Command, Arg, ErrorKind, ArgAction};
/// let res = Command::new("prog")
/// .arg(Arg::new("file")
/// .takes_value(true)
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .short('F'))
/// .arg(Arg::new("word"))
/// .try_get_matches_from(vec![
@ -1898,7 +1810,6 @@ impl<'help> Arg<'help> {
/// ]);
///
/// assert!(delims.is_present("option"));
/// assert_eq!(delims.occurrences_of("option"), 1);
/// assert_eq!(delims.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
/// ```
/// The next example shows the difference when turning delimiters off. This is the default
@ -1915,7 +1826,6 @@ impl<'help> Arg<'help> {
/// ]);
///
/// assert!(nodelims.is_present("option"));
/// assert_eq!(nodelims.occurrences_of("option"), 1);
/// assert_eq!(nodelims.value_of("option").unwrap(), "val1,val2,val3");
/// ```
/// [`Arg::value_delimiter`]: Arg::value_delimiter()
@ -2160,8 +2070,7 @@ impl<'help> Arg<'help> {
///
/// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will
/// still return `true`. If you wish to determine whether the argument was used at runtime or
/// not, consider [`ArgMatches::occurrences_of`] which will return `0` if the argument was *not*
/// used at runtime.
/// not, consider [`ArgMatches::value_source`][crate::ArgMatches::value_source].
///
/// **NOTE:** This setting is perfectly compatible with [`Arg::default_value_if`] but slightly
/// different. `Arg::default_value` *only* takes effect when the user has not provided this arg
@ -2178,7 +2087,7 @@ impl<'help> Arg<'help> {
/// First we use the default value without providing any value at runtime.
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ValueSource};
/// let m = Command::new("prog")
/// .arg(Arg::new("opt")
/// .long("myopt")
@ -2189,13 +2098,13 @@ impl<'help> Arg<'help> {
///
/// assert_eq!(m.value_of("opt"), Some("myval"));
/// assert!(m.is_present("opt"));
/// assert_eq!(m.occurrences_of("opt"), 0);
/// assert_eq!(m.value_source("opt"), Some(ValueSource::DefaultValue));
/// ```
///
/// Next we provide a value at runtime to override the default.
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ValueSource};
/// let m = Command::new("prog")
/// .arg(Arg::new("opt")
/// .long("myopt")
@ -2206,7 +2115,7 @@ impl<'help> Arg<'help> {
///
/// assert_eq!(m.value_of("opt"), Some("non_default"));
/// assert!(m.is_present("opt"));
/// assert_eq!(m.occurrences_of("opt"), 1);
/// assert_eq!(m.value_source("opt"), Some(ValueSource::CommandLine));
/// ```
/// [`ArgMatches::occurrences_of`]: crate::ArgMatches::occurrences_of()
/// [`ArgMatches::value_of`]: crate::ArgMatches::value_of()
@ -2272,7 +2181,7 @@ impl<'help> Arg<'help> {
/// Here is an implementation of the common POSIX style `--color` argument.
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ValueSource};
///
/// macro_rules! cmd {
/// () => {{
@ -2300,7 +2209,7 @@ impl<'help> Arg<'help> {
///
/// assert_eq!(m.value_of("color"), Some("auto"));
/// assert!(m.is_present("color"));
/// assert_eq!(m.occurrences_of("color"), 0);
/// assert_eq!(m.value_source("color"), Some(ValueSource::DefaultValue));
///
/// // next, we'll provide a runtime value to override the default (as usually done).
///
@ -2310,7 +2219,7 @@ impl<'help> Arg<'help> {
///
/// assert_eq!(m.value_of("color"), Some("never"));
/// assert!(m.is_present("color"));
/// assert_eq!(m.occurrences_of("color"), 1);
/// assert_eq!(m.value_source("color"), Some(ValueSource::CommandLine));
///
/// // finally, we will use the shortcut and only provide the argument without a value.
///
@ -2320,9 +2229,8 @@ impl<'help> Arg<'help> {
///
/// assert_eq!(m.value_of("color"), Some("always"));
/// assert!(m.is_present("color"));
/// assert_eq!(m.occurrences_of("color"), 1);
/// assert_eq!(m.value_source("color"), Some(ValueSource::CommandLine));
/// ```
/// [`ArgMatches::occurrences_of`]: ArgMatches::occurrences_of()
/// [`ArgMatches::value_of`]: ArgMatches::value_of()
/// [`Arg::takes_value(true)`]: Arg::takes_value()
/// [`ArgMatches::is_present`]: ArgMatches::is_present()
@ -2503,7 +2411,6 @@ impl<'help> Arg<'help> {
///
/// assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]);
/// ```
/// [`ArgMatches::occurrences_of`]: ArgMatches::occurrences_of()
/// [`ArgMatches::value_of`]: crate::ArgMatches::value_of()
/// [`ArgMatches::is_present`]: ArgMatches::is_present()
/// [`Arg::takes_value(true)`]: Arg::takes_value()
@ -4183,7 +4090,6 @@ impl<'help> Arg<'help> {
/// .arg(arg!(--flag "some flag").overrides_with("flag"))
/// .get_matches_from(vec!["posix", "--flag", "--flag"]);
/// assert!(m.is_present("flag"));
/// assert_eq!(m.occurrences_of("flag"), 1);
/// ```
///
/// Making an arg [`Arg::multiple_occurrences`] and override itself
@ -4196,7 +4102,6 @@ impl<'help> Arg<'help> {
/// .arg(arg!(--flag ... "some flag").overrides_with("flag"))
/// .get_matches_from(vec!["", "--flag", "--flag", "--flag", "--flag"]);
/// assert!(m.is_present("flag"));
/// assert_eq!(m.occurrences_of("flag"), 4);
/// ```
///
/// Now notice with options (which *do not* set
@ -4209,7 +4114,6 @@ impl<'help> Arg<'help> {
/// .arg(arg!(--opt <val> "some option").overrides_with("opt"))
/// .get_matches_from(vec!["", "--opt=some", "--opt=other"]);
/// assert!(m.is_present("opt"));
/// assert_eq!(m.occurrences_of("opt"), 1);
/// assert_eq!(m.value_of("opt"), Some("other"));
/// ```
///
@ -4227,7 +4131,6 @@ impl<'help> Arg<'help> {
/// )
/// .get_matches_from(vec!["", "--opt", "1", "2", "--opt", "3", "4", "5"]);
/// assert!(m.is_present("opt"));
/// assert_eq!(m.occurrences_of("opt"), 1);
/// assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["3", "4", "5"]);
/// ```
///
@ -4242,7 +4145,6 @@ impl<'help> Arg<'help> {
/// .overrides_with("opt"))
/// .get_matches_from(vec!["", "--opt", "first", "over", "--opt", "other", "val"]);
/// assert!(m.is_present("opt"));
/// assert_eq!(m.occurrences_of("opt"), 2);
/// assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "over", "other", "val"]);
/// ```
#[must_use]
@ -4532,7 +4434,8 @@ impl<'help> Arg<'help> {
self.is_set(ArgSettings::MultipleValues)
}
/// Report whether [`Arg::multiple_occurrences`] is set
/// [`Arg::multiple_occurrences`] is going away ([Issue #3772](https://github.com/clap-rs/clap/issues/3772))
#[deprecated(since = "3.2.0", note = "`multiple_occurrences` away (Issue #3772)")]
pub fn is_multiple_occurrences_set(&self) -> bool {
self.is_set(ArgSettings::MultipleOccurrences)
}
@ -4902,6 +4805,21 @@ impl<'help> Arg<'help> {
} else {
self.settings.unset(ArgSettings::TakesValue);
}
match action {
ArgAction::StoreValue
| ArgAction::IncOccurrence
| ArgAction::Help
| ArgAction::Version => {}
ArgAction::Set
| ArgAction::Append
| ArgAction::SetTrue
| ArgAction::SetFalse
| ArgAction::Count => {
if !self.is_positional() {
self.settings.set(ArgSettings::MultipleOccurrences);
}
}
}
}
if self.value_parser.is_none() {

View file

@ -910,17 +910,8 @@ impl<'help> App<'help> {
}
}
/// Specifies that all arguments override themselves.
///
/// This is the equivalent to saying the `foo` arg using [`Arg::overrides_with("foo")`] for all
/// defined arguments.
///
/// **NOTE:** This will not be applied when [`Arg::multiple_occurrences(true)`].
///
/// **NOTE:** This choice is propagated to all child subcommands.
///
/// [`Arg::overrides_with("foo")`]: crate::Arg::overrides_with()
#[inline]
/// Deprecated, replaced with [`ArgAction::Set`][super::ArgAction::Set]
#[deprecated(since = "3.2.0", note = "Replaced with `Arg::action(ArgAction::Set)`")]
pub fn args_override_self(self, yes: bool) -> Self {
if yes {
self.global_setting(AppSettings::AllArgsOverrideSelf)

View file

@ -538,8 +538,11 @@ fn _verify_positionals(cmd: &Command) -> bool {
let count = cmd
.get_positionals()
.filter(|p| {
p.is_multiple_occurrences_set()
|| (p.is_multiple_values_set() && p.num_vals.is_none())
#[allow(deprecated)]
{
p.is_multiple_occurrences_set()
|| (p.is_multiple_values_set() && p.num_vals.is_none())
}
})
.count();
let ok = count <= 1

View file

@ -44,6 +44,7 @@ pub use value_parser::OsStringValueParser;
pub use value_parser::PathBufValueParser;
pub use value_parser::PossibleValuesParser;
pub use value_parser::RangedI64ValueParser;
pub use value_parser::RangedU64ValueParser;
pub use value_parser::StringValueParser;
pub use value_parser::TypedValueParser;
pub use value_parser::ValueParser;

View file

@ -81,7 +81,7 @@ impl ValueParser {
/// Pre-existing implementations include:
/// - [`ArgEnumValueParser`] and [`PossibleValuesParser`] for static enumerated values
/// - [`BoolishValueParser`] and [`FalseyValueParser`] for alternative `bool` implementations
/// - [`RangedI64ValueParser`]
/// - [`RangedI64ValueParser`] and [`RangedU64ValueParser`]
/// - [`NonEmptyStringValueParser`]
///
/// # Example
@ -302,6 +302,8 @@ impl<P: AnyValueParser + Send + Sync + 'static> From<P> for ValueParser {
///
/// See [`RangedI64ValueParser`] for more control over the output type.
///
/// See also [`RangedU64ValueParser`]
///
/// # Examples
///
/// ```rust
@ -330,6 +332,8 @@ impl From<std::ops::Range<i64>> for ValueParser {
///
/// See [`RangedI64ValueParser`] for more control over the output type.
///
/// See also [`RangedU64ValueParser`]
///
/// # Examples
///
/// ```rust
@ -358,6 +362,8 @@ impl From<std::ops::RangeInclusive<i64>> for ValueParser {
///
/// See [`RangedI64ValueParser`] for more control over the output type.
///
/// See also [`RangedU64ValueParser`]
///
/// # Examples
///
/// ```rust
@ -386,6 +392,8 @@ impl From<std::ops::RangeFrom<i64>> for ValueParser {
///
/// See [`RangedI64ValueParser`] for more control over the output type.
///
/// See also [`RangedU64ValueParser`]
///
/// # Examples
///
/// ```rust
@ -414,6 +422,8 @@ impl From<std::ops::RangeTo<i64>> for ValueParser {
///
/// See [`RangedI64ValueParser`] for more control over the output type.
///
/// See also [`RangedU64ValueParser`]
///
/// # Examples
///
/// ```rust
@ -442,6 +452,8 @@ impl From<std::ops::RangeToInclusive<i64>> for ValueParser {
///
/// See [`RangedI64ValueParser`] for more control over the output type.
///
/// See also [`RangedU64ValueParser`]
///
/// # Examples
///
/// ```rust
@ -1235,6 +1247,201 @@ impl<T: std::convert::TryFrom<i64>> Default for RangedI64ValueParser<T> {
}
}
/// Parse number that fall within a range of values
///
/// # Example
///
/// Usage:
/// ```rust
/// let mut cmd = clap::Command::new("raw")
/// .arg(
/// clap::Arg::new("port")
/// .long("port")
/// .value_parser(clap::value_parser!(u64).range(3000..))
/// .takes_value(true)
/// .required(true)
/// );
///
/// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap();
/// let port: u64 = *m.get_one("port")
/// .expect("required");
/// assert_eq!(port, 3001);
/// ```
///
/// Semantics:
/// ```rust
/// # use std::ffi::OsStr;
/// # use clap::builder::TypedValueParser;
/// # let cmd = clap::Command::new("test");
/// # let arg = None;
/// let value_parser = clap::builder::RangedU64ValueParser::<u32>::new().range(0..200);
/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err());
/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err());
/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200")).is_err());
/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300")).is_err());
/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1")).is_err());
/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), 0);
/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50);
/// ```
#[derive(Copy, Clone, Debug)]
pub struct RangedU64ValueParser<T: std::convert::TryFrom<u64> = u64> {
bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>),
target: std::marker::PhantomData<T>,
}
impl<T: std::convert::TryFrom<u64>> RangedU64ValueParser<T> {
/// Select full range of `u64`
pub fn new() -> Self {
Self::from(..)
}
/// Narrow the supported range
pub fn range<B: RangeBounds<u64>>(mut self, range: B) -> Self {
// Consideration: when the user does `value_parser!(u8).range()`
// - Avoid programming mistakes by accidentally expanding the range
// - Make it convenient to limit the range like with `..10`
let start = match range.start_bound() {
l @ std::ops::Bound::Included(i) => {
debug_assert!(
self.bounds.contains(i),
"{} must be in {:?}",
i,
self.bounds
);
l.cloned()
}
l @ std::ops::Bound::Excluded(i) => {
debug_assert!(
self.bounds.contains(&i.saturating_add(1)),
"{} must be in {:?}",
i,
self.bounds
);
l.cloned()
}
std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(),
};
let end = match range.end_bound() {
l @ std::ops::Bound::Included(i) => {
debug_assert!(
self.bounds.contains(i),
"{} must be in {:?}",
i,
self.bounds
);
l.cloned()
}
l @ std::ops::Bound::Excluded(i) => {
debug_assert!(
self.bounds.contains(&i.saturating_sub(1)),
"{} must be in {:?}",
i,
self.bounds
);
l.cloned()
}
std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(),
};
self.bounds = (start, end);
self
}
fn format_bounds(&self) -> String {
let mut result = match self.bounds.0 {
std::ops::Bound::Included(i) => i.to_string(),
std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(),
std::ops::Bound::Unbounded => u64::MIN.to_string(),
};
result.push_str("..");
match self.bounds.1 {
std::ops::Bound::Included(i) => {
result.push('=');
result.push_str(&i.to_string());
}
std::ops::Bound::Excluded(i) => {
result.push_str(&i.to_string());
}
std::ops::Bound::Unbounded => {
result.push_str(&u64::MAX.to_string());
}
}
result
}
}
impl<T: std::convert::TryFrom<u64>> TypedValueParser for RangedU64ValueParser<T>
where
<T as std::convert::TryFrom<u64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
{
type Value = T;
fn parse_ref(
&self,
cmd: &crate::Command,
arg: Option<&crate::Arg>,
raw_value: &std::ffi::OsStr,
) -> Result<Self::Value, crate::Error> {
let value = raw_value.to_str().ok_or_else(|| {
crate::Error::invalid_utf8(
cmd,
crate::output::Usage::new(cmd).create_usage_with_title(&[]),
)
})?;
let value = value.parse::<u64>().map_err(|err| {
let arg = arg
.map(|a| a.to_string())
.unwrap_or_else(|| "...".to_owned());
crate::Error::value_validation(
arg,
raw_value.to_string_lossy().into_owned(),
err.into(),
)
.with_cmd(cmd)
})?;
if !self.bounds.contains(&value) {
let arg = arg
.map(|a| a.to_string())
.unwrap_or_else(|| "...".to_owned());
return Err(crate::Error::value_validation(
arg,
raw_value.to_string_lossy().into_owned(),
format!("{} is not in {}", value, self.format_bounds()).into(),
)
.with_cmd(cmd));
}
let value: Result<Self::Value, _> = value.try_into();
let value = value.map_err(|err| {
let arg = arg
.map(|a| a.to_string())
.unwrap_or_else(|| "...".to_owned());
crate::Error::value_validation(
arg,
raw_value.to_string_lossy().into_owned(),
err.into(),
)
.with_cmd(cmd)
})?;
Ok(value)
}
}
impl<T: std::convert::TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> {
fn from(range: B) -> Self {
Self {
bounds: (range.start_bound().cloned(), range.end_bound().cloned()),
target: Default::default(),
}
}
}
impl<T: std::convert::TryFrom<u64>> Default for RangedU64ValueParser<T> {
fn default() -> Self {
Self::new()
}
}
/// Implementation for [`ValueParser::bool`]
///
/// Useful for composing new [`TypedValueParser`]s
@ -1252,7 +1459,7 @@ impl BoolValueParser {
["true", "false"]
.iter()
.copied()
.map(|l| crate::PossibleValue::new(l))
.map(crate::PossibleValue::new)
}
}
@ -1687,6 +1894,12 @@ impl ValueParserFactory for i64 {
RangedI64ValueParser::new()
}
}
impl ValueParserFactory for u64 {
type Parser = RangedU64ValueParser<u64>;
fn value_parser() -> Self::Parser {
RangedU64ValueParser::new()
}
}
#[doc(hidden)]
#[derive(Debug)]
@ -1784,6 +1997,8 @@ pub mod via_prelude {
/// assert_eq!(format!("{:?}", parser), "ValueParser::path_buf");
/// let parser = clap::value_parser!(u16).range(3000..);
/// assert_eq!(format!("{:?}", parser), "RangedI64ValueParser { bounds: (Included(3000), Included(65535)), target: PhantomData }");
/// let parser = clap::value_parser!(u64).range(3000..);
/// assert_eq!(format!("{:?}", parser), "RangedU64ValueParser { bounds: (Included(3000), Unbounded), target: PhantomData }");
///
/// // FromStr types
/// let parser = clap::value_parser!(usize);

View file

@ -425,7 +425,10 @@ macro_rules! arg_impl {
@arg
({
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
}
let mut arg = $arg;
let long = $crate::arg_impl! { @string $long };
@ -447,7 +450,10 @@ macro_rules! arg_impl {
@arg
({
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
}
let mut arg = $arg;
let long = $crate::arg_impl! { @string $long };
@ -470,7 +476,10 @@ macro_rules! arg_impl {
({
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
}
$arg.short($crate::arg_impl! { @char $short })
})
@ -488,7 +497,10 @@ macro_rules! arg_impl {
({
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
}
$arg.short($crate::arg_impl! { @char $short })
})
@ -504,7 +516,10 @@ macro_rules! arg_impl {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
}
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
@ -530,7 +545,10 @@ macro_rules! arg_impl {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
}
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
@ -556,7 +574,10 @@ macro_rules! arg_impl {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
}
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
@ -586,7 +607,10 @@ macro_rules! arg_impl {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
#[allow(deprecated)]
{
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
}
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
@ -615,9 +639,9 @@ macro_rules! arg_impl {
) => {
$crate::arg_impl! {
@arg
({
({#[allow(deprecated)]{
$arg.multiple_occurrences(true)
})
}})
$($tail)*
}
};

View file

@ -70,11 +70,13 @@ impl ArgMatcher {
// We have to check if the parent's global arg wasn't used but still exists
// such as from a default value.
//
// For example, `myprog subcommand --global-arg=value` where --global-arg defines
// For example, `myprog subcommand --global-arg=value` where `--global-arg` defines
// a default value of `other` myprog would have an existing MatchedArg for
// --global-arg where the value is `other`, however the occurs will be 0.
// `--global-arg` where the value is `other`
let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 {
if parent_ma.check_explicit(ArgPredicate::IsPresent)
&& !ma.check_explicit(ArgPredicate::IsPresent)
{
parent_ma
} else {
ma
@ -169,6 +171,7 @@ impl ArgMatcher {
let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
ma.set_source(ValueSource::CommandLine);
#[allow(deprecated)]
ma.inc_occurrences();
ma.new_val_group();
}
@ -178,6 +181,7 @@ impl ArgMatcher {
let ma = self.entry(id).or_insert(MatchedArg::new_group());
debug_assert_eq!(ma.type_id(), None);
ma.set_source(ValueSource::CommandLine);
#[allow(deprecated)]
ma.inc_occurrences();
ma.new_val_group();
}
@ -195,6 +199,7 @@ impl ArgMatcher {
)
);
ma.set_source(ValueSource::CommandLine);
#[allow(deprecated)]
ma.inc_occurrences();
ma.new_val_group();
}
@ -225,6 +230,7 @@ impl ArgMatcher {
true
} else if let Some(num) = o.num_vals {
debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
#[allow(deprecated)]
if o.is_multiple_occurrences_set() {
(current_num % num) != 0
} else {

View file

@ -29,15 +29,13 @@ use crate::INTERNAL_ERROR_MSG;
/// # Examples
///
/// ```no_run
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ValueSource};
/// let matches = Command::new("MyApp")
/// .arg(Arg::new("out")
/// .long("output")
/// .required(true)
/// .takes_value(true))
/// .arg(Arg::new("debug")
/// .short('d')
/// .multiple_occurrences(true))
/// .takes_value(true)
/// .default_value("-"))
/// .arg(Arg::new("cfg")
/// .short('c')
/// .takes_value(true))
@ -57,14 +55,11 @@ use crate::INTERNAL_ERROR_MSG;
///
/// // You can check the presence of an argument
/// if matches.is_present("out") {
/// // Another way to check if an argument was present, or if it occurred multiple times is to
/// // use occurrences_of() which returns 0 if an argument isn't found at runtime, or the
/// // number of times that it occurred, if it was. To allow an argument to appear more than
/// // once, you must use the .multiple_occurrences(true) method, otherwise it will only return 1 or 0.
/// if matches.occurrences_of("debug") > 2 {
/// println!("Debug mode is REALLY on, don't be crazy");
/// // However, if you want to know where the value came from
/// if matches.value_source("out").expect("checked is_present") == ValueSource::CommandLine {
/// println!("`out` set by user");
/// } else {
/// println!("Debug mode kind of on");
/// println!("`out` is defaulted");
/// }
/// }
/// ```
@ -92,7 +87,7 @@ impl ArgMatches {
/// Returns `None` if the option wasn't present.
///
/// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set.
/// [`occurrences_of`] can be used to check if a value is present at runtime.
/// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
///
/// # Panic
///
@ -118,7 +113,6 @@ impl ArgMatches {
/// [option]: crate::Arg::takes_value()
/// [positional]: crate::Arg::index()
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: crate::ArgMatches::occurrences_of()
#[track_caller]
pub fn get_one<T: Any + Clone + Send + Sync + 'static>(&self, name: &str) -> Option<&T> {
let id = Id::from(name);
@ -141,10 +135,10 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, value_parser};
/// # use clap::{Command, Arg, value_parser, ArgAction};
/// let m = Command::new("myprog")
/// .arg(Arg::new("ports")
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .value_parser(value_parser!(usize))
/// .short('p')
/// .takes_value(true)
@ -223,7 +217,7 @@ impl ArgMatches {
/// Returns `None` if the option wasn't present.
///
/// *NOTE:* This will always return `Some(value)` if [`default_value`] has been set.
/// [`occurrences_of`] can be used to check if a value is present at runtime.
/// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
///
/// # Panic
///
@ -248,7 +242,6 @@ impl ArgMatches {
/// [option]: crate::Arg::takes_value()
/// [positional]: crate::Arg::index()
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: crate::ArgMatches::occurrences_of()
#[track_caller]
pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(&mut self, name: &str) -> Option<T> {
let id = Id::from(name);
@ -271,10 +264,11 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, value_parser};
/// # use clap::{Command, Arg, value_parser, ArgAction};
/// let mut m = Command::new("myprog")
/// .arg(Arg::new("file")
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .multiple_values(true)
/// .required(true)
/// .takes_value(true))
/// .get_matches_from(vec![
@ -381,12 +375,12 @@ impl ArgMatches {
///
/// # Examples
/// ```rust
/// # use clap::{Command,Arg};
/// # use clap::{Command,Arg, ArgAction};
/// let m = Command::new("myprog")
/// .arg(Arg::new("exec")
/// .short('x')
/// .min_values(1)
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .value_terminator(";"))
/// .get_matches_from(vec![
/// "myprog", "-x", "echo", "hi", ";", "-x", "echo", "bye"]);
@ -500,7 +494,7 @@ impl ArgMatches {
/// Check if an argument was present at runtime.
///
/// *NOTE:* This will always return `true` if [`default_value`] has been set.
/// [`occurrences_of`] can be used to check if a value is present at runtime.
/// [`ArgMatches::value_source`] can be used to check if a value is present at runtime.
///
/// # Panics
///
@ -521,7 +515,6 @@ impl ArgMatches {
/// ```
///
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: ArgMatches::occurrences_of()
pub fn is_present<T: Key>(&self, id: T) -> bool {
let id = Id::from(id);
@ -552,7 +545,6 @@ impl ArgMatches {
/// ```
///
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: ArgMatches::occurrences_of()
pub fn value_source<T: Key>(&self, id: T) -> Option<ValueSource> {
let id = Id::from(id);
@ -561,51 +553,14 @@ impl ArgMatches {
value.and_then(MatchedArg::source)
}
/// The number of times an argument was used at runtime.
///
/// If an argument isn't present it will return `0`.
///
/// **NOTE:** This returns the number of times the argument was used, *not* the number of
/// values. For example, `-o val1 val2 val3 -o val4` would return `2` (2 occurrences, but 4
/// values). See [Arg::multiple_occurrences][crate::Arg::multiple_occurrences].
///
/// # Panics
///
/// If `id` is is not a valid argument or group name.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d')
/// .multiple_occurrences(true))
/// .get_matches_from(vec![
/// "myprog", "-d", "-d", "-d"
/// ]);
///
/// assert_eq!(m.occurrences_of("debug"), 3);
/// ```
///
/// This next example shows that counts actual uses of the argument, not just `-`'s
///
/// ```rust
/// # use clap::{Command, Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d')
/// .multiple_occurrences(true))
/// .arg(Arg::new("flag")
/// .short('f'))
/// .get_matches_from(vec![
/// "myprog", "-ddfd"
/// ]);
///
/// assert_eq!(m.occurrences_of("debug"), 3);
/// assert_eq!(m.occurrences_of("flag"), 1);
/// ```
/// Deprecated, replaced with [`ArgMatches::get_many`]`.len()` or
/// [`ArgAction::Count`][crate::ArgAction].
#[deprecated(
since = "3.2.0",
note = "Replaced with either `ArgMatches::get_many(...).len()` or `ArgAction::Count`"
)]
pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
#![allow(deprecated)]
self.get_arg(&Id::from(id))
.map_or(0, |a| a.get_occurrences())
}
@ -787,21 +742,21 @@ impl ArgMatches {
/// Another quick example is when flags and options are used together
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ArgAction};
/// let m = Command::new("myapp")
/// .arg(Arg::new("option")
/// .short('o')
/// .takes_value(true)
/// .multiple_occurrences(true))
/// .action(ArgAction::Append))
/// .arg(Arg::new("flag")
/// .short('f')
/// .multiple_occurrences(true))
/// .action(ArgAction::Count))
/// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
/// // ARGV indices: ^0 ^1 ^2 ^3 ^4 ^5 ^6
/// // clap indices: ^2 ^3 ^5 ^6
///
/// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
/// assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]);
/// assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[6]);
/// ```
///
/// One final example, which is an odd case; if we *don't* use value delimiter as we did with
@ -1296,11 +1251,11 @@ pub(crate) struct SubCommand {
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ArgAction};
/// let mut m = Command::new("myapp")
/// .arg(Arg::new("output")
/// .short('o')
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .takes_value(true))
/// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]);
///
@ -1353,11 +1308,11 @@ impl<T> Default for Values2<T> {
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg};
/// # use clap::{Command, Arg, ArgAction};
/// let m = Command::new("myapp")
/// .arg(Arg::new("output")
/// .short('o')
/// .multiple_occurrences(true)
/// .action(ArgAction::Append)
/// .takes_value(true))
/// .get_matches_from(vec!["myapp", "-o", "val1", "-o", "val2"]);
///

View file

@ -67,14 +67,17 @@ impl MatchedArg {
}
}
#[deprecated(since = "3.2.0")]
pub(crate) fn inc_occurrences(&mut self) {
self.occurs += 1;
}
#[deprecated(since = "3.2.0")]
pub(crate) fn set_occurrences(&mut self, occurs: u64) {
self.occurs = occurs
}
#[deprecated(since = "3.2.0")]
pub(crate) fn get_occurrences(&self) -> u64 {
self.occurs
}

View file

@ -1176,6 +1176,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
Ok(ParseResult::ValuesDone)
}
#[allow(deprecated)]
ArgAction::StoreValue => {
if ident == Some(Identifier::Index)
&& arg.is_multiple_values_set()
@ -1196,6 +1197,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
if ident == Some(Identifier::Index) && arg.is_multiple_values_set() {
// HACK: Maintain existing occurrence behavior
let matched = matcher.get_mut(&arg.id).unwrap();
#[allow(deprecated)]
matched.set_occurrences(matched.num_vals() as u64);
}
if cfg!(debug_assertions) && matcher.needs_more_vals(arg) {
@ -1205,6 +1207,7 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
Ok(ParseResult::ValuesDone)
}
#[allow(deprecated)]
ArgAction::IncOccurrence => {
debug_assert_eq!(raw_vals, Vec::<OsString>::new());
if source == ValueSource::CommandLine {
@ -1362,7 +1365,9 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
} else {
match arg.get_action() {
#[allow(deprecated)]
ArgAction::StoreValue => unreachable!("{:?} is not a flag", arg.get_id()),
#[allow(deprecated)]
ArgAction::IncOccurrence => {
debug!("Parser::add_env: Found a flag with value `{:?}`", val);
let predicate = str_to_bool(val.to_str_lossy());
@ -1558,6 +1563,10 @@ impl<'help, 'cmd> Parser<'help, 'cmd> {
}
fn start_custom_arg(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>, source: ValueSource) {
if source == ValueSource::CommandLine {
// With each new occurrence, remove overrides from prior occurrences
self.remove_overrides(arg, matcher);
}
matcher.start_custom_arg(arg, source);
for group in self.cmd.groups_for_arg(&arg.id) {
matcher.start_custom_group(&group, source);

View file

@ -330,6 +330,7 @@ impl<'help, 'cmd> Validator<'help, 'cmd> {
}
fn validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> {
#![allow(deprecated)]
debug!(
"Validator::validate_arg_num_occurs: {:?}={}",
a.name,
@ -374,6 +375,7 @@ impl<'help, 'cmd> Validator<'help, 'cmd> {
if let Some(num) = a.num_vals {
let total_num = ma.num_vals();
debug!("Validator::validate_arg_num_vals: num_vals set...{}", num);
#[allow(deprecated)]
let should_err = if a.is_multiple_occurrences_set() {
total_num % num != 0
} else {
@ -385,6 +387,7 @@ impl<'help, 'cmd> Validator<'help, 'cmd> {
self.cmd,
a.to_string(),
num,
#[allow(deprecated)]
if a.is_multiple_occurrences_set() {
total_num % num
} else {

View file

@ -11,7 +11,10 @@ fn set() {
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(matches.get_one::<String>("mammal"), None);
assert_eq!(matches.is_present("mammal"), false);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), None);
let matches = cmd
@ -20,7 +23,10 @@ fn set() {
.unwrap();
assert_eq!(matches.get_one::<String>("mammal").unwrap(), "dog");
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
let matches = cmd
@ -29,7 +35,10 @@ fn set() {
.unwrap();
assert_eq!(matches.get_one::<String>("mammal").unwrap(), "cat");
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(4));
}
@ -40,7 +49,10 @@ fn append() {
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(matches.get_one::<String>("mammal"), None);
assert_eq!(matches.is_present("mammal"), false);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), None);
let matches = cmd
@ -49,7 +61,10 @@ fn append() {
.unwrap();
assert_eq!(matches.get_one::<String>("mammal").unwrap(), "dog");
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(
matches.indices_of("mammal").unwrap().collect::<Vec<_>>(),
vec![2]
@ -68,7 +83,10 @@ fn append() {
vec!["dog", "cat"]
);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(
matches.indices_of("mammal").unwrap().collect::<Vec<_>>(),
vec![2, 4]
@ -83,7 +101,10 @@ fn set_true() {
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
@ -92,7 +113,10 @@ fn set_true() {
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
@ -101,7 +125,10 @@ fn set_true() {
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
}
@ -120,13 +147,19 @@ fn set_true_with_explicit_default_value() {
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
}
@ -225,7 +258,10 @@ fn set_false() {
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
@ -234,7 +270,10 @@ fn set_false() {
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
@ -243,7 +282,10 @@ fn set_false() {
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
}
@ -262,13 +304,19 @@ fn set_false_with_explicit_default_value() {
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
}
@ -333,7 +381,10 @@ fn count() {
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 0);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
@ -342,7 +393,10 @@ fn count() {
.unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 1);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
@ -351,7 +405,10 @@ fn count() {
.unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 2);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
}
@ -370,13 +427,19 @@ fn count_with_explicit_default_value() {
.unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 1);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 10);
assert_eq!(matches.is_present("mammal"), true);
assert_eq!(matches.occurrences_of("mammal"), 0);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
}

View file

@ -1,6 +1,6 @@
use std::ffi::OsString;
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, AppSettings, Arg, Command};
@ -1064,6 +1064,7 @@ fn built_in_subcommand_escaped() {
#[test]
fn aaos_flags() {
#![allow(deprecated)]
// flags
let res = Command::new("posix")
.args_override_self(true)
@ -1077,6 +1078,7 @@ fn aaos_flags() {
#[test]
fn aaos_flags_mult() {
#![allow(deprecated)]
// flags with multiple
let res = Command::new("posix")
.args_override_self(true)
@ -1090,6 +1092,7 @@ fn aaos_flags_mult() {
#[test]
fn aaos_opts() {
#![allow(deprecated)]
// opts
let res = Command::new("posix")
.args_override_self(true)
@ -1107,6 +1110,7 @@ fn aaos_opts() {
#[test]
fn aaos_opts_w_other_overrides() {
#![allow(deprecated)]
// opts with other overrides
let res = Command::new("posix")
.args_override_self(true)
@ -1130,6 +1134,7 @@ fn aaos_opts_w_other_overrides() {
#[test]
fn aaos_opts_w_other_overrides_rev() {
#![allow(deprecated)]
// opts with other overrides, rev
let res = Command::new("posix")
.args_override_self(true)
@ -1152,6 +1157,7 @@ fn aaos_opts_w_other_overrides_rev() {
#[test]
fn aaos_opts_w_other_overrides_2() {
#![allow(deprecated)]
// opts with other overrides
let res = Command::new("posix")
.args_override_self(true)
@ -1175,6 +1181,7 @@ fn aaos_opts_w_other_overrides_2() {
#[test]
fn aaos_opts_w_other_overrides_rev_2() {
#![allow(deprecated)]
// opts with other overrides, rev
let res = Command::new("posix")
.args_override_self(true)
@ -1197,6 +1204,7 @@ fn aaos_opts_w_other_overrides_rev_2() {
#[test]
fn aaos_opts_w_override_as_conflict_1() {
#![allow(deprecated)]
// opts with other overrides, rev
let res = Command::new("posix")
.args_override_self(true)
@ -1216,6 +1224,7 @@ fn aaos_opts_w_override_as_conflict_1() {
#[test]
fn aaos_opts_w_override_as_conflict_2() {
#![allow(deprecated)]
// opts with other overrides, rev
let res = Command::new("posix")
.args_override_self(true)
@ -1238,6 +1247,7 @@ fn aaos_opts_w_override_as_conflict_2() {
#[test]
fn aaos_opts_mult() {
#![allow(deprecated)]
// opts with multiple
let res = Command::new("posix")
.args_override_self(true)
@ -1264,6 +1274,7 @@ fn aaos_opts_mult() {
#[test]
fn aaos_opts_mult_req_delims() {
#![allow(deprecated)]
// opts with multiple and require delims
let res = Command::new("posix")
.args_override_self(true)
@ -1293,6 +1304,7 @@ fn aaos_opts_mult_req_delims() {
#[test]
fn aaos_pos_mult() {
#![allow(deprecated)]
// opts with multiple
let res = Command::new("posix")
.args_override_self(true)
@ -1313,6 +1325,7 @@ fn aaos_pos_mult() {
#[test]
fn aaos_option_use_delim_false() {
#![allow(deprecated)]
let m = Command::new("posix")
.args_override_self(true)
.arg(arg!(--opt <val> "some option").use_value_delimiter(false))

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, Arg, Command};

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, Arg, Command};

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgGroup, Command};

View file

@ -19,7 +19,10 @@ fn opt_missing() {
m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
"auto"
);
assert_eq!(m.occurrences_of("color"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("color"), 0);
}
assert_eq!(
m.value_source("color").unwrap(),
clap::ValueSource::DefaultValue
@ -46,7 +49,10 @@ fn opt_present_with_missing_value() {
m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
"always"
);
assert_eq!(m.occurrences_of("color"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("color"), 1);
}
assert_eq!(
m.value_source("color").unwrap(),
clap::ValueSource::CommandLine
@ -73,7 +79,10 @@ fn opt_present_with_value() {
m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
"never"
);
assert_eq!(m.occurrences_of("color"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("color"), 1);
}
assert_eq!(
m.value_source("color").unwrap(),
clap::ValueSource::CommandLine
@ -99,7 +108,10 @@ fn opt_present_with_empty_value() {
m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
""
);
assert_eq!(m.occurrences_of("color"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("color"), 1);
}
assert_eq!(
m.value_source("color").unwrap(),
clap::ValueSource::CommandLine
@ -164,7 +176,10 @@ fn default_missing_value_flag_value() {
m.get_one::<String>("flag").map(|v| v.as_str()),
Some("false")
);
assert_eq!(m.occurrences_of("flag"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("flag"), 0);
}
assert_eq!(
m.value_source("flag").unwrap(),
clap::ValueSource::DefaultValue
@ -179,7 +194,10 @@ fn default_missing_value_flag_value() {
m.get_one::<String>("flag").map(|v| v.as_str()),
Some("true")
);
assert_eq!(m.occurrences_of("flag"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("flag"), 1);
}
assert_eq!(
m.value_source("flag").unwrap(),
clap::ValueSource::CommandLine
@ -194,7 +212,10 @@ fn default_missing_value_flag_value() {
m.get_one::<String>("flag").map(|v| v.as_str()),
Some("true")
);
assert_eq!(m.occurrences_of("flag"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("flag"), 1);
}
assert_eq!(
m.value_source("flag").unwrap(),
clap::ValueSource::CommandLine
@ -206,7 +227,10 @@ fn default_missing_value_flag_value() {
m.get_one::<String>("flag").map(|v| v.as_str()),
Some("false")
);
assert_eq!(m.occurrences_of("flag"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("flag"), 1);
}
assert_eq!(
m.value_source("flag").unwrap(),
clap::ValueSource::CommandLine
@ -233,7 +257,10 @@ fn delimited_missing_value() {
.collect::<Vec<_>>(),
vec!["one", "two"]
);
assert_eq!(m.occurrences_of("flag"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("flag"), 0);
}
let m = cmd.try_get_matches_from(["test", "--flag"]).unwrap();
assert_eq!(
@ -243,7 +270,10 @@ fn delimited_missing_value() {
.collect::<Vec<_>>(),
vec!["three", "four"]
);
assert_eq!(m.occurrences_of("flag"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("flag"), 1);
}
}
#[cfg(debug_assertions)]
@ -295,7 +325,10 @@ fn valid_index() {
m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
"always"
);
assert_eq!(m.occurrences_of("color"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("color"), 1);
}
assert_eq!(
m.value_source("color").unwrap(),
clap::ValueSource::CommandLine

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, Arg, Command};
#[test]

View file

@ -10,7 +10,10 @@ fn opt_default_no_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_one::<String>("option").map(|v| v.as_str()).unwrap(),
"val1,val2,val3"
@ -27,7 +30,10 @@ fn opt_eq_no_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_one::<String>("option").map(|v| v.as_str()).unwrap(),
"val1,val2,val3"
@ -44,7 +50,10 @@ fn opt_s_eq_no_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_one::<String>("option").map(|v| v.as_str()).unwrap(),
"val1,val2,val3"
@ -61,7 +70,10 @@ fn opt_s_default_no_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_one::<String>("option").map(|v| v.as_str()).unwrap(),
"val1,val2,val3"
@ -78,7 +90,10 @@ fn opt_s_no_space_no_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_one::<String>("option").map(|v| v.as_str()).unwrap(),
"val1,val2,val3"
@ -100,7 +115,10 @@ fn opt_s_no_space_mult_no_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_one::<String>("option").map(|v| v.as_str()).unwrap(),
"val1,val2,val3"
@ -123,7 +141,10 @@ fn opt_eq_mult_def_delim() {
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("option"), 1);
}
assert_eq!(
m.get_many::<String>("option")
.unwrap()

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use std::str;

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::Command;

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{error::ErrorKind, Arg, Command};

View file

@ -16,7 +16,10 @@ fn env() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"env"
@ -37,7 +40,10 @@ fn env_bool_literal() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("present"));
assert_eq!(m.occurrences_of("present"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("present"), 0);
}
assert_eq!(m.get_one::<String>("present").map(|v| v.as_str()), None);
assert!(!m.is_present("negated"));
assert!(!m.is_present("absent"));
@ -58,7 +64,10 @@ fn env_os() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"env"
@ -82,7 +91,10 @@ fn no_env() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(m.get_one::<String>("arg").map(|v| v.as_str()), None);
}
@ -99,7 +111,10 @@ fn no_env_no_takes_value() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(m.get_one::<String>("arg").map(|v| v.as_str()), None);
}
@ -119,7 +134,10 @@ fn with_default() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"env"
@ -141,7 +159,10 @@ fn opt_user_override() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 1);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"opt"
@ -171,7 +192,10 @@ fn positionals() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"env"
@ -193,7 +217,10 @@ fn positionals_user_override() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 1);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 1);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"opt"
@ -225,7 +252,10 @@ fn multiple_one() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_many::<String>("arg")
.unwrap()
@ -252,7 +282,10 @@ fn multiple_three() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_many::<String>("arg")
.unwrap()
@ -278,7 +311,10 @@ fn multiple_no_delimiter() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_many::<String>("arg")
.unwrap()
@ -304,7 +340,10 @@ fn possible_value() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"env"
@ -349,7 +388,10 @@ fn value_parser() {
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("arg"), 0);
}
assert_eq!(
m.get_one::<String>("arg").map(|v| v.as_str()).unwrap(),
"env"

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, value_parser, Arg, Command, Error};

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, Arg, Command};

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, Arg, Command};
const USE_FLAG_AS_ARGUMENT: &str =
@ -56,7 +56,10 @@ fn lots_o_flags_sep() {
assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("o"), 297);
} // i.e. more than u8
}
#[test]
@ -74,7 +77,10 @@ fn lots_o_flags_combined() {
assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
#[allow(deprecated)]
{
assert_eq!(m.occurrences_of("o"), 297);
} // i.e. more than u8
}
#[test]

View file

@ -1,6 +1,6 @@
#![cfg(feature = "unstable-grouped")]
use clap::{Arg, Command};
use clap::{Arg, ArgAction, Command};
#[test]
fn grouped_value_works() {
@ -10,7 +10,7 @@ fn grouped_value_works() {
.long("option")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.try_get_matches_from(&[
"cli",
@ -42,7 +42,7 @@ fn issue_1026() {
.long("target")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.try_get_matches_from(&[
"backup", "-s", "server", "-u", "user", "--target", "target1", "file1", "file2",
@ -70,7 +70,7 @@ fn grouped_value_long_flag_delimiter() {
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.try_get_matches_from(vec![
"myapp",
@ -100,7 +100,7 @@ fn grouped_value_short_flag_delimiter() {
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.try_get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"])
.unwrap();
@ -183,41 +183,41 @@ fn grouped_interleaved_positional_values() {
.short('f')
.long("flag")
.takes_value(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
);
let m = cmd
.try_get_matches_from(["foo", "1", "2", "-f", "a", "3", "-f", "b", "4"])
.unwrap();
let pos: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
assert_eq!(pos, vec![vec!["1", "2", "3", "4"]]);
assert_eq!(m.occurrences_of("pos"), 4);
let flag: Vec<_> = m.grouped_values_of("flag").unwrap().collect();
assert_eq!(flag, vec![vec!["a"], vec!["b"]]);
assert_eq!(m.occurrences_of("flag"), 2);
}
#[test]
fn grouped_interleaved_positional_occurrences() {
let cmd = clap::Command::new("foo")
.arg(clap::Arg::new("pos").multiple_occurrences(true))
.arg(clap::Arg::new("pos").multiple_values(true))
.arg(
clap::Arg::new("flag")
.short('f')
.long("flag")
.takes_value(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
);
let m = cmd
.try_get_matches_from(["foo", "1", "2", "-f", "a", "3", "-f", "b", "4"])
.unwrap();
let pos: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
assert_eq!(pos, vec![vec!["1"], vec!["2"], vec!["3"], vec!["4"]]);
assert_eq!(m.occurrences_of("pos"), 4);
assert_eq!(pos, vec![vec!["1", "2", "3", "4"]]);
let flag: Vec<_> = m.grouped_values_of("flag").unwrap().collect();
assert_eq!(flag, vec![vec!["a"], vec!["b"]]);
assert_eq!(m.occurrences_of("flag"), 2);
}
#[test]
@ -228,7 +228,7 @@ fn issue_1374() {
.long("input")
.overrides_with("input")
.min_values(0)
.multiple_occurrences(true),
.action(ArgAction::Append),
);
let matches = cmd
.clone()
@ -251,7 +251,8 @@ fn issue_1374() {
}
#[test]
fn issue_2171() {
fn issue_2171_deprecated() {
#![allow(deprecated)]
let schema = Command::new("ripgrep#1701 reproducer")
.args_override_self(true)
.arg(Arg::new("pretty").short('p').long("pretty"))
@ -271,3 +272,34 @@ fn issue_2171() {
let _ = schema.clone().try_get_matches_from(argv).unwrap();
}
}
#[test]
fn issue_2171() {
let schema = Command::new("ripgrep#1701 reproducer")
.arg(
Arg::new("pretty")
.short('p')
.long("pretty")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("search_zip")
.short('z')
.long("search-zip")
.action(ArgAction::SetTrue),
);
let test_args = &[
vec!["reproducer", "-pz", "-p"],
vec!["reproducer", "-pzp"],
vec!["reproducer", "-zpp"],
vec!["reproducer", "-pp", "-z"],
vec!["reproducer", "-p", "-p", "-z"],
vec!["reproducer", "-p", "-pz"],
vec!["reproducer", "-ppz"],
];
for argv in test_args {
let _ = schema.clone().try_get_matches_from(argv).unwrap();
}
}

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgGroup, Command};

View file

@ -1,6 +1,6 @@
use crate::utils;
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgGroup, Command, PossibleValue};
use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command, PossibleValue};
static REQUIRE_DELIM_HELP: &str = "test 1.3
Kevin K.
@ -672,7 +672,7 @@ fn help_multi_subcommand_error() {
)
.required(false)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
),
),
);
@ -720,7 +720,7 @@ fn args_with_last_usage() {
.help("Prints out more stuff.")
.short('v')
.long("verbose")
.multiple_occurrences(true),
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("timeout")
@ -822,7 +822,7 @@ fn multi_level_sc_help() {
)
.required(false)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
),
),
);
@ -2514,7 +2514,8 @@ fn positional_multiple_occurrences_is_dotted() {
Arg::new("foo")
.required(true)
.takes_value(true)
.multiple_occurrences(true),
.multiple_values(true)
.action(ArgAction::Append),
);
utils::assert_output(
cmd,
@ -2538,7 +2539,8 @@ OPTIONS:
.required(true)
.takes_value(true)
.value_name("BAR")
.multiple_occurrences(true),
.multiple_values(true)
.action(ArgAction::Append),
);
utils::assert_output(
cmd,

View file

@ -4,7 +4,7 @@ use std::env;
use clap::{Arg, Command};
use crate::utils;
use super::utils;
static HIDE_ENV: &str = "ctest 0.1

View file

@ -1,4 +1,4 @@
use crate::utils;
use super::utils;
use clap::{arg, Arg, Command};

View file

@ -1,4 +1,4 @@
use clap::{Arg, Command};
use clap::{Arg, ArgAction, Command};
#[test]
fn indices_mult_opts() {
@ -8,7 +8,7 @@ fn indices_mult_opts() {
.short('e')
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(
Arg::new("include")
@ -37,7 +37,7 @@ fn index_mult_opts() {
.short('e')
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
.action(ArgAction::Append),
)
.arg(
Arg::new("include")
@ -67,88 +67,64 @@ fn index_flag() {
#[test]
fn index_flags() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("exclude").short('e').action(ArgAction::SetTrue))
.arg(Arg::new("include").short('i').action(ArgAction::SetTrue))
.try_get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"])
.unwrap();
assert_eq!(m.index_of("exclude"), Some(1));
assert_eq!(m.index_of("include"), Some(2));
assert_eq!(m.index_of("exclude"), Some(4));
assert_eq!(m.index_of("include"), Some(5));
}
#[test]
fn indices_mult_flags() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("exclude").short('e').action(ArgAction::SetTrue))
.arg(Arg::new("include").short('i').action(ArgAction::SetTrue))
.try_get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[4]);
assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[5]);
}
#[test]
fn indices_mult_flags_combined() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("exclude").short('e').action(ArgAction::SetTrue))
.arg(Arg::new("include").short('i').action(ArgAction::SetTrue))
.try_get_matches_from(vec!["ind", "-eieei"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[4]);
assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[5]);
}
#[test]
fn indices_mult_flags_opt_combined() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("exclude").short('e').action(ArgAction::SetTrue))
.arg(Arg::new("include").short('i').action(ArgAction::SetTrue))
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["ind", "-eieeio", "val"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[4]);
assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[5]);
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]);
}
#[test]
fn indices_mult_flags_opt_combined_eq() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("exclude").short('e').action(ArgAction::SetTrue))
.arg(Arg::new("include").short('i').action(ArgAction::SetTrue))
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["ind", "-eieeio=val"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[4]);
assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[5]);
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]);
}
@ -187,16 +163,11 @@ fn indices_mult_opt_value_no_delim_eq() {
#[test]
fn indices_mult_opt_mult_flag() {
let m = Command::new("myapp")
.arg(
Arg::new("option")
.short('o')
.takes_value(true)
.multiple_occurrences(true),
)
.arg(Arg::new("flag").short('f').multiple_occurrences(true))
.arg(Arg::new("option").short('o').action(ArgAction::Append))
.arg(Arg::new("flag").short('f').action(ArgAction::SetTrue))
.try_get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"])
.unwrap();
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]);
assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[6]);
}

View file

@ -0,0 +1,505 @@
#![allow(clippy::bool_assert_comparison)]
use clap::Arg;
use clap::ArgAction;
use clap::Command;
#[test]
fn set() {
let cmd = Command::new("test").arg(Arg::new("mammal").long("mammal").action(ArgAction::Set));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(matches.get_one::<String>("mammal"), None);
assert_eq!(matches.is_present("mammal"), false);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), None);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "dog"])
.unwrap();
assert_eq!(matches.get_one::<String>("mammal").unwrap(), "dog");
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "dog", "--mammal", "cat"])
.unwrap();
assert_eq!(matches.get_one::<String>("mammal").unwrap(), "cat");
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(4));
}
#[test]
fn append() {
let cmd = Command::new("test").arg(Arg::new("mammal").long("mammal").action(ArgAction::Append));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(matches.get_one::<String>("mammal"), None);
assert_eq!(matches.is_present("mammal"), false);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), None);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "dog"])
.unwrap();
assert_eq!(matches.get_one::<String>("mammal").unwrap(), "dog");
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(
matches.indices_of("mammal").unwrap().collect::<Vec<_>>(),
vec![2]
);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "dog", "--mammal", "cat"])
.unwrap();
assert_eq!(
matches
.get_many::<String>("mammal")
.unwrap()
.map(|s| s.as_str())
.collect::<Vec<_>>(),
vec!["dog", "cat"]
);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(
matches.indices_of("mammal").unwrap().collect::<Vec<_>>(),
vec![2, 4]
);
}
#[test]
fn set_true() {
let cmd =
Command::new("test").arg(Arg::new("mammal").long("mammal").action(ArgAction::SetTrue));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
}
#[test]
fn set_true_with_explicit_default_value() {
let cmd = Command::new("test").arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetTrue)
.default_value("false"),
);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
}
#[test]
fn set_true_with_default_value_if_present() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetTrue)
.default_value_if("dog", None, Some("true")),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::SetTrue));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
let matches = cmd.clone().try_get_matches_from(["test", "--dog"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
}
#[test]
fn set_true_with_default_value_if_value() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetTrue)
.default_value_if("dog", Some("true"), Some("true")),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::SetTrue));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
let matches = cmd.clone().try_get_matches_from(["test", "--dog"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
}
#[test]
fn set_true_with_required_if_eq() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetTrue)
.required_if_eq("dog", "true"),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::SetTrue));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
cmd.clone()
.try_get_matches_from(["test", "--dog"])
.unwrap_err();
let matches = cmd
.clone()
.try_get_matches_from(["test", "--dog", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
}
#[test]
fn set_false() {
let cmd = Command::new("test").arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetFalse),
);
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
}
#[test]
fn set_false_with_explicit_default_value() {
let cmd = Command::new("test").arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetFalse)
.default_value("true"),
);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
}
#[test]
fn set_false_with_default_value_if_present() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetFalse)
.default_value_if("dog", None, Some("false")),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::SetFalse));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
let matches = cmd.clone().try_get_matches_from(["test", "--dog"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
}
#[test]
fn set_false_with_default_value_if_value() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::SetFalse)
.default_value_if("dog", Some("false"), Some("false")),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::SetFalse));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), true);
let matches = cmd.clone().try_get_matches_from(["test", "--dog"]).unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), false);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<bool>("dog").unwrap(), true);
assert_eq!(*matches.get_one::<bool>("mammal").unwrap(), false);
}
#[test]
fn count() {
let cmd = Command::new("test").arg(Arg::new("mammal").long("mammal").action(ArgAction::Count));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 0);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 1);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 2);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(2));
}
#[test]
fn count_with_explicit_default_value() {
let cmd = Command::new("test").arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::Count)
.default_value("10"),
);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 1);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 10);
assert_eq!(matches.is_present("mammal"), true);
#[allow(deprecated)]
{
assert_eq!(matches.occurrences_of("mammal"), 0);
}
assert_eq!(matches.index_of("mammal"), Some(1));
}
#[test]
fn count_with_default_value_if_present() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::Count)
.default_value_if("dog", None, Some("10")),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::Count));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 0);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 0);
let matches = cmd.clone().try_get_matches_from(["test", "--dog"]).unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 1);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 10);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 0);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 1);
}
#[test]
fn count_with_default_value_if_value() {
let cmd = Command::new("test")
.arg(
Arg::new("mammal")
.long("mammal")
.action(ArgAction::Count)
.default_value_if("dog", Some("2"), Some("10")),
)
.arg(Arg::new("dog").long("dog").action(ArgAction::Count));
let matches = cmd.clone().try_get_matches_from(["test"]).unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 0);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 0);
let matches = cmd.clone().try_get_matches_from(["test", "--dog"]).unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 1);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 0);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--dog", "--dog"])
.unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 2);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 10);
let matches = cmd
.clone()
.try_get_matches_from(["test", "--mammal"])
.unwrap();
assert_eq!(*matches.get_one::<u64>("dog").unwrap(), 0);
assert_eq!(*matches.get_one::<u64>("mammal").unwrap(), 1);
}

View file

@ -0,0 +1,28 @@
#![cfg(feature = "cargo")]
#![allow(deprecated)]
use clap::{app_from_crate, error::ErrorKind};
static EVERYTHING: &str = "clap {{version}}
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
clap
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
#[test]
fn app_from_crate() {
let res = app_from_crate!().try_get_matches_from(vec!["clap", "--help"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayHelp);
assert_eq!(
err.to_string(),
EVERYTHING.replace("{{version}}", env!("CARGO_PKG_VERSION"))
);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,196 @@
use super::utils;
use clap::{arg, Arg, Command};
static SC_VISIBLE_ALIAS_HELP: &str = "ct-test 1.2
Some help
USAGE:
ct test [OPTIONS]
OPTIONS:
-f, --flag [aliases: v_flg, flag2, flg3]
-h, --help Print help information
-o, --opt <opt> [aliases: visible]
-V, --version Print version information
";
static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2
Some help
USAGE:
ct test [OPTIONS]
OPTIONS:
-f, --flag
-h, --help Print help information
-o, --opt <opt>
-V, --version Print version information
";
#[test]
fn single_alias_of_option() {
let a = Command::new("single_alias")
.arg(
Arg::new("alias")
.long("alias")
.takes_value(true)
.help("single alias")
.alias("new-opt"),
)
.try_get_matches_from(vec!["", "--new-opt", "cool"]);
assert!(a.is_ok(), "{}", a.unwrap_err());
let a = a.unwrap();
assert!(a.is_present("alias"));
assert_eq!(a.value_of("alias").unwrap(), "cool");
}
#[test]
fn multiple_aliases_of_option() {
let a = Command::new("multiple_aliases").arg(
Arg::new("aliases")
.long("aliases")
.takes_value(true)
.help("multiple aliases")
.aliases(&["alias1", "alias2", "alias3"]),
);
let long = a
.clone()
.try_get_matches_from(vec!["", "--aliases", "value"]);
assert!(long.is_ok(), "{}", long.unwrap_err());
let long = long.unwrap();
let als1 = a
.clone()
.try_get_matches_from(vec!["", "--alias1", "value"]);
assert!(als1.is_ok(), "{}", als1.unwrap_err());
let als1 = als1.unwrap();
let als2 = a
.clone()
.try_get_matches_from(vec!["", "--alias2", "value"]);
assert!(als2.is_ok(), "{}", als2.unwrap_err());
let als2 = als2.unwrap();
let als3 = a
.clone()
.try_get_matches_from(vec!["", "--alias3", "value"]);
assert!(als3.is_ok(), "{}", als3.unwrap_err());
let als3 = als3.unwrap();
assert!(long.is_present("aliases"));
assert!(als1.is_present("aliases"));
assert!(als2.is_present("aliases"));
assert!(als3.is_present("aliases"));
assert_eq!(long.value_of("aliases").unwrap(), "value");
assert_eq!(als1.value_of("aliases").unwrap(), "value");
assert_eq!(als2.value_of("aliases").unwrap(), "value");
assert_eq!(als3.value_of("aliases").unwrap(), "value");
}
#[test]
fn single_alias_of_flag() {
let a = Command::new("test")
.arg(Arg::new("flag").long("flag").alias("alias"))
.try_get_matches_from(vec!["", "--alias"]);
assert!(a.is_ok(), "{}", a.unwrap_err());
let a = a.unwrap();
assert!(a.is_present("flag"));
}
#[test]
fn multiple_aliases_of_flag() {
let a = Command::new("test").arg(Arg::new("flag").long("flag").aliases(&[
"invisible",
"set",
"of",
"cool",
"aliases",
]));
let flag = a.clone().try_get_matches_from(vec!["", "--flag"]);
assert!(flag.is_ok(), "{}", flag.unwrap_err());
let flag = flag.unwrap();
let inv = a.clone().try_get_matches_from(vec!["", "--invisible"]);
assert!(inv.is_ok(), "{}", inv.unwrap_err());
let inv = inv.unwrap();
let cool = a.clone().try_get_matches_from(vec!["", "--cool"]);
assert!(cool.is_ok(), "{}", cool.unwrap_err());
let cool = cool.unwrap();
let als = a.clone().try_get_matches_from(vec!["", "--aliases"]);
assert!(als.is_ok(), "{}", als.unwrap_err());
let als = als.unwrap();
assert!(flag.is_present("flag"));
assert!(inv.is_present("flag"));
assert!(cool.is_present("flag"));
assert!(als.is_present("flag"));
}
#[test]
fn alias_on_a_subcommand_option() {
let m = Command::new("test")
.subcommand(
Command::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.alias("opt")
.help("testing testing"),
),
)
.arg(Arg::new("other").long("other").aliases(&["o1", "o2", "o3"]))
.try_get_matches_from(vec!["test", "some", "--opt", "awesome"])
.unwrap();
assert!(m.subcommand_matches("some").is_some());
let sub_m = m.subcommand_matches("some").unwrap();
assert!(sub_m.is_present("test"));
assert_eq!(sub_m.value_of("test").unwrap(), "awesome");
}
#[test]
fn invisible_arg_aliases_help_output() {
let cmd = Command::new("ct").author("Salim Afiune").subcommand(
Command::new("test")
.about("Some help")
.version("1.2")
.arg(
Arg::new("opt")
.long("opt")
.short('o')
.takes_value(true)
.aliases(&["invisible", "als1", "more"]),
)
.arg(arg!(-f - -flag).aliases(&["unseeable", "flg1", "anyway"])),
);
utils::assert_output(cmd, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false);
}
#[test]
fn visible_arg_aliases_help_output() {
let cmd = Command::new("ct").author("Salim Afiune").subcommand(
Command::new("test")
.about("Some help")
.version("1.2")
.arg(
Arg::new("opt")
.long("opt")
.short('o')
.takes_value(true)
.alias("invisible")
.visible_alias("visible"),
)
.arg(
Arg::new("flg")
.long("flag")
.short('f')
.visible_aliases(&["v_flg", "flag2", "flg3"]),
),
);
utils::assert_output(cmd, "ct test --help", SC_VISIBLE_ALIAS_HELP, false);
}

View file

@ -0,0 +1,193 @@
use super::utils;
use clap::{arg, Arg, Command};
static SC_VISIBLE_ALIAS_HELP: &str = "ct-test 1.2
Some help
USAGE:
ct test [OPTIONS]
OPTIONS:
-f, --flag [aliases: flag1] [short aliases: a, b, 🦆]
-h, --help Print help information
-o, --opt <opt> [short aliases: v]
-V, --version Print version information
";
static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2
Some help
USAGE:
ct test [OPTIONS]
OPTIONS:
-f, --flag
-h, --help Print help information
-o, --opt <opt>
-V, --version Print version information
";
#[test]
fn single_short_alias_of_option() {
let a = Command::new("single_alias")
.arg(
Arg::new("alias")
.long("alias")
.takes_value(true)
.help("single short alias")
.short_alias('a'),
)
.try_get_matches_from(vec!["", "-a", "cool"]);
assert!(a.is_ok(), "{}", a.unwrap_err());
let a = a.unwrap();
assert!(a.is_present("alias"));
assert_eq!(a.value_of("alias").unwrap(), "cool");
}
#[test]
fn multiple_short_aliases_of_option() {
let a = Command::new("multiple_aliases").arg(
Arg::new("aliases")
.long("aliases")
.takes_value(true)
.help("multiple aliases")
.short_aliases(&['1', '2', '3']),
);
let long = a
.clone()
.try_get_matches_from(vec!["", "--aliases", "value"]);
assert!(long.is_ok(), "{}", long.unwrap_err());
let long = long.unwrap();
let als1 = a.clone().try_get_matches_from(vec!["", "-1", "value"]);
assert!(als1.is_ok(), "{}", als1.unwrap_err());
let als1 = als1.unwrap();
let als2 = a.clone().try_get_matches_from(vec!["", "-2", "value"]);
assert!(als2.is_ok(), "{}", als2.unwrap_err());
let als2 = als2.unwrap();
let als3 = a.clone().try_get_matches_from(vec!["", "-3", "value"]);
assert!(als3.is_ok(), "{}", als3.unwrap_err());
let als3 = als3.unwrap();
assert!(long.is_present("aliases"));
assert!(als1.is_present("aliases"));
assert!(als2.is_present("aliases"));
assert!(als3.is_present("aliases"));
assert_eq!(long.value_of("aliases").unwrap(), "value");
assert_eq!(als1.value_of("aliases").unwrap(), "value");
assert_eq!(als2.value_of("aliases").unwrap(), "value");
assert_eq!(als3.value_of("aliases").unwrap(), "value");
}
#[test]
fn single_short_alias_of_flag() {
let a = Command::new("test")
.arg(Arg::new("flag").long("flag").short_alias('f'))
.try_get_matches_from(vec!["", "-f"]);
assert!(a.is_ok(), "{}", a.unwrap_err());
let a = a.unwrap();
assert!(a.is_present("flag"));
}
#[test]
fn multiple_short_aliases_of_flag() {
let a = Command::new("test").arg(
Arg::new("flag")
.long("flag")
.short_aliases(&['a', 'b', 'c', 'd', 'e']),
);
let flag = a.clone().try_get_matches_from(vec!["", "--flag"]);
assert!(flag.is_ok(), "{}", flag.unwrap_err());
let flag = flag.unwrap();
let als1 = a.clone().try_get_matches_from(vec!["", "-a"]);
assert!(als1.is_ok(), "{}", als1.unwrap_err());
let als1 = als1.unwrap();
let als2 = a.clone().try_get_matches_from(vec!["", "-b"]);
assert!(als2.is_ok(), "{}", als2.unwrap_err());
let als2 = als2.unwrap();
let als3 = a.clone().try_get_matches_from(vec!["", "-c"]);
assert!(als3.is_ok(), "{}", als3.unwrap_err());
let als3 = als3.unwrap();
assert!(flag.is_present("flag"));
assert!(als1.is_present("flag"));
assert!(als2.is_present("flag"));
assert!(als3.is_present("flag"));
}
#[test]
fn short_alias_on_a_subcommand_option() {
let m = Command::new("test")
.subcommand(
Command::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.short_alias('o')
.help("testing testing"),
),
)
.arg(
Arg::new("other")
.long("other")
.short_aliases(&['1', '2', '3']),
)
.try_get_matches_from(vec!["test", "some", "-o", "awesome"])
.unwrap();
assert!(m.subcommand_matches("some").is_some());
let sub_m = m.subcommand_matches("some").unwrap();
assert!(sub_m.is_present("test"));
assert_eq!(sub_m.value_of("test").unwrap(), "awesome");
}
#[test]
fn invisible_short_arg_aliases_help_output() {
let cmd = Command::new("ct").author("Salim Afiune").subcommand(
Command::new("test")
.about("Some help")
.version("1.2")
.arg(
Arg::new("opt")
.long("opt")
.short('o')
.takes_value(true)
.short_aliases(&['a', 'b', 'c']),
)
.arg(arg!(-f - -flag).short_aliases(&['x', 'y', 'z'])),
);
utils::assert_output(cmd, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false);
}
#[test]
fn visible_short_arg_aliases_help_output() {
let cmd = Command::new("ct").author("Salim Afiune").subcommand(
Command::new("test")
.about("Some help")
.version("1.2")
.arg(
Arg::new("opt")
.long("opt")
.short('o')
.takes_value(true)
.short_alias('i')
.visible_short_alias('v'),
)
.arg(
Arg::new("flg")
.long("flag")
.short('f')
.visible_alias("flag1")
.visible_short_aliases(&['a', 'b', '🦆']),
),
);
utils::assert_output(cmd, "ct test --help", SC_VISIBLE_ALIAS_HELP, false);
}

View file

@ -0,0 +1,41 @@
#[cfg(debug_assertions)]
use clap::{Arg, Command};
#[test]
#[cfg(debug_assertions)]
#[should_panic = "`f` is not a name of an argument or a group."]
fn arg_matches_if_present_wrong_arg() {
let m = Command::new("test")
.arg(Arg::new("flag").short('f'))
.try_get_matches_from(&["test", "-f"])
.unwrap();
assert!(m.is_present("flag"));
m.is_present("f");
}
#[test]
#[cfg(debug_assertions)]
#[should_panic = "`o` is not a name of an argument or a group."]
fn arg_matches_value_of_wrong_arg() {
let m = Command::new("test")
.arg(Arg::new("opt").short('o').takes_value(true))
.try_get_matches_from(&["test", "-o", "val"])
.unwrap();
assert_eq!(m.value_of("opt"), Some("val"));
m.value_of("o");
}
#[test]
#[cfg(debug_assertions)]
#[should_panic = "`seed` is not a name of a subcommand."]
fn arg_matches_subcommand_matches_wrong_sub() {
let m = Command::new("test")
.subcommand(Command::new("speed"))
.try_get_matches_from(&["test", "speed"])
.unwrap();
assert!(m.subcommand_matches("speed").is_some());
m.subcommand_matches("seed");
}

View file

@ -0,0 +1,44 @@
#![allow(deprecated)]
use clap::{Arg, ArgSettings};
#[test]
fn setting() {
let m = Arg::new("setting").setting(ArgSettings::Required);
assert!(m.is_required_set());
}
#[test]
fn unset_setting() {
let m = Arg::new("unset_setting").setting(ArgSettings::Required);
assert!(m.is_required_set());
let m = m.unset_setting(ArgSettings::Required);
assert!(!m.is_required_set(), "{:#?}", m);
}
#[test]
fn setting_bitor() {
let m = Arg::new("setting_bitor")
.setting(ArgSettings::Required | ArgSettings::Hidden | ArgSettings::Last);
assert!(m.is_required_set());
assert!(m.is_hide_set());
assert!(m.is_last_set());
}
#[test]
fn unset_setting_bitor() {
let m = Arg::new("unset_setting_bitor")
.setting(ArgSettings::Required)
.setting(ArgSettings::Hidden)
.setting(ArgSettings::Last);
assert!(m.is_required_set());
assert!(m.is_hide_set());
assert!(m.is_last_set());
let m = m.unset_setting(ArgSettings::Required | ArgSettings::Hidden | ArgSettings::Last);
assert!(!m.is_required_set(), "{:#?}", m);
assert!(!m.is_hide_set(), "{:#?}", m);
assert!(!m.is_last_set(), "{:#?}", m);
}

View file

@ -0,0 +1,17 @@
use clap::{Arg, Command};
#[test]
fn borrowed_args() {
let arg = Arg::new("some").short('s').long("some").help("other help");
let arg2 = Arg::new("some2")
.short('S')
.long("some-thing")
.help("other help");
let result = Command::new("sub_command_negate")
.arg(Arg::new("test").index(1))
.arg(&arg)
.arg(&arg2)
.subcommand(Command::new("sub1").arg(&arg))
.try_get_matches_from(vec!["prog"]);
assert!(result.is_ok(), "{}", result.unwrap_err());
}

View file

@ -0,0 +1,80 @@
#![cfg(feature = "cargo")]
use clap::{
crate_authors, crate_description, crate_name, crate_version, error::ErrorKind, Command,
};
static DESCRIPTION_ONLY: &str = "prog 1
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
prog
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
static AUTHORS_ONLY: &str = "prog 1
USAGE:
prog
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
#[test]
fn crate_version() {
let res = Command::new("prog")
.version(crate_version!())
.try_get_matches_from(vec!["prog", "--version"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayVersion);
assert_eq!(
err.to_string(),
format!("prog {}\n", env!("CARGO_PKG_VERSION"))
);
}
#[test]
fn crate_description() {
let res = Command::new("prog")
.version("1")
.about(crate_description!())
.try_get_matches_from(vec!["prog", "--help"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayHelp);
assert_eq!(err.to_string(), DESCRIPTION_ONLY);
}
#[test]
fn crate_authors() {
let res = Command::new("prog")
.version("1")
.author(crate_authors!())
.try_get_matches_from(vec!["prog", "--help"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayHelp);
assert_eq!(err.to_string(), AUTHORS_ONLY);
}
#[test]
fn crate_name() {
let res = Command::new(crate_name!())
.version("3.0")
.try_get_matches_from(vec!["clap", "--version"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayVersion);
assert_eq!(err.to_string(), "clap 3.0\n");
}

View file

@ -0,0 +1,27 @@
#![cfg(feature = "cargo")]
use clap::{command, error::ErrorKind};
static EVERYTHING: &str = "clap {{version}}
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
clap
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
#[test]
fn command() {
let res = command!().try_get_matches_from(vec!["clap", "--help"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayHelp);
assert_eq!(
err.to_string(),
EVERYTHING.replace("{{version}}", env!("CARGO_PKG_VERSION"))
);
}

View file

@ -0,0 +1,509 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgGroup, Command};
static CONFLICT_ERR: &str = "error: The argument '--flag' cannot be used with '-F'
USAGE:
clap-test --flag --long-option-2 <option2> <positional> <positional2>
For more information try --help
";
static CONFLICT_ERR_REV: &str = "error: The argument '-F' cannot be used with '--flag'
USAGE:
clap-test -F --long-option-2 <option2> <positional> <positional2>
For more information try --help
";
static CONFLICT_ERR_THREE: &str = "error: The argument '--one' cannot be used with:
--two
--three
USAGE:
three_conflicting_arguments --one
For more information try --help
";
#[test]
fn flag_conflict() {
let result = Command::new("flag_conflict")
.arg(arg!(-f --flag "some flag").conflicts_with("other"))
.arg(arg!(-o --other "some flag"))
.try_get_matches_from(vec!["myprog", "-f", "-o"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn flag_conflict_2() {
let result = Command::new("flag_conflict")
.arg(arg!(-f --flag "some flag").conflicts_with("other"))
.arg(arg!(-o --other "some flag"))
.try_get_matches_from(vec!["myprog", "-o", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn flag_conflict_with_all() {
let result = Command::new("flag_conflict")
.arg(arg!(-f --flag "some flag").conflicts_with_all(&["other"]))
.arg(arg!(-o --other "some flag"))
.try_get_matches_from(vec!["myprog", "-o", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn flag_conflict_with_everything() {
let result = 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"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn arg_conflicts_with_group() {
let mut cmd = Command::new("group_conflict")
.arg(arg!(-f --flag "some flag").conflicts_with("gr"))
.group(ArgGroup::new("gr").arg("some").arg("other"))
.arg(arg!(--some "some arg"))
.arg(arg!(--other "other arg"));
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "-f", "--some"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--some"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--flag"]);
if let Err(err) = result {
panic!("{}", err);
}
}
#[test]
fn arg_conflicts_with_group_with_multiple_sources() {
let mut cmd = clap::Command::new("group_conflict")
.arg(clap::arg!(-f --flag "some flag").conflicts_with("gr"))
.group(clap::ArgGroup::new("gr").multiple(true))
.arg(
clap::arg!(--some <name> "some arg")
.required(false)
.group("gr"),
)
.arg(
clap::arg!(--other <secs> "other arg")
.required(false)
.default_value("1000")
.group("gr"),
);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "-f"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--some", "usb1"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--some", "usb1", "--other", "40"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "-f", "--some", "usb1"]);
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn group_conflicts_with_arg() {
let mut cmd = Command::new("group_conflict")
.arg(arg!(-f --flag "some flag"))
.group(
ArgGroup::new("gr")
.arg("some")
.arg("other")
.conflicts_with("flag"),
)
.arg(arg!(--some "some arg"))
.arg(arg!(--other "other arg"));
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "-f", "--some"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--some"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--flag"]);
if let Err(err) = result {
panic!("{}", err);
}
}
#[test]
fn arg_conflicts_with_required_group() {
let mut cmd = Command::new("group_conflict")
.arg(arg!(-f --flag "some flag").conflicts_with("gr"))
.group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
.arg(arg!(--some "some arg"))
.arg(arg!(--other "other arg"));
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "-f", "--some"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--some"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other"]);
if let Err(err) = result {
panic!("{}", err);
}
}
#[test]
fn required_group_conflicts_with_arg() {
let mut cmd = Command::new("group_conflict")
.arg(arg!(-f --flag "some flag"))
.group(
ArgGroup::new("gr")
.required(true)
.arg("some")
.arg("other")
.conflicts_with("flag"),
)
.arg(arg!(--some "some arg"))
.arg(arg!(--other "other arg"));
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "-f", "--some"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--some"]);
if let Err(err) = result {
panic!("{}", err);
}
let result = cmd.try_get_matches_from_mut(vec!["myprog", "--other"]);
if let Err(err) = result {
panic!("{}", err);
}
}
#[test]
fn conflict_output() {
utils::assert_output(
utils::complex_app(),
"clap-test val1 fa --flag --long-option-2 val2 -F",
CONFLICT_ERR,
true,
);
}
#[test]
fn conflict_output_rev() {
utils::assert_output(
utils::complex_app(),
"clap-test val1 fa -F --long-option-2 val2 --flag",
CONFLICT_ERR_REV,
true,
);
}
#[test]
fn conflict_output_with_required() {
utils::assert_output(
utils::complex_app(),
"clap-test val1 --flag --long-option-2 val2 -F",
CONFLICT_ERR,
true,
);
}
#[test]
fn conflict_output_rev_with_required() {
utils::assert_output(
utils::complex_app(),
"clap-test val1 -F --long-option-2 val2 --flag",
CONFLICT_ERR_REV,
true,
);
}
#[test]
fn conflict_output_three_conflicting() {
let cmd = Command::new("three_conflicting_arguments")
.arg(
Arg::new("one")
.long("one")
.conflicts_with_all(&["two", "three"]),
)
.arg(
Arg::new("two")
.long("two")
.conflicts_with_all(&["one", "three"]),
)
.arg(
Arg::new("three")
.long("three")
.conflicts_with_all(&["one", "two"]),
);
utils::assert_output(
cmd,
"three_conflicting_arguments --one --two --three",
CONFLICT_ERR_THREE,
true,
);
}
#[test]
fn two_conflicting_arguments() {
let a = Command::new("two_conflicting_arguments")
.arg(
Arg::new("develop")
.long("develop")
.conflicts_with("production"),
)
.arg(
Arg::new("production")
.long("production")
.conflicts_with("develop"),
)
.try_get_matches_from(vec!["", "--develop", "--production"]);
assert!(a.is_err());
let a = a.unwrap_err();
assert!(
a.to_string()
.contains("The argument \'--develop\' cannot be used with \'--production\'"),
"{}",
a
);
}
#[test]
fn three_conflicting_arguments() {
let a = Command::new("three_conflicting_arguments")
.arg(
Arg::new("one")
.long("one")
.conflicts_with_all(&["two", "three"]),
)
.arg(
Arg::new("two")
.long("two")
.conflicts_with_all(&["one", "three"]),
)
.arg(
Arg::new("three")
.long("three")
.conflicts_with_all(&["one", "two"]),
)
.try_get_matches_from(vec!["", "--one", "--two", "--three"]);
assert!(a.is_err());
let a = a.unwrap_err();
assert!(
a.to_string()
.contains("The argument \'--one\' cannot be used with:"),
"{}",
a
);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument 'config' cannot conflict with itself"]
fn self_conflicting_arg() {
let _ = Command::new("prog")
.arg(Arg::new("config").long("config").conflicts_with("config"))
.try_get_matches_from(vec!["", "--config"]);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument or group 'extra' specified in 'conflicts_with*' for 'config' does not exist"]
fn conflicts_with_invalid_arg() {
let _ = Command::new("prog")
.arg(Arg::new("config").long("config").conflicts_with("extra"))
.try_get_matches_from(vec!["", "--config"]);
}
#[test]
fn conflict_with_unused_default() {
let result = Command::new("conflict")
.arg(
arg!(-o --opt <opt> "some opt")
.required(false)
.default_value("default"),
)
.arg(arg!(-f --flag "some flag").conflicts_with("opt"))
.try_get_matches_from(vec!["myprog", "-f"]);
assert!(result.is_ok(), "{}", result.unwrap_err());
let m = result.unwrap();
assert_eq!(m.value_of("opt"), Some("default"));
assert!(m.is_present("flag"));
}
#[test]
fn conflicts_with_alongside_default() {
let result = Command::new("conflict")
.arg(
arg!(-o --opt <opt> "some opt")
.default_value("default")
.required(false)
.conflicts_with("flag"),
)
.arg(arg!(-f --flag "some flag"))
.try_get_matches_from(vec!["myprog", "-f"]);
assert!(
result.is_ok(),
"conflicts_with should ignore default_value: {:?}",
result.unwrap_err()
);
let m = result.unwrap();
assert_eq!(m.value_of("opt"), Some("default"));
assert!(m.is_present("flag"));
}
#[test]
fn group_in_conflicts_with() {
let result = Command::new("conflict")
.arg(
Arg::new("opt")
.long("opt")
.default_value("default")
.group("one"),
)
.arg(Arg::new("flag").long("flag").conflicts_with("one"))
.try_get_matches_from(vec!["myprog", "--flag"]);
assert!(
result.is_ok(),
"conflicts_with on an arg group should ignore default_value: {:?}",
result.unwrap_err()
);
let m = result.unwrap();
assert_eq!(m.value_of("opt"), Some("default"));
assert!(m.is_present("flag"));
}
#[test]
fn group_conflicts_with_default_value() {
let result = Command::new("conflict")
.arg(
Arg::new("opt")
.long("opt")
.default_value("default")
.group("one"),
)
.arg(Arg::new("flag").long("flag").group("one"))
.try_get_matches_from(vec!["myprog", "--flag"]);
assert!(
result.is_ok(),
"arg group count should ignore default_value: {:?}",
result.unwrap_err()
);
let m = result.unwrap();
assert_eq!(m.value_of("opt"), Some("default"));
assert!(m.is_present("flag"));
}
#[test]
fn group_conflicts_with_default_arg() {
let result = Command::new("conflict")
.arg(Arg::new("opt").long("opt").default_value("default"))
.arg(Arg::new("flag").long("flag").group("one"))
.group(ArgGroup::new("one").conflicts_with("opt"))
.try_get_matches_from(vec!["myprog", "--flag"]);
assert!(
result.is_ok(),
"arg group conflicts_with should ignore default_value: {:?}",
result.unwrap_err()
);
let m = result.unwrap();
assert_eq!(m.value_of("opt"), Some("default"));
assert!(m.is_present("flag"));
}
#[test]
fn exclusive_with_required() {
let cmd = Command::new("bug")
.arg(Arg::new("test").long("test").exclusive(true))
.arg(Arg::new("input").takes_value(true).required(true));
cmd.clone()
.try_get_matches_from(["bug", "--test", "required"])
.unwrap_err();
cmd.clone()
.try_get_matches_from(["bug", "required"])
.unwrap();
cmd.clone().try_get_matches_from(["bug", "--test"]).unwrap();
}

View file

@ -0,0 +1,187 @@
use clap::{arg, Arg, ArgMatches, Command};
#[test]
fn opt_missing() {
let r = Command::new("df")
.arg(
Arg::new("color")
.long("color")
.default_value("auto")
.min_values(0)
.require_equals(true)
.default_missing_value("always"),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "auto");
assert_eq!(m.occurrences_of("color"), 0);
}
#[test]
fn opt_present_with_missing_value() {
let r = Command::new("df")
.arg(
Arg::new("color")
.long("color")
.default_value("auto")
.min_values(0)
.require_equals(true)
.default_missing_value("always"),
)
.try_get_matches_from(vec!["", "--color"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "always");
assert_eq!(m.occurrences_of("color"), 1);
}
#[test]
fn opt_present_with_value() {
let r = Command::new("df")
.arg(
Arg::new("color")
.long("color")
.default_value("auto")
.min_values(0)
.require_equals(true)
.default_missing_value("always"),
)
.try_get_matches_from(vec!["", "--color=never"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "never");
assert_eq!(m.occurrences_of("color"), 1);
}
#[test]
fn opt_present_with_empty_value() {
let r = Command::new("df")
.arg(
Arg::new("color")
.long("color")
.default_value("auto")
.require_equals(true)
.default_missing_value("always"),
)
.try_get_matches_from(vec!["", "--color="]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "");
assert_eq!(m.occurrences_of("color"), 1);
}
//## `default_value`/`default_missing_value` non-interaction checks
#[test]
fn opt_default() {
// assert no change to usual argument handling when adding default_missing_value()
let r = Command::new("cmd")
.arg(
arg!(o: -o [opt] "some opt")
.default_value("default")
.default_missing_value("default_missing"),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.value_of("o").unwrap(), "default");
}
#[test]
fn opt_default_user_override() {
// assert no change to usual argument handling when adding default_missing_value()
let r = Command::new("cmd")
.arg(
arg!(o: -o [opt] "some opt")
.default_value("default")
.default_missing_value("default_missing"),
)
.try_get_matches_from(vec!["", "-o=value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.value_of("o").unwrap(), "value");
}
#[test]
#[allow(clippy::bool_assert_comparison)]
fn default_missing_value_flag_value() {
let cmd = Command::new("test").arg(
Arg::new("flag")
.long("flag")
.takes_value(true)
.default_missing_value("true"),
);
fn flag_value(m: ArgMatches) -> bool {
match m.value_of("flag") {
None => false,
Some(x) => x.parse().expect("non boolean value"),
}
}
assert_eq!(
flag_value(cmd.clone().try_get_matches_from(&["test"]).unwrap()),
false
);
assert_eq!(
flag_value(
cmd.clone()
.try_get_matches_from(&["test", "--flag"])
.unwrap()
),
true
);
assert_eq!(
flag_value(
cmd.clone()
.try_get_matches_from(&["test", "--flag=true"])
.unwrap()
),
true
);
assert_eq!(
flag_value(
cmd.clone()
.try_get_matches_from(&["test", "--flag=false"])
.unwrap()
),
false
);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument `arg`'s default_missing_value=value doesn't match possible values"]
fn default_missing_values_are_possible_values() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.possible_values(["one", "two"])
.default_missing_value("value"),
)
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument `arg`'s default_missing_value=value failed validation: invalid digit found in string"]
fn default_missing_values_are_valid() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string()))
.default_missing_value("value"),
)
.try_get_matches();
}

View file

@ -0,0 +1,731 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, Command};
#[test]
fn opts() {
let r = Command::new("df")
.arg(
arg!(o: -o <opt> "some opt")
.required(false)
.default_value("default"),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.value_of("o").unwrap(), "default");
}
#[test]
fn opt_without_value_fail() {
let r = Command::new("df")
.arg(
arg!(o: -o <opt> "some opt")
.required(false)
.default_value("default")
.forbid_empty_values(true),
)
.try_get_matches_from(vec!["", "-o"]);
assert!(r.is_err());
let err = r.unwrap_err();
assert_eq!(err.kind(), ErrorKind::EmptyValue);
assert!(err
.to_string()
.contains("The argument '-o <opt>' requires a value but none was supplied"));
}
#[test]
fn opt_user_override() {
let r = Command::new("df")
.arg(
arg!(--opt <FILE> "some arg")
.required(false)
.default_value("default"),
)
.try_get_matches_from(vec!["", "--opt", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.value_of("opt").unwrap(), "value");
}
#[test]
fn positionals() {
let r = Command::new("df")
.arg(arg!([arg] "some opt").default_value("default"))
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
#[test]
fn positional_user_override() {
let r = Command::new("df")
.arg(arg!([arg] "some arg").default_value("default"))
.try_get_matches_from(vec!["", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "value");
}
// OsStr Default Values
#[test]
fn osstr_opts() {
use std::ffi::OsStr;
let expected = OsStr::new("default");
let r = Command::new("df")
.arg(
arg!(o: -o <opt> "some opt")
.required(false)
.default_value_os(expected),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.value_of("o").unwrap(), expected);
}
#[test]
fn osstr_opt_user_override() {
use std::ffi::OsStr;
let default = OsStr::new("default");
let r = Command::new("df")
.arg(
arg!(--opt <FILE> "some arg")
.required(false)
.default_value_os(default),
)
.try_get_matches_from(vec!["", "--opt", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.value_of("opt").unwrap(), "value");
}
#[test]
fn osstr_positionals() {
use std::ffi::OsStr;
let expected = OsStr::new("default");
let r = Command::new("df")
.arg(arg!([arg] "some opt").default_value_os(expected))
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), expected);
}
#[test]
fn osstr_positional_user_override() {
use std::ffi::OsStr;
let default = OsStr::new("default");
let r = Command::new("df")
.arg(arg!([arg] "some arg").default_value_os(default))
.try_get_matches_from(vec!["", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "value");
}
// --- Default if arg is present
#[test]
fn default_if_arg_present_no_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(true))
.arg(arg!([arg] "some arg").default_value_if("opt", None, Some("default")))
.try_get_matches_from(vec!["", "--opt", "some"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
#[test]
fn default_if_arg_present_no_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!([arg] "some arg").default_value_if("opt", None, Some("default")))
.try_get_matches_from(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
#[test]
fn default_if_arg_present_no_arg_with_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", None, Some("default")),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "first");
}
#[test]
fn default_if_arg_present_with_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", None, Some("default")),
)
.try_get_matches_from(vec!["", "--opt", "some"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
#[test]
fn default_if_arg_present_with_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", None, Some("default")),
)
.try_get_matches_from(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
#[test]
fn default_if_arg_present_no_arg_with_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", None, Some("default")),
)
.try_get_matches_from(vec!["", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
// Conditional Default Values
#[test]
fn default_if_arg_present_with_value_no_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!([arg] "some arg").default_value_if("opt", Some("value"), Some("default")))
.try_get_matches_from(vec!["", "--opt", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
#[test]
fn default_if_arg_present_with_value_no_default_fail() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!([arg] "some arg").default_value_if("opt", Some("value"), Some("default")))
.try_get_matches_from(vec!["", "--opt", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert!(m.value_of("arg").is_none());
}
#[test]
fn default_if_arg_present_with_value_no_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!([arg] "some arg").default_value_if("opt", Some("some"), Some("default")))
.try_get_matches_from(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
#[test]
fn default_if_arg_present_with_value_no_arg_with_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", Some("some"), Some("default")),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "first");
}
#[test]
fn default_if_arg_present_with_value_no_arg_with_default_fail() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", Some("some"), Some("default")),
)
.try_get_matches_from(vec!["", "--opt", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "first");
}
#[test]
fn default_if_arg_present_with_value_with_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", Some("some"), Some("default")),
)
.try_get_matches_from(vec!["", "--opt", "some"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
#[test]
fn default_if_arg_present_with_value_with_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", Some("some"), Some("default")),
)
.try_get_matches_from(vec!["", "--opt", "some", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
#[test]
fn default_if_arg_present_no_arg_with_value_with_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", Some("some"), Some("default")),
)
.try_get_matches_from(vec!["", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
#[test]
fn default_if_arg_present_no_arg_with_value_with_default_user_override_fail() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_if("opt", Some("some"), Some("default")),
)
.try_get_matches_from(vec!["", "--opt", "value", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
// Unsetting the default
#[test]
fn no_default_if_arg_present_with_value_no_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!([arg] "some arg").default_value_if("opt", Some("value"), None))
.try_get_matches_from(vec!["", "--opt", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
}
#[test]
fn no_default_if_arg_present_with_value_with_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("default")
.default_value_if("opt", Some("value"), None),
)
.try_get_matches_from(vec!["", "--opt", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert!(m.value_of("arg").is_none());
}
#[test]
fn no_default_if_arg_present_with_value_with_default_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("default")
.default_value_if("opt", Some("value"), None),
)
.try_get_matches_from(vec!["", "--opt", "value", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "other");
}
#[test]
fn no_default_if_arg_present_no_arg_with_value_with_default() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(
arg!([arg] "some arg")
.default_value("default")
.default_value_if("opt", Some("value"), None),
)
.try_get_matches_from(vec!["", "--opt", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
// Multiple conditions
#[test]
fn default_ifs_arg_present() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!(--flag "some arg"))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_ifs(&[
("opt", Some("some"), Some("default")),
("flag", None, Some("flg")),
]),
)
.try_get_matches_from(vec!["", "--flag"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "flg");
}
#[test]
fn no_default_ifs_arg_present() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!(--flag "some arg"))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_ifs(&[("opt", Some("some"), Some("default")), ("flag", None, None)]),
)
.try_get_matches_from(vec!["", "--flag"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert!(m.value_of("arg").is_none());
}
#[test]
fn default_ifs_arg_present_user_override() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!(--flag "some arg"))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_ifs(&[
("opt", Some("some"), Some("default")),
("flag", None, Some("flg")),
]),
)
.try_get_matches_from(vec!["", "--flag", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "value");
}
#[test]
fn default_ifs_arg_present_order() {
let r = Command::new("df")
.arg(arg!(--opt <FILE> "some arg").required(false))
.arg(arg!(--flag "some arg"))
.arg(
arg!([arg] "some arg")
.default_value("first")
.default_value_ifs(&[
("opt", Some("some"), Some("default")),
("flag", None, Some("flg")),
]),
)
.try_get_matches_from(vec!["", "--opt=some", "--flag"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.value_of("arg").unwrap(), "default");
}
// Interaction with requires
#[test]
fn conditional_reqs_pass() {
let m = Command::new("Test cmd")
.arg(
Arg::new("target")
.takes_value(true)
.default_value("file")
.long("target"),
)
.arg(
Arg::new("input")
.takes_value(true)
.required(true)
.long("input"),
)
.arg(
Arg::new("output")
.takes_value(true)
.required_if_eq("target", "file")
.long("output"),
)
.try_get_matches_from(vec!["test", "--input", "some", "--output", "other"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert_eq!(m.value_of("output"), Some("other"));
assert_eq!(m.value_of("input"), Some("some"));
}
#[test]
fn multiple_defaults() {
let r = Command::new("diff")
.arg(
Arg::new("files")
.long("files")
.number_of_values(2)
.allow_invalid_utf8(true)
.default_values(&["old", "new"]),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.values_of_lossy("files").unwrap(), vec!["old", "new"]);
}
#[test]
fn multiple_defaults_override() {
let r = Command::new("diff")
.arg(
Arg::new("files")
.long("files")
.number_of_values(2)
.allow_invalid_utf8(true)
.default_values(&["old", "new"]),
)
.try_get_matches_from(vec!["", "--files", "other", "mine"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("files"));
assert_eq!(m.values_of_lossy("files").unwrap(), vec!["other", "mine"]);
}
#[test]
fn default_vals_donnot_show_in_smart_usage() {
let cmd = Command::new("bug")
.arg(
Arg::new("foo")
.long("config")
.takes_value(true)
.default_value("bar"),
)
.arg(Arg::new("input").required(true));
utils::assert_output(
cmd,
"bug",
"error: The following required arguments were not provided:
<input>
USAGE:
bug [OPTIONS] <input>
For more information try --help
",
true,
);
}
#[test]
fn issue_1050_num_vals_and_defaults() {
let res = Command::new("hello")
.arg(
Arg::new("exit-code")
.long("exit-code")
.takes_value(true)
.number_of_values(1)
.default_value("0"),
)
.try_get_matches_from(vec!["hello", "--exit-code=1"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert_eq!(m.value_of("exit-code"), Some("1"));
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group 'group' is required but all of it's arguments have a default value."]
fn required_groups_with_default_values() {
use clap::{Arg, ArgGroup, Command};
let _ = Command::new("test")
.arg(Arg::new("arg").default_value("value"))
.group(ArgGroup::new("group").args(&["arg"]).required(true))
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument 'arg' is required and can't have a default value"]
fn required_args_with_default_values() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(Arg::new("arg").required(true).default_value("value"))
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument `arg`'s default_value=value doesn't match possible values"]
fn default_values_are_possible_values() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.possible_values(["one", "two"])
.default_value("value"),
)
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument `arg`'s default_value=one failed validation: invalid digit found in string"]
fn invalid_default_values() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string()))
.default_value("one"),
)
.try_get_matches();
}
#[test]
fn valid_delimited_default_values() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string()))
.use_value_delimiter(true)
.require_value_delimiter(true)
.default_value("1,2,3"),
)
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument `arg`'s default_value=one failed validation: invalid digit found in string"]
fn invalid_delimited_default_values() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(
Arg::new("arg")
.validator(|val| val.parse::<u32>().map_err(|e| e.to_string()))
.use_value_delimiter(true)
.require_value_delimiter(true)
.default_value("one,two"),
)
.try_get_matches();
}
#[test]
fn with_value_delimiter() {
let cmd = Command::new("multiple_values").arg(
Arg::new("option")
.long("option")
.help("multiple options")
.value_delimiter(';')
.default_value("first;second"),
);
let matches = cmd.try_get_matches_from(vec![""]).unwrap();
assert_eq!(
matches.values_of("option").unwrap().collect::<Vec<_>>(),
["first", "second"]
);
}
#[test]
fn missing_with_value_delimiter() {
let cmd = Command::new("program").arg(
Arg::new("option")
.long("option")
.value_delimiter(';')
.default_missing_values(&["value1;value2;value3", "value4;value5"]),
);
let matches = cmd
.try_get_matches_from(vec!["program", "--option"])
.unwrap();
assert_eq!(
matches.values_of("option").unwrap().collect::<Vec<_>>(),
["value1", "value2", "value3", "value4", "value5"]
);
}

View file

@ -0,0 +1,113 @@
use clap::{Arg, Command};
#[test]
fn opt_default_no_delim() {
let m = Command::new("no_delim")
.arg(Arg::new("option").long("option").takes_value(true))
.try_get_matches_from(vec!["", "--option", "val1,val2,val3"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
}
#[test]
fn opt_eq_no_delim() {
let m = Command::new("no_delim")
.arg(Arg::new("option").long("option").takes_value(true))
.try_get_matches_from(vec!["", "--option=val1,val2,val3"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
}
#[test]
fn opt_s_eq_no_delim() {
let m = Command::new("no_delim")
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["", "-o=val1,val2,val3"]);
assert!(m.is_ok(), "{:?}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
}
#[test]
fn opt_s_default_no_delim() {
let m = Command::new("no_delim")
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["", "-o", "val1,val2,val3"]);
assert!(m.is_ok(), "{:?}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
}
#[test]
fn opt_s_no_space_no_delim() {
let m = Command::new("no_delim")
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["", "-o", "val1,val2,val3"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
}
#[test]
fn opt_s_no_space_mult_no_delim() {
let m = Command::new("no_delim")
.arg(
Arg::new("option")
.short('o')
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec!["", "-o", "val1,val2,val3"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.occurrences_of("option"), 1);
assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
}
#[test]
fn opt_eq_mult_def_delim() {
let m = Command::new("no_delim")
.arg(
Arg::new("option")
.long("opt")
.takes_value(true)
.multiple_values(true)
.use_value_delimiter(true),
)
.try_get_matches_from(vec!["", "--opt=val1,val2,val3"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
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", "val3"]
);
}

View file

@ -0,0 +1,293 @@
use super::utils;
use std::str;
use clap::{AppSettings, Arg, Command};
static NO_DERIVE_ORDER: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
--flag_a second flag
--flag_b first flag
-h, --help Print help information
--option_a <option_a> second option
--option_b <option_b> first option
-V, --version Print version information
";
static UNIFIED_HELP_AND_DERIVE: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
--flag_b first flag
--option_b <option_b> first option
--flag_a second flag
--option_a <option_a> second option
-h, --help Print help information
-V, --version Print version information
";
static UNIFIED_DERIVE_SC_PROP: &str = "test-sub 1.2
USAGE:
test sub [OPTIONS]
OPTIONS:
--flag_b first flag
--option_b <option_b> first option
--flag_a second flag
--option_a <option_a> second option
-h, --help Print help information
-V, --version Print version information
";
static UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER: &str = "test-sub 1.2
USAGE:
test sub [OPTIONS]
OPTIONS:
--flag_a second flag
--flag_b first flag
--option_b <option_b> first option
--option_a <option_a> second option
-h, --help Print help information
-V, --version Print version information
";
static PREFER_USER_HELP_DERIVE_ORDER: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
-h, --help Print help message
--flag_b first flag
--flag_a second flag
-V, --version Print version information
";
static PREFER_USER_HELP_SUBCMD_DERIVE_ORDER: &str = "test-sub 1.2
USAGE:
test sub [OPTIONS]
OPTIONS:
-h, --help Print help message
--flag_b first flag
--flag_a second flag
-V, --version Print version information
";
#[test]
fn no_derive_order() {
let cmd = Command::new("test").version("1.2").args(&[
Arg::new("flag_b").long("flag_b").help("first flag"),
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::new("flag_a").long("flag_a").help("second flag"),
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]);
utils::assert_output(cmd, "test --help", NO_DERIVE_ORDER, false);
}
#[test]
fn derive_order() {
let cmd = Command::new("test")
.setting(AppSettings::DeriveDisplayOrder)
.version("1.2")
.args(&[
Arg::new("flag_b").long("flag_b").help("first flag"),
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::new("flag_a").long("flag_a").help("second flag"),
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]);
utils::assert_output(cmd, "test --help", UNIFIED_HELP_AND_DERIVE, false);
}
#[test]
fn derive_order_next_order() {
static HELP: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
--flag_b first flag
--option_b <option_b> first option
-h, --help Print help information
-V, --version Print version information
--flag_a second flag
--option_a <option_a> second option
";
let cmd = Command::new("test")
.setting(AppSettings::DeriveDisplayOrder)
.version("1.2")
.next_display_order(10000)
.arg(Arg::new("flag_a").long("flag_a").help("second flag"))
.arg(
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
)
.next_display_order(10)
.arg(Arg::new("flag_b").long("flag_b").help("first flag"))
.arg(
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
);
utils::assert_output(cmd, "test --help", HELP, false);
}
#[test]
fn derive_order_no_next_order() {
static HELP: &str = "test 1.2
USAGE:
test [OPTIONS]
OPTIONS:
--flag_a first flag
--flag_b second flag
-h, --help Print help information
--option_a <option_a> first option
--option_b <option_b> second option
-V, --version Print version information
";
let cmd = Command::new("test")
.setting(AppSettings::DeriveDisplayOrder)
.version("1.2")
.next_display_order(None)
.arg(Arg::new("flag_a").long("flag_a").help("first flag"))
.arg(
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("first option"),
)
.arg(Arg::new("flag_b").long("flag_b").help("second flag"))
.arg(
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("second option"),
);
utils::assert_output(cmd, "test --help", HELP, false);
}
#[test]
fn derive_order_subcommand_propagate() {
let cmd = Command::new("test")
.global_setting(AppSettings::DeriveDisplayOrder)
.subcommand(
Command::new("sub").version("1.2").args(&[
Arg::new("flag_b").long("flag_b").help("first flag"),
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::new("flag_a").long("flag_a").help("second flag"),
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]),
);
utils::assert_output(cmd, "test sub --help", UNIFIED_DERIVE_SC_PROP, false);
}
#[test]
fn derive_order_subcommand_propagate_with_explicit_display_order() {
let cmd = Command::new("test")
.global_setting(AppSettings::DeriveDisplayOrder)
.subcommand(
Command::new("sub").version("1.2").args(&[
Arg::new("flag_b").long("flag_b").help("first flag"),
Arg::new("option_b")
.long("option_b")
.takes_value(true)
.help("first option"),
Arg::new("flag_a")
.long("flag_a")
.help("second flag")
.display_order(0),
Arg::new("option_a")
.long("option_a")
.takes_value(true)
.help("second option"),
]),
);
utils::assert_output(
cmd,
"test sub --help",
UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER,
false,
);
}
#[test]
fn prefer_user_help_with_derive_order() {
let cmd = Command::new("test")
.setting(AppSettings::DeriveDisplayOrder)
.version("1.2")
.args(&[
Arg::new("help")
.long("help")
.short('h')
.help("Print help message"),
Arg::new("flag_b").long("flag_b").help("first flag"),
Arg::new("flag_a").long("flag_a").help("second flag"),
]);
utils::assert_output(cmd, "test --help", PREFER_USER_HELP_DERIVE_ORDER, false);
}
#[test]
fn prefer_user_help_in_subcommand_with_derive_order() {
let cmd = Command::new("test")
.global_setting(AppSettings::DeriveDisplayOrder)
.subcommand(
Command::new("sub").version("1.2").args(&[
Arg::new("help")
.long("help")
.short('h')
.help("Print help message"),
Arg::new("flag_b").long("flag_b").help("first flag"),
Arg::new("flag_a").long("flag_a").help("second flag"),
]),
);
utils::assert_output(
cmd,
"test sub --help",
PREFER_USER_HELP_SUBCMD_DERIVE_ORDER,
false,
);
}

View file

@ -0,0 +1,26 @@
use super::utils;
use clap::Command;
#[test]
fn very_large_display_order() {
let cmd = Command::new("test").subcommand(Command::new("sub").display_order(usize::MAX));
utils::assert_output(
cmd,
"test --help",
"test
USAGE:
test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
sub
",
false,
);
}

View file

@ -0,0 +1,88 @@
use clap::{error::ErrorKind, Arg, Command};
static HELP: &str = "prog
USAGE:
prog [OPTIONS]
OPTIONS:
-a
-b
-c
-h, --help Print help information
";
static ONLY_B_ERROR: &str = "error: The following required arguments were not provided:
-c
USAGE:
prog -b -c
For more information try --help
";
static ONLY_C_ERROR: &str = "error: The following required arguments were not provided:
-b
USAGE:
prog -c -b
For more information try --help
";
fn cmd() -> Command<'static> {
Command::new("prog")
.arg(
Arg::new("a")
.short('a')
.required_unless_present_any(&["b", "c"])
.conflicts_with_all(&["b", "c"]),
)
.arg(
Arg::new("b")
.short('b')
.required_unless_present("a")
.requires("c"),
)
.arg(
Arg::new("c")
.short('c')
.required_unless_present("a")
.requires("b"),
)
}
#[test]
fn valid_cases() {
let res = cmd().try_get_matches_from(vec!["", "-a"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let res = cmd().clone().try_get_matches_from(vec!["", "-b", "-c"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let res = cmd().try_get_matches_from(vec!["", "-c", "-b"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
}
#[test]
fn help_text() {
let res = cmd().try_get_matches_from(vec!["prog", "--help"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayHelp);
println!("{}", err);
assert_eq!(err.to_string(), HELP);
}
#[test]
fn no_duplicate_error() {
let res = cmd().try_get_matches_from(vec!["", "-b"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
assert_eq!(err.to_string(), ONLY_B_ERROR);
let res = cmd().try_get_matches_from(vec!["", "-c"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
assert_eq!(err.to_string(), ONLY_C_ERROR);
}

View file

@ -0,0 +1,128 @@
use super::utils;
use clap::{error::ErrorKind, Arg, Command};
#[test]
fn empty_values() {
let m = Command::new("config")
.arg(Arg::new("config").long("config").takes_value(true))
.try_get_matches_from(&["config", "--config", ""])
.unwrap();
assert_eq!(m.value_of("config"), Some(""));
}
#[test]
fn empty_values_with_equals() {
let m = Command::new("config")
.arg(Arg::new("config").long("config").takes_value(true))
.try_get_matches_from(&["config", "--config="])
.unwrap();
assert_eq!(m.value_of("config"), Some(""));
let m = Command::new("config")
.arg(Arg::new("config").short('c').takes_value(true))
.try_get_matches_from(&["config", "-c="])
.unwrap();
assert_eq!(m.value_of("config"), Some(""))
}
#[test]
fn no_empty_values() {
let m = Command::new("config")
.arg(
Arg::new("config")
.long("config")
.takes_value(true)
.forbid_empty_values(true),
)
.try_get_matches_from(&["config", "--config", ""]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::EmptyValue);
let m = Command::new("config")
.arg(
Arg::new("config")
.short('c')
.takes_value(true)
.forbid_empty_values(true),
)
.try_get_matches_from(&["config", "-c", ""]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::EmptyValue)
}
#[test]
fn no_empty_values_with_equals() {
let m = Command::new("config")
.arg(
Arg::new("config")
.long("config")
.takes_value(true)
.forbid_empty_values(true),
)
.try_get_matches_from(&["config", "--config="]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::EmptyValue);
let m = Command::new("config")
.arg(
Arg::new("config")
.short('c')
.takes_value(true)
.forbid_empty_values(true),
)
.try_get_matches_from(&["config", "-c="]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::EmptyValue);
}
#[test]
fn no_empty_values_without_equals() {
let m = Command::new("config")
.arg(
Arg::new("config")
.long("config")
.takes_value(true)
.forbid_empty_values(true),
)
.try_get_matches_from(&["config", "--config"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::EmptyValue);
let m = Command::new("config")
.arg(
Arg::new("config")
.short('c')
.takes_value(true)
.forbid_empty_values(true),
)
.try_get_matches_from(&["config", "-c"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::EmptyValue)
}
#[test]
fn no_empty_values_without_equals_but_requires_equals() {
let cmd = Command::new("config").arg(
Arg::new("config")
.long("config")
.takes_value(true)
.forbid_empty_values(true)
.require_equals(true),
);
let m = cmd.clone().try_get_matches_from(&["config", "--config"]);
// Should error on no equals rather than empty value.
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::NoEquals);
static NO_EUQALS_ERROR: &str =
"error: Equal sign is needed when assigning values to '--config=<config>'.
USAGE:
config [OPTIONS]
For more information try --help
";
utils::assert_output(cmd, "config --config", NO_EUQALS_ERROR, true);
}

352
tests/builder/legacy/env.rs Normal file
View file

@ -0,0 +1,352 @@
#![cfg(feature = "env")]
use std::env;
use std::ffi::OsStr;
use clap::{arg, Arg, Command};
#[test]
fn env() {
env::set_var("CLP_TEST_ENV", "env");
let r = Command::new("df")
.arg(arg!([arg] "some opt").env("CLP_TEST_ENV").takes_value(true))
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg").unwrap(), "env");
}
#[test]
fn env_bool_literal() {
env::set_var("CLP_TEST_FLAG_TRUE", "On");
env::set_var("CLP_TEST_FLAG_FALSE", "nO");
let r = Command::new("df")
.arg(Arg::new("present").short('p').env("CLP_TEST_FLAG_TRUE"))
.arg(Arg::new("negated").short('n').env("CLP_TEST_FLAG_FALSE"))
.arg(Arg::new("absent").short('a').env("CLP_TEST_FLAG_ABSENT"))
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("present"));
assert_eq!(m.occurrences_of("present"), 0);
assert_eq!(m.value_of("present"), None);
assert!(!m.is_present("negated"));
assert!(!m.is_present("absent"));
}
#[test]
fn env_os() {
env::set_var("CLP_TEST_ENV_OS", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env_os(OsStr::new("CLP_TEST_ENV_OS"))
.takes_value(true),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg").unwrap(), "env");
}
#[test]
fn no_env() {
// All the other tests use the presence of the Environment variable...
// we need another variable just in case one of the others is running at the same time...
env::remove_var("CLP_TEST_ENV_NONE");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_NONE")
.takes_value(true),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg"), None);
}
#[test]
fn no_env_no_takes_value() {
// All the other tests use the presence of the Environment variable...
// we need another variable just in case one of the others is running at the same time...
env::remove_var("CLP_TEST_ENV_NONE");
let r = Command::new("df")
.arg(arg!([arg] "some opt").env("CLP_TEST_ENV_NONE"))
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(!m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg"), None);
}
#[test]
fn with_default() {
env::set_var("CLP_TEST_ENV_WD", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_WD")
.takes_value(true)
.default_value("default"),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg").unwrap(), "env");
}
#[test]
fn opt_user_override() {
env::set_var("CLP_TEST_ENV_OR", "env");
let r = Command::new("df")
.arg(
arg!(--arg [FILE] "some arg")
.env("CLP_TEST_ENV_OR")
.takes_value(true),
)
.try_get_matches_from(vec!["", "--arg", "opt"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 1);
assert_eq!(m.value_of("arg").unwrap(), "opt");
// see https://github.com/clap-rs/clap/issues/1835
let values: Vec<_> = m.values_of("arg").unwrap().collect();
assert_eq!(values, vec!["opt"]);
}
#[test]
fn positionals() {
env::set_var("CLP_TEST_ENV_P", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_P")
.takes_value(true),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg").unwrap(), "env");
}
#[test]
fn positionals_user_override() {
env::set_var("CLP_TEST_ENV_POR", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_POR")
.takes_value(true),
)
.try_get_matches_from(vec!["", "opt"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 1);
assert_eq!(m.value_of("arg").unwrap(), "opt");
// see https://github.com/clap-rs/clap/issues/1835
let values: Vec<_> = m.values_of("arg").unwrap().collect();
assert_eq!(values, vec!["opt"]);
}
#[test]
fn multiple_one() {
env::set_var("CLP_TEST_ENV_MO", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_MO")
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), vec!["env"]);
}
#[test]
fn multiple_three() {
env::set_var("CLP_TEST_ENV_MULTI1", "env1,env2,env3");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_MULTI1")
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(
m.values_of("arg").unwrap().collect::<Vec<_>>(),
vec!["env1", "env2", "env3"]
);
}
#[test]
fn multiple_no_delimiter() {
env::set_var("CLP_TEST_ENV_MULTI2", "env1 env2 env3");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_MULTI2")
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(
m.values_of("arg").unwrap().collect::<Vec<_>>(),
vec!["env1 env2 env3"]
);
}
#[test]
fn possible_value() {
env::set_var("CLP_TEST_ENV_PV", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_PV")
.takes_value(true)
.possible_value("env"),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg").unwrap(), "env");
}
#[test]
fn not_possible_value() {
env::set_var("CLP_TEST_ENV_NPV", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_NPV")
.takes_value(true)
.possible_value("never"),
)
.try_get_matches_from(vec![""]);
assert!(r.is_err());
}
#[test]
fn validator() {
env::set_var("CLP_TEST_ENV_VDOR", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_VDOR")
.takes_value(true)
.validator(|s| {
if s == "env" {
Ok(())
} else {
Err("not equal".to_string())
}
}),
)
.try_get_matches_from(vec![""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(m.occurrences_of("arg"), 0);
assert_eq!(m.value_of("arg").unwrap(), "env");
}
#[test]
fn validator_output() {
env::set_var("CLP_TEST_ENV_VO", "42");
let m = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_VO")
.takes_value(true)
.validator(|s| s.parse::<i32>()),
)
.try_get_matches_from(vec![""])
.unwrap();
assert_eq!(m.value_of("arg").unwrap().parse(), Ok(42));
}
#[test]
fn validator_invalid() {
env::set_var("CLP_TEST_ENV_IV", "env");
let r = Command::new("df")
.arg(
arg!([arg] "some opt")
.env("CLP_TEST_ENV_IV")
.takes_value(true)
.validator(|s| {
if s != "env" {
Ok(())
} else {
Err("is equal".to_string())
}
}),
)
.try_get_matches_from(vec![""]);
assert!(r.is_err());
}

View file

@ -0,0 +1,90 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, Command, Error};
fn assert_error(err: Error, expected_kind: ErrorKind, expected_output: &str, stderr: bool) {
let actual_output = err.to_string();
assert_eq!(
stderr,
err.use_stderr(),
"Should Use STDERR failed. Should be {} but is {}",
stderr,
err.use_stderr()
);
assert_eq!(expected_kind, err.kind());
utils::assert_eq(expected_output, actual_output)
}
#[test]
fn app_error() {
static MESSAGE: &str = "error: Failed for mysterious reasons
USAGE:
test [OPTIONS] --all
For more information try --help
";
let cmd = Command::new("test")
.arg(
Arg::new("all")
.short('a')
.long("all")
.required(true)
.help("Also do versioning for private crates (will not be published)"),
)
.arg(
Arg::new("exact")
.long("exact")
.help("Specify inter dependency version numbers exactly with `=`"),
)
.arg(
Arg::new("no_git_commit")
.long("no-git-commit")
.help("Do not commit version changes"),
)
.arg(
Arg::new("no_git_push")
.long("no-git-push")
.help("Do not push generated commit and tags to git remote"),
);
let mut cmd = cmd;
let expected_kind = ErrorKind::InvalidValue;
let err = cmd.error(expected_kind, "Failed for mysterious reasons");
assert_error(err, expected_kind, MESSAGE, true);
}
#[test]
fn value_validation_has_newline() {
let m = Command::new("test")
.arg(arg!(<PORT>).help("Network port to use"))
.try_get_matches_from(["test", "foo"])
.unwrap();
let res = m.value_of_t::<usize>("PORT");
assert!(res.is_err());
let err = res.unwrap_err();
assert!(
err.to_string().ends_with('\n'),
"Errors should have a trailing newline, got {:?}",
err.to_string()
);
}
#[test]
fn argument_not_found_auto_has_newline() {
let m = Command::new("test")
.arg(arg!([PORT]).help("Network port to use"))
.try_get_matches_from(["test"])
.unwrap();
let res = m.value_of_t::<usize>("PORT");
assert!(res.is_err());
let err = res.unwrap_err();
assert!(
err.to_string().ends_with('\n'),
"Errors should have a trailing newline, got {:?}",
err.to_string()
);
}

View file

@ -0,0 +1,613 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, Command};
#[test]
fn flag_subcommand_normal() {
let matches = Command::new("test")
.subcommand(
Command::new("some").short_flag('S').long_flag("some").arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
),
)
.try_get_matches_from(vec!["myprog", "some", "--test"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_normal_with_alias() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.short_flag('S')
.long_flag("S")
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.alias("result"),
)
.try_get_matches_from(vec!["myprog", "result", "--test"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_short() {
let matches = Command::new("test")
.subcommand(
Command::new("some").short_flag('S').arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
),
)
.try_get_matches_from(vec!["myprog", "-S", "--test"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_short_with_args() {
let matches = Command::new("test")
.subcommand(
Command::new("some").short_flag('S').arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
),
)
.try_get_matches_from(vec!["myprog", "-St"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_short_with_alias() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.short_flag('S')
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.short_flag_alias('M')
.short_flag_alias('B'),
)
.try_get_matches_from(vec!["myprog", "-Bt"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_short_with_alias_same_as_short_flag() {
let matches = Command::new("test")
.subcommand(Command::new("some").short_flag('S').short_flag_alias('S'))
.try_get_matches_from(vec!["myprog", "-S"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
}
#[test]
fn flag_subcommand_long_with_alias_same_as_long_flag() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.long_flag("sync")
.long_flag_alias("sync"),
)
.try_get_matches_from(vec!["myprog", "--sync"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
}
#[test]
fn flag_subcommand_short_with_aliases_vis_and_hidden() {
let cmd = Command::new("test").subcommand(
Command::new("some")
.short_flag('S')
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.visible_short_flag_aliases(&['M', 'B'])
.short_flag_alias('C'),
);
let app1 = cmd.clone();
let matches1 = app1.try_get_matches_from(vec!["test", "-M"]).unwrap();
assert_eq!(matches1.subcommand_name().unwrap(), "some");
let app2 = cmd.clone();
let matches2 = app2.try_get_matches_from(vec!["test", "-C"]).unwrap();
assert_eq!(matches2.subcommand_name().unwrap(), "some");
let app3 = cmd.clone();
let matches3 = app3.try_get_matches_from(vec!["test", "-B"]).unwrap();
assert_eq!(matches3.subcommand_name().unwrap(), "some");
}
#[test]
fn flag_subcommand_short_with_aliases() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.short_flag('S')
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.short_flag_aliases(&['M', 'B']),
)
.try_get_matches_from(vec!["myprog", "-Bt"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
#[should_panic]
fn flag_subcommand_short_with_alias_hyphen() {
let _ = Command::new("test")
.subcommand(
Command::new("some")
.short_flag('S')
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.short_flag_alias('-'),
)
.try_get_matches_from(vec!["myprog", "-Bt"])
.unwrap();
}
#[test]
#[should_panic]
fn flag_subcommand_short_with_aliases_hyphen() {
let _ = Command::new("test")
.subcommand(
Command::new("some")
.short_flag('S')
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.short_flag_aliases(&['-', '-', '-']),
)
.try_get_matches_from(vec!["myprog", "-Bt"])
.unwrap();
}
#[test]
fn flag_subcommand_short_after_long_arg() {
let m = Command::new("pacman")
.subcommand(
Command::new("sync")
.short_flag('S')
.arg(Arg::new("clean").short('c')),
)
.arg(Arg::new("arg").long("arg").takes_value(true))
.try_get_matches_from(vec!["pacman", "--arg", "foo", "-Sc"])
.unwrap();
let subm = m.subcommand_matches("sync");
assert!(subm.is_some());
let subm = subm.unwrap();
assert!(subm.is_present("clean"));
}
#[test]
fn flag_subcommand_long() {
let matches = Command::new("test")
.subcommand(
Command::new("some").long_flag("some").arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
),
)
.try_get_matches_from(vec!["myprog", "--some", "--test"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_long_with_alias() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.long_flag("some")
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.long_flag_alias("result"),
)
.try_get_matches_from(vec!["myprog", "--result", "--test"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_long_with_aliases() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.long_flag("some")
.arg(
Arg::new("test")
.short('t')
.long("test")
.help("testing testing"),
)
.long_flag_aliases(&["result", "someall"]),
)
.try_get_matches_from(vec!["myprog", "--result", "--test"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("test"));
}
#[test]
fn flag_subcommand_multiple() {
let matches = Command::new("test")
.subcommand(
Command::new("some")
.short_flag('S')
.long_flag("some")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-p --print "print something"))
.subcommand(
Command::new("result")
.short_flag('R')
.long_flag("result")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-p --print "print something")),
),
)
.try_get_matches_from(vec!["myprog", "-SfpRfp"])
.unwrap();
assert_eq!(matches.subcommand_name().unwrap(), "some");
let sub_matches = matches.subcommand_matches("some").unwrap();
assert!(sub_matches.is_present("flag"));
assert!(sub_matches.is_present("print"));
assert_eq!(sub_matches.subcommand_name().unwrap(), "result");
let result_matches = sub_matches.subcommand_matches("result").unwrap();
assert!(result_matches.is_present("flag"));
assert!(result_matches.is_present("print"));
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "the \'-f\' short flag for the \'test\' argument conflicts with the short flag for \'some\' subcommand"]
fn flag_subcommand_short_conflict_with_arg() {
let _ = Command::new("test")
.subcommand(Command::new("some").short_flag('f').long_flag("some"))
.arg(Arg::new("test").short('f'))
.try_get_matches_from(vec!["myprog", "-f"])
.unwrap();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "the \'-f\' short flag is specified for both \'some\' and \'result\' subcommands"]
fn flag_subcommand_short_conflict_with_alias() {
let _ = Command::new("test")
.subcommand(Command::new("some").short_flag('f').long_flag("some"))
.subcommand(Command::new("result").short_flag('t').short_flag_alias('f'))
.try_get_matches_from(vec!["myprog", "-f"])
.unwrap();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "the \'--flag\' long flag is specified for both \'some\' and \'result\' subcommands"]
fn flag_subcommand_long_conflict_with_alias() {
let _ = Command::new("test")
.subcommand(Command::new("some").long_flag("flag"))
.subcommand(
Command::new("result")
.long_flag("test")
.long_flag_alias("flag"),
)
.try_get_matches_from(vec!["myprog", "--flag"])
.unwrap();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "the \'-f\' short flag for the \'test\' argument conflicts with the short flag for \'some\' subcommand"]
fn flag_subcommand_short_conflict_with_arg_alias() {
let _ = Command::new("test")
.subcommand(Command::new("some").short_flag('f').long_flag("some"))
.arg(Arg::new("test").short('t').short_alias('f'))
.try_get_matches_from(vec!["myprog", "-f"])
.unwrap();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "the \'--some\' long flag for the \'test\' argument conflicts with the short flag for \'some\' subcommand"]
fn flag_subcommand_long_conflict_with_arg_alias() {
let _ = Command::new("test")
.subcommand(Command::new("some").short_flag('f').long_flag("some"))
.arg(Arg::new("test").long("test").alias("some"))
.try_get_matches_from(vec!["myprog", "--some"])
.unwrap();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "the \'--flag\' long flag for the \'flag\' argument conflicts with the short flag for \'some\' subcommand"]
fn flag_subcommand_long_conflict_with_arg() {
let _ = Command::new("test")
.subcommand(Command::new("some").short_flag('a').long_flag("flag"))
.arg(Arg::new("flag").long("flag"))
.try_get_matches_from(vec!["myprog", "--flag"])
.unwrap();
}
#[test]
fn flag_subcommand_conflict_with_help() {
let _ = Command::new("test")
.subcommand(Command::new("help").short_flag('h').long_flag("help"))
.try_get_matches_from(vec!["myprog", "--help"])
.unwrap();
}
#[test]
fn flag_subcommand_conflict_with_version() {
let _ = Command::new("test")
.subcommand(Command::new("ver").short_flag('V').long_flag("version"))
.try_get_matches_from(vec!["myprog", "--version"])
.unwrap();
}
#[test]
fn flag_subcommand_long_infer_pass() {
let m = Command::new("prog")
.infer_subcommands(true)
.subcommand(Command::new("test").long_flag("test"))
.try_get_matches_from(vec!["prog", "--te"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("test"));
}
#[cfg(not(feature = "suggestions"))]
#[test]
fn flag_subcommand_long_infer_fail() {
let m = Command::new("prog")
.infer_subcommands(true)
.subcommand(Command::new("test").long_flag("test"))
.subcommand(Command::new("temp").long_flag("temp"))
.try_get_matches_from(vec!["prog", "--te"]);
assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
}
#[cfg(feature = "suggestions")]
#[test]
fn flag_subcommand_long_infer_fail() {
let m = Command::new("prog")
.infer_subcommands(true)
.subcommand(Command::new("test").long_flag("test"))
.subcommand(Command::new("temp").long_flag("temp"))
.try_get_matches_from(vec!["prog", "--te"]);
assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
}
#[test]
fn flag_subcommand_long_infer_pass_close() {
let m = Command::new("prog")
.infer_subcommands(true)
.subcommand(Command::new("test").long_flag("test"))
.subcommand(Command::new("temp").long_flag("temp"))
.try_get_matches_from(vec!["prog", "--tes"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("test"));
}
#[test]
fn flag_subcommand_long_infer_exact_match() {
let m = Command::new("prog")
.infer_subcommands(true)
.subcommand(Command::new("test").long_flag("test"))
.subcommand(Command::new("testa").long_flag("testa"))
.subcommand(Command::new("testb").long_flag("testb"))
.try_get_matches_from(vec!["prog", "--test"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("test"));
}
static FLAG_SUBCOMMAND_HELP: &str = "pacman-query
Query the package database.
USAGE:
pacman {query|--query|-Q} [OPTIONS]
OPTIONS:
-h, --help Print help information
-i, --info <info>... view package information
-s, --search <search>... search locally installed packages for matching strings
";
#[test]
fn flag_subcommand_long_short_normal_usage_string() {
let cmd = Command::new("pacman")
.about("package manager utility")
.version("5.2.1")
.subcommand_required(true)
.author("Pacman Development Team")
// Query subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("query")
.short_flag('Q')
.long_flag("query")
.about("Query the package database.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.help("search locally installed packages for matching strings")
.conflicts_with("info")
.takes_value(true)
.multiple_values(true),
)
.arg(
Arg::new("info")
.long("info")
.short('i')
.conflicts_with("search")
.help("view package information")
.takes_value(true)
.multiple_values(true),
),
);
utils::assert_output(cmd, "pacman -Qh", FLAG_SUBCOMMAND_HELP, false);
}
static FLAG_SUBCOMMAND_NO_SHORT_HELP: &str = "pacman-query
Query the package database.
USAGE:
pacman {query|--query} [OPTIONS]
OPTIONS:
-h, --help Print help information
-i, --info <info>... view package information
-s, --search <search>... search locally installed packages for matching strings
";
#[test]
fn flag_subcommand_long_normal_usage_string() {
let cmd = Command::new("pacman")
.about("package manager utility")
.version("5.2.1")
.subcommand_required(true)
.author("Pacman Development Team")
// Query subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("query")
.long_flag("query")
.about("Query the package database.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.help("search locally installed packages for matching strings")
.conflicts_with("info")
.takes_value(true)
.multiple_values(true),
)
.arg(
Arg::new("info")
.long("info")
.short('i')
.conflicts_with("search")
.help("view package information")
.takes_value(true)
.multiple_values(true),
),
);
utils::assert_output(
cmd,
"pacman query --help",
FLAG_SUBCOMMAND_NO_SHORT_HELP,
false,
);
}
static FLAG_SUBCOMMAND_NO_LONG_HELP: &str = "pacman-query
Query the package database.
USAGE:
pacman {query|-Q} [OPTIONS]
OPTIONS:
-h, --help Print help information
-i, --info <info>... view package information
-s, --search <search>... search locally installed packages for matching strings
";
#[test]
fn flag_subcommand_short_normal_usage_string() {
let cmd = Command::new("pacman")
.about("package manager utility")
.version("5.2.1")
.subcommand_required(true)
.author("Pacman Development Team")
// Query subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("query")
.short_flag('Q')
.about("Query the package database.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.help("search locally installed packages for matching strings")
.conflicts_with("info")
.takes_value(true)
.multiple_values(true),
)
.arg(
Arg::new("info")
.long("info")
.short('i')
.conflicts_with("search")
.help("view package information")
.takes_value(true)
.multiple_values(true),
),
);
utils::assert_output(
cmd,
"pacman query --help",
FLAG_SUBCOMMAND_NO_LONG_HELP,
false,
);
}

View file

@ -0,0 +1,198 @@
use super::utils;
use clap::{arg, Arg, Command};
const USE_FLAG_AS_ARGUMENT: &str =
"error: Found argument '--another-flag' which wasn't expected, or isn't valid in this context
\tIf you tried to supply `--another-flag` as a value rather than a flag, use `-- --another-flag`
USAGE:
mycat [OPTIONS] [filename]
For more information try --help
";
#[test]
fn flag_using_short() {
let m = Command::new("flag")
.args(&[
arg!(-f --flag "some flag"),
arg!(-c --color "some other flag"),
])
.try_get_matches_from(vec!["", "-f", "-c"])
.unwrap();
assert!(m.is_present("flag"));
assert!(m.is_present("color"));
}
#[test]
fn lots_o_flags_sep() {
let r = Command::new("opts")
.arg(arg!(o: -o ... "some flag"))
.try_get_matches_from(vec![
"", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
"-o", "-o", "-o",
]);
assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
}
#[test]
fn lots_o_flags_combined() {
let r = Command::new("opts")
.arg(arg!(o: -o ... "some flag"))
.try_get_matches_from(vec![
"",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
"-ooooooooooooooooooooooooooooooooooooooooo",
]);
assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
}
#[test]
fn flag_using_long() {
let m = Command::new("flag")
.args(&[arg!(--flag "some flag"), arg!(--color "some other flag")])
.try_get_matches_from(vec!["", "--flag", "--color"])
.unwrap();
assert!(m.is_present("flag"));
assert!(m.is_present("color"));
}
#[test]
fn flag_using_long_with_literals() {
use clap::error::ErrorKind;
let m = Command::new("flag")
.arg(Arg::new("rainbow").long("rainbow"))
.try_get_matches_from(vec!["", "--rainbow=false"]);
assert!(m.is_err(), "{:#?}", m.unwrap());
assert_eq!(m.unwrap_err().kind(), ErrorKind::TooManyValues);
}
#[test]
fn flag_using_mixed() {
let m = Command::new("flag")
.args(&[
arg!(-f --flag "some flag"),
arg!(-c --color "some other flag"),
])
.try_get_matches_from(vec!["", "-f", "--color"])
.unwrap();
assert!(m.is_present("flag"));
assert!(m.is_present("color"));
let m = Command::new("flag")
.args(&[
arg!(-f --flag "some flag"),
arg!(-c --color "some other flag"),
])
.try_get_matches_from(vec!["", "--flag", "-c"])
.unwrap();
assert!(m.is_present("flag"));
assert!(m.is_present("color"));
}
#[test]
fn multiple_flags_in_single() {
let m = Command::new("multe_flags")
.args(&[
arg!(-f --flag "some flag"),
arg!(-c --color "some other flag"),
arg!(-d --debug "another other flag"),
])
.try_get_matches_from(vec!["", "-fcd"])
.unwrap();
assert!(m.is_present("flag"));
assert!(m.is_present("color"));
assert!(m.is_present("debug"));
}
#[test]
fn issue_1284_argument_in_flag_style() {
let cmd = Command::new("mycat")
.arg(Arg::new("filename"))
.arg(Arg::new("a-flag").long("a-flag"));
let m = cmd
.clone()
.try_get_matches_from(vec!["", "--", "--another-flag"])
.unwrap();
assert_eq!(m.value_of("filename"), Some("--another-flag"));
let m = cmd
.clone()
.try_get_matches_from(vec!["", "--a-flag"])
.unwrap();
assert!(m.is_present("a-flag"));
let m = cmd
.clone()
.try_get_matches_from(vec!["", "--", "--a-flag"])
.unwrap();
assert_eq!(m.value_of("filename"), Some("--a-flag"));
utils::assert_output(cmd, "mycat --another-flag", USE_FLAG_AS_ARGUMENT, true);
}
#[test]
fn issue_2308_multiple_dashes() {
static MULTIPLE_DASHES: &str =
"error: Found argument '-----' which wasn't expected, or isn't valid in this context
If you tried to supply `-----` as a value rather than a flag, use `-- -----`
USAGE:
test <arg>
For more information try --help
";
let cmd = Command::new("test").arg(Arg::new("arg").takes_value(true).required(true));
utils::assert_output(cmd, "test -----", MULTIPLE_DASHES, true);
}
#[test]
#[cfg(not(feature = "unstable-v4"))]
fn leading_dash_stripped() {
let cmd = Command::new("mycat").arg(Arg::new("filename").long("--filename"));
let matches = cmd.try_get_matches_from(["mycat", "--filename"]).unwrap();
assert!(matches.is_present("filename"));
}
#[test]
#[cfg(feature = "unstable-v4")]
#[cfg(debug_assertions)]
#[should_panic = "Argument filename: long \"--filename\" must not start with a `-`, that will be handled by the parser"]
fn leading_dash_stripped() {
let cmd = Command::new("mycat").arg(Arg::new("filename").long("--filename"));
cmd.debug_assert();
}

View file

@ -0,0 +1,114 @@
use clap::{arg, Arg, Command};
#[test]
fn issue_1076() {
let mut cmd = Command::new("myprog")
.arg(
Arg::new("GLOBAL_ARG")
.long("global-arg")
.help("Specifies something needed by the subcommands")
.global(true)
.takes_value(true)
.default_value("default_value"),
)
.arg(
Arg::new("GLOBAL_FLAG")
.long("global-flag")
.help("Specifies something needed by the subcommands")
.global(true)
.takes_value(true),
)
.subcommand(Command::new("outer").subcommand(Command::new("inner")));
let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
}
#[test]
fn propagate_global_arg_in_subcommand_to_subsubcommand_1385() {
let m1 = Command::new("foo")
.subcommand(
Command::new("sub1")
.arg(Arg::new("arg1").long("arg1").takes_value(true).global(true))
.subcommand(Command::new("sub1a")),
)
.try_get_matches_from(&["foo", "sub1", "--arg1", "v1", "sub1a"])
.unwrap();
assert_eq!(
"v1",
m1.subcommand_matches("sub1")
.unwrap()
.subcommand_matches("sub1a")
.unwrap()
.value_of("arg1")
.unwrap()
);
}
#[test]
fn propagate_global_arg_to_subcommand_in_subsubcommand_2053() {
let m = Command::new("opts")
.arg(arg!(--"global-flag").global(true))
.arg(arg!(--"global-str" <str>).required(false).global(true))
.subcommand(
Command::new("test")
.arg(arg!(--"sub-flag").global(true))
.arg(arg!(--"sub-str" <str>).required(false).global(true))
.subcommand(Command::new("test")),
)
.try_get_matches_from(&[
"cmd",
"test",
"test",
"--global-flag",
"--global-str",
"hello",
"--sub-flag",
"--sub-str",
"world",
])
.unwrap();
assert_eq!(
Some("world"),
m.subcommand_matches("test").unwrap().value_of("sub-str")
);
}
#[test]
fn global_arg_available_in_subcommand() {
let m = Command::new("opt")
.args(&[
Arg::new("global").global(true).long("global"),
Arg::new("not").global(false).long("not"),
])
.subcommand(Command::new("ping"))
.try_get_matches_from(&["opt", "ping", "--global"])
.unwrap();
assert!(m.is_present("global"));
assert!(m.subcommand_matches("ping").unwrap().is_present("global"));
}
#[test]
fn deeply_nested_discovery() {
let cmd = Command::new("a")
.arg(arg!(--"long-a").global(true))
.subcommand(
Command::new("b")
.arg(arg!(--"long-b").global(true))
.subcommand(
Command::new("c")
.arg(arg!(--"long-c").global(true))
.subcommand(Command::new("d")),
),
);
let m = cmd
.try_get_matches_from(["a", "b", "c", "d", "--long-a", "--long-b", "--long-c"])
.unwrap();
assert!(m.is_present("long-a"));
let m = m.subcommand_matches("b").unwrap();
assert!(m.is_present("long-b"));
let m = m.subcommand_matches("c").unwrap();
assert!(m.is_present("long-c"));
}

View file

@ -0,0 +1,221 @@
#![cfg(feature = "unstable-grouped")]
use clap::{Arg, Command};
#[test]
fn grouped_value_works() {
let m = Command::new("cli")
.arg(
Arg::new("option")
.long("option")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.try_get_matches_from(&[
"cli",
"--option",
"fr_FR:mon option 1",
"en_US:my option 1",
"--option",
"fr_FR:mon option 2",
"en_US:my option 2",
])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
assert_eq!(
grouped_vals,
vec![
vec!["fr_FR:mon option 1", "en_US:my option 1",],
vec!["fr_FR:mon option 2", "en_US:my option 2",],
]
);
}
#[test]
fn issue_1026() {
let m = Command::new("cli")
.arg(Arg::new("server").short('s').takes_value(true))
.arg(Arg::new("user").short('u').takes_value(true))
.arg(
Arg::new("target")
.long("target")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.try_get_matches_from(&[
"backup", "-s", "server", "-u", "user", "--target", "target1", "file1", "file2",
"file3", "--target", "target2", "file4", "file5", "file6", "file7", "--target",
"target3", "file8",
])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("target").unwrap().collect();
assert_eq!(
grouped_vals,
vec![
vec!["target1", "file1", "file2", "file3"],
vec!["target2", "file4", "file5", "file6", "file7",],
vec!["target3", "file8"]
]
);
}
#[test]
fn grouped_value_long_flag_delimiter() {
let m = Command::new("myapp")
.arg(
Arg::new("option")
.long("option")
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.try_get_matches_from(vec![
"myapp",
"--option=hmm",
"--option=val1,val2,val3",
"--option",
"alice,bob",
])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
assert_eq!(
grouped_vals,
vec![
vec!["hmm"],
vec!["val1", "val2", "val3"],
vec!["alice", "bob"]
]
);
}
#[test]
fn grouped_value_short_flag_delimiter() {
let m = Command::new("myapp")
.arg(
Arg::new("option")
.short('o')
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.try_get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("option").unwrap().collect();
assert_eq!(
grouped_vals,
vec![vec!["foo"], vec!["val1", "val2", "val3"], vec!["bar"]]
);
}
#[test]
fn grouped_value_positional_arg() {
let m = Command::new("multiple_values")
.arg(
Arg::new("pos")
.help("multiple positionals")
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec![
"myprog", "val1", "val2", "val3", "val4", "val5", "val6",
])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("pos").unwrap().collect();
assert_eq!(
grouped_vals,
vec![vec!["val1", "val2", "val3", "val4", "val5", "val6"]]
);
}
#[test]
fn grouped_value_multiple_positional_arg() {
let m = Command::new("multiple_values")
.arg(Arg::new("pos1").help("multiple positionals"))
.arg(
Arg::new("pos2")
.help("multiple positionals")
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec![
"myprog", "val1", "val2", "val3", "val4", "val5", "val6",
])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
assert_eq!(
grouped_vals,
vec![vec!["val2", "val3", "val4", "val5", "val6"]]
);
}
#[test]
fn grouped_value_multiple_positional_arg_last_multiple() {
let m = Command::new("multiple_values")
.arg(Arg::new("pos1").help("multiple positionals"))
.arg(
Arg::new("pos2")
.help("multiple positionals")
.takes_value(true)
.multiple_values(true)
.last(true),
)
.try_get_matches_from(vec![
"myprog", "val1", "--", "val2", "val3", "val4", "val5", "val6",
])
.unwrap();
let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
assert_eq!(
grouped_vals,
vec![vec!["val2", "val3", "val4", "val5", "val6"]]
);
}
#[test]
fn issue_1374() {
let cmd = Command::new("MyApp").arg(
Arg::new("input")
.takes_value(true)
.long("input")
.overrides_with("input")
.min_values(0)
.multiple_occurrences(true),
);
let matches = cmd
.clone()
.try_get_matches_from(&["MyApp", "--input", "a", "b", "c", "--input", "d"])
.unwrap();
let vs = matches.values_of("input").unwrap();
assert_eq!(vs.collect::<Vec<_>>(), vec!["a", "b", "c", "d"]);
let matches = cmd
.clone()
.try_get_matches_from(&["MyApp", "--input", "a", "b", "--input", "c", "d"])
.unwrap();
let vs = matches.values_of("input").unwrap();
assert_eq!(vs.collect::<Vec<_>>(), vec!["a", "b", "c", "d"]);
}
#[test]
fn issue_2171() {
let schema = Command::new("ripgrep#1701 reproducer")
.args_override_self(true)
.arg(Arg::new("pretty").short('p').long("pretty"))
.arg(Arg::new("search_zip").short('z').long("search-zip"));
let test_args = &[
vec!["reproducer", "-pz", "-p"],
vec!["reproducer", "-pzp"],
vec!["reproducer", "-zpp"],
vec!["reproducer", "-pp", "-z"],
vec!["reproducer", "-p", "-p", "-z"],
vec!["reproducer", "-p", "-pz"],
vec!["reproducer", "-ppz"],
];
for argv in test_args {
let _ = schema.clone().try_get_matches_from(argv).unwrap();
}
}

View file

@ -0,0 +1,325 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgGroup, Command};
static REQ_GROUP_USAGE: &str = "error: The following required arguments were not provided:
<base|--delete>
USAGE:
clap-test <base|--delete>
For more information try --help
";
static REQ_GROUP_CONFLICT_USAGE: &str =
"error: The argument '--delete' cannot be used with '<base>'
USAGE:
clap-test <base|--delete>
For more information try --help
";
static REQ_GROUP_CONFLICT_ONLY_OPTIONS: &str =
"error: The argument '--delete' cannot be used with '--all'
USAGE:
clap-test <--all|--delete>
For more information try --help
";
#[test]
fn required_group_missing_arg() {
let result = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!( -c --color "some other flag"))
.group(ArgGroup::new("req").args(&["flag", "color"]).required(true))
.try_get_matches_from(vec![""]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group 'req' contains non-existent argument"]
fn non_existing_arg() {
let _ = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color "some other flag"))
.group(ArgGroup::new("req").args(&["flg", "color"]).required(true))
.try_get_matches_from(vec![""]);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name must be unique\n\n\t'req' is already in use"]
fn unique_group_name() {
let _ = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color "some other flag"))
.group(ArgGroup::new("req").args(&["flag"]).required(true))
.group(ArgGroup::new("req").args(&["color"]).required(true))
.try_get_matches_from(vec![""]);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name '' must not conflict with argument name"]
fn groups_new_of_arg_name() {
let _ = Command::new("group")
.arg(Arg::new("a").long("a").group("a"))
.try_get_matches_from(vec!["", "--a"]);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name 'a' must not conflict with argument name"]
fn arg_group_new_of_arg_name() {
let _ = Command::new("group")
.arg(Arg::new("a").long("a").group("a"))
.group(ArgGroup::new("a"))
.try_get_matches_from(vec!["", "--a"]);
}
#[test]
fn group_single_value() {
let res = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color [color] "some option"))
.group(ArgGroup::new("grp").args(&["flag", "color"]))
.try_get_matches_from(vec!["", "-c", "blue"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("grp"));
assert_eq!(m.value_of("grp").unwrap(), "blue");
}
#[test]
fn group_single_flag() {
let res = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color [color] "some option"))
.group(ArgGroup::new("grp").args(&["flag", "color"]))
.try_get_matches_from(vec!["", "-f"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("grp"));
assert!(m.value_of("grp").is_none());
}
#[test]
fn group_empty() {
let res = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color [color] "some option"))
.group(ArgGroup::new("grp").args(&["flag", "color"]))
.try_get_matches_from(vec![""]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(!m.is_present("grp"));
assert!(m.value_of("grp").is_none());
}
#[test]
fn group_reqired_flags_empty() {
let result = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color "some option"))
.group(ArgGroup::new("grp").required(true).args(&["flag", "color"]))
.try_get_matches_from(vec![""]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
}
#[test]
fn group_multi_value_single_arg() {
let res = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color <color> "some option").multiple_values(true))
.group(ArgGroup::new("grp").args(&["flag", "color"]))
.try_get_matches_from(vec!["", "-c", "blue", "red", "green"]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind());
let m = res.unwrap();
assert!(m.is_present("grp"));
assert_eq!(
&*m.values_of("grp").unwrap().collect::<Vec<_>>(),
&["blue", "red", "green"]
);
}
#[test]
fn empty_group() {
let r = Command::new("empty_group")
.arg(arg!(-f --flag "some flag"))
.group(ArgGroup::new("vers").required(true))
.try_get_matches_from(vec!["empty_prog"]);
assert!(r.is_err());
let err = r.err().unwrap();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
}
#[test]
fn req_group_usage_string() {
let cmd = Command::new("req_group")
.arg(arg!([base] "Base commit"))
.arg(arg!(
-d --delete "Remove the base commit information"
))
.group(
ArgGroup::new("base_or_delete")
.args(&["base", "delete"])
.required(true),
);
utils::assert_output(cmd, "clap-test", REQ_GROUP_USAGE, true);
}
#[test]
fn req_group_with_conflict_usage_string() {
let cmd = Command::new("req_group")
.arg(arg!([base] "Base commit").conflicts_with("delete"))
.arg(arg!(
-d --delete "Remove the base commit information"
))
.group(
ArgGroup::new("base_or_delete")
.args(&["base", "delete"])
.required(true),
);
utils::assert_output(
cmd,
"clap-test --delete base",
REQ_GROUP_CONFLICT_USAGE,
true,
);
}
#[test]
fn req_group_with_conflict_usage_string_only_options() {
let cmd = Command::new("req_group")
.arg(arg!(-a --all "All").conflicts_with("delete"))
.arg(arg!(
-d --delete "Remove the base commit information"
))
.group(
ArgGroup::new("all_or_delete")
.args(&["all", "delete"])
.required(true),
);
utils::assert_output(
cmd,
"clap-test --delete --all",
REQ_GROUP_CONFLICT_ONLY_OPTIONS,
true,
);
}
#[test]
fn required_group_multiple_args() {
let result = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color "some other flag"))
.group(
ArgGroup::new("req")
.args(&["flag", "color"])
.required(true)
.multiple(true),
)
.try_get_matches_from(vec!["group", "-f", "-c"]);
assert!(result.is_ok(), "{}", result.unwrap_err());
let m = result.unwrap();
assert!(m.is_present("flag"));
assert!(m.is_present("color"));
}
#[test]
fn group_multiple_args_error() {
let result = Command::new("group")
.arg(arg!(-f --flag "some flag"))
.arg(arg!(-c --color "some other flag"))
.group(ArgGroup::new("req").args(&["flag", "color"]))
.try_get_matches_from(vec!["group", "-f", "-c"]);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn group_overrides_required() {
let command = Command::new("group")
.arg(arg!(--foo <FOO>))
.arg(arg!(--bar <BAR>))
.group(ArgGroup::new("group").args(&["foo", "bar"]).required(true));
let result = command.try_get_matches_from(vec!["group", "--foo", "value"]);
assert!(result.is_ok(), "{}", result.unwrap_err());
let m = result.unwrap();
assert!(m.is_present("foo"));
assert!(!m.is_present("bar"));
}
#[test]
fn group_usage_use_val_name() {
static GROUP_USAGE_USE_VAL_NAME: &str = "prog
USAGE:
prog <A>
ARGS:
<A>
OPTIONS:
-h, --help Print help information
";
let cmd = Command::new("prog")
.arg(Arg::new("a").value_name("A"))
.group(ArgGroup::new("group").arg("a").required(true));
utils::assert_output(cmd, "prog --help", GROUP_USAGE_USE_VAL_NAME, false);
}
#[test]
fn group_acts_like_arg() {
let result = Command::new("prog")
.arg(Arg::new("debug").long("debug").group("mode"))
.arg(Arg::new("verbose").long("verbose").group("mode"))
.try_get_matches_from(vec!["prog", "--debug"]);
assert!(result.is_ok(), "{}", result.unwrap_err());
let m = result.unwrap();
assert!(m.is_present("mode"));
}
/* This is used to be fixed in a hack, we need to find a better way to fix it.
#[test]
fn issue_1794() {
let cmd = clap::Command::new("hello")
.bin_name("deno")
.arg(Arg::new("option1").long("option1").takes_value(false))
.arg(Arg::new("pos1").takes_value(true))
.arg(Arg::new("pos2").takes_value(true))
.group(
ArgGroup::new("arg1")
.args(&["pos1", "option1"])
.required(true),
);
let m = cmd.clone().try_get_matches_from(&["cmd", "pos1", "pos2"]).unwrap();
assert_eq!(m.value_of("pos1"), Some("pos1"));
assert_eq!(m.value_of("pos2"), Some("pos2"));
assert!(!m.is_present("option1"));
let m = cmd
.clone()
.try_get_matches_from(&["cmd", "--option1", "positional"]).unwrap();
assert_eq!(m.value_of("pos1"), None);
assert_eq!(m.value_of("pos2"), Some("positional"));
assert!(m.is_present("option1"));
}
*/

2867
tests/builder/legacy/help.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,227 @@
#![cfg(feature = "env")]
use std::env;
use clap::{Arg, Command};
use super::utils;
static HIDE_ENV: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe <FILE> A coffeehouse, coffee shop, or café.
-h, --help Print help information
-V, --version Print version information
";
static SHOW_ENV: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL]
-h, --help Print help information
-V, --version Print version information
";
static HIDE_ENV_VALS: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR]
-h, --help Print help information
-V, --version Print version information
";
static SHOW_ENV_VALS: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL]
-h, --help Print help information
-V, --version Print version information
";
static HIDE_ENV_FLAG: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe A coffeehouse, coffee shop, or café.
-h, --help Print help information
-V, --version Print version information
";
static SHOW_ENV_FLAG: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL]
-h, --help Print help information
-V, --version Print version information
";
static HIDE_ENV_VALS_FLAG: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe A coffeehouse, coffee shop, or café. [env: ENVVAR]
-h, --help Print help information
-V, --version Print version information
";
static SHOW_ENV_VALS_FLAG: &str = "ctest 0.1
USAGE:
ctest [OPTIONS]
OPTIONS:
-c, --cafe A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL]
-h, --help Print help information
-V, --version Print version information
";
#[test]
fn hide_env() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.value_name("FILE")
.hide_env(true)
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
utils::assert_output(cmd, "ctest --help", HIDE_ENV, false);
}
#[test]
fn show_env() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.value_name("FILE")
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
utils::assert_output(cmd, "ctest --help", SHOW_ENV, false);
}
#[test]
fn hide_env_vals() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.value_name("FILE")
.hide_env_values(true)
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
utils::assert_output(cmd, "ctest --help", HIDE_ENV_VALS, false);
}
#[test]
fn show_env_vals() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.value_name("FILE")
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café.")
.takes_value(true),
);
utils::assert_output(cmd, "ctest --help", SHOW_ENV_VALS, false);
}
#[test]
fn hide_env_flag() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.hide_env(true)
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café."),
);
utils::assert_output(cmd, "ctest --help", HIDE_ENV_FLAG, false);
}
#[test]
fn show_env_flag() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café."),
);
utils::assert_output(cmd, "ctest --help", SHOW_ENV_FLAG, false);
}
#[test]
fn hide_env_vals_flag() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.hide_env_values(true)
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café."),
);
utils::assert_output(cmd, "ctest --help", HIDE_ENV_VALS_FLAG, false);
}
#[test]
fn show_env_vals_flag() {
env::set_var("ENVVAR", "MYVAL");
let cmd = Command::new("ctest").version("0.1").arg(
Arg::new("cafe")
.short('c')
.long("cafe")
.env("ENVVAR")
.help("A coffeehouse, coffee shop, or café."),
);
utils::assert_output(cmd, "ctest --help", SHOW_ENV_VALS_FLAG, false);
}

View file

@ -0,0 +1,290 @@
use super::utils;
use clap::{arg, Arg, Command};
static HIDDEN_ARGS: &str = "test 1.4
Kevin K.
tests stuff
USAGE:
test [OPTIONS]
OPTIONS:
-F, --flag2 some other flag
-h, --help Print help information
--option <opt> some option
-V, --version Print version information
";
#[test]
fn hide_args() {
let cmd = Command::new("test")
.author("Kevin K.")
.about("tests stuff")
.version("1.4")
.args(&[
arg!(-f --flag "some flag").hide(true),
arg!(-F --flag2 "some other flag"),
arg!(--option <opt> "some option").required(false),
Arg::new("DUMMY").hide(true),
]);
utils::assert_output(cmd, "test --help", HIDDEN_ARGS, false);
}
static HIDDEN_SHORT_ARGS: &str = "test 2.31.2
Steve P.
hides short args
USAGE:
test [OPTIONS]
OPTIONS:
-h, --help Print help information
-v, --visible This text should be visible
-V, --version Print version information
";
static HIDDEN_SHORT_ARGS_LONG_HELP: &str = "test 2.31.2
Steve P.
hides short args
USAGE:
test [OPTIONS]
OPTIONS:
-c, --config
Some help text describing the --config arg
-h, --help
Print help information
-v, --visible
This text should be visible
-V, --version
Print version information
";
/// Ensure hide with short option
#[test]
fn hide_short_args() {
let cmd = Command::new("test")
.about("hides short args")
.author("Steve P.")
.version("2.31.2")
.args(&[
Arg::new("cfg")
.short('c')
.long("config")
.hide_short_help(true)
.help("Some help text describing the --config arg"),
Arg::new("visible")
.short('v')
.long("visible")
.help("This text should be visible"),
]);
utils::assert_output(cmd, "test -h", HIDDEN_SHORT_ARGS, false);
}
/// Ensure visible with opposite option
#[test]
fn hide_short_args_long_help() {
let cmd = Command::new("test")
.about("hides short args")
.author("Steve P.")
.version("2.31.2")
.args(&[
Arg::new("cfg")
.short('c')
.long("config")
.hide_short_help(true)
.help("Some help text describing the --config arg"),
Arg::new("visible")
.short('v')
.long("visible")
.help("This text should be visible"),
]);
utils::assert_output(cmd, "test --help", HIDDEN_SHORT_ARGS_LONG_HELP, false);
}
static HIDDEN_LONG_ARGS: &str = "test 2.31.2
Steve P.
hides long args
USAGE:
test [OPTIONS]
OPTIONS:
-h, --help
Print help information
-v, --visible
This text should be visible
-V, --version
Print version information
";
#[test]
fn hide_long_args() {
let cmd = Command::new("test")
.about("hides long args")
.author("Steve P.")
.version("2.31.2")
.args(&[
Arg::new("cfg")
.short('c')
.long("config")
.hide_long_help(true)
.help("Some help text describing the --config arg"),
Arg::new("visible")
.short('v')
.long("visible")
.help("This text should be visible"),
]);
utils::assert_output(cmd, "test --help", HIDDEN_LONG_ARGS, false);
}
static HIDDEN_LONG_ARGS_SHORT_HELP: &str = "test 2.31.2
Steve P.
hides long args
USAGE:
test [OPTIONS]
OPTIONS:
-c, --config Some help text describing the --config arg
-h, --help Print help information
-v, --visible This text should be visible
-V, --version Print version information
";
#[test]
fn hide_long_args_short_help() {
let cmd = Command::new("test")
.about("hides long args")
.author("Steve P.")
.version("2.31.2")
.args(&[
Arg::new("cfg")
.short('c')
.long("config")
.hide_long_help(true)
.help("Some help text describing the --config arg"),
Arg::new("visible")
.short('v')
.long("visible")
.help("This text should be visible"),
]);
utils::assert_output(cmd, "test -h", HIDDEN_LONG_ARGS_SHORT_HELP, false);
}
static HIDDEN_POS_ARGS: &str = "test 1.4
USAGE:
test [another]
ARGS:
<another> another pos
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
#[test]
fn hide_pos_args() {
let cmd = Command::new("test").version("1.4").args(&[
Arg::new("pos").help("some pos").hide(true),
Arg::new("another").help("another pos"),
]);
utils::assert_output(cmd, "test --help", HIDDEN_POS_ARGS, false);
}
static HIDDEN_SUBCMDS: &str = "test 1.4
USAGE:
test
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
#[test]
fn hide_subcmds() {
let cmd = Command::new("test")
.version("1.4")
.subcommand(Command::new("sub").hide(true));
utils::assert_output(cmd, "test --help", HIDDEN_SUBCMDS, false);
}
static HIDDEN_OPT_ARGS_ONLY: &str = "test 1.4
USAGE:
test
After help
";
#[test]
fn hide_opt_args_only() {
let cmd = Command::new("test")
.version("1.4")
.after_help("After help")
.mut_arg("help", |a| a.hide(true))
.mut_arg("version", |a| a.hide(true))
.arg(
arg!(--option <opt> "some option")
.required(false)
.hide(true),
);
utils::assert_output(cmd, "test --help", HIDDEN_OPT_ARGS_ONLY, false);
}
static HIDDEN_POS_ARGS_ONLY: &str = "test 1.4
USAGE:
test
After help
";
#[test]
fn hide_pos_args_only() {
let cmd = Command::new("test")
.version("1.4")
.after_help("After help")
.mut_arg("help", |a| a.hide(true))
.mut_arg("version", |a| a.hide(true))
.args(&[Arg::new("pos").help("some pos").hide(true)]);
utils::assert_output(cmd, "test --help", HIDDEN_POS_ARGS_ONLY, false);
}
static HIDDEN_SUBCMDS_ONLY: &str = "test 1.4
USAGE:
test
After help
";
#[test]
fn hide_subcmds_only() {
let cmd = Command::new("test")
.version("1.4")
.after_help("After help")
.mut_arg("help", |a| a.hide(true))
.mut_arg("version", |a| a.hide(true))
.subcommand(Command::new("sub").hide(true));
utils::assert_output(cmd, "test --help", HIDDEN_SUBCMDS_ONLY, false);
}

View file

@ -0,0 +1,117 @@
use clap::{arg, Arg, Command};
#[test]
fn single_short_arg_without_value() {
let cmd = Command::new("cmd").ignore_errors(true).arg(arg!(
-c --config [FILE] "Sets a custom config file"
));
let r = cmd.try_get_matches_from(vec!["cmd", "-c" /* missing: , "config file" */]);
assert!(r.is_ok(), "unexpected error: {:?}", r);
let m = r.unwrap();
assert!(m.is_present("config"));
}
#[test]
fn single_long_arg_without_value() {
let cmd = Command::new("cmd").ignore_errors(true).arg(arg!(
-c --config [FILE] "Sets a custom config file"
));
let r = cmd.try_get_matches_from(vec!["cmd", "--config" /* missing: , "config file" */]);
assert!(r.is_ok(), "unexpected error: {:?}", r);
let m = r.unwrap();
assert!(m.is_present("config"));
}
#[test]
fn multiple_args_and_final_arg_without_value() {
let cmd = Command::new("cmd")
.ignore_errors(true)
.arg(arg!(
-c --config [FILE] "Sets a custom config file"
))
.arg(arg!(
-x --stuff [FILE] "Sets a custom stuff file"
))
.arg(arg!(f: -f "Flag"));
let r = cmd.try_get_matches_from(vec![
"cmd", "-c", "file", "-f", "-x", /* missing: , "some stuff" */
]);
assert!(r.is_ok(), "unexpected error: {:?}", r);
let m = r.unwrap();
assert_eq!(m.value_of("config"), Some("file"));
assert!(m.is_present("f"));
assert_eq!(m.value_of("stuff"), None);
}
#[test]
fn multiple_args_and_intermittent_arg_without_value() {
let cmd = Command::new("cmd")
.ignore_errors(true)
.arg(arg!(
-c --config[FILE] "Sets a custom config file"
))
.arg(arg!(
-x --stuff[FILE] "Sets a custom stuff file"
))
.arg(arg!(f: -f "Flag"));
let r = cmd.try_get_matches_from(vec![
"cmd", "-x", /* missing: ,"some stuff" */
"-c", "file", "-f",
]);
assert!(r.is_ok(), "unexpected error: {:?}", r);
let m = r.unwrap();
assert_eq!(m.value_of("config"), Some("file"));
assert!(m.is_present("f"));
assert_eq!(m.value_of("stuff"), None);
}
#[test]
fn subcommand() {
let cmd = Command::new("test")
.ignore_errors(true)
.subcommand(
Command::new("some")
.arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
)
.arg(
Arg::new("stuff")
.short('x')
.long("stuff")
.takes_value(true)
.help("stuf value"),
),
)
.arg(Arg::new("other").long("other"));
let m = cmd
.try_get_matches_from(vec![
"myprog",
"some",
"--test", /* missing: ,"some val" */
"-x",
"some other val",
])
.unwrap();
assert_eq!(m.subcommand_name().unwrap(), "some");
let sub_m = m.subcommand_matches("some").unwrap();
assert!(
sub_m.is_present("test"),
"expected subcommand to be present due to partial parsing"
);
assert_eq!(sub_m.value_of("test"), None);
assert_eq!(sub_m.value_of("stuff"), Some("some other val"));
}

View file

@ -0,0 +1,202 @@
use clap::{Arg, Command};
#[test]
fn indices_mult_opts() {
let m = Command::new("ind")
.arg(
Arg::new("exclude")
.short('e')
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.arg(
Arg::new("include")
.short('i')
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[2, 3, 8]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[5, 6]
);
}
#[test]
fn index_mult_opts() {
let m = Command::new("ind")
.arg(
Arg::new("exclude")
.short('e')
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.arg(
Arg::new("include")
.short('i')
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"])
.unwrap();
assert_eq!(m.index_of("exclude"), Some(2));
assert_eq!(m.index_of("include"), Some(5));
}
#[test]
fn index_flag() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e'))
.arg(Arg::new("include").short('i'))
.try_get_matches_from(vec!["ind", "-e", "-i"])
.unwrap();
assert_eq!(m.index_of("exclude"), Some(1));
assert_eq!(m.index_of("include"), Some(2));
}
#[test]
fn index_flags() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.try_get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"])
.unwrap();
assert_eq!(m.index_of("exclude"), Some(1));
assert_eq!(m.index_of("include"), Some(2));
}
#[test]
fn indices_mult_flags() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.try_get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
}
#[test]
fn indices_mult_flags_combined() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.try_get_matches_from(vec!["ind", "-eieei"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
}
#[test]
fn indices_mult_flags_opt_combined() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["ind", "-eieeio", "val"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]);
}
#[test]
fn indices_mult_flags_opt_combined_eq() {
let m = Command::new("ind")
.arg(Arg::new("exclude").short('e').multiple_occurrences(true))
.arg(Arg::new("include").short('i').multiple_occurrences(true))
.arg(Arg::new("option").short('o').takes_value(true))
.try_get_matches_from(vec!["ind", "-eieeio=val"])
.unwrap();
assert_eq!(
m.indices_of("exclude").unwrap().collect::<Vec<_>>(),
&[1, 3, 4]
);
assert_eq!(
m.indices_of("include").unwrap().collect::<Vec<_>>(),
&[2, 5]
);
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]);
}
#[test]
fn indices_mult_opt_value_delim_eq() {
let m = Command::new("myapp")
.arg(
Arg::new("option")
.short('o')
.takes_value(true)
.use_value_delimiter(true)
.multiple_values(true),
)
.try_get_matches_from(vec!["myapp", "-o=val1,val2,val3"])
.unwrap();
assert_eq!(
m.indices_of("option").unwrap().collect::<Vec<_>>(),
&[2, 3, 4]
);
}
#[test]
fn indices_mult_opt_value_no_delim_eq() {
let m = Command::new("myapp")
.arg(
Arg::new("option")
.short('o')
.takes_value(true)
.multiple_values(true),
)
.try_get_matches_from(vec!["myapp", "-o=val1,val2,val3"])
.unwrap();
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
}
#[test]
fn indices_mult_opt_mult_flag() {
let m = Command::new("myapp")
.arg(
Arg::new("option")
.short('o')
.takes_value(true)
.multiple_occurrences(true),
)
.arg(Arg::new("flag").short('f').multiple_occurrences(true))
.try_get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"])
.unwrap();
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]);
}

View file

@ -0,0 +1,50 @@
#![allow(deprecated)]
mod app_from_crate;
mod app_settings;
mod arg_aliases;
mod arg_aliases_short;
mod arg_matcher_assertions;
mod arg_settings;
mod borrowed;
mod cargo;
mod command;
mod conflicts;
mod default_missing_vals;
mod default_vals;
mod delimiters;
mod derive_order;
mod display_order;
mod double_require;
mod empty_values;
mod env;
mod error;
mod flag_subcommands;
mod flags;
mod global_args;
mod grouped_values;
mod groups;
mod help;
mod help_env;
mod hidden_args;
mod ignore_errors;
mod indices;
mod multiple_occurrences;
mod multiple_values;
mod opts;
mod positionals;
mod posix_compatible;
mod possible_values;
mod propagate_globals;
mod regex;
mod require;
mod subcommands;
mod template_help;
mod tests;
mod unicode;
mod unique_args;
mod utf16;
mod utf8;
mod utils;
mod validators;
mod version;

View file

@ -0,0 +1,241 @@
use clap::{arg, error::ErrorKind, Arg, Command};
#[test]
fn multiple_occurrences_of_flags_long() {
let m = Command::new("mo_flags_long")
.arg(arg!(--multflag "allowed multiple flag").multiple_occurrences(true))
.arg(arg!(--flag "disallowed multiple flag"))
.try_get_matches_from(vec!["", "--multflag", "--flag", "--multflag"])
.unwrap();
assert!(m.is_present("multflag"));
assert_eq!(m.occurrences_of("multflag"), 2);
assert!(m.is_present("flag"));
assert_eq!(m.occurrences_of("flag"), 1)
}
#[test]
fn multiple_occurrences_of_flags_short() {
let m = Command::new("mo_flags_short")
.arg(arg!(-m --multflag "allowed multiple flag").multiple_occurrences(true))
.arg(arg!(-f --flag "disallowed multiple flag"))
.try_get_matches_from(vec!["", "-m", "-f", "-m"])
.unwrap();
assert!(m.is_present("multflag"));
assert_eq!(m.occurrences_of("multflag"), 2);
assert!(m.is_present("flag"));
assert_eq!(m.occurrences_of("flag"), 1);
}
#[test]
fn multiple_occurrences_of_flags_mixed() {
let m = Command::new("mo_flags_mixed")
.arg(arg!(-m --multflag1 "allowed multiple flag").multiple_occurrences(true))
.arg(arg!(-n --multflag2 "another allowed multiple flag").multiple_occurrences(true))
.arg(arg!(-f --flag "disallowed multiple flag"))
.try_get_matches_from(vec![
"",
"-m",
"-f",
"-n",
"--multflag1",
"-m",
"--multflag2",
])
.unwrap();
assert!(m.is_present("multflag1"));
assert_eq!(m.occurrences_of("multflag1"), 3);
assert!(m.is_present("multflag2"));
assert_eq!(m.occurrences_of("multflag2"), 2);
assert!(m.is_present("flag"));
assert_eq!(m.occurrences_of("flag"), 1);
}
#[test]
fn multiple_occurrences_of_positional() {
let cmd = Command::new("test").arg(Arg::new("multi").multiple_occurrences(true));
let m = cmd
.clone()
.try_get_matches_from(&["test"])
.expect("zero occurrences work");
assert!(!m.is_present("multi"));
assert_eq!(m.occurrences_of("multi"), 0);
assert!(m.values_of("multi").is_none());
let m = cmd
.clone()
.try_get_matches_from(&["test", "one"])
.expect("single occurrence work");
assert!(m.is_present("multi"));
assert_eq!(m.occurrences_of("multi"), 1);
assert_eq!(m.values_of("multi").unwrap().collect::<Vec<_>>(), ["one"]);
let m = cmd
.clone()
.try_get_matches_from(&["test", "one", "two", "three", "four"])
.expect("many occurrences work");
assert!(m.is_present("multi"));
assert_eq!(m.occurrences_of("multi"), 4);
assert_eq!(
m.values_of("multi").unwrap().collect::<Vec<_>>(),
["one", "two", "three", "four"]
);
}
#[test]
fn multiple_occurrences_of_flags_large_quantity() {
let args: Vec<&str> = vec![""]
.into_iter()
.chain(vec!["-m"; 1024].into_iter())
.collect();
let m = Command::new("mo_flags_large_qty")
.arg(arg!(-m --multflag "allowed multiple flag").multiple_occurrences(true))
.try_get_matches_from(args)
.unwrap();
assert!(m.is_present("multflag"));
assert_eq!(m.occurrences_of("multflag"), 1024);
}
#[cfg(feature = "env")]
#[test]
fn multiple_occurrences_of_before_env() {
let cmd = Command::new("mo_before_env").arg(
Arg::new("verbose")
.env("VERBOSE")
.short('v')
.long("verbose")
.takes_value(false)
.multiple_occurrences(true),
);
let m = cmd.clone().try_get_matches_from(vec![""]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 0);
let m = cmd.clone().try_get_matches_from(vec!["", "-v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 1);
let m = cmd.clone().try_get_matches_from(vec!["", "-vv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 2);
let m = cmd.clone().try_get_matches_from(vec!["", "-vvv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
}
#[cfg(feature = "env")]
#[test]
fn multiple_occurrences_of_after_env() {
let cmd = Command::new("mo_after_env").arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.takes_value(false)
.multiple_occurrences(true)
.env("VERBOSE"),
);
let m = cmd.clone().try_get_matches_from(vec![""]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 0);
let m = cmd.clone().try_get_matches_from(vec!["", "-v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 1);
let m = cmd.clone().try_get_matches_from(vec!["", "-vv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 2);
let m = cmd.clone().try_get_matches_from(vec!["", "-vvv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
}
#[test]
fn max_occurrences_implies_multiple_occurrences() {
let cmd = Command::new("prog").arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.max_occurrences(3),
);
let m = cmd.try_get_matches_from(vec!["prog", "-vvv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
// One max should not imply multiple occurrences
let cmd = Command::new("prog").arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.max_occurrences(1),
);
let m = cmd.try_get_matches_from(vec!["prog", "-vvv"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnexpectedMultipleUsage);
}
#[test]
fn max_occurrences_try_inputs() {
let cmd = Command::new("prog").arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.max_occurrences(3),
);
let m = cmd.clone().try_get_matches_from(vec!["prog", "-v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 1);
let m = cmd.clone().try_get_matches_from(vec!["prog", "-vv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 2);
let m = cmd.clone().try_get_matches_from(vec!["prog", "-vvv"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
let m = cmd.clone().try_get_matches_from(vec!["prog", "-vvvv"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::TooManyOccurrences);
let m = cmd
.clone()
.try_get_matches_from(vec!["prog", "-v", "-v", "-v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
let m = cmd
.clone()
.try_get_matches_from(vec!["prog", "-v", "-vv", "-v"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::TooManyOccurrences);
}
#[test]
fn max_occurrences_positional() {
let cmd = Command::new("prog").arg(Arg::new("verbose").max_occurrences(3));
let m = cmd.clone().try_get_matches_from(vec!["prog", "v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 1);
let m = cmd.clone().try_get_matches_from(vec!["prog", "v", "v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 2);
let m = cmd
.clone()
.try_get_matches_from(vec!["prog", "v", "v", "v"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(m.unwrap().occurrences_of("verbose"), 3);
let m = cmd
.clone()
.try_get_matches_from(vec!["prog", "v", "v", "v", "v"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::TooManyOccurrences);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,616 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgMatches, Command};
#[cfg(feature = "suggestions")]
static DYM: &str =
"error: Found argument '--optio' which wasn't expected, or isn't valid in this context
\tDid you mean '--option'?
\tIf you tried to supply `--optio` as a value rather than a flag, use `-- --optio`
USAGE:
clap-test --option <opt>...
For more information try --help
";
#[cfg(feature = "suggestions")]
static DYM_ISSUE_1073: &str =
"error: Found argument '--files-without-matches' which wasn't expected, or isn't valid in this context
\tDid you mean '--files-without-match'?
\tIf you tried to supply `--files-without-matches` as a value rather than a flag, use `-- --files-without-matches`
USAGE:
ripgrep-616 --files-without-match
For more information try --help
";
#[test]
fn require_equals_fail() {
let res = Command::new("prog")
.arg(
Arg::new("cfg")
.require_equals(true)
.forbid_empty_values(true)
.takes_value(true)
.long("config"),
)
.try_get_matches_from(vec!["prog", "--config", "file.conf"]);
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind(), ErrorKind::NoEquals);
}
#[test]
fn require_equals_fail_message() {
static NO_EQUALS: &str =
"error: Equal sign is needed when assigning values to '--config=<cfg>'.
USAGE:
prog [OPTIONS]
For more information try --help
";
let cmd = Command::new("prog").arg(
Arg::new("cfg")
.require_equals(true)
.takes_value(true)
.long("config"),
);
utils::assert_output(cmd, "prog --config file.conf", NO_EQUALS, true);
}
#[test]
fn require_equals_min_values_zero() {
let res = Command::new("prog")
.arg(
Arg::new("cfg")
.takes_value(true)
.require_equals(true)
.min_values(0)
.long("config"),
)
.arg(Arg::new("cmd"))
.try_get_matches_from(vec!["prog", "--config", "cmd"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("cfg"));
assert_eq!(m.value_of("cmd"), Some("cmd"));
}
#[test]
fn double_hyphen_as_value() {
let res = Command::new("prog")
.arg(
Arg::new("cfg")
.takes_value(true)
.allow_hyphen_values(true)
.long("config"),
)
.try_get_matches_from(vec!["prog", "--config", "--"]);
assert!(res.is_ok(), "{:?}", res);
assert_eq!(res.unwrap().value_of("cfg"), Some("--"));
}
#[test]
fn require_equals_no_empty_values_fail() {
let res = Command::new("prog")
.arg(
Arg::new("cfg")
.takes_value(true)
.require_equals(true)
.forbid_empty_values(true)
.long("config"),
)
.arg(Arg::new("some"))
.try_get_matches_from(vec!["prog", "--config=", "file.conf"]);
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind(), ErrorKind::EmptyValue);
}
#[test]
fn require_equals_empty_vals_pass() {
let res = Command::new("prog")
.arg(
Arg::new("cfg")
.takes_value(true)
.require_equals(true)
.long("config"),
)
.try_get_matches_from(vec!["prog", "--config="]);
assert!(res.is_ok(), "{}", res.unwrap_err());
}
#[test]
fn require_equals_pass() {
let res = Command::new("prog")
.arg(
Arg::new("cfg")
.takes_value(true)
.require_equals(true)
.long("config"),
)
.try_get_matches_from(vec!["prog", "--config=file.conf"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
}
#[test]
fn stdin_char() {
let r = Command::new("opts")
.arg(arg!(f: -f [flag] "some flag"))
.try_get_matches_from(vec!["", "-f", "-"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("f"));
assert_eq!(m.value_of("f").unwrap(), "-");
}
#[test]
fn opts_using_short() {
let r = Command::new("opts")
.args(&[
arg!(f: -f [flag] "some flag"),
arg!(c: -c [color] "some other flag"),
])
.try_get_matches_from(vec!["", "-f", "some", "-c", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("f"));
assert_eq!(m.value_of("f").unwrap(), "some");
assert!(m.is_present("c"));
assert_eq!(m.value_of("c").unwrap(), "other");
}
#[test]
fn lots_o_vals() {
let r = Command::new("opts")
.arg(arg!(o: -o <opt> "some opt").multiple_values(true))
.try_get_matches_from(vec![
"", "-o", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some",
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().count(), 297); // i.e. more than u8
}
#[test]
fn opts_using_long_space() {
let r = Command::new("opts")
.args(&[
arg!(--flag [flag] "some flag"),
arg!(--color [color] "some other flag"),
])
.try_get_matches_from(vec!["", "--flag", "some", "--color", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "some");
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other");
}
#[test]
fn opts_using_long_equals() {
let r = Command::new("opts")
.args(&[
arg!(--flag [flag] "some flag"),
arg!(--color [color] "some other flag"),
])
.try_get_matches_from(vec!["", "--flag=some", "--color=other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "some");
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other");
}
#[test]
fn opts_using_mixed() {
let r = Command::new("opts")
.args(&[
arg!(-f --flag [flag] "some flag"),
arg!(-c --color [color] "some other flag"),
])
.try_get_matches_from(vec!["", "-f", "some", "--color", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "some");
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other");
}
#[test]
fn opts_using_mixed2() {
let r = Command::new("opts")
.args(&[
arg!(-f --flag [flag] "some flag"),
arg!(-c --color [color] "some other flag"),
])
.try_get_matches_from(vec!["", "--flag=some", "-c", "other"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "some");
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other");
}
#[test]
fn default_values_user_value() {
let r = Command::new("df")
.arg(arg!(o: -o [opt] "some opt").default_value("default"))
.try_get_matches_from(vec!["", "-o", "value"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.value_of("o").unwrap(), "value");
}
#[test]
fn multiple_vals_pos_arg_equals() {
let r = Command::new("mvae")
.arg(arg!(o: -o [opt] ... "some opt"))
.arg(arg!([file] "some file"))
.try_get_matches_from(vec!["", "-o=1", "some"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.value_of("o").unwrap(), "1");
assert!(m.is_present("file"));
assert_eq!(m.value_of("file").unwrap(), "some");
}
#[test]
fn multiple_vals_pos_arg_delim() {
let r = Command::new("mvae")
.arg(
arg!(o: -o <opt> "some opt")
.multiple_values(true)
.use_value_delimiter(true),
)
.arg(arg!([file] "some file"))
.try_get_matches_from(vec!["", "-o", "1,2", "some"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["1", "2"]);
assert!(m.is_present("file"));
assert_eq!(m.value_of("file").unwrap(), "some");
}
#[test]
fn require_delims_no_delim() {
let r = Command::new("mvae")
.arg(
arg!(o: -o [opt] ... "some opt")
.use_value_delimiter(true)
.require_value_delimiter(true),
)
.arg(arg!([file] "some file"))
.try_get_matches_from(vec!["mvae", "-o", "1", "2", "some"]);
assert!(r.is_err());
let err = r.unwrap_err();
assert_eq!(err.kind(), ErrorKind::UnknownArgument);
}
#[test]
fn require_delims() {
let r = Command::new("mvae")
.arg(
arg!(o: -o <opt> "some opt")
.multiple_values(true)
.use_value_delimiter(true)
.require_value_delimiter(true),
)
.arg(arg!([file] "some file"))
.try_get_matches_from(vec!["", "-o", "1,2", "some"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["1", "2"]);
assert!(m.is_present("file"));
assert_eq!(m.value_of("file").unwrap(), "some");
}
#[test]
fn leading_hyphen_pass() {
let r = Command::new("mvae")
.arg(
arg!(o: -o <opt> "some opt")
.multiple_values(true)
.allow_hyphen_values(true),
)
.try_get_matches_from(vec!["", "-o", "-2", "3"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2", "3"]);
}
#[test]
fn leading_hyphen_fail() {
let r = Command::new("mvae")
.arg(arg!(o: -o <opt> "some opt"))
.try_get_matches_from(vec!["", "-o", "-2"]);
assert!(r.is_err());
let m = r.unwrap_err();
assert_eq!(m.kind(), ErrorKind::UnknownArgument);
}
#[test]
fn leading_hyphen_with_flag_after() {
let r = Command::new("mvae")
.arg(
arg!(o: -o <opt> "some opt")
.multiple_values(true)
.allow_hyphen_values(true),
)
.arg(arg!(f: -f "some flag"))
.try_get_matches_from(vec!["", "-o", "-2", "-f"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2", "-f"]);
assert!(!m.is_present("f"));
}
#[test]
fn leading_hyphen_with_flag_before() {
let r = Command::new("mvae")
.arg(arg!(o: -o [opt] ... "some opt").allow_hyphen_values(true))
.arg(arg!(f: -f "some flag"))
.try_get_matches_from(vec!["", "-f", "-o", "-2"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2"]);
assert!(m.is_present("f"));
}
#[test]
fn leading_hyphen_with_only_pos_follows() {
let r = Command::new("mvae")
.arg(
arg!(o: -o [opt] ... "some opt")
.number_of_values(1)
.takes_value(true)
.allow_hyphen_values(true),
)
.arg(arg!([arg] "some arg"))
.try_get_matches_from(vec!["", "-o", "-2", "--", "val"]);
assert!(r.is_ok(), "{:?}", r);
let m = r.unwrap();
assert!(m.is_present("o"));
assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2"]);
assert_eq!(m.value_of("arg"), Some("val"));
}
#[test]
#[cfg(feature = "suggestions")]
fn did_you_mean() {
utils::assert_output(utils::complex_app(), "clap-test --optio=foo", DYM, true);
}
#[test]
fn issue_1047_min_zero_vals_default_val() {
let m = Command::new("foo")
.arg(
Arg::new("del")
.short('d')
.long("del")
.takes_value(true)
.require_equals(true)
.min_values(0)
.default_missing_value("default"),
)
.try_get_matches_from(vec!["foo", "-d"])
.unwrap();
assert_eq!(m.occurrences_of("del"), 1);
assert_eq!(m.value_of("del"), Some("default"));
}
fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches, clap::Error> {
Command::new("opts")
.arg(arg!(-o --option <opt> "some option"))
.arg(arg!(--flag "some flag"))
.try_get_matches_from(argv)
}
#[test]
fn issue_1105_empty_value_long_fail() {
let r = issue_1105_setup(vec!["cmd", "--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!["cmd", "--option", ""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
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!["cmd", "--option="]);
assert!(r.is_ok(), "{}", r.unwrap_err());
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!["cmd", "-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!["cmd", "-o", ""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
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!["cmd", "-o="]);
assert!(r.is_ok(), "{}", r.unwrap_err());
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!["cmd", "-o", ""]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert_eq!(m.value_of("option"), Some(""));
}
#[test]
#[cfg(feature = "suggestions")]
fn issue_1073_suboptimal_flag_suggestion() {
let cmd = Command::new("ripgrep-616")
.arg(Arg::new("files-with-matches").long("files-with-matches"))
.arg(Arg::new("files-without-match").long("files-without-match"));
utils::assert_output(
cmd,
"ripgrep-616 --files-without-matches",
DYM_ISSUE_1073,
true,
);
}
#[test]
fn short_non_ascii_no_space() {
let matches = Command::new("cmd")
.arg(arg!(opt: -'磨' <opt>))
.try_get_matches_from(&["test", "-磨VALUE"])
.unwrap();
assert_eq!("VALUE", matches.value_of("opt").unwrap());
}
#[test]
fn short_eq_val_starts_with_eq() {
let matches = Command::new("cmd")
.arg(arg!(opt: -f <opt>))
.try_get_matches_from(&["test", "-f==value"])
.unwrap();
assert_eq!("=value", matches.value_of("opt").unwrap());
}
#[test]
fn long_eq_val_starts_with_eq() {
let matches = Command::new("cmd")
.arg(arg!(opt: --foo <opt>))
.try_get_matches_from(&["test", "--foo==value"])
.unwrap();
assert_eq!("=value", matches.value_of("opt").unwrap());
}
#[test]
fn issue_2022_get_flags_misuse() {
let cmd = Command::new("test")
.next_help_heading(Some("test"))
.arg(Arg::new("a").long("a").default_value("32"));
let matches = cmd.try_get_matches_from(&[""]).unwrap();
assert!(matches.value_of("a").is_some())
}
#[test]
fn issue_2279() {
let before_help_heading = Command::new("cmd")
.arg(Arg::new("foo").short('f').default_value("bar"))
.next_help_heading(Some("This causes default_value to be ignored"))
.try_get_matches_from(&[""])
.unwrap();
assert_eq!(before_help_heading.value_of("foo"), Some("bar"));
let after_help_heading = Command::new("cmd")
.next_help_heading(Some("This causes default_value to be ignored"))
.arg(Arg::new("foo").short('f').default_value("bar"))
.try_get_matches_from(&[""])
.unwrap();
assert_eq!(after_help_heading.value_of("foo"), Some("bar"));
}
#[test]
fn infer_long_arg() {
let cmd = Command::new("test")
.infer_long_args(true)
.arg(Arg::new("racetrack").long("racetrack").alias("autobahn"))
.arg(Arg::new("racecar").long("racecar").takes_value(true));
let matches = cmd
.clone()
.try_get_matches_from(&["test", "--racec=hello"])
.unwrap();
assert!(!matches.is_present("racetrack"));
assert_eq!(matches.value_of("racecar"), Some("hello"));
let matches = cmd
.clone()
.try_get_matches_from(&["test", "--racet"])
.unwrap();
assert!(matches.is_present("racetrack"));
assert_eq!(matches.value_of("racecar"), None);
let matches = cmd
.clone()
.try_get_matches_from(&["test", "--auto"])
.unwrap();
assert!(matches.is_present("racetrack"));
assert_eq!(matches.value_of("racecar"), None);
let cmd = Command::new("test")
.infer_long_args(true)
.arg(Arg::new("arg").long("arg"));
let matches = cmd.clone().try_get_matches_from(&["test", "--"]).unwrap();
assert!(!matches.is_present("arg"));
let matches = cmd.clone().try_get_matches_from(&["test", "--a"]).unwrap();
assert!(matches.is_present("arg"));
}

View file

@ -0,0 +1,310 @@
use clap::{arg, error::ErrorKind, Arg, Command};
#[test]
fn only_pos_follow() {
let r = Command::new("onlypos")
.args(&[arg!(f: -f [flag] "some opt"), arg!([arg] "some arg")])
.try_get_matches_from(vec!["", "--", "-f"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert!(!m.is_present("f"));
assert_eq!(m.value_of("arg").unwrap(), "-f");
}
#[test]
fn issue_946() {
let r = Command::new("compiletest")
.allow_hyphen_values(true)
.arg(arg!(--exact "filters match exactly"))
.arg(
clap::Arg::new("filter")
.index(1)
.takes_value(true)
.help("filters to apply to output"),
)
.try_get_matches_from(vec!["compiletest", "--exact"]);
assert!(r.is_ok(), "{:#?}", r);
let matches = r.unwrap();
assert!(matches.is_present("exact"));
assert!(matches.value_of("filter").is_none());
}
#[test]
fn positional() {
let r = Command::new("positional")
.args(&[arg!(-f --flag "some flag"), Arg::new("positional").index(1)])
.try_get_matches_from(vec!["", "-f", "test"]);
assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap();
assert!(m.is_present("positional"));
assert!(m.is_present("flag"));
assert_eq!(m.value_of("positional").unwrap(), "test");
let m = Command::new("positional")
.args(&[arg!(-f --flag "some flag"), Arg::new("positional").index(1)])
.try_get_matches_from(vec!["", "test", "--flag"])
.unwrap();
assert!(m.is_present("positional"));
assert!(m.is_present("flag"));
assert_eq!(m.value_of("positional").unwrap(), "test");
}
#[test]
fn lots_o_vals() {
let r = Command::new("opts")
.arg(arg!(<opt>... "some pos"))
.try_get_matches_from(vec![
"", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some",
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.values_of("opt").unwrap().count(), 297); // i.e. more than u8
}
#[test]
fn positional_multiple() {
let r = Command::new("positional_multiple")
.args(&[
arg!(-f --flag "some flag"),
Arg::new("positional")
.index(1)
.takes_value(true)
.multiple_values(true),
])
.try_get_matches_from(vec!["", "-f", "test1", "test2", "test3"]);
assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap();
assert!(m.is_present("positional"));
assert!(m.is_present("flag"));
assert_eq!(
&*m.values_of("positional").unwrap().collect::<Vec<_>>(),
&["test1", "test2", "test3"]
);
}
#[test]
fn positional_multiple_3() {
let r = Command::new("positional_multiple")
.args(&[
arg!(-f --flag "some flag"),
Arg::new("positional")
.index(1)
.takes_value(true)
.multiple_values(true),
])
.try_get_matches_from(vec!["", "test1", "test2", "test3", "--flag"]);
assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap();
assert!(m.is_present("positional"));
assert!(m.is_present("flag"));
assert_eq!(
&*m.values_of("positional").unwrap().collect::<Vec<_>>(),
&["test1", "test2", "test3"]
);
}
#[test]
fn positional_multiple_2() {
let result = Command::new("positional_multiple")
.args(&[arg!(-f --flag "some flag"), Arg::new("positional").index(1)])
.try_get_matches_from(vec!["", "-f", "test1", "test2", "test3"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::UnknownArgument);
}
#[test]
fn positional_possible_values() {
let r = Command::new("positional_possible_values")
.args(&[
arg!(-f --flag "some flag"),
Arg::new("positional").index(1).possible_value("test123"),
])
.try_get_matches_from(vec!["", "-f", "test123"]);
assert!(r.is_ok(), "{:#?}", r);
let m = r.unwrap();
assert!(m.is_present("positional"));
assert!(m.is_present("flag"));
assert_eq!(
&*m.values_of("positional").unwrap().collect::<Vec<_>>(),
&["test123"]
);
}
#[test]
fn create_positional() {
let _ = Command::new("test")
.arg(Arg::new("test").index(1).help("testing testing"))
.try_get_matches_from(vec![""])
.unwrap();
}
#[test]
fn positional_hyphen_does_not_panic() {
let _ = Command::new("test")
.arg(Arg::new("dummy"))
.try_get_matches_from(vec!["test", "-"])
.unwrap();
}
#[test]
fn single_positional_usage_string() {
let mut cmd = Command::new("test").arg(arg!([FILE] "some file"));
assert_eq!(cmd.render_usage(), "USAGE:\n test [FILE]");
}
#[test]
fn single_positional_multiple_usage_string() {
let mut cmd = Command::new("test").arg(arg!([FILE]... "some file"));
assert_eq!(cmd.render_usage(), "USAGE:\n test [FILE]...");
}
#[test]
fn multiple_positional_usage_string() {
let mut cmd = Command::new("test")
.arg(arg!([FILE] "some file"))
.arg(arg!([FILES]... "some file"));
assert_eq!(cmd.render_usage(), "USAGE:\n test [ARGS]");
}
#[test]
fn multiple_positional_one_required_usage_string() {
let mut cmd = Command::new("test")
.arg(arg!(<FILE> "some file"))
.arg(arg!([FILES]... "some file"));
assert_eq!(cmd.render_usage(), "USAGE:\n test <FILE> [FILES]...");
}
#[test]
fn single_positional_required_usage_string() {
let mut cmd = Command::new("test").arg(arg!(<FILE> "some file"));
assert_eq!(cmd.render_usage(), "USAGE:\n test <FILE>");
}
// This tests a programmer error and will only succeed with debug_assertions
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Found non-required positional argument \
with a lower index than a required positional argument"]
fn missing_required() {
let _ = Command::new("test")
.arg(arg!([FILE1] "some file"))
.arg(arg!(<FILE2> "some file"))
.try_get_matches_from(vec![""]);
}
#[test]
fn missing_required_2() {
let r = Command::new("test")
.arg(arg!(<FILE1> "some file"))
.arg(arg!(<FILE2> "some file"))
.try_get_matches_from(vec!["test", "file"]);
assert!(r.is_err());
assert_eq!(r.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
}
#[test]
fn last_positional() {
let r = Command::new("test")
.arg(arg!(<TARGET> "some target"))
.arg(arg!([CORPUS] "some corpus"))
.arg(arg!([ARGS]... "some file").last(true))
.try_get_matches_from(vec!["test", "tgt", "--", "arg"]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &["arg"]);
}
#[test]
fn last_positional_no_double_dash() {
let r = Command::new("test")
.arg(arg!(<TARGET> "some target"))
.arg(arg!([CORPUS] "some corpus"))
.arg(arg!([ARGS]... "some file").last(true))
.try_get_matches_from(vec!["test", "tgt", "crp", "arg"]);
assert!(r.is_err());
assert_eq!(r.unwrap_err().kind(), ErrorKind::UnknownArgument);
}
#[test]
fn last_positional_second_to_last_mult() {
let r = Command::new("test")
.arg(arg!(<TARGET> "some target"))
.arg(arg!([CORPUS]... "some corpus"))
.arg(arg!([ARGS]... "some file").last(true))
.try_get_matches_from(vec!["test", "tgt", "crp1", "crp2", "--", "arg"]);
assert!(r.is_ok(), "{:?}", r.unwrap_err().kind());
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument 'arg' is a positional argument and can't have short or long name versions"]
fn positional_arg_with_long() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(Arg::new("arg").index(1).long("arg"))
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument 'arg' is a positional argument and can't have short or long name versions"]
fn positional_arg_with_short() {
use clap::{Arg, Command};
let _ = Command::new("test")
.arg(Arg::new("arg").index(1).short('a'))
.try_get_matches();
}
#[test]
fn ignore_hyphen_values_on_last() {
let cmd = clap::Command::new("foo")
.arg(
clap::Arg::new("cmd")
.multiple_values(true)
.last(true)
.allow_hyphen_values(true),
)
.arg(
clap::Arg::new("name")
.long("name")
.short('n')
.takes_value(true)
.required(false),
);
let matches = cmd.try_get_matches_from(["test", "-n", "foo"]).unwrap();
assert_eq!(matches.value_of("name"), Some("foo"));
}

View file

@ -0,0 +1,401 @@
use clap::{arg, error::ErrorKind, Arg, Command};
#[test]
fn flag_overrides_itself() {
let res = Command::new("posix")
.arg(
arg!(--flag "some flag"
)
.overrides_with("flag"),
)
.try_get_matches_from(vec!["", "--flag", "--flag"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("flag"));
assert_eq!(m.occurrences_of("flag"), 1);
}
#[test]
fn mult_flag_overrides_itself() {
let res = Command::new("posix")
.arg(arg!(--flag ... "some flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "--flag", "--flag", "--flag", "--flag"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("flag"));
assert_eq!(m.occurrences_of("flag"), 4);
}
#[test]
fn option_overrides_itself() {
let res = Command::new("posix")
.arg(
arg!(--opt <val> "some option")
.required(false)
.overrides_with("opt"),
)
.try_get_matches_from(vec!["", "--opt=some", "--opt=other"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.occurrences_of("opt"), 1);
assert_eq!(m.value_of("opt"), Some("other"));
}
#[test]
fn mult_option_require_delim_overrides_itself() {
let res = Command::new("posix")
.arg(
arg!(--opt <val> ... "some option")
.required(false)
.overrides_with("opt")
.number_of_values(1)
.takes_value(true)
.use_value_delimiter(true)
.require_value_delimiter(true),
)
.try_get_matches_from(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.occurrences_of("opt"), 3);
assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["some", "other", "one", "two"]
);
}
#[test]
fn mult_option_overrides_itself() {
let res = Command::new("posix")
.arg(
arg!(--opt <val> ... "some option")
.required(false)
.multiple_values(true)
.overrides_with("opt"),
)
.try_get_matches_from(vec![
"",
"--opt",
"first",
"overrides",
"--opt",
"some",
"other",
"val",
]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.occurrences_of("opt"), 2);
assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["first", "overrides", "some", "other", "val"]
);
}
#[test]
fn option_use_delim_false_override_itself() {
let m = Command::new("posix")
.arg(
arg!(--opt <val> "some option")
.required(false)
.overrides_with("opt"),
)
.try_get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"])
.unwrap();
assert!(m.is_present("opt"));
assert_eq!(m.occurrences_of("opt"), 1);
assert_eq!(
m.values_of("opt").unwrap().collect::<Vec<_>>(),
&["one,two"]
);
}
#[test]
fn pos_mult_overrides_itself() {
// opts with multiple
let res = Command::new("posix")
.arg(arg!([val] ... "some pos").overrides_with("val"))
.try_get_matches_from(vec!["", "some", "other", "value"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.is_present("val"));
assert_eq!(m.occurrences_of("val"), 3);
assert_eq!(
m.values_of("val").unwrap().collect::<Vec<_>>(),
&["some", "other", "value"]
);
}
#[test]
fn posix_compatible_flags_long() {
let m = Command::new("posix")
.arg(arg!(--flag "some flag").overrides_with("color"))
.arg(arg!(--color "some other flag"))
.try_get_matches_from(vec!["", "--flag", "--color"])
.unwrap();
assert!(m.is_present("color"));
assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_flags_long_rev() {
let m = Command::new("posix")
.arg(arg!(--flag "some flag").overrides_with("color"))
.arg(arg!(--color "some other flag"))
.try_get_matches_from(vec!["", "--color", "--flag"])
.unwrap();
assert!(!m.is_present("color"));
assert!(m.is_present("flag"));
}
#[test]
fn posix_compatible_flags_short() {
let m = Command::new("posix")
.arg(arg!(-f --flag "some flag").overrides_with("color"))
.arg(arg!(-c --color "some other flag"))
.try_get_matches_from(vec!["", "-f", "-c"])
.unwrap();
assert!(m.is_present("color"));
assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_flags_short_rev() {
let m = Command::new("posix")
.arg(arg!(-f --flag "some flag").overrides_with("color"))
.arg(arg!(-c --color "some other flag"))
.try_get_matches_from(vec!["", "-c", "-f"])
.unwrap();
assert!(!m.is_present("color"));
assert!(m.is_present("flag"));
}
#[test]
fn posix_compatible_opts_long() {
let m = Command::new("posix")
.arg(
arg!(--flag <flag> "some flag")
.required(false)
.overrides_with("color"),
)
.arg(arg!(--color <color> "some other flag").required(false))
.try_get_matches_from(vec!["", "--flag", "some", "--color", "other"])
.unwrap();
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other");
assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_opts_long_rev() {
let m = Command::new("posix")
.arg(
arg!(--flag <flag> "some flag")
.required(false)
.overrides_with("color"),
)
.arg(arg!(--color <color> "some other flag").required(false))
.try_get_matches_from(vec!["", "--color", "some", "--flag", "other"])
.unwrap();
assert!(!m.is_present("color"));
assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "other");
}
#[test]
fn posix_compatible_opts_long_equals() {
let m = Command::new("posix")
.arg(
arg!(--flag <flag> "some flag")
.required(false)
.overrides_with("color"),
)
.arg(arg!(--color <color> "some other flag").required(false))
.try_get_matches_from(vec!["", "--flag=some", "--color=other"])
.unwrap();
assert!(m.is_present("color"));
assert_eq!(m.value_of("color").unwrap(), "other");
assert!(!m.is_present("flag"));
}
#[test]
fn posix_compatible_opts_long_equals_rev() {
let m = Command::new("posix")
.arg(
arg!(--flag <flag> "some flag")
.required(false)
.overrides_with("color"),
)
.arg(arg!(--color <color> "some other flag").required(false))
.try_get_matches_from(vec!["", "--color=some", "--flag=other"])
.unwrap();
assert!(!m.is_present("color"));
assert!(m.is_present("flag"));
assert_eq!(m.value_of("flag").unwrap(), "other");
}
#[test]
fn posix_compatible_opts_short() {
let m = Command::new("posix")
.arg(
arg!(f: -f <flag> "some flag")
.required(false)
.overrides_with("c"),
)
.arg(arg!(c: -c <color> "some other flag").required(false))
.try_get_matches_from(vec!["", "-f", "some", "-c", "other"])
.unwrap();
assert!(m.is_present("c"));
assert_eq!(m.value_of("c").unwrap(), "other");
assert!(!m.is_present("f"));
}
#[test]
fn posix_compatible_opts_short_rev() {
let m = Command::new("posix")
.arg(
arg!(f: -f <flag> "some flag")
.required(false)
.overrides_with("c"),
)
.arg(arg!(c: -c <color> "some other flag").required(false))
.try_get_matches_from(vec!["", "-c", "some", "-f", "other"])
.unwrap();
assert!(!m.is_present("c"));
assert!(m.is_present("f"));
assert_eq!(m.value_of("f").unwrap(), "other");
}
#[test]
fn conflict_overridden() {
let m = Command::new("conflict_overridden")
.arg(arg!(-f --flag "some flag").conflicts_with("debug"))
.arg(arg!(-d --debug "other flag"))
.arg(arg!(-c --color "third flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "-f", "-c", "-d"])
.unwrap();
assert!(m.is_present("color"));
assert!(!m.is_present("flag"));
assert!(m.is_present("debug"));
}
#[test]
fn conflict_overridden_2() {
let result = Command::new("conflict_overridden")
.arg(arg!(-f --flag "some flag").conflicts_with("debug"))
.arg(arg!(-d --debug "other flag"))
.arg(arg!(-c --color "third flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "-f", "-d", "-c"]);
assert!(result.is_ok(), "{}", result.unwrap_err());
let m = result.unwrap();
assert!(m.is_present("color"));
assert!(m.is_present("debug"));
assert!(!m.is_present("flag"));
}
#[test]
fn conflict_overridden_3() {
let result = Command::new("conflict_overridden")
.arg(arg!(-f --flag "some flag").conflicts_with("debug"))
.arg(arg!(-d --debug "other flag"))
.arg(arg!(-c --color "third flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "-d", "-c", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
}
#[test]
fn conflict_overridden_4() {
let m = Command::new("conflict_overridden")
.arg(arg!(-f --flag "some flag").conflicts_with("debug"))
.arg(arg!(-d --debug "other flag"))
.arg(arg!(-c --color "third flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "-d", "-f", "-c"])
.unwrap();
assert!(m.is_present("color"));
assert!(!m.is_present("flag"));
assert!(m.is_present("debug"));
}
#[test]
fn pos_required_overridden_by_flag() {
let result = Command::new("require_overridden")
.arg(Arg::new("pos").index(1).required(true))
.arg(arg!(-c --color "some flag").overrides_with("pos"))
.try_get_matches_from(vec!["", "test", "-c"]);
assert!(result.is_ok(), "{:?}", result.unwrap_err());
}
#[test]
fn require_overridden_2() {
let m = Command::new("require_overridden")
.arg(Arg::new("req_pos").required(true))
.arg(arg!(-c --color "other flag").overrides_with("req_pos"))
.try_get_matches_from(vec!["", "-c", "req_pos"])
.unwrap();
assert!(!m.is_present("color"));
assert!(m.is_present("req_pos"));
}
#[test]
fn require_overridden_3() {
let m = Command::new("require_overridden")
.arg(arg!(-f --flag "some flag").requires("debug"))
.arg(arg!(-d --debug "other flag"))
.arg(arg!(-c --color "third flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "-f", "-c"])
.unwrap();
assert!(m.is_present("color"));
assert!(!m.is_present("flag"));
assert!(!m.is_present("debug"));
}
#[test]
fn require_overridden_4() {
let result = Command::new("require_overridden")
.arg(arg!(-f --flag "some flag").requires("debug"))
.arg(arg!(-d --debug "other flag"))
.arg(arg!(-c --color "third flag").overrides_with("flag"))
.try_get_matches_from(vec!["", "-c", "-f"]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
}
#[test]
fn issue_1374_overrides_self_with_multiple_values() {
let cmd = Command::new("test").arg(
Arg::new("input")
.long("input")
.takes_value(true)
.overrides_with("input")
.min_values(0),
);
let m = cmd
.clone()
.try_get_matches_from(&["test", "--input", "a", "b", "c", "--input", "d"])
.unwrap();
assert_eq!(m.values_of("input").unwrap().collect::<Vec<_>>(), &["d"]);
let m = cmd
.clone()
.try_get_matches_from(&["test", "--input", "a", "b", "--input", "c", "d"])
.unwrap();
assert_eq!(
m.values_of("input").unwrap().collect::<Vec<_>>(),
&["c", "d"]
);
}
#[test]
fn incremental_override() {
let mut cmd = Command::new("test")
.arg(arg!(--name <NAME>).multiple_occurrences(true))
.arg(arg!(--"no-name").overrides_with("name"));
let m = cmd
.try_get_matches_from_mut(&["test", "--name=ahmed", "--no-name", "--name=ali"])
.unwrap();
assert_eq!(m.values_of("name").unwrap().collect::<Vec<_>>(), &["ali"]);
assert!(!m.is_present("no-name"));
}

View file

@ -0,0 +1,393 @@
use super::utils;
use clap::{error::ErrorKind, Arg, Command, PossibleValue};
#[cfg(feature = "suggestions")]
static PV_ERROR: &str = "error: \"slo\" isn't a valid value for '-O <option>'
\t[possible values: slow, fast, \"ludicrous speed\"]
\tDid you mean \"slow\"?
For more information try --help
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR: &str = "error: \"slo\" isn't a valid value for '-O <option>'
\t[possible values: slow, fast, \"ludicrous speed\"]
For more information try --help
";
#[cfg(feature = "suggestions")]
static PV_ERROR_ESCAPED: &str = "error: \"ludicrous\" isn't a valid value for '-O <option>'
\t[possible values: slow, fast, \"ludicrous speed\"]
\tDid you mean \"ludicrous speed\"?
For more information try --help
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR_ESCAPED: &str = "error: \"ludicrous\" isn't a valid value for '-O <option>'
\t[possible values: slow, fast, \"ludicrous speed\"]
For more information try --help
";
#[test]
fn possible_values_of_positional() {
let m = Command::new("possible_values")
.arg(Arg::new("positional").index(1).possible_value("test123"))
.try_get_matches_from(vec!["myprog", "test123"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("positional"));
assert_eq!(m.value_of("positional"), Some("test123"));
}
#[test]
fn possible_value_arg_value() {
let m = Command::new("possible_values")
.arg(
Arg::new("arg_value").index(1).possible_value(
PossibleValue::new("test123")
.hide(false)
.help("It's just a test"),
),
)
.try_get_matches_from(vec!["myprog", "test123"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("arg_value"));
assert_eq!(m.value_of("arg_value"), Some("test123"));
}
#[test]
fn possible_values_of_positional_fail() {
let m = Command::new("possible_values")
.arg(Arg::new("positional").index(1).possible_value("test123"))
.try_get_matches_from(vec!["myprog", "notest"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
}
#[test]
fn possible_values_of_positional_multiple() {
let m = Command::new("possible_values")
.arg(
Arg::new("positional")
.index(1)
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple_values(true),
)
.try_get_matches_from(vec!["myprog", "test123", "test321"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("positional"));
assert_eq!(
m.values_of("positional").unwrap().collect::<Vec<_>>(),
vec!["test123", "test321"]
);
}
#[test]
fn possible_values_of_positional_multiple_fail() {
let m = Command::new("possible_values")
.arg(
Arg::new("positional")
.index(1)
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple_values(true),
)
.try_get_matches_from(vec!["myprog", "test123", "notest"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
}
#[test]
fn possible_values_of_option() {
let m = Command::new("possible_values")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123"),
)
.try_get_matches_from(vec!["myprog", "--option", "test123"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.value_of("option"), Some("test123"));
}
#[test]
fn possible_values_of_option_fail() {
let m = Command::new("possible_values")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123"),
)
.try_get_matches_from(vec!["myprog", "--option", "notest"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
}
#[test]
fn possible_values_of_option_multiple() {
let m = Command::new("possible_values")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple_occurrences(true),
)
.try_get_matches_from(vec!["", "--option", "test123", "--option", "test321"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(
m.values_of("option").unwrap().collect::<Vec<_>>(),
vec!["test123", "test321"]
);
}
#[test]
fn possible_values_of_option_multiple_fail() {
let m = Command::new("possible_values")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple_occurrences(true),
)
.try_get_matches_from(vec!["", "--option", "test123", "--option", "notest"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
}
#[test]
fn possible_values_output() {
utils::assert_output(
Command::new("test").arg(Arg::new("option").short('O').possible_values([
"slow",
"fast",
"ludicrous speed",
])),
"clap-test -O slo",
PV_ERROR,
true,
);
}
#[test]
fn possible_values_alias_output() {
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
.short('O')
.possible_value("slow")
.possible_value(PossibleValue::new("fast").alias("fost"))
.possible_value(PossibleValue::new("ludicrous speed").aliases(["ls", "lcs"])),
),
"clap-test -O slo",
PV_ERROR,
true,
);
}
#[test]
fn possible_values_hidden_output() {
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
.short('O')
.possible_values(["slow", "fast"])
.possible_value(PossibleValue::new("ludicrous speed"))
.possible_value(PossibleValue::new("forbidden speed").hide(true)),
),
"clap-test -O slo",
PV_ERROR,
true,
);
}
#[test]
fn escaped_possible_values_output() {
utils::assert_output(
Command::new("test").arg(Arg::new("option").short('O').possible_values([
"slow",
"fast",
"ludicrous speed",
])),
"clap-test -O ludicrous",
PV_ERROR_ESCAPED,
true,
);
}
#[test]
fn missing_possible_value_error() {
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
.short('O')
.possible_value("slow")
.possible_value(PossibleValue::new("fast").alias("fost"))
.possible_value(PossibleValue::new("ludicrous speed"))
.possible_value(PossibleValue::new("forbidden speed").hide(true)),
),
"clap-test -O",
MISSING_PV_ERROR,
true,
);
}
static MISSING_PV_ERROR: &str =
"error: The argument '-O <option>' requires a value but none was supplied
\t[possible values: slow, fast, \"ludicrous speed\"]
For more information try --help
";
#[test]
fn alias() {
let m = Command::new("pv")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value(PossibleValue::new("test123").alias("123"))
.possible_value("test321")
.ignore_case(true),
)
.try_get_matches_from(vec!["pv", "--option", "123"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert!(m.unwrap().value_of("option").unwrap().eq("123"));
}
#[test]
fn aliases() {
let m = Command::new("pv")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value(PossibleValue::new("test123").aliases(["1", "2", "3"]))
.possible_value("test321")
.ignore_case(true),
)
.try_get_matches_from(vec!["pv", "--option", "2"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert!(m.unwrap().value_of("option").unwrap().eq("2"));
}
#[test]
fn ignore_case() {
let m = Command::new("pv")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.ignore_case(true),
)
.try_get_matches_from(vec!["pv", "--option", "TeSt123"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert!(m
.unwrap()
.value_of("option")
.unwrap()
.eq_ignore_ascii_case("test123"));
}
#[test]
fn ignore_case_fail() {
let m = Command::new("pv")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321"),
)
.try_get_matches_from(vec!["pv", "--option", "TeSt123"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
}
#[test]
fn ignore_case_multiple() {
let m = Command::new("pv")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple_values(true)
.ignore_case(true),
)
.try_get_matches_from(vec!["pv", "--option", "TeSt123", "teST123", "tESt321"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert_eq!(
m.unwrap().values_of("option").unwrap().collect::<Vec<_>>(),
&["TeSt123", "teST123", "tESt321"]
);
}
#[test]
fn ignore_case_multiple_fail() {
let m = Command::new("pv")
.arg(
Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple_values(true),
)
.try_get_matches_from(vec!["pv", "--option", "test123", "teST123", "test321"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
}

View file

@ -0,0 +1,144 @@
use clap::{Arg, ArgMatches, Command};
fn get_app() -> Command<'static> {
Command::new("myprog")
.arg(
Arg::new("GLOBAL_ARG")
.long("global-arg")
.help("Specifies something needed by the subcommands")
.global(true)
.takes_value(true)
.default_value("default_value"),
)
.arg(
Arg::new("GLOBAL_FLAG")
.long("global-flag")
.help("Specifies something needed by the subcommands")
.global(true)
.multiple_occurrences(true),
)
.subcommand(Command::new("outer").subcommand(Command::new("inner")))
}
fn get_matches(cmd: Command<'static>, argv: &'static str) -> ArgMatches {
cmd.try_get_matches_from(argv.split(' ').collect::<Vec<_>>())
.unwrap()
}
fn get_outer_matches(m: &ArgMatches) -> &ArgMatches {
m.subcommand_matches("outer")
.expect("could not access outer subcommand")
}
fn get_inner_matches(m: &ArgMatches) -> &ArgMatches {
get_outer_matches(m)
.subcommand_matches("inner")
.expect("could not access inner subcommand")
}
fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
m.value_of("GLOBAL_ARG") == val.into()
}
fn inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
get_inner_matches(m).value_of("GLOBAL_ARG") == val.into()
}
fn outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
get_outer_matches(m).value_of("GLOBAL_ARG") == val.into()
}
fn top_can_access_flag(m: &ArgMatches, present: bool, occurrences: u64) -> bool {
(m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
}
fn inner_can_access_flag(m: &ArgMatches, present: bool, occurrences: u64) -> bool {
let m = get_inner_matches(m);
(m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
}
fn outer_can_access_flag(m: &ArgMatches, present: bool, occurrences: u64) -> bool {
let m = get_outer_matches(m);
(m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
}
#[test]
fn global_arg_used_top_level() {
let m = get_matches(get_app(), "myprog --global-arg=some_value outer inner");
assert!(top_can_access_arg(&m, "some_value"));
assert!(inner_can_access_arg(&m, "some_value"));
assert!(outer_can_access_arg(&m, "some_value"));
}
#[test]
fn global_arg_used_outer() {
let m = get_matches(get_app(), "myprog outer --global-arg=some_value inner");
assert!(top_can_access_arg(&m, "some_value"));
assert!(inner_can_access_arg(&m, "some_value"));
assert!(outer_can_access_arg(&m, "some_value"));
}
#[test]
fn global_arg_used_inner() {
let m = get_matches(get_app(), "myprog outer inner --global-arg=some_value");
assert!(top_can_access_arg(&m, "some_value"));
assert!(inner_can_access_arg(&m, "some_value"));
assert!(outer_can_access_arg(&m, "some_value"));
}
#[test]
fn global_arg_default_value() {
let m = get_matches(get_app(), "myprog outer inner");
assert!(top_can_access_arg(&m, "default_value"));
assert!(inner_can_access_arg(&m, "default_value"));
assert!(outer_can_access_arg(&m, "default_value"));
}
#[test]
fn global_flag_used_top_level() {
let m = get_matches(get_app(), "myprog --global-flag outer inner");
assert!(top_can_access_flag(&m, true, 1));
assert!(inner_can_access_flag(&m, true, 1));
assert!(outer_can_access_flag(&m, true, 1));
}
#[test]
fn global_flag_used_outer() {
let m = get_matches(get_app(), "myprog outer --global-flag inner");
assert!(top_can_access_flag(&m, true, 1));
assert!(inner_can_access_flag(&m, true, 1));
assert!(outer_can_access_flag(&m, true, 1));
}
#[test]
fn global_flag_used_inner() {
let m = get_matches(get_app(), "myprog outer inner --global-flag");
assert!(top_can_access_flag(&m, true, 1));
assert!(inner_can_access_flag(&m, true, 1));
assert!(outer_can_access_flag(&m, true, 1));
}
#[test]
fn global_flag_2x_used_top_level() {
let m = get_matches(get_app(), "myprog --global-flag --global-flag outer inner");
assert!(top_can_access_flag(&m, true, 2));
assert!(inner_can_access_flag(&m, true, 2));
assert!(outer_can_access_flag(&m, true, 2));
}
#[test]
fn global_flag_2x_used_inner() {
let m = get_matches(get_app(), "myprog outer inner --global-flag --global-flag");
assert!(top_can_access_flag(&m, true, 2));
assert!(inner_can_access_flag(&m, true, 2));
assert!(outer_can_access_flag(&m, true, 2));
}

View file

@ -0,0 +1,36 @@
#![cfg(feature = "regex")]
use clap::{error::ErrorKind, Arg, Command};
use regex::{Regex, RegexSet};
#[test]
fn validator_regex() {
let priority = Regex::new(r"[A-C]").unwrap();
let m = Command::new("prog")
.arg(
Arg::new("priority")
.index(1)
.validator_regex(priority, "A, B or C are allowed"),
)
.try_get_matches_from(vec!["prog", "12345"]);
assert!(m.is_err());
assert_eq!(m.err().unwrap().kind(), ErrorKind::ValueValidation)
}
#[test]
fn validator_regex_with_regex_set() {
let priority = RegexSet::new(&[r"[A-C]", r"[X-Z]"]).unwrap();
let m = Command::new("prog")
.arg(
Arg::new("priority")
.index(1)
.validator_regex(priority, "A, B, C, X, Y or Z are allowed"),
)
.try_get_matches_from(vec!["prog", "12345"]);
assert!(m.is_err());
assert_eq!(m.err().unwrap().kind(), ErrorKind::ValueValidation)
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,696 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, Command};
static VISIBLE_ALIAS_HELP: &str = "clap-test 2.6
USAGE:
clap-test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test Some help [aliases: dongle, done]
";
static INVISIBLE_ALIAS_HELP: &str = "clap-test 2.6
USAGE:
clap-test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test Some help
";
static SUBCMD_ALPHA_ORDER: &str = "test 1
USAGE:
test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
a1 blah a1
b1 blah b1
help Print this message or the help of the given subcommand(s)
";
static SUBCMD_DECL_ORDER: &str = "test 1
USAGE:
test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
b1 blah b1
a1 blah a1
help Print this message or the help of the given subcommand(s)
";
#[cfg(feature = "suggestions")]
static DYM_SUBCMD: &str = "error: The subcommand 'subcm' wasn't recognized
Did you mean 'subcmd'?
If you believe you received this message in error, try re-running with 'dym -- subcm'
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
#[cfg(feature = "suggestions")]
static DYM_SUBCMD_AMBIGUOUS: &str = "error: The subcommand 'te' wasn't recognized
Did you mean 'test' or 'temp'?
If you believe you received this message in error, try re-running with 'dym -- te'
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
static SUBCMD_AFTER_DOUBLE_DASH: &str =
"error: Found argument 'subcmd' which wasn't expected, or isn't valid in this context
\tIf you tried to supply `subcmd` as a subcommand, remove the '--' before it.
USAGE:
cmd [SUBCOMMAND]
For more information try --help
";
#[test]
fn subcommand() {
let m = Command::new("test")
.subcommand(
Command::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
),
)
.arg(Arg::new("other").long("other"))
.try_get_matches_from(vec!["myprog", "some", "--test", "testing"])
.unwrap();
assert_eq!(m.subcommand_name().unwrap(), "some");
let sub_m = m.subcommand_matches("some").unwrap();
assert!(sub_m.is_present("test"));
assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}
#[test]
fn subcommand_none_given() {
let m = Command::new("test")
.subcommand(
Command::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
),
)
.arg(Arg::new("other").long("other"))
.try_get_matches_from(vec![""])
.unwrap();
assert!(m.subcommand_name().is_none());
}
#[test]
fn subcommand_multiple() {
let m = Command::new("test")
.subcommands(vec![
Command::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
),
Command::new("add").arg(Arg::new("roster").short('r')),
])
.arg(Arg::new("other").long("other"))
.try_get_matches_from(vec!["myprog", "some", "--test", "testing"])
.unwrap();
assert!(m.subcommand_matches("some").is_some());
assert!(m.subcommand_matches("add").is_none());
assert_eq!(m.subcommand_name().unwrap(), "some");
let sub_m = m.subcommand_matches("some").unwrap();
assert!(sub_m.is_present("test"));
assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}
#[test]
fn subcommand_display_order() {
let app_subcmd_alpha_order = Command::new("test").version("1").subcommands(vec![
Command::new("b1")
.about("blah b1")
.arg(Arg::new("test").short('t')),
Command::new("a1")
.about("blah a1")
.arg(Arg::new("roster").short('r')),
]);
utils::assert_output(
app_subcmd_alpha_order,
"test --help",
SUBCMD_ALPHA_ORDER,
false,
);
let app_subcmd_decl_order = Command::new("test")
.version("1")
.setting(clap::AppSettings::DeriveDisplayOrder)
.subcommands(vec![
Command::new("b1")
.about("blah b1")
.arg(Arg::new("test").short('t')),
Command::new("a1")
.about("blah a1")
.arg(Arg::new("roster").short('r')),
]);
utils::assert_output(
app_subcmd_decl_order,
"test --help",
SUBCMD_DECL_ORDER,
false,
);
}
#[test]
fn single_alias() {
let m = Command::new("myprog")
.subcommand(Command::new("test").alias("do-stuff"))
.try_get_matches_from(vec!["myprog", "do-stuff"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("test"));
}
#[test]
fn multiple_aliases() {
let m = Command::new("myprog")
.subcommand(Command::new("test").aliases(&["do-stuff", "test-stuff"]))
.try_get_matches_from(vec!["myprog", "test-stuff"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("test"));
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output() {
let cmd = Command::new("dym").subcommand(Command::new("subcmd"));
utils::assert_output(cmd, "dym subcm", DYM_SUBCMD, true);
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_ambiguous() {
let cmd = Command::new("dym")
.subcommand(Command::new("test"))
.subcommand(Command::new("temp"));
utils::assert_output(cmd, "dym te", DYM_SUBCMD_AMBIGUOUS, true);
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg() {
static EXPECTED: &str =
"error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
\tIf you tried to supply `--subcmarg` as a value rather than a flag, use `-- --subcmarg`
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
let cmd = Command::new("dym").subcommand(
Command::new("subcmd").arg(arg!(-s --subcmdarg <subcmdarg> "tests").required(false)),
);
utils::assert_output(cmd, "dym --subcmarg subcmd", EXPECTED, true);
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg_false_positives() {
static EXPECTED: &str =
"error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
\tIf you tried to supply `--subcmarg` as a value rather than a flag, use `-- --subcmarg`
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
let cmd = Command::new("dym").subcommand(
Command::new("subcmd").arg(arg!(-s --subcmdarg <subcmdarg> "tests").required(false)),
);
utils::assert_output(cmd, "dym --subcmarg foo", EXPECTED, true);
}
#[test]
fn alias_help() {
let m = Command::new("myprog")
.subcommand(Command::new("test").alias("do-stuff"))
.try_get_matches_from(vec!["myprog", "help", "do-stuff"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::DisplayHelp);
}
#[test]
fn visible_aliases_help_output() {
let cmd = Command::new("clap-test").version("2.6").subcommand(
Command::new("test")
.about("Some help")
.alias("invisible")
.visible_alias("dongle")
.visible_alias("done"),
);
utils::assert_output(cmd, "clap-test --help", VISIBLE_ALIAS_HELP, false);
}
#[test]
fn invisible_aliases_help_output() {
let cmd = Command::new("clap-test")
.version("2.6")
.subcommand(Command::new("test").about("Some help").alias("invisible"));
utils::assert_output(cmd, "clap-test --help", INVISIBLE_ALIAS_HELP, false);
}
#[test]
#[cfg(feature = "unstable-replace")]
fn replace() {
let m = Command::new("prog")
.subcommand(
Command::new("module").subcommand(Command::new("install").about("Install module")),
)
.replace("install", &["module", "install"])
.try_get_matches_from(vec!["prog", "install"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("module"));
assert_eq!(
m.subcommand_matches("module").unwrap().subcommand_name(),
Some("install")
);
}
#[test]
fn issue_1031_args_with_same_name() {
let res = Command::new("prog")
.arg(arg!(--"ui-path" <PATH>))
.subcommand(Command::new("signer"))
.try_get_matches_from(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 = Command::new("prog")
.arg(arg!(--"ui-path" <PATH>))
.subcommand(Command::new("signer"))
.try_get_matches_from(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"));
}
#[test]
fn issue_1161_multiple_hyphen_hyphen() {
// from example 22
let res = Command::new("myprog")
.arg(Arg::new("eff").short('f'))
.arg(Arg::new("pea").short('p').takes_value(true))
.arg(
Arg::new("slop")
.takes_value(true)
.multiple_values(true)
.last(true),
)
.try_get_matches_from(vec![
"-f",
"-p=bob",
"--",
"sloppy",
"slop",
"-a",
"--",
"subprogram",
"position",
"args",
]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind());
let m = res.unwrap();
let expected = Some(vec![
"sloppy",
"slop",
"-a",
"--",
"subprogram",
"position",
"args",
]);
let actual = m.values_of("slop").map(|vals| vals.collect::<Vec<_>>());
assert_eq!(expected, actual);
}
#[test]
fn issue_1722_not_emit_error_when_arg_follows_similar_to_a_subcommand() {
let m = Command::new("myprog")
.subcommand(Command::new("subcommand"))
.arg(Arg::new("argument"))
.try_get_matches_from(vec!["myprog", "--", "subcommand"]);
assert_eq!(m.unwrap().value_of("argument"), Some("subcommand"));
}
#[test]
fn subcommand_placeholder_test() {
let mut cmd = Command::new("myprog")
.subcommand(Command::new("subcommand"))
.subcommand_value_name("TEST_PLACEHOLDER")
.subcommand_help_heading("TEST_HEADER");
assert_eq!(&cmd.render_usage(), "USAGE:\n myprog [TEST_PLACEHOLDER]");
let mut help_text = Vec::new();
cmd.write_help(&mut help_text)
.expect("Failed to write to internal buffer");
assert!(String::from_utf8(help_text)
.unwrap()
.contains("TEST_HEADER:"));
}
#[test]
fn subcommand_used_after_double_dash() {
let cmd = Command::new("cmd").subcommand(Command::new("subcmd"));
utils::assert_output(cmd, "cmd -- subcmd", SUBCMD_AFTER_DOUBLE_DASH, true);
}
#[test]
fn subcommand_after_argument() {
let m = Command::new("myprog")
.arg(Arg::new("some_text"))
.subcommand(Command::new("test"))
.try_get_matches_from(vec!["myprog", "teat", "test"])
.unwrap();
assert_eq!(m.value_of("some_text"), Some("teat"));
assert_eq!(m.subcommand().unwrap().0, "test");
}
#[test]
fn subcommand_after_argument_looks_like_help() {
let m = Command::new("myprog")
.arg(Arg::new("some_text"))
.subcommand(Command::new("test"))
.try_get_matches_from(vec!["myprog", "helt", "test"])
.unwrap();
assert_eq!(m.value_of("some_text"), Some("helt"));
assert_eq!(m.subcommand().unwrap().0, "test");
}
#[test]
fn issue_2494_subcommand_is_present() {
let cmd = Command::new("opt")
.arg(Arg::new("global").long("global"))
.subcommand(Command::new("global"));
let m = cmd
.clone()
.try_get_matches_from(&["opt", "--global", "global"])
.unwrap();
assert_eq!(m.subcommand_name().unwrap(), "global");
assert!(m.is_present("global"));
let m = cmd
.clone()
.try_get_matches_from(&["opt", "--global"])
.unwrap();
assert!(m.subcommand_name().is_none());
assert!(m.is_present("global"));
let m = cmd.try_get_matches_from(&["opt", "global"]).unwrap();
assert_eq!(m.subcommand_name().unwrap(), "global");
assert!(!m.is_present("global"));
}
#[test]
fn subcommand_not_recognized() {
let cmd = Command::new("fake")
.subcommand(Command::new("sub"))
.disable_help_subcommand(true)
.infer_subcommands(true);
utils::assert_output(
cmd,
"fake help",
"error: The subcommand 'help' wasn't recognized
USAGE:
fake [SUBCOMMAND]
For more information try --help
",
true,
);
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn busybox_like_multicall() {
fn applet_commands() -> [Command<'static>; 2] {
[Command::new("true"), Command::new("false")]
}
let cmd = Command::new("busybox")
.multicall(true)
.subcommand(Command::new("busybox").subcommands(applet_commands()))
.subcommands(applet_commands());
let m = cmd
.clone()
.try_get_matches_from(&["busybox", "true"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("busybox"));
assert_eq!(m.subcommand().unwrap().1.subcommand_name(), Some("true"));
let m = cmd.clone().try_get_matches_from(&["true"]).unwrap();
assert_eq!(m.subcommand_name(), Some("true"));
let m = cmd.clone().try_get_matches_from(&["a.out"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnrecognizedSubcommand);
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn hostname_like_multicall() {
let mut cmd = Command::new("hostname")
.multicall(true)
.subcommand(Command::new("hostname"))
.subcommand(Command::new("dnsdomainname"));
let m = cmd.clone().try_get_matches_from(&["hostname"]).unwrap();
assert_eq!(m.subcommand_name(), Some("hostname"));
let m = cmd
.clone()
.try_get_matches_from(&["dnsdomainname"])
.unwrap();
assert_eq!(m.subcommand_name(), Some("dnsdomainname"));
let m = cmd.clone().try_get_matches_from(&["a.out"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnrecognizedSubcommand);
let m = cmd.try_get_matches_from_mut(&["hostname", "hostname"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
let m = cmd.try_get_matches_from(&["hostname", "dnsdomainname"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn bad_multicall_command_error() {
let cmd = Command::new("repl")
.version("1.0.0")
.propagate_version(true)
.multicall(true)
.subcommand(Command::new("foo"))
.subcommand(Command::new("bar"));
let err = cmd.clone().try_get_matches_from(&["world"]).unwrap_err();
assert_eq!(err.kind(), ErrorKind::UnrecognizedSubcommand);
static HELLO_EXPECTED: &str = "\
error: The subcommand 'world' wasn't recognized
USAGE:
<SUBCOMMAND>
For more information try help
";
utils::assert_eq(HELLO_EXPECTED, err.to_string());
let err = cmd.clone().try_get_matches_from(&["baz"]).unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidSubcommand);
static BAZ_EXPECTED: &str = "\
error: The subcommand 'baz' wasn't recognized
\tDid you mean 'bar'?
If you believe you received this message in error, try re-running with ' -- baz'
USAGE:
<SUBCOMMAND>
For more information try help
";
utils::assert_eq(BAZ_EXPECTED, err.to_string());
// Verify whatever we did to get the above to work didn't disable `--help` and `--version`.
let err = cmd
.clone()
.try_get_matches_from(&["foo", "--help"])
.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayHelp);
let err = cmd
.clone()
.try_get_matches_from(&["foo", "--version"])
.unwrap_err();
assert_eq!(err.kind(), ErrorKind::DisplayVersion);
}
#[cfg(feature = "unstable-multicall")]
#[test]
#[should_panic = "Command repl: Arguments like oh-no cannot be set on a multicall command"]
fn cant_have_args_with_multicall() {
let mut cmd = Command::new("repl")
.version("1.0.0")
.propagate_version(true)
.multicall(true)
.subcommand(Command::new("foo"))
.subcommand(Command::new("bar"))
.arg(Arg::new("oh-no"));
cmd.build();
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn multicall_help_flag() {
static EXPECTED: &str = "\
foo-bar 1.0.0
USAGE:
foo bar [value]
ARGS:
<value>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
let cmd = Command::new("repl")
.version("1.0.0")
.propagate_version(true)
.multicall(true)
.subcommand(Command::new("foo").subcommand(Command::new("bar").arg(Arg::new("value"))));
utils::assert_output(cmd, "foo bar --help", EXPECTED, false);
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn multicall_help_subcommand() {
static EXPECTED: &str = "\
foo-bar 1.0.0
USAGE:
foo bar [value]
ARGS:
<value>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
let cmd = Command::new("repl")
.version("1.0.0")
.propagate_version(true)
.multicall(true)
.subcommand(Command::new("foo").subcommand(Command::new("bar").arg(Arg::new("value"))));
utils::assert_output(cmd, "help foo bar", EXPECTED, false);
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn multicall_render_help() {
static EXPECTED: &str = "\
foo-bar 1.0.0
USAGE:
foo bar [value]
ARGS:
<value>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
";
let mut cmd = Command::new("repl")
.version("1.0.0")
.propagate_version(true)
.multicall(true)
.subcommand(Command::new("foo").subcommand(Command::new("bar").arg(Arg::new("value"))));
cmd.build();
let subcmd = cmd.find_subcommand_mut("foo").unwrap();
let subcmd = subcmd.find_subcommand_mut("bar").unwrap();
let mut buf = Vec::new();
subcmd.write_help(&mut buf).unwrap();
utils::assert_eq(EXPECTED, String::from_utf8(buf).unwrap());
}

View file

@ -0,0 +1,149 @@
use super::utils;
use clap::{arg, Command};
static EXAMPLE1_TMPL_S: &str = "{bin} {version}
{author}
{about}
USAGE:
{usage}
{all-args}";
static EXAMPLE1_TMPS_F: &str = "{bin} {version}
{author}
{about}
USAGE:
{usage}
OPTIONS:
{options}
ARGS:
{positionals}
SUBCOMMANDS:
{subcommands}";
static CUSTOM_TEMPL_HELP: &str = "MyApp 1.0
Kevin K. <kbknapp@gmail.com>
Does awesome things
USAGE:
MyApp [OPTIONS] <output> [SUBCOMMAND]
OPTIONS:
-c, --config <FILE> Sets a custom config file
-d Turn debugging information on
-h, --help Print help information
-V, --version Print version information
ARGS:
<output> Sets an optional output file
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test does testing things
";
static SIMPLE_TEMPLATE: &str = "MyApp 1.0
Kevin K. <kbknapp@gmail.com>
Does awesome things
USAGE:
MyApp [OPTIONS] <output> [SUBCOMMAND]
ARGS:
<output> Sets an optional output file
OPTIONS:
-c, --config <FILE> Sets a custom config file
-d Turn debugging information on
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test does testing things
";
#[test]
fn with_template() {
let cmd = get_app().help_template(EXAMPLE1_TMPL_S);
utils::assert_output(cmd, "MyApp --help", SIMPLE_TEMPLATE, false);
}
#[test]
fn custom_template() {
let cmd = get_app().help_template(EXAMPLE1_TMPS_F);
utils::assert_output(cmd, "MyApp --help", CUSTOM_TEMPL_HELP, false);
}
#[test]
fn template_empty() {
let cmd = Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.help_template("");
utils::assert_output(cmd, "MyApp --help", "\n", false);
}
#[test]
fn template_notag() {
let cmd = Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.help_template("test no tag test");
utils::assert_output(cmd, "MyApp --help", "test no tag test\n", false);
}
#[test]
fn template_unknowntag() {
let cmd = Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.help_template("test {unknown_tag} test");
utils::assert_output(cmd, "MyApp --help", "test {unknown_tag} test\n", false);
}
#[test]
fn template_author_version() {
let cmd = Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.help_template("{author}\n{version}\n{about}\n{bin}");
utils::assert_output(
cmd,
"MyApp --help",
"Kevin K. <kbknapp@gmail.com>\n1.0\nDoes awesome things\nMyApp\n",
false,
);
}
// ----------
fn get_app() -> Command<'static> {
Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.arg(
arg!(
-c --config <FILE> "Sets a custom config file"
)
.required(false),
)
.arg(arg!(
<output> "Sets an optional output file"
))
.arg(arg!(
d: -d ... "Turn debugging information on"
))
.subcommand(
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values")),
)
}

View file

@ -0,0 +1,426 @@
use super::utils;
use std::io::Write;
use std::str;
use clap::{Arg, Command};
static SCF2OP: &str = "flag present 2 times
option NOT present
positional NOT present
flag2 NOT present
option2 maybe present with value of: Nothing
positional2 maybe present with value of: Nothing
option3 NOT present
positional3 NOT present
option NOT present
positional NOT present
subcmd present
flag present 2 times
scoption present with value: some
An scoption: some
scpositional present with value: value
";
static SCFOP: &str = "flag present 1 times
option NOT present
positional NOT present
flag2 NOT present
option2 maybe present with value of: Nothing
positional2 maybe present with value of: Nothing
option3 NOT present
positional3 NOT present
option NOT present
positional NOT present
subcmd present
flag present 1 times
scoption present with value: some
An scoption: some
scpositional present with value: value
";
static O2P: &str = "flag NOT present
option present 2 times with value: some
An option: some
An option: other
positional present with value: value
flag2 NOT present
option2 maybe present with value of: Nothing
positional2 maybe present with value of: Nothing
option3 NOT present
positional3 NOT present
option present 2 times with value: some
An option: some
An option: other
positional present with value: value
subcmd NOT present
";
static F2OP: &str = "flag present 2 times
option present 1 times with value: some
An option: some
positional present with value: value
flag2 NOT present
option2 maybe present with value of: Nothing
positional2 maybe present with value of: Nothing
option3 NOT present
positional3 NOT present
option present 1 times with value: some
An option: some
positional present with value: value
subcmd NOT present
";
static FOP: &str = "flag present 1 times
option present 1 times with value: some
An option: some
positional present with value: value
flag2 NOT present
option2 maybe present with value of: Nothing
positional2 maybe present with value of: Nothing
option3 NOT present
positional3 NOT present
option present 1 times with value: some
An option: some
positional present with value: value
subcmd NOT present
";
pub fn check_complex_output(args: &str, out: &str) {
let mut w = vec![];
let matches = utils::complex_app()
.try_get_matches_from(args.split(' ').collect::<Vec<_>>())
.unwrap();
if matches.is_present("flag") {
writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap();
} else {
writeln!(w, "flag NOT present").unwrap();
}
if matches.is_present("option") {
if let Some(v) = matches.value_of("option") {
writeln!(
w,
"option present {} times with value: {}",
matches.occurrences_of("option"),
v
)
.unwrap();
}
if let Some(ov) = matches.values_of("option") {
for o in ov {
writeln!(w, "An option: {}", o).unwrap();
}
}
} else {
writeln!(w, "option NOT present").unwrap();
}
if let Some(p) = matches.value_of("positional") {
writeln!(w, "positional present with value: {}", p).unwrap();
} else {
writeln!(w, "positional NOT present").unwrap();
}
if matches.is_present("flag2") {
writeln!(w, "flag2 present").unwrap();
writeln!(
w,
"option2 present with value of: {}",
matches.value_of("long-option-2").unwrap()
)
.unwrap();
writeln!(
w,
"positional2 present with value of: {}",
matches.value_of("positional2").unwrap()
)
.unwrap();
} else {
writeln!(w, "flag2 NOT present").unwrap();
writeln!(
w,
"option2 maybe present with value of: {}",
matches.value_of("long-option-2").unwrap_or("Nothing")
)
.unwrap();
writeln!(
w,
"positional2 maybe present with value of: {}",
matches.value_of("positional2").unwrap_or("Nothing")
)
.unwrap();
}
let _ = match matches.value_of("option3").unwrap_or("") {
"fast" => writeln!(w, "option3 present quickly"),
"slow" => writeln!(w, "option3 present slowly"),
_ => writeln!(w, "option3 NOT present"),
};
let _ = match matches.value_of("positional3").unwrap_or("") {
"vi" => writeln!(w, "positional3 present in vi mode"),
"emacs" => writeln!(w, "positional3 present in emacs mode"),
_ => writeln!(w, "positional3 NOT present"),
};
if matches.is_present("option") {
if let Some(v) = matches.value_of("option") {
writeln!(
w,
"option present {} times with value: {}",
matches.occurrences_of("option"),
v
)
.unwrap();
}
if let Some(ov) = matches.values_of("option") {
for o in ov {
writeln!(w, "An option: {}", o).unwrap();
}
}
} else {
writeln!(w, "option NOT present").unwrap();
}
if let Some(p) = matches.value_of("positional") {
writeln!(w, "positional present with value: {}", p).unwrap();
} else {
writeln!(w, "positional NOT present").unwrap();
}
if let Some("subcmd") = matches.subcommand_name() {
writeln!(w, "subcmd present").unwrap();
if let Some(matches) = matches.subcommand_matches("subcmd") {
if matches.is_present("flag") {
writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap();
} else {
writeln!(w, "flag NOT present").unwrap();
}
if matches.is_present("option") {
if let Some(v) = matches.value_of("option") {
writeln!(w, "scoption present with value: {}", v).unwrap();
}
if let Some(ov) = matches.values_of("option") {
for o in ov {
writeln!(w, "An scoption: {}", o).unwrap();
}
}
} else {
writeln!(w, "scoption NOT present").unwrap();
}
if let Some(p) = matches.value_of("scpositional") {
writeln!(w, "scpositional present with value: {}", p).unwrap();
}
}
} else {
writeln!(w, "subcmd NOT present").unwrap();
}
let res = str::from_utf8(&w).unwrap();
assert_eq!(res, out);
}
#[test]
fn create_app() {
let _ = Command::new("test")
.version("1.0")
.author("kevin")
.about("does awesome things")
.try_get_matches_from(vec![""])
.unwrap();
}
#[test]
fn add_multiple_arg() {
let _ = Command::new("test")
.args(&[Arg::new("test").short('s'), Arg::new("test2").short('l')])
.try_get_matches_from(vec![""])
.unwrap();
}
#[test]
fn flag_x2_opt() {
check_complex_output(
"clap-test value -f -f -o some",
"flag present 2 times
option present 1 times with value: some
An option: some
positional present with value: value
flag2 NOT present
option2 maybe present with value of: Nothing
positional2 maybe present with value of: Nothing
option3 NOT present
positional3 NOT present
option present 1 times with value: some
An option: some
positional present with value: value
subcmd NOT present
",
);
}
#[test]
fn long_opt_x2_pos() {
check_complex_output("clap-test value --option some --option other", O2P);
}
#[test]
fn long_opt_eq_x2_pos() {
check_complex_output("clap-test value --option=some --option=other", O2P);
}
#[test]
fn short_opt_x2_pos() {
check_complex_output("clap-test value -o some -o other", O2P);
}
#[test]
fn short_opt_eq_x2_pos() {
check_complex_output("clap-test value -o=some -o=other", O2P);
}
#[test]
fn short_flag_x2_comb_short_opt_pos() {
check_complex_output("clap-test value -ff -o some", F2OP);
}
#[test]
fn short_flag_short_opt_pos() {
check_complex_output("clap-test value -f -o some", FOP);
}
#[test]
fn long_flag_long_opt_pos() {
check_complex_output("clap-test value --flag --option some", FOP);
}
#[test]
fn long_flag_long_opt_eq_pos() {
check_complex_output("clap-test value --flag --option=some", FOP);
}
#[test]
fn sc_long_flag_long_opt() {
check_complex_output("clap-test subcmd value --flag --option some", SCFOP);
}
#[test]
fn sc_long_flag_short_opt_pos() {
check_complex_output("clap-test subcmd value --flag -o some", SCFOP);
}
#[test]
fn sc_long_flag_long_opt_eq_pos() {
check_complex_output("clap-test subcmd value --flag --option=some", SCFOP);
}
#[test]
fn sc_short_flag_long_opt_pos() {
check_complex_output("clap-test subcmd value -f --option some", SCFOP);
}
#[test]
fn sc_short_flag_short_opt_pos() {
check_complex_output("clap-test subcmd value -f -o some", SCFOP);
}
#[test]
fn sc_short_flag_short_opt_eq_pos() {
check_complex_output("clap-test subcmd value -f -o=some", SCFOP);
}
#[test]
fn sc_short_flag_long_opt_eq_pos() {
check_complex_output("clap-test subcmd value -f --option=some", SCFOP);
}
#[test]
fn sc_short_flag_x2_comb_long_opt_pos() {
check_complex_output("clap-test subcmd value -ff --option some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_comb_short_opt_pos() {
check_complex_output("clap-test subcmd value -ff -o some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_comb_long_opt_eq_pos() {
check_complex_output("clap-test subcmd value -ff --option=some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_comb_short_opt_eq_pos() {
check_complex_output("clap-test subcmd value -ff -o=some", SCF2OP);
}
#[test]
fn sc_long_flag_x2_long_opt_pos() {
check_complex_output("clap-test subcmd value --flag --flag --option some", SCF2OP);
}
#[test]
fn sc_long_flag_x2_short_opt_pos() {
check_complex_output("clap-test subcmd value --flag --flag -o some", SCF2OP);
}
#[test]
fn sc_long_flag_x2_short_opt_eq_pos() {
check_complex_output("clap-test subcmd value --flag --flag -o=some", SCF2OP);
}
#[test]
fn sc_long_flag_x2_long_opt_eq_pos() {
check_complex_output("clap-test subcmd value --flag --flag --option=some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_long_opt_pos() {
check_complex_output("clap-test subcmd value -f -f --option some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_short_opt_pos() {
check_complex_output("clap-test subcmd value -f -f -o some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_short_opt_eq_pos() {
check_complex_output("clap-test subcmd value -f -f -o=some", SCF2OP);
}
#[test]
fn sc_short_flag_x2_long_opt_eq_pos() {
check_complex_output("clap-test subcmd value -f -f --option=some", SCF2OP);
}
#[test]
fn mut_arg_all() {
let mut cmd = utils::complex_app();
let arg_names = cmd
.get_arguments()
.map(|a| a.get_id())
.filter(|a| *a != "version" && *a != "help")
.collect::<Vec<_>>();
for arg_name in arg_names {
cmd = cmd.mut_arg(arg_name, |arg| arg.hide_possible_values(true));
}
}
#[test]
fn issue_3669_command_build_recurses() {
let mut cmd = Command::new("ctest").subcommand(
Command::new("subcmd").subcommand(
Command::new("multi")
.about("tests subcommands")
.author("Kevin K. <kbknapp@gmail.com>")
.version("0.1")
.arg(clap::arg!(
<FLAG> "tests flags"
)),
),
);
cmd.build();
}

View file

@ -0,0 +1,18 @@
#![cfg(feature = "unicode")]
#[test]
fn possible_values_ignore_case() {
let m = clap::Command::new("pv")
.arg(
clap::Arg::new("option")
.short('o')
.long("option")
.takes_value(true)
.possible_value("ä")
.ignore_case(true),
)
.try_get_matches_from(vec!["pv", "--option", "Ä"]);
assert!(m.is_ok(), "{}", m.unwrap_err());
assert!(m.unwrap().value_of("option").is_some());
}

View file

@ -0,0 +1,32 @@
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument names must be unique, but 'arg1' is in use by more than one argument or group"]
fn unique_arg_names() {
use clap::{Arg, Command};
let _ = Command::new("some")
.args(&[Arg::new("arg1").short('a'), Arg::new("arg1").short('b')])
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Short option names must be unique for each argument, but '-a' is in use by both 'arg1' and 'arg2'"]
fn unique_arg_shorts() {
use clap::{Arg, Command};
let _ = Command::new("some")
.args(&[Arg::new("arg1").short('a'), Arg::new("arg2").short('a')])
.try_get_matches();
}
#[cfg(debug_assertions)]
#[test]
#[should_panic = "Long option names must be unique for each argument, but '--long' is in use by both 'arg1' and 'arg2'"]
fn unique_arg_longs() {
use clap::{Arg, Command};
let _ = Command::new("some")
.args(&[Arg::new("arg1").long("long"), Arg::new("arg2").long("long")])
.try_get_matches();
}

View file

@ -0,0 +1,169 @@
//! These Windows-only tests are ported from the Unix-only tests in
//! tests/utf16.rs. The tests that use StrictUtf8 mode are omitted here,
//! because that's a Unix-only feature.
#![cfg(windows)]
use clap::{arg, Command};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
// Take a slice of ASCII bytes, convert them to UTF-16, and then append a
// dangling surrogate character to make the result invalid UTF-16.
fn bad_osstring(ascii: &[u8]) -> OsString {
let mut wide_chars: Vec<u16> = ascii.iter().map(|&c| c as u16).collect();
// UTF-16 surrogate characters are only valid in pairs.
let surrogate_char: u16 = 0xDC00;
wide_chars.push(surrogate_char);
let os = OsString::from_wide(&wide_chars);
assert!(os.to_str().is_none(), "invalid Unicode");
os
}
#[test]
fn invalid_utf16_lossy_positional() {
let r = Command::new("bad_utf16")
.arg(arg!(<arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf16_lossy_option_short_space() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("-a"),
bad_osstring(b""),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf16_lossy_option_short_equals() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"-a=")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf16_lossy_option_short_no_space() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"-a")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf16_lossy_option_long_space() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("--arg"),
bad_osstring(b""),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf16_lossy_option_long_equals() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"--arg=")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf16_positional() {
let r = Command::new("bad_utf16")
.arg(arg!(<arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*bad_osstring(b""));
}
#[test]
fn invalid_utf16_option_short_space() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("-a"),
bad_osstring(b""),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*bad_osstring(b""));
}
#[test]
fn invalid_utf16_option_short_equals() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"-a=")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*bad_osstring(b""));
}
#[test]
fn invalid_utf16_option_short_no_space() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"-a")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*bad_osstring(b""));
}
#[test]
fn invalid_utf16_option_long_space() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("--arg"),
bad_osstring(b""),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*bad_osstring(b""));
}
#[test]
fn invalid_utf16_option_long_equals() {
let r = Command::new("bad_utf16")
.arg(arg!(-a --arg <arg> "some arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), bad_osstring(b"--arg=")]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_os("arg").unwrap(), &*bad_osstring(b""));
}

View file

@ -0,0 +1,480 @@
#![cfg(not(windows))]
use clap::{arg, error::ErrorKind, Arg, Command};
use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt;
#[test]
fn invalid_utf8_strict_positional() {
let m = Command::new("bad_utf8")
.arg(Arg::new("arg"))
.try_get_matches_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn invalid_utf8_strict_option_short_space() {
let m = Command::new("bad_utf8")
.arg(Arg::new("arg").short('a').long("arg").takes_value(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("-a"),
OsString::from_vec(vec![0xe9]),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn invalid_utf8_strict_option_short_equals() {
let m = Command::new("bad_utf8")
.arg(Arg::new("arg").short('a').long("arg").takes_value(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn invalid_utf8_strict_option_short_no_space() {
let m = Command::new("bad_utf8")
.arg(Arg::new("arg").short('a').long("arg").takes_value(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn invalid_utf8_strict_option_long_space() {
let m = Command::new("bad_utf8")
.arg(Arg::new("arg").short('a').long("arg").takes_value(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("--arg"),
OsString::from_vec(vec![0xe9]),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn invalid_utf8_strict_option_long_equals() {
let m = Command::new("bad_utf8")
.arg(Arg::new("arg").short('a').long("arg").takes_value(true))
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn invalid_utf8_lossy_positional() {
let r = Command::new("bad_utf8")
.arg(Arg::new("arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf8_lossy_option_short_space() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("-a"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf8_lossy_option_short_equals() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf8_lossy_option_short_no_space() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf8_lossy_option_long_space() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("--arg"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf8_lossy_option_long_equals() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
}
#[test]
fn invalid_utf8_positional() {
let r = Command::new("bad_utf8")
.arg(Arg::new("arg").allow_invalid_utf8(true))
.try_get_matches_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
}
#[test]
fn invalid_utf8_option_short_space() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("-a"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
}
#[test]
fn invalid_utf8_option_short_equals() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
}
#[test]
fn invalid_utf8_option_short_no_space() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
}
#[test]
fn invalid_utf8_option_long_space() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("--arg"),
OsString::from_vec(vec![0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
}
#[test]
fn invalid_utf8_option_long_equals() {
let r = Command::new("bad_utf8")
.arg(
Arg::new("arg")
.short('a')
.long("arg")
.takes_value(true)
.allow_invalid_utf8(true),
)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
]);
assert!(r.is_ok(), "{}", r.unwrap_err());
let m = r.unwrap();
assert!(m.is_present("arg"));
assert_eq!(
&*m.value_of_os("arg").unwrap(),
&*OsString::from_vec(vec![0xe9])
);
}
#[test]
fn refuse_invalid_utf8_subcommand_with_allow_external_subcommands() {
let m = Command::new("bad_utf8")
.allow_external_subcommands(true)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0xe9]),
OsString::from("normal"),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn refuse_invalid_utf8_subcommand_when_args_are_allowed_with_allow_external_subcommands() {
let m = Command::new("bad_utf8")
.allow_external_subcommands(true)
.allow_invalid_utf8_for_external_subcommands(true)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from_vec(vec![0xe9]),
OsString::from("normal"),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn refuse_invalid_utf8_subcommand_args_with_allow_external_subcommands() {
let m = Command::new("bad_utf8")
.allow_external_subcommands(true)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("subcommand"),
OsString::from("normal"),
OsString::from_vec(vec![0xe9]),
OsString::from("--another_normal"),
]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
}
#[test]
fn allow_invalid_utf8_subcommand_args_with_allow_external_subcommands() {
let m = Command::new("bad_utf8")
.allow_external_subcommands(true)
.allow_invalid_utf8_for_external_subcommands(true)
.try_get_matches_from(vec![
OsString::from(""),
OsString::from("subcommand"),
OsString::from("normal"),
OsString::from_vec(vec![0xe9]),
OsString::from("--another_normal"),
]);
assert!(m.is_ok(), "{}", m.unwrap_err());
let m = m.unwrap();
let (subcommand, args) = m.subcommand().unwrap();
let args = args.values_of_os("").unwrap().collect::<Vec<_>>();
assert_eq!(subcommand, OsString::from("subcommand"));
assert_eq!(
args,
vec![
OsString::from("normal"),
OsString::from_vec(vec![0xe9]),
OsString::from("--another_normal"),
]
);
}
#[test]
fn allow_validated_utf8_value_of() {
let a = Command::new("test").arg(arg!(--name <NAME>));
let m = a.try_get_matches_from(["test", "--name", "me"]).unwrap();
let _ = m.value_of("name");
}
#[test]
#[should_panic = "Must use `Arg::allow_invalid_utf8` with `_os` lookups at `name`"]
fn panic_validated_utf8_value_of_os() {
let a = Command::new("test").arg(arg!(--name <NAME>));
let m = a.try_get_matches_from(["test", "--name", "me"]).unwrap();
let _ = m.value_of_os("name");
}
#[test]
#[should_panic = "Must use `Arg::allow_invalid_utf8` with `_os` lookups at `value`"]
fn panic_validated_utf8_with_defaults() {
let a = Command::new("test").arg(arg!(--value <VALUE>).required(false).default_value("foo"));
let m = a.try_get_matches_from(["test"]).unwrap();
let _ = m.value_of("value");
let _ = m.value_of_os("value");
}
#[test]
fn allow_invalid_utf8_value_of_os() {
let a = Command::new("test").arg(arg!(--name <NAME>).allow_invalid_utf8(true));
let m = a.try_get_matches_from(["test", "--name", "me"]).unwrap();
let _ = m.value_of_os("name");
}
#[test]
#[should_panic = "Must use `_os` lookups with `Arg::allow_invalid_utf8` at `name`"]
fn panic_invalid_utf8_value_of() {
let a = Command::new("test").arg(arg!(--name <NAME>).allow_invalid_utf8(true));
let m = a.try_get_matches_from(["test", "--name", "me"]).unwrap();
let _ = m.value_of("name");
}
#[test]
#[should_panic = "Must use `_os` lookups with `Arg::allow_invalid_utf8` at `value`"]
fn panic_invalid_utf8_with_defaults() {
let a = Command::new("test").arg(
arg!(--value <VALUE>)
.required(false)
.default_value("foo")
.allow_invalid_utf8(true),
);
let m = a.try_get_matches_from(["test"]).unwrap();
let _ = m.value_of("value");
let _ = m.value_of_os("value");
}
#[test]
fn allow_validated_utf8_external_subcommand_values_of() {
let a = Command::new("test").allow_external_subcommands(true);
let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
let (_ext, args) = m.subcommand().unwrap();
let _ = args.values_of("").unwrap_or_default().count();
}
#[test]
#[should_panic = "Must use `Arg::allow_invalid_utf8` with `_os` lookups"]
fn panic_validated_utf8_external_subcommand_values_of_os() {
let a = Command::new("test").allow_external_subcommands(true);
let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
let (_ext, args) = m.subcommand().unwrap();
let _ = args.values_of_os("").unwrap_or_default().count();
}
#[test]
fn allow_invalid_utf8_external_subcommand_values_of_os() {
let a = Command::new("test")
.allow_external_subcommands(true)
.allow_invalid_utf8_for_external_subcommands(true);
let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
let (_ext, args) = m.subcommand().unwrap();
let _ = args.values_of_os("").unwrap_or_default().count();
}
#[test]
#[should_panic = "Must use `_os` lookups with `Arg::allow_invalid_utf8`"]
fn panic_invalid_utf8_external_subcommand_values_of() {
let a = Command::new("test")
.allow_external_subcommands(true)
.allow_invalid_utf8_for_external_subcommands(true);
let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
let (_ext, args) = m.subcommand().unwrap();
let _ = args.values_of("").unwrap_or_default().count();
}

View file

@ -0,0 +1,107 @@
#![allow(unused_imports, dead_code)]
use std::io::{BufRead, Cursor, Write};
use std::str;
use regex::Regex;
use clap::{arg, Arg, ArgGroup, Command};
#[track_caller]
pub fn assert_eq<S, S2>(expected: S, actual: S2)
where
S: AsRef<str>,
S2: AsRef<str>,
{
let expected = expected.as_ref();
let actual = actual.as_ref();
snapbox::assert_eq(expected, actual);
}
#[track_caller]
pub fn assert_output(l: Command, args: &str, expected: &str, stderr: bool) {
let mut buf = Cursor::new(Vec::with_capacity(50));
let res = l.try_get_matches_from(args.split(' ').collect::<Vec<_>>());
let err = res.unwrap_err();
write!(&mut buf, "{}", err).unwrap();
let actual = buf.into_inner();
let actual = String::from_utf8(actual).unwrap();
assert_eq!(
stderr,
err.use_stderr(),
"Should Use STDERR failed. Should be {} but is {}",
stderr,
err.use_stderr()
);
assert_eq(expected, actual)
}
// Legacy tests from the python script days
pub fn complex_app() -> Command<'static> {
let opt3_vals = ["fast", "slow"];
let pos3_vals = ["vi", "emacs"];
Command::new("clap-test")
.version("v1.4.8")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(
arg!(
-o --option <opt> "tests options"
)
.required(false)
.multiple_values(true)
.multiple_occurrences(true),
)
.arg(arg!([positional] "tests positionals"))
.arg(arg!(-f --flag ... "tests flags").global(true))
.args(&[
arg!(flag2: -F "tests flags with exclusions")
.conflicts_with("flag")
.requires("long-option-2"),
arg!(--"long-option-2" <option2> "tests long options with exclusions")
.required(false)
.conflicts_with("option")
.requires("positional2"),
arg!([positional2] "tests positionals with exclusions"),
arg!(-O --option3 <option3> "specific vals")
.required(false)
.possible_values(opt3_vals),
arg!([positional3] ... "tests specific values").possible_values(pos3_vals),
arg!(--multvals "Tests multiple values, not mult occs")
.value_names(&["one", "two"])
.required(false),
arg!(--multvalsmo ... "Tests multiple values, and mult occs")
.value_names(&["one", "two"])
.required(false),
arg!(--minvals2 <minvals> "Tests 2 min vals")
.required(false)
.min_values(2),
arg!(--maxvals3 <maxvals> "Tests 3 max vals")
.required(false)
.max_values(3),
arg!(--optvaleq <optval> "Tests optional value, require = sign")
.required(false)
.min_values(0)
.number_of_values(1)
.require_equals(true),
arg!(--optvalnoeq <optval> "Tests optional value")
.required(false)
.min_values(0)
.number_of_values(1),
])
.subcommand(
Command::new("subcmd")
.about("tests subcommands")
.version("0.1")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(
arg!(-o --option <scoption> "tests options")
.required(false)
.multiple_values(true),
)
.arg(arg!(-s --subcmdarg <subcmdarg> "tests other args").required(false))
.arg(arg!([scpositional] "tests positionals")),
)
}

Some files were not shown because too many files have changed in this diff Show more