Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(95636)

Delta Between Two Patch Sets: Lib/test/test_gdb.py

Issue 16510: Using appropriate checks in tests
Left Patch Set: Created 5 years, 9 months ago
Right Patch Set: Created 5 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/test_gc.py ('k') | Lib/test/test_grammar.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # Verify that gdb can pretty-print the various PyObject* types 1 # Verify that gdb can pretty-print the various PyObject* types
2 # 2 #
3 # The code for testing gdb was adapted from similar work in Unladen Swallow's 3 # The code for testing gdb was adapted from similar work in Unladen Swallow's
4 # Lib/test/test_jit_gdb.py 4 # Lib/test/test_jit_gdb.py
5 5
6 import os 6 import os
7 import re 7 import re
8 import pprint 8 import pprint
9 import subprocess 9 import subprocess
10 import sys 10 import sys
(...skipping 23 matching lines...) Expand all
34 if gdb_major_version < 7: 34 if gdb_major_version < 7:
35 raise unittest.SkipTest("gdb versions before 7.0 didn't support python embed ding" 35 raise unittest.SkipTest("gdb versions before 7.0 didn't support python embed ding"
36 " Saw:\n" + gdb_version.decode('ascii', 'replace')) 36 " Saw:\n" + gdb_version.decode('ascii', 'replace'))
37 37
38 if not sysconfig.is_python_build(): 38 if not sysconfig.is_python_build():
39 raise unittest.SkipTest("test_gdb only works on source builds at the moment. ") 39 raise unittest.SkipTest("test_gdb only works on source builds at the moment. ")
40 40
41 # Location of custom hooks file in a repository checkout. 41 # Location of custom hooks file in a repository checkout.
42 checkout_hook_path = os.path.join(os.path.dirname(sys.executable), 42 checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
43 'python-gdb.py') 43 'python-gdb.py')
44
45 PYTHONHASHSEED = '123'
44 46
45 def run_gdb(*args, **env_vars): 47 def run_gdb(*args, **env_vars):
46 """Runs gdb in --batch mode with the additional arguments given by *args. 48 """Runs gdb in --batch mode with the additional arguments given by *args.
47 49
48 Returns its (stdout, stderr) decoded from utf-8 using the replace handler. 50 Returns its (stdout, stderr) decoded from utf-8 using the replace handler.
49 """ 51 """
50 if env_vars: 52 if env_vars:
51 env = os.environ.copy() 53 env = os.environ.copy()
52 env.update(env_vars) 54 env.update(env_vars)
53 else: 55 else:
54 env = None 56 env = None
55 base_cmd = ('gdb', '--batch') 57 base_cmd = ('gdb', '--batch')
56 if (gdb_major_version, gdb_minor_version) >= (7, 4): 58 if (gdb_major_version, gdb_minor_version) >= (7, 4):
57 base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) 59 base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path)
58 out, err = subprocess.Popen(base_cmd + args, 60 out, err = subprocess.Popen(base_cmd + args,
59 stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, 61 stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
60 ).communicate() 62 ).communicate()
61 return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') 63 return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace')
62 64
63 # Verify that "gdb" was built with the embedded python support enabled: 65 # Verify that "gdb" was built with the embedded python support enabled:
64 gdbpy_version, _ = run_gdb("--eval-command=python import sys; print sys.version_ info") 66 gdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_ info)")
65 if not gdbpy_version: 67 if not gdbpy_version:
66 raise unittest.SkipTest("gdb not built with embedded python support") 68 raise unittest.SkipTest("gdb not built with embedded python support")
67 69
68 # Verify that "gdb" can load our custom hooks, as OS security settings may 70 # Verify that "gdb" can load our custom hooks, as OS security settings may
69 # disallow this without a customised .gdbinit. 71 # disallow this without a customised .gdbinit.
70 cmd = ['--args', sys.executable] 72 cmd = ['--args', sys.executable]
71 _, gdbpy_errors = run_gdb('--args', sys.executable) 73 _, gdbpy_errors = run_gdb('--args', sys.executable)
72 if "auto-loading has been declined" in gdbpy_errors: 74 if "auto-loading has been declined" in gdbpy_errors:
73 msg = "gdb security settings prevent use of custom hooks: " 75 msg = "gdb security settings prevent use of custom hooks: "
74 raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) 76 raise unittest.SkipTest(msg + gdbpy_errors.rstrip())
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 if not import_site: 138 if not import_site:
137 # -S suppresses the default 'import site' 139 # -S suppresses the default 'import site'
138 args += ["-S"] 140 args += ["-S"]
139 141
140 if source: 142 if source:
141 args += ["-c", source] 143 args += ["-c", source]
142 elif script: 144 elif script:
143 args += [script] 145 args += [script]
144 146
145 # print args 147 # print args
146 # print ' '.join(args) 148 # print (' '.join(args))
147 149
148 # Use "args" to invoke gdb, capturing stdout, stderr: 150 # Use "args" to invoke gdb, capturing stdout, stderr:
149 out, err = run_gdb(*args, PYTHONHASHSEED='0') 151 out, err = run_gdb(*args, PYTHONHASHSEED=PYTHONHASHSEED)
150 152
151 errlines = err.splitlines() 153 errlines = err.splitlines()
152 unexpected_errlines = [] 154 unexpected_errlines = []
153 155
154 # Ignore some benign messages on stderr. 156 # Ignore some benign messages on stderr.
155 ignore_patterns = ( 157 ignore_patterns = (
156 'Function "%s" not defined.' % breakpoint, 158 'Function "%s" not defined.' % breakpoint,
157 "warning: no loadable sections found in added symbol-file" 159 "warning: no loadable sections found in added symbol-file"
158 " system-supplied DSO", 160 " system-supplied DSO",
159 "warning: Unable to find libthread_db matching" 161 "warning: Unable to find libthread_db matching"
160 " inferior's thread library, thread debugging will" 162 " inferior's thread library, thread debugging will"
161 " not be available.", 163 " not be available.",
162 "warning: Cannot initialize thread debugging" 164 "warning: Cannot initialize thread debugging"
163 " library: Debugger service failed", 165 " library: Debugger service failed",
164 'warning: Could not load shared library symbols for ' 166 'warning: Could not load shared library symbols for '
165 'linux-vdso.so', 167 'linux-vdso.so',
166 'warning: Could not load shared library symbols for ' 168 'warning: Could not load shared library symbols for '
167 'linux-gate.so', 169 'linux-gate.so',
168 'Do you need "set solib-search-path" or ' 170 'Do you need "set solib-search-path" or '
169 '"set sysroot"?', 171 '"set sysroot"?',
170 'warning: Source file is more recent than executable.', 172 'warning: Source file is more recent than executable.',
173 # Issue #19753: missing symbols on System Z
174 'Missing separate debuginfo for ',
175 'Try: zypper install -C ',
171 ) 176 )
172 for line in errlines: 177 for line in errlines:
173 if not line.startswith(ignore_patterns): 178 if not line.startswith(ignore_patterns):
174 unexpected_errlines.append(line) 179 unexpected_errlines.append(line)
175 180
176 # Ensure no unexpected error messages: 181 # Ensure no unexpected error messages:
177 self.assertEqual(unexpected_errlines, []) 182 self.assertEqual(unexpected_errlines, [])
178 return out 183 return out
179 184
180 def get_gdb_repr(self, source, 185 def get_gdb_repr(self, source,
181 cmds_after_breakpoint=None, 186 cmds_after_breakpoint=None,
182 import_site=False): 187 import_site=False):
183 # Given an input python source representation of data, 188 # Given an input python source representation of data,
184 # run "python -c'id(DATA)'" under gdb with a breakpoint on 189 # run "python -c'id(DATA)'" under gdb with a breakpoint on
185 # builtin_id and scrape out gdb's representation of the "op" 190 # builtin_id and scrape out gdb's representation of the "op"
186 # parameter, and verify that the gdb displays the same string 191 # parameter, and verify that the gdb displays the same string
187 # 192 #
188 # Verify that the gdb displays the expected string 193 # Verify that the gdb displays the expected string
189 # 194 #
190 # For a nested structure, the first time we hit the breakpoint will 195 # For a nested structure, the first time we hit the breakpoint will
191 # give us the top-level structure 196 # give us the top-level structure
197
198 # NOTE: avoid decoding too much of the traceback as some
199 # undecodable characters may lurk there in optimized mode
200 # (issue #19743).
201 cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"]
192 gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN, 202 gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN,
193 cmds_after_breakpoint=cmds_after_break point, 203 cmds_after_breakpoint=cmds_after_break point,
194 import_site=import_site) 204 import_site=import_site)
195 # gdb can insert additional '\n' and space characters in various places 205 # gdb can insert additional '\n' and space characters in various places
196 # in its output, depending on the width of the terminal it's connected 206 # in its output, depending on the width of the terminal it's connected
197 # to (using its "wrap_here" function) 207 # to (using its "wrap_here" function)
198 m = re.match('.*#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)\)\s+at\s+\S*P ython/bltinmodule.c.*', 208 m = re.match('.*#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)\)\s+at\s+\S*P ython/bltinmodule.c.*',
199 gdb_output, re.DOTALL) 209 gdb_output, re.DOTALL)
200 if not m: 210 if not m:
201 self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output) ) 211 self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output) )
(...skipping 10 matching lines...) Expand all
212 self.fail(msg='%r did not match %r' % (actual, pattern)) 222 self.fail(msg='%r did not match %r' % (actual, pattern))
213 223
214 def get_sample_script(self): 224 def get_sample_script(self):
215 return findfile('gdb_sample.py') 225 return findfile('gdb_sample.py')
216 226
217 class PrettyPrintTests(DebuggerTests): 227 class PrettyPrintTests(DebuggerTests):
218 def test_getting_backtrace(self): 228 def test_getting_backtrace(self):
219 gdb_output = self.get_stack_trace('id(42)') 229 gdb_output = self.get_stack_trace('id(42)')
220 self.assertIn(BREAKPOINT_FN, gdb_output) 230 self.assertIn(BREAKPOINT_FN, gdb_output)
221 231
222 def assertGdbRepr(self, val, exp_repr=None, cmds_after_breakpoint=None): 232 def assertGdbRepr(self, val, exp_repr=None):
223 # Ensure that gdb's rendering of the value in a debugged process 233 # Ensure that gdb's rendering of the value in a debugged process
224 # matches repr(value) in this process: 234 # matches repr(value) in this process:
225 gdb_repr, gdb_output = self.get_gdb_repr('id(' + ascii(val) + ')', 235 gdb_repr, gdb_output = self.get_gdb_repr('id(' + ascii(val) + ')')
226 cmds_after_breakpoint)
227 if not exp_repr: 236 if not exp_repr:
228 exp_repr = repr(val) 237 exp_repr = repr(val)
229 self.assertEqual(gdb_repr, exp_repr, 238 self.assertEqual(gdb_repr, exp_repr,
230 ('%r did not equal expected %r; full output was:\n%s' 239 ('%r did not equal expected %r; full output was:\n%s'
231 % (gdb_repr, exp_repr, gdb_output))) 240 % (gdb_repr, exp_repr, gdb_output)))
232 241
233 def test_int(self): 242 def test_int(self):
234 'Verify the pretty-printing of various int values' 243 'Verify the pretty-printing of various int values'
235 self.assertGdbRepr(42) 244 self.assertGdbRepr(42)
236 self.assertGdbRepr(0) 245 self.assertGdbRepr(0)
237 self.assertGdbRepr(-7) 246 self.assertGdbRepr(-7)
238 self.assertGdbRepr(1000000000000) 247 self.assertGdbRepr(1000000000000)
239 self.assertGdbRepr(-1000000000000000) 248 self.assertGdbRepr(-1000000000000000)
240 249
241 def test_singletons(self): 250 def test_singletons(self):
242 'Verify the pretty-printing of True, False and None' 251 'Verify the pretty-printing of True, False and None'
243 self.assertGdbRepr(True) 252 self.assertGdbRepr(True)
244 self.assertGdbRepr(False) 253 self.assertGdbRepr(False)
245 self.assertGdbRepr(None) 254 self.assertGdbRepr(None)
246 255
247 def test_dicts(self): 256 def test_dicts(self):
248 'Verify the pretty-printing of dictionaries' 257 'Verify the pretty-printing of dictionaries'
249 self.assertGdbRepr({}) 258 self.assertGdbRepr({})
250 self.assertGdbRepr({'foo': 'bar'}) 259 self.assertGdbRepr({'foo': 'bar'}, "{'foo': 'bar'}")
251 self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, 260 self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'douglas': 42, 'foo' : 'bar'}")
252 "{'foo': 'bar', 'douglas': 42}")
253 261
254 def test_lists(self): 262 def test_lists(self):
255 'Verify the pretty-printing of lists' 263 'Verify the pretty-printing of lists'
256 self.assertGdbRepr([]) 264 self.assertGdbRepr([])
257 self.assertGdbRepr(list(range(5))) 265 self.assertGdbRepr(list(range(5)))
258 266
259 def test_bytes(self): 267 def test_bytes(self):
260 'Verify the pretty-printing of bytes' 268 'Verify the pretty-printing of bytes'
261 self.assertGdbRepr(b'') 269 self.assertGdbRepr(b'')
262 self.assertGdbRepr(b'And now for something hopefully the same') 270 self.assertGdbRepr(b'And now for something hopefully the same')
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 305
298 # Test a character outside the BMP: 306 # Test a character outside the BMP:
299 # U+1D121 MUSICAL SYMBOL C CLEF 307 # U+1D121 MUSICAL SYMBOL C CLEF
300 # This is: 308 # This is:
301 # UTF-8: 0xF0 0x9D 0x84 0xA1 309 # UTF-8: 0xF0 0x9D 0x84 0xA1
302 # UTF-16: 0xD834 0xDD21 310 # UTF-16: 0xD834 0xDD21
303 check_repr(chr(0x1D121)) 311 check_repr(chr(0x1D121))
304 312
305 def test_tuples(self): 313 def test_tuples(self):
306 'Verify the pretty-printing of tuples' 314 'Verify the pretty-printing of tuples'
307 self.assertGdbRepr(tuple()) 315 self.assertGdbRepr(tuple(), '()')
308 self.assertGdbRepr((1,), '(1,)') 316 self.assertGdbRepr((1,), '(1,)')
309 self.assertGdbRepr(('foo', 'bar', 'baz')) 317 self.assertGdbRepr(('foo', 'bar', 'baz'))
310 318
311 def test_sets(self): 319 def test_sets(self):
312 'Verify the pretty-printing of sets' 320 'Verify the pretty-printing of sets'
313 if (gdb_major_version, gdb_minor_version) < (7, 3): 321 if (gdb_major_version, gdb_minor_version) < (7, 3):
314 self.skipTest("pretty-printing of sets needs gdb 7.3 or later") 322 self.skipTest("pretty-printing of sets needs gdb 7.3 or later")
315 self.assertGdbRepr(set()) 323 self.assertGdbRepr(set(), 'set()')
316 self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}") 324 self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}")
317 self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}") 325 self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}")
318 326
319 # Ensure that we handle sets containing the "dummy" key value, 327 # Ensure that we handle sets containing the "dummy" key value,
320 # which happens on deletion: 328 # which happens on deletion:
321 gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b']) 329 gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b'])
322 s.pop() 330 s.remove('a')
323 id(s)''') 331 id(s)''')
324 self.assertEqual(gdb_repr, "{'b'}") 332 self.assertEqual(gdb_repr, "{'b'}")
325 333
326 def test_frozensets(self): 334 def test_frozensets(self):
327 'Verify the pretty-printing of frozensets' 335 'Verify the pretty-printing of frozensets'
328 if (gdb_major_version, gdb_minor_version) < (7, 3): 336 if (gdb_major_version, gdb_minor_version) < (7, 3):
329 self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later" ) 337 self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later" )
330 self.assertGdbRepr(frozenset()) 338 self.assertGdbRepr(frozenset(), 'frozenset()')
331 self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})") 339 self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})")
332 self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})") 340 self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})")
333 341
334 def test_exceptions(self): 342 def test_exceptions(self):
335 # Test a RuntimeError 343 # Test a RuntimeError
336 gdb_repr, gdb_output = self.get_gdb_repr(''' 344 gdb_repr, gdb_output = self.get_gdb_repr('''
337 try: 345 try:
338 raise RuntimeError("I am an error") 346 raise RuntimeError("I am an error")
339 except RuntimeError as e: 347 except RuntimeError as e:
340 id(e) 348 id(e)
(...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 run_unittest(PrettyPrintTests, 859 run_unittest(PrettyPrintTests,
852 PyListTests, 860 PyListTests,
853 StackNavigationTests, 861 StackNavigationTests,
854 PyBtTests, 862 PyBtTests,
855 PyPrintTests, 863 PyPrintTests,
856 PyLocalsTests 864 PyLocalsTests
857 ) 865 )
858 866
859 if __name__ == "__main__": 867 if __name__ == "__main__":
860 test_main() 868 test_main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+