python (3.11.7)

(root)/
lib/
python3.11/
test/
test_support.py
       1  import errno
       2  import importlib
       3  import io
       4  import os
       5  import shutil
       6  import socket
       7  import stat
       8  import subprocess
       9  import sys
      10  import sysconfig
      11  import tempfile
      12  import textwrap
      13  import unittest
      14  import warnings
      15  
      16  from test import support
      17  from test.support import import_helper
      18  from test.support import os_helper
      19  from test.support import script_helper
      20  from test.support import socket_helper
      21  from test.support import warnings_helper
      22  
      23  TESTFN = os_helper.TESTFN
      24  
      25  
      26  class ESC[4;38;5;81mTestSupport(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      27      @classmethod
      28      def setUpClass(cls):
      29          orig_filter_len = len(warnings.filters)
      30          cls._warnings_helper_token = support.ignore_deprecations_from(
      31              "test.support.warnings_helper", like=".*used in test_support.*"
      32          )
      33          cls._test_support_token = support.ignore_deprecations_from(
      34              __name__, like=".*You should NOT be seeing this.*"
      35          )
      36          assert len(warnings.filters) == orig_filter_len + 2
      37  
      38      @classmethod
      39      def tearDownClass(cls):
      40          orig_filter_len = len(warnings.filters)
      41          support.clear_ignored_deprecations(
      42              cls._warnings_helper_token,
      43              cls._test_support_token,
      44          )
      45          assert len(warnings.filters) == orig_filter_len - 2
      46  
      47      def test_ignored_deprecations_are_silent(self):
      48          """Test support.ignore_deprecations_from() silences warnings"""
      49          with warnings.catch_warnings(record=True) as warning_objs:
      50              warnings_helper._warn_about_deprecation()
      51              warnings.warn("You should NOT be seeing this.", DeprecationWarning)
      52              messages = [str(w.message) for w in warning_objs]
      53          self.assertEqual(len(messages), 0, messages)
      54  
      55      def test_import_module(self):
      56          import_helper.import_module("ftplib")
      57          self.assertRaises(unittest.SkipTest,
      58                            import_helper.import_module, "foo")
      59  
      60      def test_import_fresh_module(self):
      61          import_helper.import_fresh_module("ftplib")
      62  
      63      def test_get_attribute(self):
      64          self.assertEqual(support.get_attribute(self, "test_get_attribute"),
      65                          self.test_get_attribute)
      66          self.assertRaises(unittest.SkipTest, support.get_attribute, self, "foo")
      67  
      68      @unittest.skip("failing buildbots")
      69      def test_get_original_stdout(self):
      70          self.assertEqual(support.get_original_stdout(), sys.stdout)
      71  
      72      def test_unload(self):
      73          import sched
      74          self.assertIn("sched", sys.modules)
      75          import_helper.unload("sched")
      76          self.assertNotIn("sched", sys.modules)
      77  
      78      def test_unlink(self):
      79          with open(TESTFN, "w", encoding="utf-8") as f:
      80              pass
      81          os_helper.unlink(TESTFN)
      82          self.assertFalse(os.path.exists(TESTFN))
      83          os_helper.unlink(TESTFN)
      84  
      85      def test_rmtree(self):
      86          dirpath = os_helper.TESTFN + 'd'
      87          subdirpath = os.path.join(dirpath, 'subdir')
      88          os.mkdir(dirpath)
      89          os.mkdir(subdirpath)
      90          os_helper.rmtree(dirpath)
      91          self.assertFalse(os.path.exists(dirpath))
      92          with support.swap_attr(support, 'verbose', 0):
      93              os_helper.rmtree(dirpath)
      94  
      95          os.mkdir(dirpath)
      96          os.mkdir(subdirpath)
      97          os.chmod(dirpath, stat.S_IRUSR|stat.S_IXUSR)
      98          with support.swap_attr(support, 'verbose', 0):
      99              os_helper.rmtree(dirpath)
     100          self.assertFalse(os.path.exists(dirpath))
     101  
     102          os.mkdir(dirpath)
     103          os.mkdir(subdirpath)
     104          os.chmod(dirpath, 0)
     105          with support.swap_attr(support, 'verbose', 0):
     106              os_helper.rmtree(dirpath)
     107          self.assertFalse(os.path.exists(dirpath))
     108  
     109      def test_forget(self):
     110          mod_filename = TESTFN + '.py'
     111          with open(mod_filename, 'w', encoding="utf-8") as f:
     112              print('foo = 1', file=f)
     113          sys.path.insert(0, os.curdir)
     114          importlib.invalidate_caches()
     115          try:
     116              mod = __import__(TESTFN)
     117              self.assertIn(TESTFN, sys.modules)
     118  
     119              import_helper.forget(TESTFN)
     120              self.assertNotIn(TESTFN, sys.modules)
     121          finally:
     122              del sys.path[0]
     123              os_helper.unlink(mod_filename)
     124              os_helper.rmtree('__pycache__')
     125  
     126      @support.requires_working_socket()
     127      def test_HOST(self):
     128          s = socket.create_server((socket_helper.HOST, 0))
     129          s.close()
     130  
     131      @support.requires_working_socket()
     132      def test_find_unused_port(self):
     133          port = socket_helper.find_unused_port()
     134          s = socket.create_server((socket_helper.HOST, port))
     135          s.close()
     136  
     137      @support.requires_working_socket()
     138      def test_bind_port(self):
     139          s = socket.socket()
     140          socket_helper.bind_port(s)
     141          s.listen()
     142          s.close()
     143  
     144      # Tests for temp_dir()
     145  
     146      def test_temp_dir(self):
     147          """Test that temp_dir() creates and destroys its directory."""
     148          parent_dir = tempfile.mkdtemp()
     149          parent_dir = os.path.realpath(parent_dir)
     150  
     151          try:
     152              path = os.path.join(parent_dir, 'temp')
     153              self.assertFalse(os.path.isdir(path))
     154              with os_helper.temp_dir(path) as temp_path:
     155                  self.assertEqual(temp_path, path)
     156                  self.assertTrue(os.path.isdir(path))
     157              self.assertFalse(os.path.isdir(path))
     158          finally:
     159              os_helper.rmtree(parent_dir)
     160  
     161      def test_temp_dir__path_none(self):
     162          """Test passing no path."""
     163          with os_helper.temp_dir() as temp_path:
     164              self.assertTrue(os.path.isdir(temp_path))
     165          self.assertFalse(os.path.isdir(temp_path))
     166  
     167      def test_temp_dir__existing_dir__quiet_default(self):
     168          """Test passing a directory that already exists."""
     169          def call_temp_dir(path):
     170              with os_helper.temp_dir(path) as temp_path:
     171                  raise Exception("should not get here")
     172  
     173          path = tempfile.mkdtemp()
     174          path = os.path.realpath(path)
     175          try:
     176              self.assertTrue(os.path.isdir(path))
     177              self.assertRaises(FileExistsError, call_temp_dir, path)
     178              # Make sure temp_dir did not delete the original directory.
     179              self.assertTrue(os.path.isdir(path))
     180          finally:
     181              shutil.rmtree(path)
     182  
     183      def test_temp_dir__existing_dir__quiet_true(self):
     184          """Test passing a directory that already exists with quiet=True."""
     185          path = tempfile.mkdtemp()
     186          path = os.path.realpath(path)
     187  
     188          try:
     189              with warnings_helper.check_warnings() as recorder:
     190                  with os_helper.temp_dir(path, quiet=True) as temp_path:
     191                      self.assertEqual(path, temp_path)
     192                  warnings = [str(w.message) for w in recorder.warnings]
     193              # Make sure temp_dir did not delete the original directory.
     194              self.assertTrue(os.path.isdir(path))
     195          finally:
     196              shutil.rmtree(path)
     197  
     198          self.assertEqual(len(warnings), 1, warnings)
     199          warn = warnings[0]
     200          self.assertTrue(warn.startswith(f'tests may fail, unable to create '
     201                                          f'temporary directory {path!r}: '),
     202                          warn)
     203  
     204      @support.requires_fork()
     205      def test_temp_dir__forked_child(self):
     206          """Test that a forked child process does not remove the directory."""
     207          # See bpo-30028 for details.
     208          # Run the test as an external script, because it uses fork.
     209          script_helper.assert_python_ok("-c", textwrap.dedent("""
     210              import os
     211              from test import support
     212              from test.support import os_helper
     213              with os_helper.temp_cwd() as temp_path:
     214                  pid = os.fork()
     215                  if pid != 0:
     216                      # parent process
     217  
     218                      # wait for the child to terminate
     219                      support.wait_process(pid, exitcode=0)
     220  
     221                      # Make sure that temp_path is still present. When the child
     222                      # process leaves the 'temp_cwd'-context, the __exit__()-
     223                      # method of the context must not remove the temporary
     224                      # directory.
     225                      if not os.path.isdir(temp_path):
     226                          raise AssertionError("Child removed temp_path.")
     227          """))
     228  
     229      # Tests for change_cwd()
     230  
     231      def test_change_cwd(self):
     232          original_cwd = os.getcwd()
     233  
     234          with os_helper.temp_dir() as temp_path:
     235              with os_helper.change_cwd(temp_path) as new_cwd:
     236                  self.assertEqual(new_cwd, temp_path)
     237                  self.assertEqual(os.getcwd(), new_cwd)
     238  
     239          self.assertEqual(os.getcwd(), original_cwd)
     240  
     241      def test_change_cwd__non_existent_dir(self):
     242          """Test passing a non-existent directory."""
     243          original_cwd = os.getcwd()
     244  
     245          def call_change_cwd(path):
     246              with os_helper.change_cwd(path) as new_cwd:
     247                  raise Exception("should not get here")
     248  
     249          with os_helper.temp_dir() as parent_dir:
     250              non_existent_dir = os.path.join(parent_dir, 'does_not_exist')
     251              self.assertRaises(FileNotFoundError, call_change_cwd,
     252                                non_existent_dir)
     253  
     254          self.assertEqual(os.getcwd(), original_cwd)
     255  
     256      def test_change_cwd__non_existent_dir__quiet_true(self):
     257          """Test passing a non-existent directory with quiet=True."""
     258          original_cwd = os.getcwd()
     259  
     260          with os_helper.temp_dir() as parent_dir:
     261              bad_dir = os.path.join(parent_dir, 'does_not_exist')
     262              with warnings_helper.check_warnings() as recorder:
     263                  with os_helper.change_cwd(bad_dir, quiet=True) as new_cwd:
     264                      self.assertEqual(new_cwd, original_cwd)
     265                      self.assertEqual(os.getcwd(), new_cwd)
     266                  warnings = [str(w.message) for w in recorder.warnings]
     267  
     268          self.assertEqual(len(warnings), 1, warnings)
     269          warn = warnings[0]
     270          self.assertTrue(warn.startswith(f'tests may fail, unable to change '
     271                                          f'the current working directory '
     272                                          f'to {bad_dir!r}: '),
     273                          warn)
     274  
     275      # Tests for change_cwd()
     276  
     277      def test_change_cwd__chdir_warning(self):
     278          """Check the warning message when os.chdir() fails."""
     279          path = TESTFN + '_does_not_exist'
     280          with warnings_helper.check_warnings() as recorder:
     281              with os_helper.change_cwd(path=path, quiet=True):
     282                  pass
     283              messages = [str(w.message) for w in recorder.warnings]
     284  
     285          self.assertEqual(len(messages), 1, messages)
     286          msg = messages[0]
     287          self.assertTrue(msg.startswith(f'tests may fail, unable to change '
     288                                         f'the current working directory '
     289                                         f'to {path!r}: '),
     290                          msg)
     291  
     292      # Tests for temp_cwd()
     293  
     294      def test_temp_cwd(self):
     295          here = os.getcwd()
     296          with os_helper.temp_cwd(name=TESTFN):
     297              self.assertEqual(os.path.basename(os.getcwd()), TESTFN)
     298          self.assertFalse(os.path.exists(TESTFN))
     299          self.assertEqual(os.getcwd(), here)
     300  
     301  
     302      def test_temp_cwd__name_none(self):
     303          """Test passing None to temp_cwd()."""
     304          original_cwd = os.getcwd()
     305          with os_helper.temp_cwd(name=None) as new_cwd:
     306              self.assertNotEqual(new_cwd, original_cwd)
     307              self.assertTrue(os.path.isdir(new_cwd))
     308              self.assertEqual(os.getcwd(), new_cwd)
     309          self.assertEqual(os.getcwd(), original_cwd)
     310  
     311      def test_sortdict(self):
     312          self.assertEqual(support.sortdict({3:3, 2:2, 1:1}), "{1: 1, 2: 2, 3: 3}")
     313  
     314      def test_make_bad_fd(self):
     315          fd = os_helper.make_bad_fd()
     316          with self.assertRaises(OSError) as cm:
     317              os.write(fd, b"foo")
     318          self.assertEqual(cm.exception.errno, errno.EBADF)
     319  
     320      def test_check_syntax_error(self):
     321          support.check_syntax_error(self, "def class", lineno=1, offset=5)
     322          with self.assertRaises(AssertionError):
     323              support.check_syntax_error(self, "x=1")
     324  
     325      def test_CleanImport(self):
     326          import importlib
     327          with import_helper.CleanImport("pprint"):
     328              importlib.import_module("pprint")
     329  
     330      def test_DirsOnSysPath(self):
     331          with import_helper.DirsOnSysPath('foo', 'bar'):
     332              self.assertIn("foo", sys.path)
     333              self.assertIn("bar", sys.path)
     334          self.assertNotIn("foo", sys.path)
     335          self.assertNotIn("bar", sys.path)
     336  
     337      def test_captured_stdout(self):
     338          with support.captured_stdout() as stdout:
     339              print("hello")
     340          self.assertEqual(stdout.getvalue(), "hello\n")
     341  
     342      def test_captured_stderr(self):
     343          with support.captured_stderr() as stderr:
     344              print("hello", file=sys.stderr)
     345          self.assertEqual(stderr.getvalue(), "hello\n")
     346  
     347      def test_captured_stdin(self):
     348          with support.captured_stdin() as stdin:
     349              stdin.write('hello\n')
     350              stdin.seek(0)
     351              # call test code that consumes from sys.stdin
     352              captured = input()
     353          self.assertEqual(captured, "hello")
     354  
     355      def test_gc_collect(self):
     356          support.gc_collect()
     357  
     358      def test_python_is_optimized(self):
     359          self.assertIsInstance(support.python_is_optimized(), bool)
     360  
     361      def test_swap_attr(self):
     362          class ESC[4;38;5;81mObj:
     363              pass
     364          obj = Obj()
     365          obj.x = 1
     366          with support.swap_attr(obj, "x", 5) as x:
     367              self.assertEqual(obj.x, 5)
     368              self.assertEqual(x, 1)
     369          self.assertEqual(obj.x, 1)
     370          with support.swap_attr(obj, "y", 5) as y:
     371              self.assertEqual(obj.y, 5)
     372              self.assertIsNone(y)
     373          self.assertFalse(hasattr(obj, 'y'))
     374          with support.swap_attr(obj, "y", 5):
     375              del obj.y
     376          self.assertFalse(hasattr(obj, 'y'))
     377  
     378      def test_swap_item(self):
     379          D = {"x":1}
     380          with support.swap_item(D, "x", 5) as x:
     381              self.assertEqual(D["x"], 5)
     382              self.assertEqual(x, 1)
     383          self.assertEqual(D["x"], 1)
     384          with support.swap_item(D, "y", 5) as y:
     385              self.assertEqual(D["y"], 5)
     386              self.assertIsNone(y)
     387          self.assertNotIn("y", D)
     388          with support.swap_item(D, "y", 5):
     389              del D["y"]
     390          self.assertNotIn("y", D)
     391  
     392      class ESC[4;38;5;81mRefClass:
     393          attribute1 = None
     394          attribute2 = None
     395          _hidden_attribute1 = None
     396          __magic_1__ = None
     397  
     398      class ESC[4;38;5;81mOtherClass:
     399          attribute2 = None
     400          attribute3 = None
     401          __magic_1__ = None
     402          __magic_2__ = None
     403  
     404      def test_detect_api_mismatch(self):
     405          missing_items = support.detect_api_mismatch(self.RefClass,
     406                                                      self.OtherClass)
     407          self.assertEqual({'attribute1'}, missing_items)
     408  
     409          missing_items = support.detect_api_mismatch(self.OtherClass,
     410                                                      self.RefClass)
     411          self.assertEqual({'attribute3', '__magic_2__'}, missing_items)
     412  
     413      def test_detect_api_mismatch__ignore(self):
     414          ignore = ['attribute1', 'attribute3', '__magic_2__', 'not_in_either']
     415  
     416          missing_items = support.detect_api_mismatch(
     417                  self.RefClass, self.OtherClass, ignore=ignore)
     418          self.assertEqual(set(), missing_items)
     419  
     420          missing_items = support.detect_api_mismatch(
     421                  self.OtherClass, self.RefClass, ignore=ignore)
     422          self.assertEqual(set(), missing_items)
     423  
     424      def test_check__all__(self):
     425          extra = {'tempdir'}
     426          not_exported = {'template'}
     427          support.check__all__(self,
     428                               tempfile,
     429                               extra=extra,
     430                               not_exported=not_exported)
     431  
     432          extra = {
     433              'TextTestResult',
     434              'findTestCases',
     435              'getTestCaseNames',
     436              'installHandler',
     437              'makeSuite',
     438          }
     439          not_exported = {'load_tests', "TestProgram", "BaseTestSuite"}
     440          support.check__all__(self,
     441                               unittest,
     442                               ("unittest.result", "unittest.case",
     443                                "unittest.suite", "unittest.loader",
     444                                "unittest.main", "unittest.runner",
     445                                "unittest.signals", "unittest.async_case"),
     446                               extra=extra,
     447                               not_exported=not_exported)
     448  
     449          self.assertRaises(AssertionError, support.check__all__, self, unittest)
     450  
     451      @unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'),
     452                           'need os.waitpid() and os.WNOHANG')
     453      @support.requires_fork()
     454      def test_reap_children(self):
     455          # Make sure that there is no other pending child process
     456          support.reap_children()
     457  
     458          # Create a child process
     459          pid = os.fork()
     460          if pid == 0:
     461              # child process: do nothing, just exit
     462              os._exit(0)
     463  
     464          was_altered = support.environment_altered
     465          try:
     466              support.environment_altered = False
     467              stderr = io.StringIO()
     468  
     469              for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
     470                  with support.swap_attr(support.print_warning, 'orig_stderr', stderr):
     471                      support.reap_children()
     472  
     473                  # Use environment_altered to check if reap_children() found
     474                  # the child process
     475                  if support.environment_altered:
     476                      break
     477  
     478              msg = "Warning -- reap_children() reaped child process %s" % pid
     479              self.assertIn(msg, stderr.getvalue())
     480              self.assertTrue(support.environment_altered)
     481          finally:
     482              support.environment_altered = was_altered
     483  
     484          # Just in case, check again that there is no other
     485          # pending child process
     486          support.reap_children()
     487  
     488      @support.requires_subprocess()
     489      def check_options(self, args, func, expected=None):
     490          code = f'from test.support import {func}; print(repr({func}()))'
     491          cmd = [sys.executable, *args, '-c', code]
     492          env = {key: value for key, value in os.environ.items()
     493                 if not key.startswith('PYTHON')}
     494          proc = subprocess.run(cmd,
     495                                stdout=subprocess.PIPE,
     496                                stderr=subprocess.DEVNULL,
     497                                universal_newlines=True,
     498                                env=env)
     499          if expected is None:
     500              expected = args
     501          self.assertEqual(proc.stdout.rstrip(), repr(expected))
     502          self.assertEqual(proc.returncode, 0)
     503  
     504      @support.requires_resource('cpu')
     505      def test_args_from_interpreter_flags(self):
     506          # Test test.support.args_from_interpreter_flags()
     507          for opts in (
     508              # no option
     509              [],
     510              # single option
     511              ['-B'],
     512              ['-s'],
     513              ['-S'],
     514              ['-E'],
     515              ['-v'],
     516              ['-b'],
     517              ['-P'],
     518              ['-q'],
     519              ['-I'],
     520              # same option multiple times
     521              ['-bb'],
     522              ['-vvv'],
     523              # -W options
     524              ['-Wignore'],
     525              # -X options
     526              ['-X', 'dev'],
     527              ['-Wignore', '-X', 'dev'],
     528              ['-X', 'faulthandler'],
     529              ['-X', 'importtime'],
     530              ['-X', 'showrefcount'],
     531              ['-X', 'tracemalloc'],
     532              ['-X', 'tracemalloc=3'],
     533          ):
     534              with self.subTest(opts=opts):
     535                  self.check_options(opts, 'args_from_interpreter_flags')
     536  
     537          self.check_options(['-I', '-E', '-s', '-P'],
     538                             'args_from_interpreter_flags',
     539                             ['-I'])
     540  
     541      def test_optim_args_from_interpreter_flags(self):
     542          # Test test.support.optim_args_from_interpreter_flags()
     543          for opts in (
     544              # no option
     545              [],
     546              ['-O'],
     547              ['-OO'],
     548              ['-OOOO'],
     549          ):
     550              with self.subTest(opts=opts):
     551                  self.check_options(opts, 'optim_args_from_interpreter_flags')
     552  
     553      @unittest.skipIf(support.is_emscripten, "Unstable in Emscripten")
     554      @unittest.skipIf(support.is_wasi, "Unavailable on WASI")
     555      def test_fd_count(self):
     556          # We cannot test the absolute value of fd_count(): on old Linux
     557          # kernel or glibc versions, os.urandom() keeps a FD open on
     558          # /dev/urandom device and Python has 4 FD opens instead of 3.
     559          # Test is unstable on Emscripten. The platform starts and stops
     560          # background threads that use pipes and epoll fds.
     561          start = os_helper.fd_count()
     562          fd = os.open(__file__, os.O_RDONLY)
     563          try:
     564              more = os_helper.fd_count()
     565          finally:
     566              os.close(fd)
     567          self.assertEqual(more - start, 1)
     568  
     569      def check_print_warning(self, msg, expected):
     570          stderr = io.StringIO()
     571          with support.swap_attr(support.print_warning, 'orig_stderr', stderr):
     572              support.print_warning(msg)
     573          self.assertEqual(stderr.getvalue(), expected)
     574  
     575      def test_print_warning(self):
     576          self.check_print_warning("msg",
     577                                   "Warning -- msg\n")
     578          self.check_print_warning("a\nb",
     579                                   'Warning -- a\nWarning -- b\n')
     580  
     581      def test_has_strftime_extensions(self):
     582          if support.is_emscripten or sys.platform == "win32":
     583              self.assertFalse(support.has_strftime_extensions)
     584          else:
     585              self.assertTrue(support.has_strftime_extensions)
     586  
     587      def test_get_recursion_depth(self):
     588          # test support.get_recursion_depth()
     589          code = textwrap.dedent("""
     590              from test import support
     591              import sys
     592              try:
     593                  from _testcapi import USE_STACKCHECK
     594              except ImportError:
     595                  USE_STACKCHECK = False
     596  
     597              def check(cond):
     598                  if not cond:
     599                      raise AssertionError("test failed")
     600  
     601              # depth 1
     602              check(support.get_recursion_depth() == 1)
     603  
     604              # depth 2
     605              def test_func():
     606                  check(support.get_recursion_depth() == 2)
     607              test_func()
     608  
     609              def test_recursive(depth, limit):
     610                  if depth >= limit:
     611                      # cannot call get_recursion_depth() at this depth,
     612                      # it can raise RecursionError
     613                      return
     614                  get_depth = support.get_recursion_depth()
     615                  print(f"test_recursive: {depth}/{limit}: "
     616                        f"get_recursion_depth() says {get_depth}")
     617                  check(get_depth == depth)
     618                  test_recursive(depth + 1, limit)
     619  
     620              if USE_STACKCHECK:
     621                  # f-string consumes 2 frames and -1 for USE_STACKCHECK
     622                  IGNORE = 3
     623              else:
     624                  # f-string consumes 2 frames
     625                  IGNORE = 2
     626  
     627              # depth up to 25
     628              with support.infinite_recursion(max_depth=25):
     629                  limit = sys.getrecursionlimit()
     630                  print(f"test with sys.getrecursionlimit()={limit}")
     631                  test_recursive(2, limit - IGNORE)
     632  
     633              # depth up to 500
     634              with support.infinite_recursion(max_depth=500):
     635                  limit = sys.getrecursionlimit()
     636                  print(f"test with sys.getrecursionlimit()={limit}")
     637                  test_recursive(2, limit - IGNORE)
     638          """)
     639          script_helper.assert_python_ok("-c", code)
     640  
     641      def test_recursion(self):
     642          # Test infinite_recursion() and get_recursion_available() functions.
     643          def recursive_function(depth):
     644              if depth:
     645                  recursive_function(depth - 1)
     646  
     647          for max_depth in (5, 25, 250):
     648              with support.infinite_recursion(max_depth):
     649                  available = support.get_recursion_available()
     650  
     651                  # Recursion up to 'available' additional frames should be OK.
     652                  recursive_function(available)
     653  
     654                  # Recursion up to 'available+1' additional frames must raise
     655                  # RecursionError. Avoid self.assertRaises(RecursionError) which
     656                  # can consume more than 3 frames and so raises RecursionError.
     657                  try:
     658                      recursive_function(available + 1)
     659                  except RecursionError:
     660                      pass
     661                  else:
     662                      self.fail("RecursionError was not raised")
     663  
     664          # Test the bare minimumum: max_depth=4
     665          with support.infinite_recursion(4):
     666              try:
     667                  recursive_function(4)
     668              except RecursionError:
     669                  pass
     670              else:
     671                  self.fail("RecursionError was not raised")
     672  
     673      def test_parse_memlimit(self):
     674          parse = support._parse_memlimit
     675          KiB = 1024
     676          MiB = KiB * 1024
     677          GiB = MiB * 1024
     678          TiB = GiB * 1024
     679          self.assertEqual(parse('0k'), 0)
     680          self.assertEqual(parse('3k'), 3 * KiB)
     681          self.assertEqual(parse('2.4m'), int(2.4 * MiB))
     682          self.assertEqual(parse('4g'), int(4 * GiB))
     683          self.assertEqual(parse('1t'), TiB)
     684  
     685          for limit in ('', '3', '3.5.10k', '10x'):
     686              with self.subTest(limit=limit):
     687                  with self.assertRaises(ValueError):
     688                      parse(limit)
     689  
     690      def test_set_memlimit(self):
     691          _4GiB = 4 * 1024 ** 3
     692          TiB = 1024 ** 4
     693          old_max_memuse = support.max_memuse
     694          old_real_max_memuse = support.real_max_memuse
     695          try:
     696              if sys.maxsize > 2**32:
     697                  support.set_memlimit('4g')
     698                  self.assertEqual(support.max_memuse, _4GiB)
     699                  self.assertEqual(support.real_max_memuse, _4GiB)
     700  
     701                  big = 2**100 // TiB
     702                  support.set_memlimit(f'{big}t')
     703                  self.assertEqual(support.max_memuse, sys.maxsize)
     704                  self.assertEqual(support.real_max_memuse, big * TiB)
     705              else:
     706                  support.set_memlimit('4g')
     707                  self.assertEqual(support.max_memuse, sys.maxsize)
     708                  self.assertEqual(support.real_max_memuse, _4GiB)
     709          finally:
     710              support.max_memuse = old_max_memuse
     711              support.real_max_memuse = old_real_max_memuse
     712  
     713      def test_copy_python_src_ignore(self):
     714          # Get source directory
     715          src_dir = sysconfig.get_config_var('abs_srcdir')
     716          if not src_dir:
     717              src_dir = sysconfig.get_config_var('srcdir')
     718          src_dir = os.path.abspath(src_dir)
     719  
     720          # Check that the source code is available
     721          if not os.path.exists(src_dir):
     722              self.skipTest(f"cannot access Python source code directory:"
     723                            f" {src_dir!r}")
     724          # Check that the landmark copy_python_src_ignore() expects is available
     725          # (Previously we looked for 'Lib\os.py', which is always present on Windows.)
     726          landmark = os.path.join(src_dir, 'Modules')
     727          if not os.path.exists(landmark):
     728              self.skipTest(f"cannot access Python source code directory:"
     729                            f" {landmark!r} landmark is missing")
     730  
     731          # Test support.copy_python_src_ignore()
     732  
     733          # Source code directory
     734          ignored = {'.git', '__pycache__'}
     735          names = os.listdir(src_dir)
     736          self.assertEqual(support.copy_python_src_ignore(src_dir, names),
     737                           ignored | {'build'})
     738  
     739          # Doc/ directory
     740          path = os.path.join(src_dir, 'Doc')
     741          self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)),
     742                           ignored | {'build', 'venv'})
     743  
     744          # Another directory
     745          path = os.path.join(src_dir, 'Objects')
     746          self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)),
     747                           ignored)
     748  
     749      # XXX -follows a list of untested API
     750      # make_legacy_pyc
     751      # is_resource_enabled
     752      # requires
     753      # fcmp
     754      # umaks
     755      # findfile
     756      # check_warnings
     757      # EnvironmentVarGuard
     758      # transient_internet
     759      # run_with_locale
     760      # bigmemtest
     761      # precisionbigmemtest
     762      # bigaddrspacetest
     763      # requires_resource
     764      # threading_cleanup
     765      # reap_threads
     766      # can_symlink
     767      # skip_unless_symlink
     768      # SuppressCrashReport
     769  
     770  
     771  if __name__ == '__main__':
     772      unittest.main()