#[derive(Debug, Default)]
pub(super) struct HarnessFilters<'args> {
flags: Vec<&'args str>,
filters: Vec<&'args str>,
exact: bool,
}
const VALUED: &[&str] = &[
"--test-threads",
"--logfile",
"--skip",
"--color",
"--format",
"--shuffle-seed",
"-Z",
];
impl<'args> HarnessFilters<'args> {
pub(super) fn parse(args: &'args [String]) -> Self {
let mut parsed = Self::default();
let mut index = 0;
while let Some(arg) = args.get(index) {
let arg = arg.as_str();
if arg.starts_with('-') {
parsed.flags.push(arg);
if arg == "--exact" {
parsed.exact = true;
}
if VALUED.contains(&arg)
&& let Some(value) = args.get(index + 1)
{
parsed.flags.push(value.as_str());
index += 1;
}
} else {
parsed.filters.push(arg);
}
index += 1;
}
parsed
}
pub(super) fn admits(&self, name: &str) -> bool {
if self.filters.is_empty() {
return true;
}
if self.exact {
return self.filters.contains(&name);
}
self.filters.iter().any(|filter| name.contains(filter))
}
pub(super) fn flags(&self) -> &[&'args str] {
&self.flags
}
pub(super) fn selecting(&self) -> Vec<&'args str> {
let mut args: Vec<&str> = Vec::with_capacity(self.flags.len() + self.filters.len());
let mut index = 0;
while let Some(flag) = self.flags.get(index) {
let value = VALUED.contains(flag).then(|| self.flags.get(index + 1)).flatten();
if *flag != "--format" && !flag.starts_with("--format=") {
args.push(flag);
args.extend(value);
}
index += 1 + usize::from(value.is_some());
}
args.extend_from_slice(&self.filters);
args
}
}
#[cfg(test)]
mod tests {
use super::HarnessFilters;
fn args(list: &[&str]) -> Vec<String> {
list.iter().map(|arg| (*arg).to_owned()).collect()
}
#[test]
fn an_option_value_is_not_mistaken_for_a_filter() {
let raw = args(&["--test-threads", "4", "--nocapture", "parser"]);
let parsed = HarnessFilters::parse(&raw);
assert_eq!(parsed.flags(), ["--test-threads", "4", "--nocapture"]);
assert!(parsed.admits("tests::parser_works"));
assert!(!parsed.admits("tests::lexer_works"));
}
#[test]
fn the_joined_spelling_of_an_option_needs_no_lookahead() {
let raw = args(&["--test-threads=4", "parser"]);
let parsed = HarnessFilters::parse(&raw);
assert_eq!(parsed.flags(), ["--test-threads=4"]);
assert!(parsed.admits("tests::parser_works"));
}
#[test]
fn no_positional_filter_admits_everything() {
let raw = args(&["--nocapture"]);
let parsed = HarnessFilters::parse(&raw);
assert!(parsed.admits("anything at all"));
}
#[test]
fn the_users_exact_flag_makes_their_filters_whole_name_matches() {
let raw = args(&["--exact", "tests::parser"]);
let parsed = HarnessFilters::parse(&raw);
assert!(parsed.admits("tests::parser"));
assert!(!parsed.admits("tests::parser_works"), "`--exact` is a whole-name match");
}
#[test]
fn several_filters_are_matched_with_or_exactly_as_libtest_does() {
let raw = args(&["parser", "lexer"]);
let parsed = HarnessFilters::parse(&raw);
assert!(parsed.admits("tests::parser_works"));
assert!(parsed.admits("tests::lexer_works"));
assert!(!parsed.admits("tests::writer_works"));
}
#[test]
fn a_listing_drops_only_the_format_the_user_asked_for() {
let raw = args(&[
"--test-threads",
"4",
"--format",
"json",
"--include-ignored",
"--skip",
"slow",
"--exact",
"parser",
]);
let parsed = HarnessFilters::parse(&raw);
assert_eq!(
parsed.selecting(),
["--test-threads", "4", "--include-ignored", "--skip", "slow", "--exact", "parser"]
);
}
#[test]
fn the_joined_spelling_of_a_format_is_dropped_from_a_listing_too() {
let raw = args(&["--format=json", "--skip=slow", "parser"]);
let parsed = HarnessFilters::parse(&raw);
assert_eq!(parsed.selecting(), ["--skip=slow", "parser"]);
}
}