@@ -89,7 +89,7 @@ const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in qu
8989// to be used by rustc to compile tests in libtest
9090pub mod test {
9191 pub use { assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
92- Bencher , DynTestFn , DynTestName , Metric , MetricMap , Options , ShouldPanic ,
92+ Bencher , DynTestFn , DynTestName , Metric , MetricMap , Options , RunIgnored , ShouldPanic ,
9393 StaticBenchFn , StaticTestFn , StaticTestName , TestDesc , TestDescAndFn , TestName ,
9494 TestOpts , TestResult , TrFailed , TrFailedMsg , TrIgnored , TrOk } ;
9595}
@@ -357,12 +357,19 @@ pub enum OutputFormat {
357357 Json ,
358358}
359359
360+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
361+ pub enum RunIgnored {
362+ Yes ,
363+ No ,
364+ Only ,
365+ }
366+
360367#[ derive( Debug ) ]
361368pub struct TestOpts {
362369 pub list : bool ,
363370 pub filter : Option < String > ,
364371 pub filter_exact : bool ,
365- pub run_ignored : bool ,
372+ pub run_ignored : RunIgnored ,
366373 pub run_tests : bool ,
367374 pub bench_benchmarks : bool ,
368375 pub logfile : Option < PathBuf > ,
@@ -381,7 +388,7 @@ impl TestOpts {
381388 list : false ,
382389 filter : None ,
383390 filter_exact : false ,
384- run_ignored : false ,
391+ run_ignored : RunIgnored :: No ,
385392 run_tests : false ,
386393 bench_benchmarks : false ,
387394 logfile : None ,
@@ -400,7 +407,8 @@ pub type OptRes = Result<TestOpts, String>;
400407
401408fn optgroups ( ) -> getopts:: Options {
402409 let mut opts = getopts:: Options :: new ( ) ;
403- opts. optflag ( "" , "ignored" , "Run ignored tests" )
410+ opts. optflag ( "" , "include-ignored" , "Run ignored and not ignored tests" )
411+ . optflag ( "" , "ignored" , "Run only ignored tests" )
404412 . optflag ( "" , "test" , "Run tests and not benchmarks" )
405413 . optflag ( "" , "bench" , "Run benchmarks instead of tests" )
406414 . optflag ( "" , "list" , "List all tests and benchmarks" )
@@ -499,8 +507,8 @@ Test Attributes:
499507 contain: #[should_panic(expected = "foo")].
500508 #[ignore] - When applied to a function which is already attributed as a
501509 test, then the test runner will ignore these tests during
502- normal test runs. Running with --ignored will run these
503- tests."# ,
510+ normal test runs. Running with --ignored or --include-ignored will run
511+ these tests."# ,
504512 usage = options. usage( & message)
505513 ) ;
506514}
@@ -553,7 +561,21 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
553561 None
554562 } ;
555563
556- let run_ignored = matches. opt_present ( "ignored" ) ;
564+ let include_ignored = matches. opt_present ( "include-ignored" ) ;
565+ if !allow_unstable && include_ignored {
566+ return Some ( Err (
567+ "The \" include-ignored\" flag is only accepted on the nightly compiler" . into ( )
568+ ) ) ;
569+ }
570+
571+ let run_ignored = match ( include_ignored, matches. opt_present ( "ignored" ) ) {
572+ ( true , true ) => return Some ( Err (
573+ "the options --include-ignored and --ignored are mutually exclusive" . into ( )
574+ ) ) ,
575+ ( true , false ) => RunIgnored :: Yes ,
576+ ( false , true ) => RunIgnored :: Only ,
577+ ( false , false ) => RunIgnored :: No ,
578+ } ;
557579 let quiet = matches. opt_present ( "quiet" ) ;
558580 let exact = matches. opt_present ( "exact" ) ;
559581 let list = matches. opt_present ( "list" ) ;
@@ -1305,55 +1327,36 @@ fn get_concurrency() -> usize {
13051327
13061328pub fn filter_tests ( opts : & TestOpts , tests : Vec < TestDescAndFn > ) -> Vec < TestDescAndFn > {
13071329 let mut filtered = tests;
1308- // Remove tests that don't match the test filter
1309- filtered = match opts. filter {
1310- None => filtered,
1311- Some ( ref filter) => filtered
1312- . into_iter ( )
1313- . filter ( |test| {
1314- if opts. filter_exact {
1315- test. desc . name . as_slice ( ) == & filter[ ..]
1316- } else {
1317- test. desc . name . as_slice ( ) . contains ( & filter[ ..] )
1318- }
1319- } )
1320- . collect ( ) ,
1330+ let matches_filter = |test : & TestDescAndFn , filter : & str | {
1331+ let test_name = test. desc . name . as_slice ( ) ;
1332+
1333+ match opts. filter_exact {
1334+ true => test_name == filter,
1335+ false => test_name. contains ( filter) ,
1336+ }
13211337 } ;
13221338
1323- // Skip tests that match any of the skip filters
1324- filtered = filtered
1325- . into_iter ( )
1326- . filter ( |t| {
1327- !opts. skip . iter ( ) . any ( |sf| {
1328- if opts. filter_exact {
1329- t. desc . name . as_slice ( ) == & sf[ ..]
1330- } else {
1331- t. desc . name . as_slice ( ) . contains ( & sf[ ..] )
1332- }
1333- } )
1334- } )
1335- . collect ( ) ;
1339+ // Remove tests that don't match the test filter
1340+ if let Some ( ref filter) = opts. filter {
1341+ filtered. retain ( |test| matches_filter ( test, filter) ) ;
1342+ }
13361343
1337- // Maybe pull out the ignored test and unignore them
1338- filtered = if !opts. run_ignored {
1339- filtered
1340- } else {
1341- fn filter ( test : TestDescAndFn ) -> Option < TestDescAndFn > {
1342- if test. desc . ignore {
1343- let TestDescAndFn { desc, testfn } = test;
1344- Some ( TestDescAndFn {
1345- desc : TestDesc {
1346- ignore : false ,
1347- ..desc
1348- } ,
1349- testfn,
1350- } )
1351- } else {
1352- None
1353- }
1344+ // Skip tests that match any of the skip filters
1345+ filtered. retain ( |test| {
1346+ !opts. skip . iter ( ) . any ( |sf| matches_filter ( test, sf) )
1347+ } ) ;
1348+
1349+ // maybe unignore tests
1350+ match opts. run_ignored {
1351+ RunIgnored :: Yes => {
1352+ filtered. iter_mut ( ) . for_each ( |test| test. desc . ignore = false ) ;
1353+ } ,
1354+ RunIgnored :: Only => {
1355+ filtered. retain ( |test| test. desc . ignore ) ;
1356+ filtered. iter_mut ( ) . for_each ( |test| test. desc . ignore = false ) ;
13541357 }
1355- filtered . into_iter ( ) . filter_map ( filter ) . collect ( )
1356- } ;
1358+ RunIgnored :: No => { }
1359+ }
13571360
13581361 // Sort the tests alphabetically
13591362 filtered. sort_by ( |t1, t2| t1. desc . name . as_slice ( ) . cmp ( t2. desc . name . as_slice ( ) ) ) ;
@@ -1742,13 +1745,37 @@ pub mod bench {
17421745
17431746#[ cfg( test) ]
17441747mod tests {
1745- use test:: { filter_tests, parse_opts, run_test, DynTestFn , DynTestName , MetricMap , ShouldPanic ,
1746- StaticTestName , TestDesc , TestDescAndFn , TestOpts , TrFailed , TrFailedMsg ,
1747- TrIgnored , TrOk } ;
1748+ use test:: { filter_tests, parse_opts, run_test, DynTestFn , DynTestName , MetricMap , RunIgnored ,
1749+ ShouldPanic , StaticTestName , TestDesc , TestDescAndFn , TestOpts , TrFailed ,
1750+ TrFailedMsg , TrIgnored , TrOk } ;
17481751 use std:: sync:: mpsc:: channel;
17491752 use bench;
17501753 use Bencher ;
17511754
1755+
1756+ fn one_ignored_one_unignored_test ( ) -> Vec < TestDescAndFn > {
1757+ vec ! [
1758+ TestDescAndFn {
1759+ desc: TestDesc {
1760+ name: StaticTestName ( "1" ) ,
1761+ ignore: true ,
1762+ should_panic: ShouldPanic :: No ,
1763+ allow_fail: false ,
1764+ } ,
1765+ testfn: DynTestFn ( Box :: new( move || { } ) ) ,
1766+ } ,
1767+ TestDescAndFn {
1768+ desc: TestDesc {
1769+ name: StaticTestName ( "2" ) ,
1770+ ignore: false ,
1771+ should_panic: ShouldPanic :: No ,
1772+ allow_fail: false ,
1773+ } ,
1774+ testfn: DynTestFn ( Box :: new( move || { } ) ) ,
1775+ } ,
1776+ ]
1777+ }
1778+
17521779 #[ test]
17531780 pub fn do_not_run_ignored_tests ( ) {
17541781 fn f ( ) {
@@ -1874,11 +1901,20 @@ mod tests {
18741901 "filter" . to_string( ) ,
18751902 "--ignored" . to_string( ) ,
18761903 ] ;
1877- let opts = match parse_opts ( & args) {
1878- Some ( Ok ( o) ) => o,
1879- _ => panic ! ( "Malformed arg in parse_ignored_flag" ) ,
1880- } ;
1881- assert ! ( ( opts. run_ignored) ) ;
1904+ let opts = parse_opts ( & args) . unwrap ( ) . unwrap ( ) ;
1905+ assert_eq ! ( opts. run_ignored, RunIgnored :: Only ) ;
1906+ }
1907+
1908+ #[ test]
1909+ fn parse_include_ignored_flag ( ) {
1910+ let args = vec ! [
1911+ "progname" . to_string( ) ,
1912+ "filter" . to_string( ) ,
1913+ "-Zunstable-options" . to_string( ) ,
1914+ "--include-ignored" . to_string( ) ,
1915+ ] ;
1916+ let opts = parse_opts ( & args) . unwrap ( ) . unwrap ( ) ;
1917+ assert_eq ! ( opts. run_ignored, RunIgnored :: Yes ) ;
18821918 }
18831919
18841920 #[ test]
@@ -1888,35 +1924,33 @@ mod tests {
18881924
18891925 let mut opts = TestOpts :: new ( ) ;
18901926 opts. run_tests = true ;
1891- opts. run_ignored = true ;
1927+ opts. run_ignored = RunIgnored :: Only ;
18921928
1893- let tests = vec ! [
1894- TestDescAndFn {
1895- desc: TestDesc {
1896- name: StaticTestName ( "1" ) ,
1897- ignore: true ,
1898- should_panic: ShouldPanic :: No ,
1899- allow_fail: false ,
1900- } ,
1901- testfn: DynTestFn ( Box :: new( move || { } ) ) ,
1902- } ,
1903- TestDescAndFn {
1904- desc: TestDesc {
1905- name: StaticTestName ( "2" ) ,
1906- ignore: false ,
1907- should_panic: ShouldPanic :: No ,
1908- allow_fail: false ,
1909- } ,
1910- testfn: DynTestFn ( Box :: new( move || { } ) ) ,
1911- } ,
1912- ] ;
1929+ let tests = one_ignored_one_unignored_test ( ) ;
19131930 let filtered = filter_tests ( & opts, tests) ;
19141931
19151932 assert_eq ! ( filtered. len( ) , 1 ) ;
19161933 assert_eq ! ( filtered[ 0 ] . desc. name. to_string( ) , "1" ) ;
19171934 assert ! ( !filtered[ 0 ] . desc. ignore) ;
19181935 }
19191936
1937+ #[ test]
1938+ pub fn run_include_ignored_option ( ) {
1939+ // When we "--include-ignored" tests, the ignore flag should be set to false on
1940+ // all tests and no test filtered out
1941+
1942+ let mut opts = TestOpts :: new ( ) ;
1943+ opts. run_tests = true ;
1944+ opts. run_ignored = RunIgnored :: Yes ;
1945+
1946+ let tests = one_ignored_one_unignored_test ( ) ;
1947+ let filtered = filter_tests ( & opts, tests) ;
1948+
1949+ assert_eq ! ( filtered. len( ) , 2 ) ;
1950+ assert ! ( !filtered[ 0 ] . desc. ignore) ;
1951+ assert ! ( !filtered[ 1 ] . desc. ignore) ;
1952+ }
1953+
19201954 #[ test]
19211955 pub fn exact_filter_match ( ) {
19221956 fn tests ( ) -> Vec < TestDescAndFn > {
@@ -2024,7 +2058,9 @@ mod tests {
20242058 "test::ignored_tests_result_in_ignored" . to_string( ) ,
20252059 "test::first_free_arg_should_be_a_filter" . to_string( ) ,
20262060 "test::parse_ignored_flag" . to_string( ) ,
2061+ "test::parse_include_ignored_flag" . to_string( ) ,
20272062 "test::filter_for_ignored_option" . to_string( ) ,
2063+ "test::run_include_ignored_option" . to_string( ) ,
20282064 "test::sort_tests" . to_string( ) ,
20292065 ] ;
20302066 let tests = {
@@ -2055,6 +2091,8 @@ mod tests {
20552091 "test::first_free_arg_should_be_a_filter" . to_string( ) ,
20562092 "test::ignored_tests_result_in_ignored" . to_string( ) ,
20572093 "test::parse_ignored_flag" . to_string( ) ,
2094+ "test::parse_include_ignored_flag" . to_string( ) ,
2095+ "test::run_include_ignored_option" . to_string( ) ,
20582096 "test::sort_tests" . to_string( ) ,
20592097 ] ;
20602098
0 commit comments