libtest: allow multiple filters
This commit is contained in:
@@ -10,7 +10,7 @@ use super::time::TestTimeOptions;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TestOpts {
|
pub struct TestOpts {
|
||||||
pub list: bool,
|
pub list: bool,
|
||||||
pub filter: Option<String>,
|
pub filters: Vec<String>,
|
||||||
pub filter_exact: bool,
|
pub filter_exact: bool,
|
||||||
pub force_run_in_process: bool,
|
pub force_run_in_process: bool,
|
||||||
pub exclude_should_panic: bool,
|
pub exclude_should_panic: bool,
|
||||||
@@ -148,12 +148,13 @@ fn optgroups() -> getopts::Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(binary: &str, options: &getopts::Options) {
|
fn usage(binary: &str, options: &getopts::Options) {
|
||||||
let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
|
let message = format!("Usage: {} [OPTIONS] [FILTERS...]", binary);
|
||||||
println!(
|
println!(
|
||||||
r#"{usage}
|
r#"{usage}
|
||||||
|
|
||||||
The FILTER string is tested against the name of all tests, and only those
|
The FILTER string is tested against the name of all tests, and only those
|
||||||
tests whose names contain the filter are run.
|
tests whose names contain the filter are run. Multiple filter strings may
|
||||||
|
be passed, which will run all tests matching any of the filters.
|
||||||
|
|
||||||
By default, all tests are run in parallel. This can be altered with the
|
By default, all tests are run in parallel. This can be altered with the
|
||||||
--test-threads flag or the RUST_TEST_THREADS environment variable when running
|
--test-threads flag or the RUST_TEST_THREADS environment variable when running
|
||||||
@@ -243,7 +244,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
|
|||||||
|
|
||||||
let logfile = get_log_file(&matches)?;
|
let logfile = get_log_file(&matches)?;
|
||||||
let run_ignored = get_run_ignored(&matches, include_ignored)?;
|
let run_ignored = get_run_ignored(&matches, include_ignored)?;
|
||||||
let filter = get_filter(&matches)?;
|
let filters = matches.free.clone();
|
||||||
let nocapture = get_nocapture(&matches)?;
|
let nocapture = get_nocapture(&matches)?;
|
||||||
let test_threads = get_test_threads(&matches)?;
|
let test_threads = get_test_threads(&matches)?;
|
||||||
let color = get_color_config(&matches)?;
|
let color = get_color_config(&matches)?;
|
||||||
@@ -253,7 +254,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
|
|||||||
|
|
||||||
let test_opts = TestOpts {
|
let test_opts = TestOpts {
|
||||||
list,
|
list,
|
||||||
filter,
|
filters,
|
||||||
filter_exact: exact,
|
filter_exact: exact,
|
||||||
force_run_in_process,
|
force_run_in_process,
|
||||||
exclude_should_panic,
|
exclude_should_panic,
|
||||||
@@ -397,12 +398,6 @@ fn get_run_ignored(matches: &getopts::Matches, include_ignored: bool) -> OptPart
|
|||||||
Ok(run_ignored)
|
Ok(run_ignored)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_filter(matches: &getopts::Matches) -> OptPartRes<Option<String>> {
|
|
||||||
let filter = if !matches.free.is_empty() { Some(matches.free[0].clone()) } else { None };
|
|
||||||
|
|
||||||
Ok(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_allow_unstable(matches: &getopts::Matches) -> OptPartRes<bool> {
|
fn get_allow_unstable(matches: &getopts::Matches) -> OptPartRes<bool> {
|
||||||
let mut allow_unstable = false;
|
let mut allow_unstable = false;
|
||||||
|
|
||||||
|
|||||||
@@ -359,8 +359,8 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Remove tests that don't match the test filter
|
// Remove tests that don't match the test filter
|
||||||
if let Some(ref filter) = opts.filter {
|
if !opts.filters.is_empty() {
|
||||||
filtered.retain(|test| matches_filter(test, filter));
|
filtered.retain(|test| opts.filters.iter().any(|filter| matches_filter(test, filter)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip tests that match any of the skip filters
|
// Skip tests that match any of the skip filters
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ impl TestOpts {
|
|||||||
fn new() -> TestOpts {
|
fn new() -> TestOpts {
|
||||||
TestOpts {
|
TestOpts {
|
||||||
list: false,
|
list: false,
|
||||||
filter: None,
|
filters: vec![],
|
||||||
filter_exact: false,
|
filter_exact: false,
|
||||||
force_run_in_process: false,
|
force_run_in_process: false,
|
||||||
exclude_should_panic: false,
|
exclude_should_panic: false,
|
||||||
@@ -469,43 +469,60 @@ pub fn exact_filter_match() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let substr =
|
let substr =
|
||||||
filter_tests(&TestOpts { filter: Some("base".into()), ..TestOpts::new() }, tests());
|
filter_tests(&TestOpts { filters: vec!["base".into()], ..TestOpts::new() }, tests());
|
||||||
assert_eq!(substr.len(), 4);
|
|
||||||
|
|
||||||
let substr = filter_tests(&TestOpts { filter: Some("bas".into()), ..TestOpts::new() }, tests());
|
|
||||||
assert_eq!(substr.len(), 4);
|
assert_eq!(substr.len(), 4);
|
||||||
|
|
||||||
let substr =
|
let substr =
|
||||||
filter_tests(&TestOpts { filter: Some("::test".into()), ..TestOpts::new() }, tests());
|
filter_tests(&TestOpts { filters: vec!["bas".into()], ..TestOpts::new() }, tests());
|
||||||
|
assert_eq!(substr.len(), 4);
|
||||||
|
|
||||||
|
let substr =
|
||||||
|
filter_tests(&TestOpts { filters: vec!["::test".into()], ..TestOpts::new() }, tests());
|
||||||
assert_eq!(substr.len(), 3);
|
assert_eq!(substr.len(), 3);
|
||||||
|
|
||||||
let substr =
|
let substr =
|
||||||
filter_tests(&TestOpts { filter: Some("base::test".into()), ..TestOpts::new() }, tests());
|
filter_tests(&TestOpts { filters: vec!["base::test".into()], ..TestOpts::new() }, tests());
|
||||||
assert_eq!(substr.len(), 3);
|
assert_eq!(substr.len(), 3);
|
||||||
|
|
||||||
|
let substr = filter_tests(
|
||||||
|
&TestOpts { filters: vec!["test1".into(), "test2".into()], ..TestOpts::new() },
|
||||||
|
tests(),
|
||||||
|
);
|
||||||
|
assert_eq!(substr.len(), 2);
|
||||||
|
|
||||||
let exact = filter_tests(
|
let exact = filter_tests(
|
||||||
&TestOpts { filter: Some("base".into()), filter_exact: true, ..TestOpts::new() },
|
&TestOpts { filters: vec!["base".into()], filter_exact: true, ..TestOpts::new() },
|
||||||
tests(),
|
tests(),
|
||||||
);
|
);
|
||||||
assert_eq!(exact.len(), 1);
|
assert_eq!(exact.len(), 1);
|
||||||
|
|
||||||
let exact = filter_tests(
|
let exact = filter_tests(
|
||||||
&TestOpts { filter: Some("bas".into()), filter_exact: true, ..TestOpts::new() },
|
&TestOpts { filters: vec!["bas".into()], filter_exact: true, ..TestOpts::new() },
|
||||||
tests(),
|
tests(),
|
||||||
);
|
);
|
||||||
assert_eq!(exact.len(), 0);
|
assert_eq!(exact.len(), 0);
|
||||||
|
|
||||||
let exact = filter_tests(
|
let exact = filter_tests(
|
||||||
&TestOpts { filter: Some("::test".into()), filter_exact: true, ..TestOpts::new() },
|
&TestOpts { filters: vec!["::test".into()], filter_exact: true, ..TestOpts::new() },
|
||||||
tests(),
|
tests(),
|
||||||
);
|
);
|
||||||
assert_eq!(exact.len(), 0);
|
assert_eq!(exact.len(), 0);
|
||||||
|
|
||||||
let exact = filter_tests(
|
let exact = filter_tests(
|
||||||
&TestOpts { filter: Some("base::test".into()), filter_exact: true, ..TestOpts::new() },
|
&TestOpts { filters: vec!["base::test".into()], filter_exact: true, ..TestOpts::new() },
|
||||||
tests(),
|
tests(),
|
||||||
);
|
);
|
||||||
assert_eq!(exact.len(), 1);
|
assert_eq!(exact.len(), 1);
|
||||||
|
|
||||||
|
let exact = filter_tests(
|
||||||
|
&TestOpts {
|
||||||
|
filters: vec!["base".into(), "base::test".into()],
|
||||||
|
filter_exact: true,
|
||||||
|
..TestOpts::new()
|
||||||
|
},
|
||||||
|
tests(),
|
||||||
|
);
|
||||||
|
assert_eq!(exact.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
17
src/test/ui/test-attrs/test-filter-multiple.rs
Normal file
17
src/test/ui/test-attrs/test-filter-multiple.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// run-pass
|
||||||
|
// compile-flags: --test
|
||||||
|
// run-flags: --test-threads=1 test1 test2
|
||||||
|
// check-run-results
|
||||||
|
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||||
|
// ignore-emscripten no threads support
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test1() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test2() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test3() {
|
||||||
|
panic!("this should not run");
|
||||||
|
}
|
||||||
7
src/test/ui/test-attrs/test-filter-multiple.run.stdout
Normal file
7
src/test/ui/test-attrs/test-filter-multiple.run.stdout
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
running 2 tests
|
||||||
|
test test1 ... ok
|
||||||
|
test test2 ... ok
|
||||||
|
|
||||||
|
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in $TIME
|
||||||
|
|
||||||
@@ -240,8 +240,8 @@ pub struct Config {
|
|||||||
/// Run ignored tests
|
/// Run ignored tests
|
||||||
pub run_ignored: bool,
|
pub run_ignored: bool,
|
||||||
|
|
||||||
/// Only run tests that match this filter
|
/// Only run tests that match these filters
|
||||||
pub filter: Option<String>,
|
pub filters: Vec<String>,
|
||||||
|
|
||||||
/// Exactly match the filter, rather than a substring
|
/// Exactly match the filter, rather than a substring
|
||||||
pub filter_exact: bool,
|
pub filter_exact: bool,
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||||||
suite: matches.opt_str("suite").unwrap(),
|
suite: matches.opt_str("suite").unwrap(),
|
||||||
debugger: None,
|
debugger: None,
|
||||||
run_ignored,
|
run_ignored,
|
||||||
filter: matches.free.first().cloned(),
|
filters: matches.free.clone(),
|
||||||
filter_exact: matches.opt_present("exact"),
|
filter_exact: matches.opt_present("exact"),
|
||||||
force_pass_mode: matches.opt_str("pass").map(|mode| {
|
force_pass_mode: matches.opt_str("pass").map(|mode| {
|
||||||
mode.parse::<PassMode>()
|
mode.parse::<PassMode>()
|
||||||
@@ -280,7 +280,7 @@ pub fn log_config(config: &Config) {
|
|||||||
logv(c, format!("stage_id: {}", config.stage_id));
|
logv(c, format!("stage_id: {}", config.stage_id));
|
||||||
logv(c, format!("mode: {}", config.mode));
|
logv(c, format!("mode: {}", config.mode));
|
||||||
logv(c, format!("run_ignored: {}", config.run_ignored));
|
logv(c, format!("run_ignored: {}", config.run_ignored));
|
||||||
logv(c, format!("filter: {}", opt_str(&config.filter)));
|
logv(c, format!("filters: {:?}", config.filters));
|
||||||
logv(c, format!("filter_exact: {}", config.filter_exact));
|
logv(c, format!("filter_exact: {}", config.filter_exact));
|
||||||
logv(
|
logv(
|
||||||
c,
|
c,
|
||||||
@@ -465,7 +465,7 @@ fn configure_lldb(config: &Config) -> Option<Config> {
|
|||||||
pub fn test_opts(config: &Config) -> test::TestOpts {
|
pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||||
test::TestOpts {
|
test::TestOpts {
|
||||||
exclude_should_panic: false,
|
exclude_should_panic: false,
|
||||||
filter: config.filter.clone(),
|
filters: config.filters.clone(),
|
||||||
filter_exact: config.filter_exact,
|
filter_exact: config.filter_exact,
|
||||||
run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
|
run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
|
||||||
format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty },
|
format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty },
|
||||||
|
|||||||
Reference in New Issue
Block a user