mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 11:14:38 +08:00
Update test_faulthandler from v3.14.2
This commit is contained in:
1 parent
6b62b4cca9
commit
6bf394d249
1 file changed
+95
-77
Vendored
+95
-77
@@ -22,6 +22,16 @@ if not support.has_subprocess_support:
|
||||
|
||||
TIMEOUT = 0.5
|
||||
|
||||
STACK_HEADER_STR = r'Stack (most recent call first):'
|
||||
|
||||
# Regular expressions
|
||||
STACK_HEADER = re.escape(STACK_HEADER_STR)
|
||||
THREAD_NAME = r'( \[.*\])?'
|
||||
THREAD_ID = fr'Thread 0x[0-9a-f]+{THREAD_NAME}'
|
||||
THREAD_HEADER = fr'{THREAD_ID} \(most recent call first\):'
|
||||
CURRENT_THREAD_ID = fr'Current thread 0x[0-9a-f]+{THREAD_NAME}'
|
||||
CURRENT_THREAD_HEADER = fr'{CURRENT_THREAD_ID} \(most recent call first\):'
|
||||
|
||||
|
||||
def expected_traceback(lineno1, lineno2, header, min_count=1):
|
||||
regex = header
|
||||
@@ -45,6 +55,13 @@ def temporary_filename():
|
||||
finally:
|
||||
os_helper.unlink(filename)
|
||||
|
||||
|
||||
ADDRESS_EXPR = "0x[0-9a-f]+"
|
||||
C_STACK_REGEX = [
|
||||
r"Current thread's C stack trace \(most recent call first\):",
|
||||
fr'( Binary file ".+"(, at .*(\+|-){ADDRESS_EXPR})? \[{ADDRESS_EXPR}\])|(<.+>)'
|
||||
]
|
||||
|
||||
class FaultHandlerTests(unittest.TestCase):
|
||||
|
||||
def get_output(self, code, filename=None, fd=None):
|
||||
@@ -93,6 +110,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
fd=None, know_current_thread=True,
|
||||
py_fatal_error=False,
|
||||
garbage_collecting=False,
|
||||
c_stack=True,
|
||||
function='<module>'):
|
||||
"""
|
||||
Check that the fault handler for fatal errors is enabled and check the
|
||||
@@ -100,21 +118,32 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
|
||||
Raise an error if the output doesn't match the expected format.
|
||||
"""
|
||||
if all_threads:
|
||||
all_threads_disabled = (
|
||||
all_threads
|
||||
and (not sys._is_gil_enabled())
|
||||
)
|
||||
if all_threads and not all_threads_disabled:
|
||||
if know_current_thread:
|
||||
header = 'Current thread 0x[0-9a-f]+'
|
||||
header = CURRENT_THREAD_HEADER
|
||||
else:
|
||||
header = 'Thread 0x[0-9a-f]+'
|
||||
header = THREAD_HEADER
|
||||
else:
|
||||
header = 'Stack'
|
||||
header = STACK_HEADER
|
||||
regex = [f'^{fatal_error}']
|
||||
if py_fatal_error:
|
||||
regex.append("Python runtime state: initialized")
|
||||
regex.append('')
|
||||
regex.append(fr'{header} \(most recent call first\):')
|
||||
if garbage_collecting:
|
||||
regex.append(' Garbage-collecting')
|
||||
regex.append(fr' File "<string>", line {lineno} in {function}')
|
||||
if all_threads_disabled and not py_fatal_error:
|
||||
regex.append("<Cannot show all threads while the GIL is disabled>")
|
||||
regex.append(fr'{header}')
|
||||
if support.Py_GIL_DISABLED and py_fatal_error and not know_current_thread:
|
||||
regex.append(" <tstate is freed>")
|
||||
else:
|
||||
if garbage_collecting and not all_threads_disabled:
|
||||
regex.append(' Garbage-collecting')
|
||||
regex.append(fr' File "<string>", line {lineno} in {function}')
|
||||
if c_stack:
|
||||
regex.extend(C_STACK_REGEX)
|
||||
regex = '\n'.join(regex)
|
||||
|
||||
if other_regex:
|
||||
@@ -137,8 +166,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
fatal_error = 'Windows fatal exception: %s' % name_regex
|
||||
self.check_error(code, line_number, fatal_error, **kw)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform.startswith('aix'),
|
||||
"the first page of memory is a mapped read-only on AIX")
|
||||
def test_read_null(self):
|
||||
@@ -162,8 +189,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
3,
|
||||
'access violation')
|
||||
|
||||
# TODO: RUSTPYTHON, AssertionError: Regex didn't match
|
||||
@unittest.expectedFailure
|
||||
@skip_segfault_on_android
|
||||
def test_sigsegv(self):
|
||||
self.check_fatal_error("""
|
||||
@@ -174,8 +199,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
3,
|
||||
'Segmentation fault')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Regex didn't match: '(?m)^Fatal Python error: Segmentation fault\n\n<Cannot show all threads while the GIL is disabled>\nStack\\ \\(most\\ recent\\ call\\ first\\):\n File "<string>", line 9 in __del__\nCurrent thread\'s C stack trace \\(most recent call first\\):\n( Binary file ".+"(, at .*(\\+|-)0x[0-9a-f]+)? \\[0x[0-9a-f]+\\])|(<.+>)' not found in 'exit'
|
||||
@skip_segfault_on_android
|
||||
def test_gc(self):
|
||||
# bpo-44466: Detect if the GC is running
|
||||
@@ -212,8 +236,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
function='__del__',
|
||||
garbage_collecting=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 == 0
|
||||
def test_fatal_error_c_thread(self):
|
||||
self.check_fatal_error("""
|
||||
import faulthandler
|
||||
@@ -226,8 +249,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
func='faulthandler_fatal_error_thread',
|
||||
py_fatal_error=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@support.skip_if_sanitizer("TSAN itercepts SIGABRT", thread=True)
|
||||
def test_sigabrt(self):
|
||||
self.check_fatal_error("""
|
||||
import faulthandler
|
||||
@@ -237,10 +259,9 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
3,
|
||||
'Aborted')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform == 'win32',
|
||||
"SIGFPE cannot be caught on Windows")
|
||||
@support.skip_if_sanitizer("TSAN itercepts SIGFPE", thread=True)
|
||||
def test_sigfpe(self):
|
||||
self.check_fatal_error("""
|
||||
import faulthandler
|
||||
@@ -252,6 +273,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(_testcapi is None, 'need _testcapi')
|
||||
@unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
|
||||
@support.skip_if_sanitizer("TSAN itercepts SIGBUS", thread=True)
|
||||
@skip_segfault_on_android
|
||||
def test_sigbus(self):
|
||||
self.check_fatal_error("""
|
||||
@@ -266,6 +288,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(_testcapi is None, 'need _testcapi')
|
||||
@unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
|
||||
@support.skip_if_sanitizer("TSAN itercepts SIGILL", thread=True)
|
||||
@skip_segfault_on_android
|
||||
def test_sigill(self):
|
||||
self.check_fatal_error("""
|
||||
@@ -291,13 +314,9 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
func='_testcapi_fatal_error_impl',
|
||||
py_fatal_error=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_fatal_error(self):
|
||||
self.check_fatal_error_func(False)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_fatal_error_without_gil(self):
|
||||
self.check_fatal_error_func(True)
|
||||
|
||||
@@ -316,8 +335,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
'(?:Segmentation fault|Bus error)',
|
||||
other_regex='unable to raise a stack overflow')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@skip_segfault_on_android
|
||||
def test_gil_released(self):
|
||||
self.check_fatal_error("""
|
||||
@@ -328,8 +345,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
3,
|
||||
'Segmentation fault')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@skip_segfault_on_android
|
||||
def test_enable_file(self):
|
||||
with temporary_filename() as filename:
|
||||
@@ -343,8 +358,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
'Segmentation fault',
|
||||
filename=filename)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform == "win32",
|
||||
"subprocess doesn't support pass_fds on Windows")
|
||||
@skip_segfault_on_android
|
||||
@@ -361,8 +374,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
'Segmentation fault',
|
||||
fd=fd)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@skip_segfault_on_android
|
||||
def test_enable_single_thread(self):
|
||||
self.check_fatal_error("""
|
||||
@@ -389,8 +400,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
"%r is present in %r" % (not_expected, stderr))
|
||||
self.assertNotEqual(exitcode, 0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Cannot find 'Extension modules:' in 'Fatal Python error: Segmentation fault\n\nCurrent thread 0x0000000000004284 (most recent call first):\n File "<string>", line 6 in <module>'
|
||||
@skip_segfault_on_android
|
||||
def test_dump_ext_modules(self):
|
||||
code = """
|
||||
@@ -511,7 +521,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
else:
|
||||
lineno = 14
|
||||
expected = [
|
||||
'Stack (most recent call first):',
|
||||
f'{STACK_HEADER_STR}',
|
||||
' File "<string>", line %s in funcB' % lineno,
|
||||
' File "<string>", line 17 in funcA',
|
||||
' File "<string>", line 19 in <module>'
|
||||
@@ -523,14 +533,11 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
def test_dump_traceback(self):
|
||||
self.check_dump_traceback()
|
||||
|
||||
# TODO: RUSTPYTHON - binary file write needs different handling
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; - binary file write needs different handling
|
||||
def test_dump_traceback_file(self):
|
||||
with temporary_filename() as filename:
|
||||
self.check_dump_traceback(filename=filename)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform == "win32",
|
||||
"subprocess doesn't support pass_fds on Windows")
|
||||
def test_dump_traceback_fd(self):
|
||||
@@ -553,7 +560,7 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
func_name=func_name,
|
||||
)
|
||||
expected = [
|
||||
'Stack (most recent call first):',
|
||||
f'{STACK_HEADER_STR}',
|
||||
' File "<string>", line 4 in %s' % truncated,
|
||||
' File "<string>", line 6 in <module>'
|
||||
]
|
||||
@@ -607,28 +614,26 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
lineno = 10
|
||||
# When the traceback is dumped, the waiter thread may be in the
|
||||
# `self.running.set()` call or in `self.stop.wait()`.
|
||||
regex = r"""
|
||||
^Thread 0x[0-9a-f]+ \(most recent call first\):
|
||||
regex = fr"""
|
||||
^{THREAD_HEADER}
|
||||
(?: File ".*threading.py", line [0-9]+ in [_a-z]+
|
||||
){{1,3}} File "<string>", line (?:22|23) in run
|
||||
File ".*threading.py", line [0-9]+ in _bootstrap_inner
|
||||
File ".*threading.py", line [0-9]+ in _bootstrap
|
||||
|
||||
Current thread 0x[0-9a-f]+ \(most recent call first\):
|
||||
{CURRENT_THREAD_HEADER}
|
||||
File "<string>", line {lineno} in dump
|
||||
File "<string>", line 28 in <module>$
|
||||
"""
|
||||
regex = dedent(regex.format(lineno=lineno)).strip()
|
||||
regex = dedent(regex).strip()
|
||||
self.assertRegex(output, regex)
|
||||
self.assertEqual(exitcode, 0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Regex didn't match: '^Thread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\n(?: File ".*threading.py", line [0-9]+ in [_a-z]+\n){1,3} File "<string>", line (?:22|23) in run\n File ".*threading.py", line [0-9]+ in _bootstrap_inner\n File ".*threading.py", line [0-9]+ in _bootstrap\n\nCurrent thread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\n File "<string>", line 10 in dump\n File "<string>", line 28 in <module>$' not found in 'Stack (most recent call first):\n File "<string>", line 10 in dump\n File "<string>", line 28 in <module>'
|
||||
def test_dump_traceback_threads(self):
|
||||
self.check_dump_traceback_threads(None)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; - TypeError: a bytes-like object is required, not 'str'
|
||||
def test_dump_traceback_threads_file(self):
|
||||
with temporary_filename() as filename:
|
||||
self.check_dump_traceback_threads(filename)
|
||||
@@ -688,44 +693,38 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
count = loops
|
||||
if repeat:
|
||||
count *= 2
|
||||
header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
|
||||
header = (fr'Timeout \({timeout_str}\)!\n'
|
||||
fr'{THREAD_HEADER}\n')
|
||||
regex = expected_traceback(17, 26, header, min_count=count)
|
||||
self.assertRegex(trace, regex)
|
||||
else:
|
||||
self.assertEqual(trace, '')
|
||||
self.assertEqual(exitcode, 0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Regex didn't match: '^Timeout \\(0:00:00.500000\\)!\\nThread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\\n File "<string>", line 17 in func\n File "<string>", line 26 in <module>$' not found in 'Traceback (most recent call last):\n File "<string>", line 26, in <module>\n File "<string>", line 14, in func\nAttributeError: \'NoneType\' object has no attribute \'fileno\''
|
||||
def test_dump_traceback_later(self):
|
||||
self.check_dump_traceback_later()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Regex didn't match: '^Timeout \\(0:00:00.500000\\)!\\nThread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\\n File "<string>", line 17 in func\n File "<string>", line 26 in <module>\nTimeout \\(0:00:00.500000\\)!\\nThread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\\n File "<string>", line 17 in func\n File "<string>", line 26 in <module>' not found in 'Traceback (most recent call last):\n File "<string>", line 26, in <module>\n File "<string>", line 14, in func\nAttributeError: \'NoneType\' object has no attribute \'fileno\''
|
||||
def test_dump_traceback_later_repeat(self):
|
||||
self.check_dump_traceback_later(repeat=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; - AttributeError: 'NoneType' object has no attribute 'fileno'
|
||||
def test_dump_traceback_later_cancel(self):
|
||||
self.check_dump_traceback_later(cancel=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Regex didn't match: '^Timeout \\(0:00:00.500000\\)!\\nThread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\\n File "<string>", line 17 in func\n File "<string>", line 26 in <module>$' not found in 'Timeout (00:00:00.500000)!\n<timeout: cannot dump traceback from watchdog thread>'
|
||||
def test_dump_traceback_later_file(self):
|
||||
with temporary_filename() as filename:
|
||||
self.check_dump_traceback_later(filename=filename)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform == "win32",
|
||||
"subprocess doesn't support pass_fds on Windows")
|
||||
def test_dump_traceback_later_fd(self):
|
||||
with tempfile.TemporaryFile('wb+') as fp:
|
||||
self.check_dump_traceback_later(fd=fp.fileno())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Regex didn't match: '^Timeout \\(0:00:00.500000\\)!\\nThread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\\n File "<string>", line 17 in func\n File "<string>", line 26 in <module>\nTimeout \\(0:00:00.500000\\)!\\nThread 0x[0-9a-f]+( \\[.*\\])? \\(most recent call first\\):\\n File "<string>", line 17 in func\n File "<string>", line 26 in <module>' not found in 'Traceback (most recent call last):\n File "<string>", line 26, in <module>\n File "<string>", line 14, in func\nAttributeError: \'NoneType\' object has no attribute \'fileno\''
|
||||
@support.requires_resource('walltime')
|
||||
def test_dump_traceback_later_twice(self):
|
||||
self.check_dump_traceback_later(loops=2)
|
||||
@@ -801,9 +800,9 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
trace = '\n'.join(trace)
|
||||
if not unregister:
|
||||
if all_threads:
|
||||
regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
|
||||
regex = fr'{CURRENT_THREAD_HEADER}\n'
|
||||
else:
|
||||
regex = r'Stack \(most recent call first\):\n'
|
||||
regex = fr'{STACK_HEADER}\n'
|
||||
regex = expected_traceback(14, 32, regex)
|
||||
self.assertRegex(trace, regex)
|
||||
else:
|
||||
@@ -813,37 +812,26 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
else:
|
||||
self.assertEqual(exitcode, 0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_register(self):
|
||||
self.check_register()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_unregister(self):
|
||||
self.check_register(unregister=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_register_file(self):
|
||||
with temporary_filename() as filename:
|
||||
self.check_register(filename=filename)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform == "win32",
|
||||
"subprocess doesn't support pass_fds on Windows")
|
||||
def test_register_fd(self):
|
||||
with tempfile.TemporaryFile('wb+') as fp:
|
||||
self.check_register(fd=fp.fileno())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_register_threads(self):
|
||||
self.check_register(all_threads=True)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@support.skip_if_sanitizer("gh-129825: hangs under TSAN", thread=True)
|
||||
def test_register_chain(self):
|
||||
self.check_register(chain=True)
|
||||
|
||||
@@ -871,8 +859,6 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
with self.check_stderr_none():
|
||||
faulthandler.register(signal.SIGUSR1)
|
||||
|
||||
# TODO: RUSTPYTHON, AttributeError: module 'msvcrt' has no attribute 'GetErrorMode'
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
|
||||
def test_raise_exception(self):
|
||||
for exc, name in (
|
||||
@@ -985,5 +971,37 @@ class FaultHandlerTests(unittest.TestCase):
|
||||
_, exitcode = self.get_output(code)
|
||||
self.assertEqual(exitcode, 0)
|
||||
|
||||
def check_c_stack(self, output):
|
||||
starting_line = output.pop(0)
|
||||
self.assertRegex(starting_line, C_STACK_REGEX[0])
|
||||
self.assertGreater(len(output), 0)
|
||||
|
||||
for line in output:
|
||||
with self.subTest(line=line):
|
||||
if line != '': # Ignore trailing or leading newlines
|
||||
self.assertRegex(line, C_STACK_REGEX[1])
|
||||
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 1 != 0
|
||||
def test_dump_c_stack(self):
|
||||
code = dedent("""
|
||||
import faulthandler
|
||||
faulthandler.dump_c_stack()
|
||||
""")
|
||||
output, exitcode = self.get_output(code)
|
||||
self.assertEqual(exitcode, 0)
|
||||
self.check_c_stack(output)
|
||||
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'faulthandler' has no attribute 'dump_c_stack'
|
||||
def test_dump_c_stack_file(self):
|
||||
import tempfile
|
||||
|
||||
with tempfile.TemporaryFile("w+") as tmp:
|
||||
faulthandler.dump_c_stack(file=tmp)
|
||||
tmp.flush() # Just in case
|
||||
tmp.seek(0)
|
||||
self.check_c_stack(tmp.read().split("\n"))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user