10
10
import tempfile
11
11
import textwrap
12
12
import time
13
+ import unittest
13
14
from test .libregrtest .cmdline import _parse_args
14
15
from test .libregrtest .runtest import (
15
- findtests , runtest ,
16
+ findtests , runtest , get_abs_module ,
16
17
STDTESTS , NOTTESTS , PASSED , FAILED , ENV_CHANGED , SKIPPED , RESOURCE_DENIED ,
17
18
INTERRUPTED , CHILD_ERROR ,
18
19
PROGRESS_MIN_TIME , format_test_result )
28
29
# to keep the test files in a subfolder. This eases the cleanup of leftover
29
30
# files using the "make distclean" command.
30
31
if sysconfig .is_python_build ():
31
- TEMPDIR = os .path .join (sysconfig .get_config_var ('srcdir' ), 'build' )
32
+ TEMPDIR = sysconfig .get_config_var ('abs_builddir' )
33
+ if TEMPDIR is None :
34
+ # bpo-30284: On Windows, only srcdir is available. Using abs_builddir
35
+ # mostly matters on UNIX when building Python out of the source tree,
36
+ # especially when the source tree is read only.
37
+ TEMPDIR = sysconfig .get_config_var ('srcdir' )
38
+ TEMPDIR = os .path .join (TEMPDIR , 'build' )
32
39
else :
33
40
TEMPDIR = tempfile .gettempdir ()
34
41
TEMPDIR = os .path .abspath (TEMPDIR )
@@ -107,7 +114,7 @@ def accumulate_result(self, test, result):
107
114
self .test_times .append ((test_time , test ))
108
115
if ok == PASSED :
109
116
self .good .append (test )
110
- elif ok == FAILED :
117
+ elif ok in ( FAILED , CHILD_ERROR ) :
111
118
self .bad .append (test )
112
119
elif ok == ENV_CHANGED :
113
120
self .environment_changed .append (test )
@@ -116,22 +123,28 @@ def accumulate_result(self, test, result):
116
123
elif ok == RESOURCE_DENIED :
117
124
self .skipped .append (test )
118
125
self .resource_denieds .append (test )
126
+ elif ok != INTERRUPTED :
127
+ raise ValueError ("invalid test result: %r" % ok )
119
128
120
129
def display_progress (self , test_index , test ):
121
130
if self .ns .quiet :
122
131
return
132
+
133
+ # "[ 51/405/1] test_tcl passed"
134
+ line = f"{ test_index :{self .test_count_width }} { self .test_count } "
123
135
if self .bad and not self .ns .pgo :
124
- fmt = "{time} [{test_index:{count_width}}{test_count}/{nbad}] {test_name}"
125
- else :
126
- fmt = "{time} [{test_index:{count_width}}{test_count}] {test_name}"
136
+ line = f"{ line } /{ len (self .bad )} "
137
+ line = f"[{ line } ] { test } "
138
+
139
+ # add the system load prefix: "load avg: 1.80 "
140
+ if hasattr (os , 'getloadavg' ):
141
+ load_avg_1min = os .getloadavg ()[0 ]
142
+ line = f"load avg: { load_avg_1min :.2f} { line } "
143
+
144
+ # add the timestamp prefix: "0:01:05 "
127
145
test_time = time .monotonic () - self .start_time
128
146
test_time = datetime .timedelta (seconds = int (test_time ))
129
- line = fmt .format (count_width = self .test_count_width ,
130
- test_index = test_index ,
131
- test_count = self .test_count ,
132
- nbad = len (self .bad ),
133
- test_name = test ,
134
- time = test_time )
147
+ line = f"{ test_time } { line } "
135
148
print (line , flush = True )
136
149
137
150
def parse_args (self , kwargs ):
@@ -179,19 +192,14 @@ def find_tests(self, tests):
179
192
self .tests = []
180
193
# regex to match 'test_builtin' in line:
181
194
# '0:00:00 [ 4/400] test_builtin -- test_dict took 1 sec'
182
- regex = (r'^(?:[0-9]+:[0-9]+:[0-9]+ *)?'
183
- r'(?:\[[0-9/ ]+\] *)?'
184
- r'(test_[a-zA-Z0-9_]+)' )
185
- regex = re .compile (regex )
195
+ regex = re .compile (r'\btest_[a-zA-Z0-9_]+\b' )
186
196
with open (os .path .join (support .SAVEDCWD , self .ns .fromfile )) as fp :
187
197
for line in fp :
198
+ line = line .split ('#' , 1 )[0 ]
188
199
line = line .strip ()
189
- if line .startswith ('#' ):
190
- continue
191
- match = regex .match (line )
192
- if match is None :
193
- continue
194
- self .tests .append (match .group (1 ))
200
+ match = regex .search (line )
201
+ if match is not None :
202
+ self .tests .append (match .group ())
195
203
196
204
removepy (self .tests )
197
205
@@ -241,6 +249,29 @@ def list_tests(self):
241
249
for name in self .selected :
242
250
print (name )
243
251
252
+ def _list_cases (self , suite ):
253
+ for test in suite :
254
+ if isinstance (test , unittest .loader ._FailedTest ):
255
+ continue
256
+ if isinstance (test , unittest .TestSuite ):
257
+ self ._list_cases (test )
258
+ elif isinstance (test , unittest .TestCase ):
259
+ print (test .id ())
260
+
261
+ def list_cases (self ):
262
+ for test in self .selected :
263
+ abstest = get_abs_module (self .ns , test )
264
+ try :
265
+ suite = unittest .defaultTestLoader .loadTestsFromName (abstest )
266
+ self ._list_cases (suite )
267
+ except unittest .SkipTest :
268
+ self .skipped .append (test )
269
+
270
+ if self .skipped :
271
+ print (file = sys .stderr )
272
+ print (count (len (self .skipped ), "test" ), "skipped:" , file = sys .stderr )
273
+ printlist (self .skipped , file = sys .stderr )
274
+
244
275
def rerun_failed_tests (self ):
245
276
self .ns .verbose = True
246
277
self .ns .failfast = False
@@ -381,23 +412,28 @@ def _test_forever(self, tests):
381
412
if self .bad :
382
413
return
383
414
415
+ def display_header (self ):
416
+ # Print basic platform information
417
+ print ("==" , platform .python_implementation (), * sys .version .split ())
418
+ print ("==" , platform .platform (aliased = True ),
419
+ "%s-endian" % sys .byteorder )
420
+ print ("== hash algorithm:" , sys .hash_info .algorithm ,
421
+ "64bit" if sys .maxsize > 2 ** 32 else "32bit" )
422
+ print ("== cwd:" , os .getcwd ())
423
+ cpu_count = os .cpu_count ()
424
+ if cpu_count :
425
+ print ("== CPU count:" , cpu_count )
426
+ print ("== encodings: locale=%s, FS=%s"
427
+ % (locale .getpreferredencoding (False ),
428
+ sys .getfilesystemencoding ()))
429
+ print ("Testing with flags:" , sys .flags )
430
+
384
431
def run_tests (self ):
385
432
# For a partial run, we do not need to clutter the output.
386
- if (self .ns .verbose
387
- or self .ns .header
388
- or not (self .ns .pgo or self .ns .quiet or self .ns .single
389
- or self .tests or self .ns .args )):
390
- # Print basic platform information
391
- print ("==" , platform .python_implementation (), * sys .version .split ())
392
- print ("== " , platform .platform (aliased = True ),
393
- "%s-endian" % sys .byteorder )
394
- print ("== " , "hash algorithm:" , sys .hash_info .algorithm ,
395
- "64bit" if sys .maxsize > 2 ** 32 else "32bit" )
396
- print ("== cwd:" , os .getcwd ())
397
- print ("== encodings: locale=%s, FS=%s"
398
- % (locale .getpreferredencoding (False ),
399
- sys .getfilesystemencoding ()))
400
- print ("Testing with flags:" , sys .flags )
433
+ if (self .ns .header
434
+ or not (self .ns .pgo or self .ns .quiet or self .ns .single
435
+ or self .tests or self .ns .args )):
436
+ self .display_header ()
401
437
402
438
if self .ns .randomize :
403
439
print ("Using random seed" , self .ns .random_seed )
@@ -487,6 +523,10 @@ def _main(self, tests, kwargs):
487
523
self .list_tests ()
488
524
sys .exit (0 )
489
525
526
+ if self .ns .list_cases :
527
+ self .list_cases ()
528
+ sys .exit (0 )
529
+
490
530
self .run_tests ()
491
531
self .display_result ()
492
532
@@ -513,7 +553,7 @@ def count(n, word):
513
553
return "%d %ss" % (n , word )
514
554
515
555
516
- def printlist (x , width = 70 , indent = 4 ):
556
+ def printlist (x , width = 70 , indent = 4 , file = None ):
517
557
"""Print the elements of iterable x to stdout.
518
558
519
559
Optional arg width (default 70) is the maximum line length.
@@ -524,7 +564,8 @@ def printlist(x, width=70, indent=4):
524
564
blanks = ' ' * indent
525
565
# Print the sorted list: 'x' may be a '--random' list or a set()
526
566
print (textwrap .fill (' ' .join (str (elt ) for elt in sorted (x )), width ,
527
- initial_indent = blanks , subsequent_indent = blanks ))
567
+ initial_indent = blanks , subsequent_indent = blanks ),
568
+ file = file )
528
569
529
570
530
571
def main (tests = None , ** kwargs ):
0 commit comments