Skip to content

Commit 9f53c87

Browse files
committed
Auto merge of #53527 - Emerentius:test_all, r=nrc
Add option to run all tests This adds the "--include-ignored" flag to libtest, which allows running ignored and unignored tests in one go. Closes #50363
2 parents cba0fdf + f6f3228 commit 9f53c87

File tree

1 file changed

+119
-81
lines changed

1 file changed

+119
-81
lines changed

src/libtest/lib.rs

+119-81
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in qu
8181
// to be used by rustc to compile tests in libtest
8282
pub mod test {
8383
pub use {assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
84-
Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, ShouldPanic,
84+
Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
8585
StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName,
8686
TestOpts, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk};
8787
}
@@ -349,12 +349,19 @@ pub enum OutputFormat {
349349
Json,
350350
}
351351

352+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
353+
pub enum RunIgnored {
354+
Yes,
355+
No,
356+
Only,
357+
}
358+
352359
#[derive(Debug)]
353360
pub struct TestOpts {
354361
pub list: bool,
355362
pub filter: Option<String>,
356363
pub filter_exact: bool,
357-
pub run_ignored: bool,
364+
pub run_ignored: RunIgnored,
358365
pub run_tests: bool,
359366
pub bench_benchmarks: bool,
360367
pub logfile: Option<PathBuf>,
@@ -373,7 +380,7 @@ impl TestOpts {
373380
list: false,
374381
filter: None,
375382
filter_exact: false,
376-
run_ignored: false,
383+
run_ignored: RunIgnored::No,
377384
run_tests: false,
378385
bench_benchmarks: false,
379386
logfile: None,
@@ -392,7 +399,8 @@ pub type OptRes = Result<TestOpts, String>;
392399

393400
fn optgroups() -> getopts::Options {
394401
let mut opts = getopts::Options::new();
395-
opts.optflag("", "ignored", "Run ignored tests")
402+
opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
403+
.optflag("", "ignored", "Run only ignored tests")
396404
.optflag("", "test", "Run tests and not benchmarks")
397405
.optflag("", "bench", "Run benchmarks instead of tests")
398406
.optflag("", "list", "List all tests and benchmarks")
@@ -491,8 +499,8 @@ Test Attributes:
491499
contain: #[should_panic(expected = "foo")].
492500
#[ignore] - When applied to a function which is already attributed as a
493501
test, then the test runner will ignore these tests during
494-
normal test runs. Running with --ignored will run these
495-
tests."#,
502+
normal test runs. Running with --ignored or --include-ignored will run
503+
these tests."#,
496504
usage = options.usage(&message)
497505
);
498506
}
@@ -545,7 +553,21 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
545553
None
546554
};
547555

548-
let run_ignored = matches.opt_present("ignored");
556+
let include_ignored = matches.opt_present("include-ignored");
557+
if !allow_unstable && include_ignored {
558+
return Some(Err(
559+
"The \"include-ignored\" flag is only accepted on the nightly compiler".into()
560+
));
561+
}
562+
563+
let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
564+
(true, true) => return Some(Err(
565+
"the options --include-ignored and --ignored are mutually exclusive".into()
566+
)),
567+
(true, false) => RunIgnored::Yes,
568+
(false, true) => RunIgnored::Only,
569+
(false, false) => RunIgnored::No,
570+
};
549571
let quiet = matches.opt_present("quiet");
550572
let exact = matches.opt_present("exact");
551573
let list = matches.opt_present("list");
@@ -1297,55 +1319,36 @@ fn get_concurrency() -> usize {
12971319

12981320
pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
12991321
let mut filtered = tests;
1300-
// Remove tests that don't match the test filter
1301-
filtered = match opts.filter {
1302-
None => filtered,
1303-
Some(ref filter) => filtered
1304-
.into_iter()
1305-
.filter(|test| {
1306-
if opts.filter_exact {
1307-
test.desc.name.as_slice() == &filter[..]
1308-
} else {
1309-
test.desc.name.as_slice().contains(&filter[..])
1310-
}
1311-
})
1312-
.collect(),
1322+
let matches_filter = |test: &TestDescAndFn, filter: &str| {
1323+
let test_name = test.desc.name.as_slice();
1324+
1325+
match opts.filter_exact {
1326+
true => test_name == filter,
1327+
false => test_name.contains(filter),
1328+
}
13131329
};
13141330

1315-
// Skip tests that match any of the skip filters
1316-
filtered = filtered
1317-
.into_iter()
1318-
.filter(|t| {
1319-
!opts.skip.iter().any(|sf| {
1320-
if opts.filter_exact {
1321-
t.desc.name.as_slice() == &sf[..]
1322-
} else {
1323-
t.desc.name.as_slice().contains(&sf[..])
1324-
}
1325-
})
1326-
})
1327-
.collect();
1331+
// Remove tests that don't match the test filter
1332+
if let Some(ref filter) = opts.filter {
1333+
filtered.retain(|test| matches_filter(test, filter));
1334+
}
13281335

1329-
// Maybe pull out the ignored test and unignore them
1330-
filtered = if !opts.run_ignored {
1331-
filtered
1332-
} else {
1333-
fn filter(test: TestDescAndFn) -> Option<TestDescAndFn> {
1334-
if test.desc.ignore {
1335-
let TestDescAndFn { desc, testfn } = test;
1336-
Some(TestDescAndFn {
1337-
desc: TestDesc {
1338-
ignore: false,
1339-
..desc
1340-
},
1341-
testfn,
1342-
})
1343-
} else {
1344-
None
1345-
}
1336+
// Skip tests that match any of the skip filters
1337+
filtered.retain(|test| {
1338+
!opts.skip.iter().any(|sf| matches_filter(test, sf))
1339+
});
1340+
1341+
// maybe unignore tests
1342+
match opts.run_ignored {
1343+
RunIgnored::Yes => {
1344+
filtered.iter_mut().for_each(|test| test.desc.ignore = false);
1345+
},
1346+
RunIgnored::Only => {
1347+
filtered.retain(|test| test.desc.ignore);
1348+
filtered.iter_mut().for_each(|test| test.desc.ignore = false);
13461349
}
1347-
filtered.into_iter().filter_map(filter).collect()
1348-
};
1350+
RunIgnored::No => {}
1351+
}
13491352

13501353
// Sort the tests alphabetically
13511354
filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
@@ -1734,13 +1737,37 @@ pub mod bench {
17341737

17351738
#[cfg(test)]
17361739
mod tests {
1737-
use test::{filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, ShouldPanic,
1738-
StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg,
1739-
TrIgnored, TrOk};
1740+
use test::{filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
1741+
ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed,
1742+
TrFailedMsg, TrIgnored, TrOk};
17401743
use std::sync::mpsc::channel;
17411744
use bench;
17421745
use Bencher;
17431746

1747+
1748+
fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
1749+
vec![
1750+
TestDescAndFn {
1751+
desc: TestDesc {
1752+
name: StaticTestName("1"),
1753+
ignore: true,
1754+
should_panic: ShouldPanic::No,
1755+
allow_fail: false,
1756+
},
1757+
testfn: DynTestFn(Box::new(move || {})),
1758+
},
1759+
TestDescAndFn {
1760+
desc: TestDesc {
1761+
name: StaticTestName("2"),
1762+
ignore: false,
1763+
should_panic: ShouldPanic::No,
1764+
allow_fail: false,
1765+
},
1766+
testfn: DynTestFn(Box::new(move || {})),
1767+
},
1768+
]
1769+
}
1770+
17441771
#[test]
17451772
pub fn do_not_run_ignored_tests() {
17461773
fn f() {
@@ -1866,11 +1893,20 @@ mod tests {
18661893
"filter".to_string(),
18671894
"--ignored".to_string(),
18681895
];
1869-
let opts = match parse_opts(&args) {
1870-
Some(Ok(o)) => o,
1871-
_ => panic!("Malformed arg in parse_ignored_flag"),
1872-
};
1873-
assert!((opts.run_ignored));
1896+
let opts = parse_opts(&args).unwrap().unwrap();
1897+
assert_eq!(opts.run_ignored, RunIgnored::Only);
1898+
}
1899+
1900+
#[test]
1901+
fn parse_include_ignored_flag() {
1902+
let args = vec![
1903+
"progname".to_string(),
1904+
"filter".to_string(),
1905+
"-Zunstable-options".to_string(),
1906+
"--include-ignored".to_string(),
1907+
];
1908+
let opts = parse_opts(&args).unwrap().unwrap();
1909+
assert_eq!(opts.run_ignored, RunIgnored::Yes);
18741910
}
18751911

18761912
#[test]
@@ -1880,35 +1916,33 @@ mod tests {
18801916

18811917
let mut opts = TestOpts::new();
18821918
opts.run_tests = true;
1883-
opts.run_ignored = true;
1919+
opts.run_ignored = RunIgnored::Only;
18841920

1885-
let tests = vec![
1886-
TestDescAndFn {
1887-
desc: TestDesc {
1888-
name: StaticTestName("1"),
1889-
ignore: true,
1890-
should_panic: ShouldPanic::No,
1891-
allow_fail: false,
1892-
},
1893-
testfn: DynTestFn(Box::new(move || {})),
1894-
},
1895-
TestDescAndFn {
1896-
desc: TestDesc {
1897-
name: StaticTestName("2"),
1898-
ignore: false,
1899-
should_panic: ShouldPanic::No,
1900-
allow_fail: false,
1901-
},
1902-
testfn: DynTestFn(Box::new(move || {})),
1903-
},
1904-
];
1921+
let tests = one_ignored_one_unignored_test();
19051922
let filtered = filter_tests(&opts, tests);
19061923

19071924
assert_eq!(filtered.len(), 1);
19081925
assert_eq!(filtered[0].desc.name.to_string(), "1");
19091926
assert!(!filtered[0].desc.ignore);
19101927
}
19111928

1929+
#[test]
1930+
pub fn run_include_ignored_option() {
1931+
// When we "--include-ignored" tests, the ignore flag should be set to false on
1932+
// all tests and no test filtered out
1933+
1934+
let mut opts = TestOpts::new();
1935+
opts.run_tests = true;
1936+
opts.run_ignored = RunIgnored::Yes;
1937+
1938+
let tests = one_ignored_one_unignored_test();
1939+
let filtered = filter_tests(&opts, tests);
1940+
1941+
assert_eq!(filtered.len(), 2);
1942+
assert!(!filtered[0].desc.ignore);
1943+
assert!(!filtered[1].desc.ignore);
1944+
}
1945+
19121946
#[test]
19131947
pub fn exact_filter_match() {
19141948
fn tests() -> Vec<TestDescAndFn> {
@@ -2016,7 +2050,9 @@ mod tests {
20162050
"test::ignored_tests_result_in_ignored".to_string(),
20172051
"test::first_free_arg_should_be_a_filter".to_string(),
20182052
"test::parse_ignored_flag".to_string(),
2053+
"test::parse_include_ignored_flag".to_string(),
20192054
"test::filter_for_ignored_option".to_string(),
2055+
"test::run_include_ignored_option".to_string(),
20202056
"test::sort_tests".to_string(),
20212057
];
20222058
let tests = {
@@ -2047,6 +2083,8 @@ mod tests {
20472083
"test::first_free_arg_should_be_a_filter".to_string(),
20482084
"test::ignored_tests_result_in_ignored".to_string(),
20492085
"test::parse_ignored_flag".to_string(),
2086+
"test::parse_include_ignored_flag".to_string(),
2087+
"test::run_include_ignored_option".to_string(),
20502088
"test::sort_tests".to_string(),
20512089
];
20522090

0 commit comments

Comments
 (0)