1111import locale
1212import os .path
1313import platform
14+ import random
1415import re
1516import subprocess
1617import sys
@@ -504,7 +505,7 @@ def list_regex(line_format, tests):
504505 if rerun is not None :
505506 regex = list_regex ('%s re-run test%s' , [rerun .name ])
506507 self .check_line (output , regex )
507- regex = LOG_PREFIX + fr "Re-running 1 failed tests in verbose mode"
508+ regex = LOG_PREFIX + r "Re-running 1 failed tests in verbose mode"
508509 self .check_line (output , regex )
509510 regex = fr"Re-running { rerun .name } in verbose mode"
510511 if rerun .match :
@@ -1019,13 +1020,13 @@ def test_run(self):
10191020 forever = True )
10201021
10211022 @without_optimizer
1022- def check_leak (self , code , what , * , multiprocessing = False ):
1023+ def check_leak (self , code , what , * , run_workers = False ):
10231024 test = self .create_test ('huntrleaks' , code = code )
10241025
10251026 filename = 'reflog.txt'
10261027 self .addCleanup (os_helper .unlink , filename )
10271028 cmd = ['--huntrleaks' , '3:3:' ]
1028- if multiprocessing :
1029+ if run_workers :
10291030 cmd .append ('-j1' )
10301031 cmd .append (test )
10311032 output = self .run_tests (* cmd ,
@@ -1044,7 +1045,7 @@ def check_leak(self, code, what, *, multiprocessing=False):
10441045 self .assertIn (line2 , reflog )
10451046
10461047 @unittest .skipUnless (support .Py_DEBUG , 'need a debug build' )
1047- def check_huntrleaks (self , * , multiprocessing : bool ):
1048+ def check_huntrleaks (self , * , run_workers : bool ):
10481049 # test --huntrleaks
10491050 code = textwrap .dedent ("""
10501051 import unittest
@@ -1055,13 +1056,13 @@ class RefLeakTest(unittest.TestCase):
10551056 def test_leak(self):
10561057 GLOBAL_LIST.append(object())
10571058 """ )
1058- self .check_leak (code , 'references' , multiprocessing = multiprocessing )
1059+ self .check_leak (code , 'references' , run_workers = run_workers )
10591060
10601061 def test_huntrleaks (self ):
1061- self .check_huntrleaks (multiprocessing = False )
1062+ self .check_huntrleaks (run_workers = False )
10621063
10631064 def test_huntrleaks_mp (self ):
1064- self .check_huntrleaks (multiprocessing = True )
1065+ self .check_huntrleaks (run_workers = True )
10651066
10661067 @unittest .skipUnless (support .Py_DEBUG , 'need a debug build' )
10671068 def test_huntrleaks_fd_leak (self ):
@@ -1139,8 +1140,6 @@ def test_method3(self):
11391140 def test_method4(self):
11401141 pass
11411142 """ )
1142- all_methods = ['test_method1' , 'test_method2' ,
1143- 'test_method3' , 'test_method4' ]
11441143 testname = self .create_test (code = code )
11451144
11461145 # only run a subset
@@ -1762,7 +1761,7 @@ def test_mp_decode_error(self):
17621761 if encoding is None :
17631762 encoding = sys .__stdout__ .encoding
17641763 if encoding is None :
1765- self .skipTest (f "cannot get regrtest worker encoding" )
1764+ self .skipTest ("cannot get regrtest worker encoding" )
17661765
17671766 nonascii = b"byte:\xa0 \xa9 \xff \n "
17681767 try :
@@ -1789,7 +1788,7 @@ def test_mp_decode_error(self):
17891788 stats = 0 )
17901789
17911790 def test_doctest (self ):
1792- code = textwrap .dedent (fr '''
1791+ code = textwrap .dedent (r '''
17931792 import doctest
17941793 import sys
17951794 from test import support
@@ -1827,6 +1826,46 @@ def load_tests(loader, tests, pattern):
18271826 randomize = True ,
18281827 stats = TestStats (1 , 1 , 0 ))
18291828
1829+ def _check_random_seed (self , run_workers : bool ):
1830+ # gh-109276: When -r/--randomize is used, random.seed() is called
1831+ # with the same random seed before running each test file.
1832+ code = textwrap .dedent (r'''
1833+ import random
1834+ import unittest
1835+
1836+ class RandomSeedTest(unittest.TestCase):
1837+ def test_randint(self):
1838+ numbers = [random.randint(0, 1000) for _ in range(10)]
1839+ print(f"Random numbers: {numbers}")
1840+ ''' )
1841+ tests = [self .create_test (name = f'test_random{ i } ' , code = code )
1842+ for i in range (1 , 3 + 1 )]
1843+
1844+ random_seed = 856_656_202
1845+ cmd = ["--randomize" , f"--randseed={ random_seed } " ]
1846+ if run_workers :
1847+ # run as many worker processes than the number of tests
1848+ cmd .append (f'-j{ len (tests )} ' )
1849+ cmd .extend (tests )
1850+ output = self .run_tests (* cmd )
1851+
1852+ random .seed (random_seed )
1853+ # Make the assumption that nothing consume entropy between libregrest
1854+ # setup_tests() which calls random.seed() and RandomSeedTest calling
1855+ # random.randint().
1856+ numbers = [random .randint (0 , 1000 ) for _ in range (10 )]
1857+ expected = f"Random numbers: { numbers } "
1858+
1859+ regex = r'^Random numbers: .*$'
1860+ matches = re .findall (regex , output , flags = re .MULTILINE )
1861+ self .assertEqual (matches , [expected ] * len (tests ))
1862+
1863+ def test_random_seed (self ):
1864+ self ._check_random_seed (run_workers = False )
1865+
1866+ def test_random_seed_workers (self ):
1867+ self ._check_random_seed (run_workers = True )
1868+
18301869
18311870class TestUtils (unittest .TestCase ):
18321871 def test_format_duration (self ):
0 commit comments