@@ -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
8282pub 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 ) ]
353360pub 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
393400fn 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
12981320pub 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) ]
17361739mod 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