7676PTRN_IMPORT_ERROR = re .compile (r".*cannot import name \'(?P<module>.*)\'.*" , re .DOTALL )
7777PTRN_REMOTE_HOST = re .compile (r"(?P<user>\w+)@(?P<host>[\w.]+):(?P<path>.+)" )
7878PTRN_VALID_CSV_NAME = re .compile (r"unittests-\d{4}-\d{2}-\d{2}.csv" )
79+ PTRN_TEST_STATUS_INDIVIDUAL = re .compile (r"(?P<name>test_[\w_]+ \(.+\)) ... (?P<status>.+)" )
80+ PTRN_TEST_STATUS_ERROR = re .compile (r"(?P<status>.+): (?P<name>test_[\w_]+ \(.+\))" )
7981
8082
8183# ----------------------------------------------------------------------------------------------------------------------
@@ -216,6 +218,13 @@ def read_csv(path):
216218 return rows
217219
218220
221+ class TestStatus (object ):
222+ ERROR = 'error'
223+ FAIL = 'fail'
224+ SKIPPED = 'skipped'
225+ OK = 'ok'
226+
227+
219228# ----------------------------------------------------------------------------------------------------------------------
220229#
221230# result (output processing)
@@ -224,35 +233,81 @@ def read_csv(path):
224233class StatEntry (object ):
225234 def __init__ (self ):
226235 self .num_tests = - 1
227- self .num_errors = - 1
228- self .num_fails = - 1
229- self .num_skipped = - 1
236+ # reported stats
237+ self ._num_errors = - 1
238+ self ._num_fails = - 1
239+ self ._num_skipped = - 1
240+ # tracked stats
241+ self ._tracked = False
230242
231243 def all_ok (self ):
232- self .num_fails = 0
233- self .num_errors = 0
234- self .num_skipped = 0
244+ self ._num_fails = 0
245+ self ._num_errors = 0
246+ self ._num_skipped = 0
247+
248+ @property
249+ def num_errors (self ):
250+ return self ._num_errors
251+
252+ @num_errors .setter
253+ def num_errors (self , value ):
254+ if not self ._tracked :
255+ self ._num_errors = value
256+
257+ @property
258+ def num_fails (self ):
259+ return self ._num_fails
260+
261+ @num_fails .setter
262+ def num_fails (self , value ):
263+ if not self ._tracked :
264+ self ._num_fails = value
265+
266+ @property
267+ def num_skipped (self ):
268+ return self ._num_skipped
269+
270+ @num_skipped .setter
271+ def num_skipped (self , value ):
272+ if not self ._tracked :
273+ self ._num_fails = value
235274
236275 @property
237276 def num_passes (self ):
238277 if self .num_tests > 0 :
239- return self .num_tests - (self .num_fails + self .num_errors + self .num_skipped )
278+ return self .num_tests - (self ._num_fails + self ._num_errors + self ._num_skipped )
240279 return - 1
241280
281+ def update (self , test_detailed_stats ):
282+ for test , stats in test_detailed_stats .items ():
283+ self ._tracked = True
284+ stats = {s .lower () for s in stats }
285+ if TestStatus .ERROR in stats :
286+ self ._num_errors = 1 if self ._num_errors == - 1 else self ._num_errors + 1
287+ elif TestStatus .FAIL in stats :
288+ self ._num_fails = 1 if self ._num_fails == - 1 else self ._num_fails + 1
289+ else :
290+ for s in stats :
291+ if s .startswith (TestStatus .SKIPPED ):
292+ self ._num_skipped = 1 if self ._num_skipped == - 1 else self ._num_skipped + 1
293+ break
294+
242295
243296def process_output (output_lines ):
244297 if isinstance (output_lines , str ):
245298 output_lines = output_lines .split ("\n " )
246299
247300 unittests = []
301+ unittest_tests = defaultdict (list )
248302 error_messages = defaultdict (set )
249303 java_exceptions = defaultdict (set )
250304 stats = defaultdict (StatEntry )
251305
252306 for line in output_lines :
253307 match = re .match (PTRN_UNITTEST , line )
254308 if match :
255- unittests .append (match .group ('unittest' ))
309+ unittest = match .group ('unittest' )
310+ unittests .append (unittest )
256311 continue
257312
258313 # extract python reported python error messages
@@ -268,6 +323,21 @@ def process_output(output_lines):
268323 continue
269324
270325 # stats
326+ # tracking
327+ match = re .match (PTRN_TEST_STATUS_INDIVIDUAL , line )
328+ if match :
329+ name = match .group ('name' )
330+ status = match .group ('status' )
331+ unittest_tests [name ].append (status )
332+ continue
333+
334+ match = re .match (PTRN_TEST_STATUS_ERROR , line )
335+ if match :
336+ name = match .group ('name' )
337+ status = match .group ('status' )
338+ unittest_tests [name ].append (status )
339+ continue
340+
271341 if line .strip () == 'OK' :
272342 stats [unittests [- 1 ]].all_ok ()
273343 continue
@@ -286,6 +356,8 @@ def process_output(output_lines):
286356 match = re .match (PTRN_NUM_TESTS , line )
287357 if match :
288358 stats [unittests [- 1 ]].num_tests = int (match .group ('num_tests' ))
359+ stats [unittests [- 1 ]].update (unittest_tests )
360+ unittest_tests .clear ()
289361 continue
290362
291363 match = re .match (PTRN_FAILED , line )
@@ -299,6 +371,7 @@ def process_output(output_lines):
299371 stats [unittests [- 1 ]].num_fails = int (fails ) if fails else 0
300372 stats [unittests [- 1 ]].num_errors = int (errs ) if errs else 0
301373 stats [unittests [- 1 ]].num_skipped = int (skipped ) if skipped else 0
374+ continue
302375
303376 return unittests , error_messages , java_exceptions , stats
304377
@@ -712,6 +785,8 @@ def main(prog, args):
712785 parser = argparse .ArgumentParser (prog = prog ,
713786 description = "Run the standard python unittests." )
714787 parser .add_argument ("-v" , "--verbose" , help = "Verbose output." , action = "store_true" )
788+ parser .add_argument ("-n" , "--no_cpython" , help = "Do not run the tests with cpython (for comparison)." ,
789+ action = "store_true" )
715790 parser .add_argument ("-l" , "--limit" , help = "Limit the number of unittests to run." , default = None , type = int )
716791 parser .add_argument ("-t" , "--tests_path" , help = "Unittests path." , default = PATH_UNITTESTS )
717792 parser .add_argument ("-T" , "--timeout" , help = "Timeout per unittest run." , default = TIMEOUT , type = int )
@@ -754,7 +829,7 @@ def _fmt(t):
754829 unittests = get_unittests (flags .tests_path , limit = flags .limit , skip_tests = skip_tests )
755830
756831 # get cpython stats
757- if not flags .gate :
832+ if not flags .gate and not flags . no_cpython :
758833 log (HR )
759834 log ("[INFO] get cpython stats" )
760835 cpy_results = run_unittests (unittests , 60 * 5 , with_cpython = True )
0 commit comments