@@ -45,6 +45,13 @@ def temporary_filename():
45
45
finally :
46
46
os_helper .unlink (filename )
47
47
48
+
49
+ ADDRESS_EXPR = "0x[0-9a-f]+"
50
+ C_STACK_REGEX = [
51
+ r"Current thread's C stack trace \(most recent call first\):" ,
52
+ fr" ((\/.+)+\(.*\+{ ADDRESS_EXPR } \) \[{ ADDRESS_EXPR } \])|(<.+>)"
53
+ ]
54
+
48
55
class FaultHandlerTests (unittest .TestCase ):
49
56
50
57
def get_output (self , code , filename = None , fd = None ):
@@ -101,16 +108,15 @@ def check_error(self, code, lineno, fatal_error, *,
101
108
102
109
Raise an error if the output doesn't match the expected format.
103
110
"""
104
- address_expr = "0x[0-9a-f]+"
105
111
all_threads_disabled = (
106
112
all_threads
107
113
and (not sys ._is_gil_enabled ())
108
114
)
109
115
if all_threads and not all_threads_disabled :
110
116
if know_current_thread :
111
- header = f'Current thread { address_expr } '
117
+ header = f'Current thread { ADDRESS_EXPR } '
112
118
else :
113
- header = f'Thread { address_expr } '
119
+ header = f'Thread { ADDRESS_EXPR } '
114
120
else :
115
121
header = 'Stack'
116
122
regex = [f'^{ fatal_error } ' ]
@@ -129,8 +135,7 @@ def check_error(self, code, lineno, fatal_error, *,
129
135
regex .append (' Garbage-collecting' )
130
136
regex .append (fr' File "<string>", line { lineno } in { function } ' )
131
137
if c_stack :
132
- regex .append ("Current thread's C stack (most recent call first):" )
133
- regex .append (fr" (\/.+\(\+.+\) \[{ address_expr } \])|(<.+>)" )
138
+ regex .extend (C_STACK_REGEX )
134
139
regex = '\n ' .join (regex )
135
140
136
141
if other_regex :
@@ -941,5 +946,35 @@ def run(self):
941
946
_ , exitcode = self .get_output (code )
942
947
self .assertEqual (exitcode , 0 )
943
948
949
+ def check_c_stack (self , output ):
950
+ starting_line = output .pop (0 )
951
+ self .assertRegex (starting_line , C_STACK_REGEX [0 ])
952
+ self .assertGreater (len (output ), 0 )
953
+
954
+ for line in output :
955
+ with self .subTest (line = line ):
956
+ if line != '' : # Ignore trailing or leading newlines
957
+ self .assertRegex (line , C_STACK_REGEX [1 ])
958
+
959
+
960
+ def test_dump_c_stack (self ):
961
+ code = dedent ("""
962
+ import faulthandler
963
+ faulthandler.dump_c_stack()
964
+ """ )
965
+ output , exitcode = self .get_output (code )
966
+ self .assertEqual (exitcode , 0 )
967
+ self .check_c_stack (output )
968
+
969
+
970
+ def test_dump_c_stack_file (self ):
971
+ import tempfile
972
+
973
+ with tempfile .TemporaryFile ("w+" ) as tmp :
974
+ faulthandler .dump_c_stack (file = tmp )
975
+ tmp .flush () # Just in case
976
+ tmp .seek (0 )
977
+ self .check_c_stack (tmp .read ().split ("\n " ))
978
+
944
979
if __name__ == "__main__" :
945
980
unittest .main ()
0 commit comments