@@ -301,6 +301,7 @@ pub enum ColorConfig {
301301
302302pub struct TestOpts {
303303 pub filter : Option < String > ,
304+ pub filter_exact : bool ,
304305 pub run_ignored : bool ,
305306 pub run_tests : bool ,
306307 pub bench_benchmarks : bool ,
@@ -317,6 +318,7 @@ impl TestOpts {
317318 fn new ( ) -> TestOpts {
318319 TestOpts {
319320 filter : None ,
321+ filter_exact : false ,
320322 run_ignored : false ,
321323 run_tests : false ,
322324 bench_benchmarks : false ,
@@ -348,6 +350,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
348350 getopts:: optmulti( "" , "skip" , "Skip tests whose names contain FILTER (this flag can \
349351 be used multiple times)", "FILTER" ) ,
350352 getopts:: optflag( "q" , "quiet" , "Display one character per test instead of one line" ) ,
353+ getopts:: optflag( "" , "exact" , "Exactly match filters rather than by substring" ) ,
351354 getopts:: optopt( "" , "color" , "Configure coloring of output:
352355 auto = colorize if stdout is a tty and tests are run on serially (default);
353356 always = always colorize output;
@@ -407,6 +410,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
407410
408411 let run_ignored = matches. opt_present ( "ignored" ) ;
409412 let quiet = matches. opt_present ( "quiet" ) ;
413+ let exact = matches. opt_present ( "exact" ) ;
410414
411415 let logfile = matches. opt_str ( "logfile" ) ;
412416 let logfile = logfile. map ( |s| PathBuf :: from ( & s) ) ;
@@ -448,6 +452,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
448452
449453 let test_opts = TestOpts {
450454 filter : filter,
455+ filter_exact : exact,
451456 run_ignored : run_ignored,
452457 run_tests : run_tests,
453458 bench_benchmarks : bench_benchmarks,
@@ -1118,14 +1123,26 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
11181123 None => filtered,
11191124 Some ( ref filter) => {
11201125 filtered. into_iter ( )
1121- . filter ( |test| test. desc . name . as_slice ( ) . contains ( & filter[ ..] ) )
1126+ . filter ( |test| {
1127+ if opts. filter_exact {
1128+ test. desc . name . as_slice ( ) == & filter[ ..]
1129+ } else {
1130+ test. desc . name . as_slice ( ) . contains ( & filter[ ..] )
1131+ }
1132+ } )
11221133 . collect ( )
11231134 }
11241135 } ;
11251136
11261137 // Skip tests that match any of the skip filters
11271138 filtered = filtered. into_iter ( )
1128- . filter ( |t| !opts. skip . iter ( ) . any ( |sf| t. desc . name . as_slice ( ) . contains ( & sf[ ..] ) ) )
1139+ . filter ( |t| !opts. skip . iter ( ) . any ( |sf| {
1140+ if opts. filter_exact {
1141+ t. desc . name . as_slice ( ) == & sf[ ..]
1142+ } else {
1143+ t. desc . name . as_slice ( ) . contains ( & sf[ ..] )
1144+ }
1145+ } ) )
11291146 . collect ( ) ;
11301147
11311148 // Maybe pull out the ignored test and unignore them
@@ -1654,6 +1671,77 @@ mod tests {
16541671 assert ! ( !filtered[ 0 ] . desc. ignore) ;
16551672 }
16561673
1674+ #[ test]
1675+ pub fn exact_filter_match ( ) {
1676+ fn tests ( ) -> Vec < TestDescAndFn > {
1677+ vec ! [ "base" ,
1678+ "base::test" ,
1679+ "base::test1" ,
1680+ "base::test2" ,
1681+ ] . into_iter ( )
1682+ . map ( |name| TestDescAndFn {
1683+ desc : TestDesc {
1684+ name : StaticTestName ( name) ,
1685+ ignore : false ,
1686+ should_panic : ShouldPanic :: No ,
1687+ } ,
1688+ testfn : DynTestFn ( Box :: new ( move |( ) | { } ) )
1689+ } )
1690+ . collect ( )
1691+ }
1692+
1693+ let substr = filter_tests ( & TestOpts {
1694+ filter : Some ( "base" . into ( ) ) ,
1695+ ..TestOpts :: new ( )
1696+ } , tests ( ) ) ;
1697+ assert_eq ! ( substr. len( ) , 4 ) ;
1698+
1699+ let substr = filter_tests ( & TestOpts {
1700+ filter : Some ( "bas" . into ( ) ) ,
1701+ ..TestOpts :: new ( )
1702+ } , tests ( ) ) ;
1703+ assert_eq ! ( substr. len( ) , 4 ) ;
1704+
1705+ let substr = filter_tests ( & TestOpts {
1706+ filter : Some ( "::test" . into ( ) ) ,
1707+ ..TestOpts :: new ( )
1708+ } , tests ( ) ) ;
1709+ assert_eq ! ( substr. len( ) , 3 ) ;
1710+
1711+ let substr = filter_tests ( & TestOpts {
1712+ filter : Some ( "base::test" . into ( ) ) ,
1713+ ..TestOpts :: new ( )
1714+ } , tests ( ) ) ;
1715+ assert_eq ! ( substr. len( ) , 3 ) ;
1716+
1717+ let exact = filter_tests ( & TestOpts {
1718+ filter : Some ( "base" . into ( ) ) ,
1719+ filter_exact : true , ..TestOpts :: new ( )
1720+ } , tests ( ) ) ;
1721+ assert_eq ! ( exact. len( ) , 1 ) ;
1722+
1723+ let exact = filter_tests ( & TestOpts {
1724+ filter : Some ( "bas" . into ( ) ) ,
1725+ filter_exact : true ,
1726+ ..TestOpts :: new ( )
1727+ } , tests ( ) ) ;
1728+ assert_eq ! ( exact. len( ) , 0 ) ;
1729+
1730+ let exact = filter_tests ( & TestOpts {
1731+ filter : Some ( "::test" . into ( ) ) ,
1732+ filter_exact : true ,
1733+ ..TestOpts :: new ( )
1734+ } , tests ( ) ) ;
1735+ assert_eq ! ( exact. len( ) , 0 ) ;
1736+
1737+ let exact = filter_tests ( & TestOpts {
1738+ filter : Some ( "base::test" . into ( ) ) ,
1739+ filter_exact : true ,
1740+ ..TestOpts :: new ( )
1741+ } , tests ( ) ) ;
1742+ assert_eq ! ( exact. len( ) , 1 ) ;
1743+ }
1744+
16571745 #[ test]
16581746 pub fn sort_tests ( ) {
16591747 let mut opts = TestOpts :: new ( ) ;
0 commit comments