@@ -254,10 +254,16 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>) {
254254 Some ( Err ( msg) ) => panic ! ( "{:?}" , msg) ,
255255 None => return ,
256256 } ;
257- match run_tests_console ( & opts, tests) {
258- Ok ( true ) => { }
259- Ok ( false ) => std:: process:: exit ( 101 ) ,
260- Err ( e) => panic ! ( "io error when running tests: {:?}" , e) ,
257+ if opts. list {
258+ if let Err ( e) = list_tests_console ( & opts, tests) {
259+ panic ! ( "io error when listing tests: {:?}" , e) ;
260+ }
261+ } else {
262+ match run_tests_console ( & opts, tests) {
263+ Ok ( true ) => { }
264+ Ok ( false ) => std:: process:: exit ( 101 ) ,
265+ Err ( e) => panic ! ( "io error when running tests: {:?}" , e) ,
266+ }
261267 }
262268}
263269
@@ -300,6 +306,7 @@ pub enum ColorConfig {
300306}
301307
302308pub struct TestOpts {
309+ pub list : bool ,
303310 pub filter : Option < String > ,
304311 pub filter_exact : bool ,
305312 pub run_ignored : bool ,
@@ -317,6 +324,7 @@ impl TestOpts {
317324 #[ cfg( test) ]
318325 fn new ( ) -> TestOpts {
319326 TestOpts {
327+ list : false ,
320328 filter : None ,
321329 filter_exact : false ,
322330 run_ignored : false ,
@@ -340,6 +348,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
340348 vec ! [ getopts:: optflag( "" , "ignored" , "Run ignored tests" ) ,
341349 getopts:: optflag( "" , "test" , "Run tests and not benchmarks" ) ,
342350 getopts:: optflag( "" , "bench" , "Run benchmarks instead of tests" ) ,
351+ getopts:: optflag( "" , "list" , "List all tests and benchmarks" ) ,
343352 getopts:: optflag( "h" , "help" , "Display this message (longer with --help)" ) ,
344353 getopts:: optopt( "" , "logfile" , "Write logs to the specified file instead \
345354 of stdout", "PATH" ) ,
@@ -411,6 +420,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
411420 let run_ignored = matches. opt_present ( "ignored" ) ;
412421 let quiet = matches. opt_present ( "quiet" ) ;
413422 let exact = matches. opt_present ( "exact" ) ;
423+ let list = matches. opt_present ( "list" ) ;
414424
415425 let logfile = matches. opt_str ( "logfile" ) ;
416426 let logfile = logfile. map ( |s| PathBuf :: from ( & s) ) ;
@@ -451,6 +461,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
451461 } ;
452462
453463 let test_opts = TestOpts {
464+ list : list,
454465 filter : filter,
455466 filter_exact : exact,
456467 run_ignored : run_ignored,
@@ -581,7 +592,8 @@ impl<T: Write> ConsoleTestState<T> {
581592 }
582593 }
583594
584- pub fn write_plain ( & mut self , s : & str ) -> io:: Result < ( ) > {
595+ pub fn write_plain < S : AsRef < str > > ( & mut self , s : S ) -> io:: Result < ( ) > {
596+ let s = s. as_ref ( ) ;
585597 match self . out {
586598 Pretty ( ref mut term) => {
587599 term. write_all ( s. as_bytes ( ) ) ?;
@@ -635,25 +647,28 @@ impl<T: Write> ConsoleTestState<T> {
635647 TEST_WARN_TIMEOUT_S ) )
636648 }
637649
638- pub fn write_log ( & mut self , test : & TestDesc , result : & TestResult ) -> io:: Result < ( ) > {
650+ pub fn write_log < S : AsRef < str > > ( & mut self , msg : S ) -> io:: Result < ( ) > {
651+ let msg = msg. as_ref ( ) ;
639652 match self . log_out {
640653 None => Ok ( ( ) ) ,
641- Some ( ref mut o) => {
642- let s = format ! ( "{} {}\n " ,
643- match * result {
644- TrOk => "ok" . to_owned( ) ,
645- TrFailed => "failed" . to_owned( ) ,
646- TrFailedMsg ( ref msg) => format!( "failed: {}" , msg) ,
647- TrIgnored => "ignored" . to_owned( ) ,
648- TrMetrics ( ref mm) => mm. fmt_metrics( ) ,
649- TrBench ( ref bs) => fmt_bench_samples( bs) ,
650- } ,
651- test. name) ;
652- o. write_all ( s. as_bytes ( ) )
653- }
654+ Some ( ref mut o) => o. write_all ( msg. as_bytes ( ) ) ,
654655 }
655656 }
656657
658+ pub fn write_log_result ( & mut self , test : & TestDesc , result : & TestResult ) -> io:: Result < ( ) > {
659+ self . write_log (
660+ format ! ( "{} {}\n " ,
661+ match * result {
662+ TrOk => "ok" . to_owned( ) ,
663+ TrFailed => "failed" . to_owned( ) ,
664+ TrFailedMsg ( ref msg) => format!( "failed: {}" , msg) ,
665+ TrIgnored => "ignored" . to_owned( ) ,
666+ TrMetrics ( ref mm) => mm. fmt_metrics( ) ,
667+ TrBench ( ref bs) => fmt_bench_samples( bs) ,
668+ } ,
669+ test. name) )
670+ }
671+
657672 pub fn write_failures ( & mut self ) -> io:: Result < ( ) > {
658673 self . write_plain ( "\n failures:\n " ) ?;
659674 let mut failures = Vec :: new ( ) ;
@@ -746,6 +761,49 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
746761 output
747762}
748763
764+ // List the tests to console, and optionally to logfile. Filters are honored.
765+ pub fn list_tests_console ( opts : & TestOpts , tests : Vec < TestDescAndFn > ) -> io:: Result < ( ) > {
766+ let mut st = ConsoleTestState :: new ( opts, None :: < io:: Stdout > ) ?;
767+
768+ let mut ntest = 0 ;
769+ let mut nbench = 0 ;
770+ let mut nmetric = 0 ;
771+
772+ for test in filter_tests ( & opts, tests) {
773+ use TestFn :: * ;
774+
775+ let TestDescAndFn { desc : TestDesc { name, .. } , testfn } = test;
776+
777+ let fntype = match testfn {
778+ StaticTestFn ( ..) | DynTestFn ( ..) => { ntest += 1 ; "test" } ,
779+ StaticBenchFn ( ..) | DynBenchFn ( ..) => { nbench += 1 ; "benchmark" } ,
780+ StaticMetricFn ( ..) | DynMetricFn ( ..) => { nmetric += 1 ; "metric" } ,
781+ } ;
782+
783+ st. write_plain ( format ! ( "{}: {}\n " , name, fntype) ) ?;
784+ st. write_log ( format ! ( "{} {}\n " , fntype, name) ) ?;
785+ }
786+
787+ fn plural ( count : u32 , s : & str ) -> String {
788+ match count {
789+ 1 => format ! ( "{} {}" , 1 , s) ,
790+ n => format ! ( "{} {}s" , n, s) ,
791+ }
792+ }
793+
794+ if !opts. quiet {
795+ if ntest != 0 || nbench != 0 || nmetric != 0 {
796+ st. write_plain ( "\n " ) ?;
797+ }
798+ st. write_plain ( format ! ( "{}, {}, {}\n " ,
799+ plural( ntest, "test" ) ,
800+ plural( nbench, "benchmark" ) ,
801+ plural( nmetric, "metric" ) ) ) ?;
802+ }
803+
804+ Ok ( ( ) )
805+ }
806+
749807// A simple console test runner
750808pub fn run_tests_console ( opts : & TestOpts , tests : Vec < TestDescAndFn > ) -> io:: Result < bool > {
751809
@@ -755,7 +813,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
755813 TeWait ( ref test, padding) => st. write_test_start ( test, padding) ,
756814 TeTimeout ( ref test) => st. write_timeout ( test) ,
757815 TeResult ( test, result, stdout) => {
758- st. write_log ( & test, & result) ?;
816+ st. write_log_result ( & test, & result) ?;
759817 st. write_result ( & result) ?;
760818 match result {
761819 TrOk => st. passed += 1 ,
0 commit comments