1111import unittest
1212from test .libregrtest .cmdline import _parse_args
1313from test .libregrtest .runtest import (
14- findtests , split_test_packages , runtest , get_abs_module , is_failed ,
15- PROGRESS_MIN_TIME ,
16- Passed , Failed , EnvChanged , Skipped , ResourceDenied , Interrupted ,
17- ChildError , DidNotRun )
14+ findtests , split_test_packages , runtest , get_abs_module ,
15+ PROGRESS_MIN_TIME , State )
1816from test .libregrtest .setup import setup_tests
1917from test .libregrtest .pgo import setup_pgo_tests
2018from test .libregrtest .utils import (removepy , count , format_duration ,
2119 printlist , get_build_info )
2220from test import support
21+ from test .support import TestStats
2322from test .support import os_helper
2423from test .support import threading_helper
2524
@@ -78,13 +77,14 @@ def __init__(self):
7877 self .good = []
7978 self .bad = []
8079 self .skipped = []
81- self .resource_denieds = []
80+ self .resource_denied = []
8281 self .environment_changed = []
8382 self .run_no_tests = []
8483 self .need_rerun = []
8584 self .rerun = []
8685 self .first_result = None
8786 self .interrupted = False
87+ self .stats_dict : dict [str , TestStats ] = {}
8888
8989 # used by --slow
9090 self .test_times = []
@@ -93,7 +93,7 @@ def __init__(self):
9393 self .tracer = None
9494
9595 # used to display the progress bar "[ 3/100]"
96- self .start_time = time .monotonic ()
96+ self .start_time = time .perf_counter ()
9797 self .test_count = ''
9898 self .test_count_width = 1
9999
@@ -111,36 +111,41 @@ def __init__(self):
111111
112112 def get_executed (self ):
113113 return (set (self .good ) | set (self .bad ) | set (self .skipped )
114- | set (self .resource_denieds ) | set (self .environment_changed )
114+ | set (self .resource_denied ) | set (self .environment_changed )
115115 | set (self .run_no_tests ))
116116
117117 def accumulate_result (self , result , rerun = False ):
118- test_name = result .name
119-
120- if not isinstance (result , (ChildError , Interrupted )) and not rerun :
121- self .test_times .append ((result .duration_sec , test_name ))
122-
123- if isinstance (result , Passed ):
124- self .good .append (test_name )
125- elif isinstance (result , ResourceDenied ):
126- self .skipped .append (test_name )
127- self .resource_denieds .append (test_name )
128- elif isinstance (result , Skipped ):
129- self .skipped .append (test_name )
130- elif isinstance (result , EnvChanged ):
131- self .environment_changed .append (test_name )
132- elif isinstance (result , Failed ):
133- if not rerun :
134- self .bad .append (test_name )
135- self .need_rerun .append (result )
136- elif isinstance (result , DidNotRun ):
137- self .run_no_tests .append (test_name )
138- elif isinstance (result , Interrupted ):
139- self .interrupted = True
140- else :
141- raise ValueError ("invalid test result: %r" % result )
118+ test_name = result .test_name
119+
120+ if result .has_meaningful_duration () and not rerun :
121+ self .test_times .append ((result .duration , test_name ))
142122
143- if rerun and not isinstance (result , (Failed , Interrupted )):
123+ match result .state :
124+ case State .PASSED :
125+ self .good .append (test_name )
126+ case State .ENV_CHANGED :
127+ self .environment_changed .append (test_name )
128+ case State .SKIPPED :
129+ self .skipped .append (test_name )
130+ case State .RESOURCE_DENIED :
131+ self .skipped .append (test_name )
132+ self .resource_denied .append (test_name )
133+ case State .INTERRUPTED :
134+ self .interrupted = True
135+ case State .DID_NOT_RUN :
136+ self .run_no_tests .append (test_name )
137+ case _:
138+ if result .is_failed (self .ns .fail_env_changed ):
139+ if not rerun :
140+ self .bad .append (test_name )
141+ self .need_rerun .append (result )
142+ else :
143+ raise ValueError (f"invalid test state: { state !r} " )
144+
145+ if result .stats is not None :
146+ self .stats_dict [result .test_name ] = result .stats
147+
148+ if rerun and not (result .is_failed (False ) or result .state == State .INTERRUPTED ):
144149 self .bad .remove (test_name )
145150
146151 xml_data = result .xml_data
@@ -162,7 +167,7 @@ def log(self, line=''):
162167 line = f"load avg: { load_avg :.2f} { line } "
163168
164169 # add the timestamp prefix: "0:01:05 "
165- test_time = time .monotonic () - self .start_time
170+ test_time = time .perf_counter () - self .start_time
166171
167172 mins , secs = divmod (int (test_time ), 60 )
168173 hours , mins = divmod (mins , 60 )
@@ -337,7 +342,7 @@ def rerun_failed_tests(self):
337342 rerun_list = list (self .need_rerun )
338343 self .need_rerun .clear ()
339344 for result in rerun_list :
340- test_name = result .name
345+ test_name = result .test_name
341346 self .rerun .append (test_name )
342347
343348 errors = result .errors or []
@@ -364,7 +369,7 @@ def rerun_failed_tests(self):
364369
365370 self .accumulate_result (result , rerun = True )
366371
367- if isinstance ( result , Interrupted ) :
372+ if result . state == State . INTERRUPTED :
368373 break
369374
370375 if self .bad :
@@ -461,7 +466,7 @@ def run_tests_sequential(self):
461466
462467 previous_test = None
463468 for test_index , test_name in enumerate (self .tests , 1 ):
464- start_time = time .monotonic ()
469+ start_time = time .perf_counter ()
465470
466471 text = test_name
467472 if previous_test :
@@ -480,14 +485,14 @@ def run_tests_sequential(self):
480485 result = runtest (self .ns , test_name )
481486 self .accumulate_result (result )
482487
483- if isinstance ( result , Interrupted ) :
488+ if result . state == State . INTERRUPTED :
484489 break
485490
486491 previous_test = str (result )
487- test_time = time .monotonic () - start_time
492+ test_time = time .perf_counter () - start_time
488493 if test_time >= PROGRESS_MIN_TIME :
489494 previous_test = "%s in %s" % (previous_test , format_duration (test_time ))
490- elif isinstance ( result , Passed ) :
495+ elif result . state == State . PASSED :
491496 # be quiet: say nothing if the test passed shortly
492497 previous_test = None
493498
@@ -496,7 +501,7 @@ def run_tests_sequential(self):
496501 if module not in save_modules and module .startswith ("test." ):
497502 support .unload (module )
498503
499- if self .ns .failfast and is_failed (result , self .ns ):
504+ if self .ns .failfast and result . is_failed (self .ns . fail_env_changed ):
500505 break
501506
502507 if previous_test :
@@ -638,13 +643,48 @@ def finalize(self):
638643 coverdir = self .ns .coverdir )
639644
640645 print ()
641- duration = time .monotonic () - self .start_time
642- print ("Total duration: %s" % format_duration (duration ))
643- print ("Tests result: %s" % self .get_tests_result ())
646+ self .display_summary ()
644647
645648 if self .ns .runleaks :
646649 os .system ("leaks %d" % os .getpid ())
647650
651+ def display_summary (self ):
652+ duration = time .perf_counter () - self .start_time
653+
654+ # Total duration
655+ print ("Total duration: %s" % format_duration (duration ))
656+
657+ # Total tests
658+ total = TestStats ()
659+ for stats in self .stats_dict .values ():
660+ total .accumulate (stats )
661+ stats = [f'run={ total .tests_run :,} ' ]
662+ if total .failures :
663+ stats .append (f'failures={ total .failures :,} ' )
664+ if total .skipped :
665+ stats .append (f'skipped={ total .skipped :,} ' )
666+ print (f"Total tests: { ' ' .join (stats )} " )
667+
668+ # Total test files
669+ report = [f'success={ len (self .good )} ' ]
670+ if self .bad :
671+ report .append (f'failed={ len (self .bad )} ' )
672+ if self .environment_changed :
673+ report .append (f'env_changed={ len (self .environment_changed )} ' )
674+ if self .skipped :
675+ report .append (f'skipped={ len (self .skipped )} ' )
676+ if self .resource_denied :
677+ report .append (f'resource_denied={ len (self .resource_denied )} ' )
678+ if self .rerun :
679+ report .append (f'rerun={ len (self .rerun )} ' )
680+ if self .run_no_tests :
681+ report .append (f'run_no_tests={ len (self .run_no_tests )} ' )
682+ print (f"Total test files: { ' ' .join (report )} " )
683+
684+ # Result
685+ result = self .get_tests_result ()
686+ print (f"Result: { result } " )
687+
648688 def save_xml_result (self ):
649689 if not self .ns .xmlpath and not self .testsuite_xml :
650690 return
0 commit comments