diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 08926bf88..0c159e02f 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -482,11 +482,8 @@ class BaseTest: self.checkequal(' a\n b', ' \ta\n\tb', 'expandtabs', 1) self.checkraises(TypeError, 'hello', 'expandtabs', 42, 42) - # TODO: RUSTPYTHON; expandtabs overflow checks - # if sys.maxsize < (1 << 32) and struct.calcsize('P') == 4: - # # This test is only valid when sizeof(int) == sizeof(void*) == 4. - if sys.maxsize < (1 << 32) and struct.calcsize('P') == 4 and False: + if sys.maxsize < (1 << 32) and struct.calcsize('P') == 4: self.checkraises(OverflowError, '\ta\n\tb', 'expandtabs', sys.maxsize) diff --git a/Lib/test/test_baseexception.py b/Lib/test/test_baseexception.py index 5870dc7f9..0c206c4e3 100644 --- a/Lib/test/test_baseexception.py +++ b/Lib/test/test_baseexception.py @@ -79,10 +79,8 @@ class ExceptionClassTests(unittest.TestCase): # Underscore-prefixed (private) exceptions don't need to be documented exc_set = set(e for e in exc_set if not e.startswith('_')) - # RUSTPYTHON specific - exc_set.discard("JitError") - # XXX: RUSTPYTHON; IncompleteInputError will be officially introduced in Python 3.15 - exc_set.discard("IncompleteInputError") + exc_set.discard("JitError") # XXX: RUSTPYTHON specific + exc_set.discard("IncompleteInputError") # XXX: RUSTPYTHON; IncompleteInputError will be officially introduced in Python 3.15 self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set) interface_tests = ("length", "args", "str", "repr") diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index 8f528812e..ea76b1282 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -9,7 +9,12 @@ high memory limit to regrtest, with the -M option. """ from test import support -from test.support import bigmemtest, _1G, _2G, _4G +from test.support import bigmemtest, _1G, _2G, _4G, import_helper +# _testcapi = import_helper.import_module('_testcapi') +try: # TODO: RUSTPYTHON + import _testcapi +except ImportError: + _testcapi = None import unittest import operator @@ -784,17 +789,14 @@ class BytesTest(unittest.TestCase, BaseStrTest): def test_swapcase(self, size): self._test_swapcase(size) - # TODO: RUSTPYTHON - @unittest.expectedFailure - @bigmemtest(size=_2G, memuse=2) - def test_isspace(self, size): - super().test_isspace(size) + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_isspace(self): + return super().test_isspace() + + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_istitle(self): + return super().test_istitle() - # TODO: RUSTPYTHON - @unittest.expectedFailure - @bigmemtest(size=_2G, memuse=2) - def test_istitle(self, size): - super().test_istitle(size) class BytearrayTest(unittest.TestCase, BaseStrTest): @@ -821,17 +823,13 @@ class BytearrayTest(unittest.TestCase, BaseStrTest): test_hash = None test_split_large = None - # TODO: RUSTPYTHON - @unittest.expectedFailure - @bigmemtest(size=_2G, memuse=2) - def test_isspace(self, size): - super().test_isspace(size) + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_isspace(self): + return super().test_isspace() - # TODO: RUSTPYTHON - @unittest.expectedFailure - @bigmemtest(size=_2G, memuse=2) - def test_istitle(self, size): - super().test_istitle(size) + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_istitle(self): + return super().test_istitle() class TupleTest(unittest.TestCase): @@ -1280,6 +1278,27 @@ class DictTest(unittest.TestCase): d[size] = 1 +class ImmortalityTest(unittest.TestCase): + + @bigmemtest(size=_2G, memuse=pointer_size * 9/8) + def test_stickiness(self, size): + """Check that immortality is "sticky", so that + once an object is immortal it remains so.""" + if size < _2G: + # Not enough memory to cause immortality on overflow + return + o1 = o2 = o3 = o4 = o5 = o6 = o7 = o8 = object() + l = [o1] * (size-20) + self.assertFalse(_testcapi.is_immortal(o1)) + for _ in range(30): + l.append(l[0]) + self.assertTrue(_testcapi.is_immortal(o1)) + del o2, o3, o4, o5, o6, o7, o8 + self.assertTrue(_testcapi.is_immortal(o1)) + del l + self.assertTrue(_testcapi.is_immortal(o1)) + + if __name__ == '__main__': if len(sys.argv) > 1: support.set_memlimit(sys.argv[1]) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index a63978fd1..ba2fa9970 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -8,7 +8,7 @@ import types import unittest from test import support -from test.support import findfile +from test.support import findfile, MS_WINDOWS if not support.has_subprocess_support: @@ -103,6 +103,7 @@ class SystemTapBackend(TraceBackend): COMMAND = ["stap", "-g"] +@unittest.skipIf(MS_WINDOWS, "Tests not compliant with trace on Windows.") class TraceTests: # unittest.TestCase options maxDiff = None @@ -159,43 +160,11 @@ class DTraceNormalTests(TraceTests, unittest.TestCase): backend = DTraceBackend() optimize_python = 0 - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_function_entry_return(self): - return super().test_function_entry_return() - - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_verify_call_opcodes(self): - return super().test_verify_call_opcodes() - - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_gc(self): - return super().test_gc() - - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_line(self): - return super().test_line() - class DTraceOptimizedTests(TraceTests, unittest.TestCase): backend = DTraceBackend() optimize_python = 2 - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_function_entry_return(self): - return super().test_function_entry_return() - - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_verify_call_opcodes(self): - return super().test_verify_call_opcodes() - - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_gc(self): - return super().test_gc() - - @unittest.expectedFailureIfWindows('TODO: RUSTPYTHON') - def test_line(self): - return super().test_line() - class SystemTapNormalTests(TraceTests, unittest.TestCase): backend = SystemTapBackend() diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index 507bbc2ec..1e1c43a6b 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -1,4 +1,4 @@ -import collections.abc +import collections import types import unittest from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, exceeds_recursion_limit @@ -194,6 +194,79 @@ class StrAndReprTests(unittest.TestCase): "MyEG('flat', [ValueError(1), TypeError(2)]), " "TypeError(2)])")) + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Tuples differ: ('test', (ValueError(1), TypeError(2))) != ('test', []) + def test_exceptions_mutation(self): + class MyEG(ExceptionGroup): + pass + + excs = [ValueError(1), TypeError(2)] + eg = MyEG('test', excs) + + self.assertEqual(repr(eg), "MyEG('test', [ValueError(1), TypeError(2)])") + excs.clear() + + # Ensure that clearing the exceptions sequence doesn't change the repr. + self.assertEqual(repr(eg), "MyEG('test', [ValueError(1), TypeError(2)])") + + # Ensure that the args are still as passed. + self.assertEqual(eg.args, ('test', [])) + + excs = (ValueError(1), KeyboardInterrupt(2)) + eg = BaseExceptionGroup('test', excs) + + # Ensure that immutable sequences still work fine. + self.assertEqual( + repr(eg), + "BaseExceptionGroup('test', (ValueError(1), KeyboardInterrupt(2)))" + ) + + # Test non-standard custom sequences. + excs = collections.deque([ValueError(1), TypeError(2)]) + eg = ExceptionGroup('test', excs) + + self.assertEqual( + repr(eg), + "ExceptionGroup('test', deque([ValueError(1), TypeError(2)]))" + ) + excs.clear() + + # Ensure that clearing the exceptions sequence doesn't change the repr. + self.assertEqual( + repr(eg), + "ExceptionGroup('test', deque([ValueError(1), TypeError(2)]))" + ) + + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: TypeError not raised + def test_repr_raises(self): + class MySeq(collections.abc.Sequence): + def __init__(self, raises): + self.raises = raises + + def __len__(self): + return 1 + + def __getitem__(self, index): + if index == 0: + return ValueError(1) + raise IndexError + + def __repr__(self): + if self.raises: + raise self.raises + return None + + seq = MySeq(None) + with self.assertRaisesRegex( + TypeError, + r"__repr__ returned non-string \(type NoneType\)" + ): + ExceptionGroup("test", seq) + + seq = MySeq(ValueError) + with self.assertRaises(ValueError): + BaseExceptionGroup("test", seq) + + def create_simple_eg(): excs = [] diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 7e79732a3..621c9d823 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2528,6 +2528,31 @@ class SyntaxErrorTests(unittest.TestCase): args = ("bad.py", 1, 2, "abcdefg", 1) self.assertRaises(TypeError, SyntaxError, "bad bad", args) + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 2 is not None + def test_syntax_error_memory_leak(self): + # gh-146250: memory leak with re-initialization of SyntaxError + e = SyntaxError("msg", ("file.py", 1, 2, "txt", 2, 3)) + e.__init__("new_msg", ("new_file.py", 2, 3, "new_txt", 3, 4)) + self.assertEqual(e.msg, "new_msg") + self.assertEqual(e.args, ("new_msg", ("new_file.py", 2, 3, "new_txt", 3, 4))) + self.assertEqual(e.filename, "new_file.py") + self.assertEqual(e.lineno, 2) + self.assertEqual(e.offset, 3) + self.assertEqual(e.text, "new_txt") + self.assertEqual(e.end_lineno, 3) + self.assertEqual(e.end_offset, 4) + + e = SyntaxError("msg", ("file.py", 1, 2, "txt", 2, 3)) + e.__init__("new_msg", ("new_file.py", 2, 3, "new_txt")) + self.assertEqual(e.msg, "new_msg") + self.assertEqual(e.args, ("new_msg", ("new_file.py", 2, 3, "new_txt"))) + self.assertEqual(e.filename, "new_file.py") + self.assertEqual(e.lineno, 2) + self.assertEqual(e.offset, 3) + self.assertEqual(e.text, "new_txt") + self.assertIsNone(e.end_lineno) + self.assertIsNone(e.end_offset) + class TestInvalidExceptionMatcher(unittest.TestCase): def test_except_star_invalid_exception_type(self): diff --git a/Lib/test/test_fileutils.py b/Lib/test/test_fileutils.py new file mode 100644 index 000000000..ff13498fb --- /dev/null +++ b/Lib/test/test_fileutils.py @@ -0,0 +1,30 @@ +# Run tests for functions in Python/fileutils.c. + +import os +import os.path +import unittest +from test.support import import_helper + +# Skip this test if the _testcapi module isn't available. +_testcapi = import_helper.import_module('_testinternalcapi') + + +class PathTests(unittest.TestCase): + + def test_capi_normalize_path(self): + if os.name == 'nt': + raise unittest.SkipTest('Windows has its own helper for this') + else: + from test.test_posixpath import PosixPathTest as posixdata + tests = posixdata.NORMPATH_CASES + for filename, expected in tests: + if not os.path.isabs(filename): + continue + with self.subTest(filename): + result = _testcapi.normalize_path(filename) + self.assertEqual(result, expected, + msg=f'input: {filename!r} expected output: {expected!r}') + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py index c9cd182d6..23bbd6c88 100644 --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -37,9 +37,8 @@ from test.test_doctest import (test_doctest, def _run_object_doctest(obj, module): from test.support.rustpython import DocTestChecker # TODO: RUSTPYTHON finder = doctest.DocTestFinder(verbose=verbose, recurse=False) - # TODO: RUSTPYTHON - # runner = doctest.DocTestRunner(verbose=verbose) - runner = doctest.DocTestRunner(verbose=verbose, checker=DocTestChecker()) + runner = doctest.DocTestRunner(verbose=verbose) + runner = doctest.DocTestRunner(verbose=verbose, checker=DocTestChecker()) # TODO: RUSTPYTHON # Use the object's fully qualified name if it has one # Otherwise, use the module's name try: