mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
Add tests, fix grouped_values_of()
Fix clippy type complexity fix
This commit is contained in:
parent
451c5382cc
commit
58b9f35771
3 changed files with 203 additions and 15 deletions
|
@ -242,8 +242,21 @@ impl ArgMatches {
|
|||
}
|
||||
|
||||
/// Placeholder documentation.
|
||||
pub fn grouped_values_of<T: Key>(&self, id: T) -> Option<Iter<Vec<OsString>>> {
|
||||
self.args.get(&Id::from(id)).map(|arg| arg.vals())
|
||||
pub fn grouped_values_of<T: Key>(&self, id: T) -> Option<GroupedValues> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
let arg_values: for<'a> fn(
|
||||
&'a MatchedArg,
|
||||
) -> Map<
|
||||
std::slice::Iter<'a, Vec<OsString>>,
|
||||
fn(&Vec<OsString>) -> Vec<&str>,
|
||||
> = |arg| {
|
||||
arg.vals()
|
||||
.map(|g| g.iter().map(|x| x.to_str().expect(INVALID_UTF8)).collect())
|
||||
};
|
||||
self.args
|
||||
.get(&Id::from(id))
|
||||
.map(arg_values)
|
||||
.map(|iter| GroupedValues { iter })
|
||||
}
|
||||
|
||||
/// Gets the lossy values of a specific argument. If the option wasn't present at runtime
|
||||
|
@ -991,7 +1004,7 @@ impl ArgMatches {
|
|||
#[allow(missing_debug_implementations)]
|
||||
pub struct Values<'a> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
iter: Map<Flatten<std::slice::Iter<'a, Vec<OsString>>>, for<'r> fn(&'r OsString) -> &'r str>,
|
||||
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, for<'r> fn(&'r OsString) -> &'r str>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Values<'a> {
|
||||
|
@ -1017,12 +1030,44 @@ impl<'a> ExactSizeIterator for Values<'a> {}
|
|||
impl<'a> Default for Values<'a> {
|
||||
fn default() -> Self {
|
||||
static EMPTY: [Vec<OsString>; 0] = [];
|
||||
// This is never called because the iterator is empty:
|
||||
fn to_str_slice(_: &OsString) -> &str {
|
||||
unreachable!()
|
||||
}
|
||||
Values {
|
||||
iter: EMPTY[..].iter().flatten().map(to_str_slice),
|
||||
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct GroupedValues<'a> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
iter: Map<std::slice::Iter<'a, Vec<OsString>>, fn(&Vec<OsString>) -> Vec<&str>>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for GroupedValues<'a> {
|
||||
type Item = Vec<&'a str>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next()
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for GroupedValues<'a> {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for GroupedValues<'a> {}
|
||||
|
||||
/// Creates an empty iterator. Used for `unwrap_or_default()`.
|
||||
impl<'a> Default for GroupedValues<'a> {
|
||||
fn default() -> Self {
|
||||
static EMPTY: [Vec<OsString>; 0] = [];
|
||||
GroupedValues {
|
||||
iter: EMPTY[..].iter().map(|_| unreachable!()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1052,7 +1097,7 @@ impl<'a> Default for Values<'a> {
|
|||
#[allow(missing_debug_implementations)]
|
||||
pub struct OsValues<'a> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
iter: Map<Flatten<std::slice::Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
|
||||
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for OsValues<'a> {
|
||||
|
@ -1078,12 +1123,8 @@ impl<'a> ExactSizeIterator for OsValues<'a> {}
|
|||
impl Default for OsValues<'_> {
|
||||
fn default() -> Self {
|
||||
static EMPTY: [Vec<OsString>; 0] = [];
|
||||
// This is never called because the iterator is empty:
|
||||
fn to_str_slice(_: &OsString) -> &OsStr {
|
||||
unreachable!()
|
||||
}
|
||||
OsValues {
|
||||
iter: EMPTY[..].iter().flatten().map(to_str_slice),
|
||||
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1251,7 +1251,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
vals
|
||||
} else {
|
||||
arg_split.into_iter().collect()
|
||||
arg_split.collect()
|
||||
};
|
||||
let vals = vals.into_iter().map(|x| x.to_os_string()).collect();
|
||||
self.add_multiple_vals_to_arg(arg, vals, matcher, ty, append);
|
||||
|
|
147
tests/grouped_values.rs
Normal file
147
tests/grouped_values.rs
Normal file
|
@ -0,0 +1,147 @@
|
|||
mod utils;
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
#[test]
|
||||
fn value_sets_works() {
|
||||
let m = App::new("cli")
|
||||
.arg(Arg::new("option").long("option").multiple(true))
|
||||
.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",
|
||||
]);
|
||||
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 = App::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").multiple(true))
|
||||
.get_matches_from(&[
|
||||
"backup", "-s", "server", "-u", "user", "--target", "target1", "file1", "file2",
|
||||
"file3", "--target", "target2", "file4", "file5", "file6", "file7", "--target",
|
||||
"target3", "file8",
|
||||
]);
|
||||
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 value_sets_long_flag_delimiter() {
|
||||
let m = App::new("myapp")
|
||||
.arg(
|
||||
Arg::new("option")
|
||||
.long("option")
|
||||
.takes_value(true)
|
||||
.use_delimiter(true)
|
||||
.multiple(true),
|
||||
)
|
||||
.get_matches_from(vec![
|
||||
"myapp",
|
||||
"--option=hmm",
|
||||
"--option=val1,val2,val3",
|
||||
"--option",
|
||||
"alice,bob",
|
||||
]);
|
||||
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 value_sets_short_flag_delimiter() {
|
||||
let m = App::new("myapp")
|
||||
.arg(
|
||||
Arg::new("option")
|
||||
.short('o')
|
||||
.takes_value(true)
|
||||
.use_delimiter(true)
|
||||
.multiple(true),
|
||||
)
|
||||
.get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"]);
|
||||
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 value_sets_positional_arg() {
|
||||
let m = App::new("multiple_values")
|
||||
.arg(Arg::new("pos").about("multiple positionals").multiple(true))
|
||||
.get_matches_from(vec![
|
||||
"myprog", "val1", "val2", "val3", "val4", "val5", "val6",
|
||||
]);
|
||||
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 value_sets_multiple_positional_arg() {
|
||||
let m = App::new("multiple_values")
|
||||
.arg(Arg::new("pos1").about("multiple positionals"))
|
||||
.arg(
|
||||
Arg::new("pos2")
|
||||
.about("multiple positionals")
|
||||
.multiple(true),
|
||||
)
|
||||
.get_matches_from(vec![
|
||||
"myprog", "val1", "val2", "val3", "val4", "val5", "val6",
|
||||
]);
|
||||
let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
|
||||
assert_eq!(
|
||||
grouped_vals,
|
||||
vec![vec!["val2", "val3", "val4", "val5", "val6"]]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_sets_multiple_positional_arg_last_multiple() {
|
||||
let m = App::new("multiple_values")
|
||||
.arg(Arg::new("pos1").about("multiple positionals"))
|
||||
.arg(
|
||||
Arg::new("pos2")
|
||||
.about("multiple positionals")
|
||||
.multiple(true)
|
||||
.last(true),
|
||||
)
|
||||
.get_matches_from(vec![
|
||||
"myprog", "val1", "--", "val2", "val3", "val4", "val5", "val6",
|
||||
]);
|
||||
let grouped_vals: Vec<_> = m.grouped_values_of("pos2").unwrap().collect();
|
||||
assert_eq!(
|
||||
grouped_vals,
|
||||
vec![vec!["val2", "val3", "val4", "val5", "val6"]]
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue