@@ -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