| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 1 | # Verify that gdb can pretty-print the various PyObject* types | 
 | 2 | # | 
 | 3 | # The code for testing gdb was adapted from similar work in Unladen Swallow's | 
 | 4 | # Lib/test/test_jit_gdb.py | 
 | 5 |  | 
 | 6 | import os | 
 | 7 | import re | 
 | 8 | import subprocess | 
 | 9 | import sys | 
| Zachary Ware | d833c77 | 2016-08-24 11:14:34 -0500 | [diff] [blame] | 10 | import sysconfig | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 11 | import unittest | 
| Antoine Pitrou | 22db735 | 2010-07-08 18:54:04 +0000 | [diff] [blame] | 12 | import sysconfig | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 13 |  | 
| Victor Stinner | 3c5ce40 | 2015-09-03 09:51:59 +0200 | [diff] [blame] | 14 | from test import test_support | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 15 | from test.test_support import run_unittest, findfile | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 16 |  | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 17 | # Is this Python configured to support threads? | 
 | 18 | try: | 
 | 19 |     import thread | 
 | 20 | except ImportError: | 
 | 21 |     thread = None | 
 | 22 |  | 
| Victor Stinner | 3c5ce40 | 2015-09-03 09:51:59 +0200 | [diff] [blame] | 23 | def get_gdb_version(): | 
 | 24 |     try: | 
 | 25 |         proc = subprocess.Popen(["gdb", "-nx", "--version"], | 
 | 26 |                                 stdout=subprocess.PIPE, | 
| Benjamin Peterson | 499378f | 2016-09-06 10:06:31 -0700 | [diff] [blame] | 27 |                                 stderr=subprocess.PIPE, | 
| Victor Stinner | 3c5ce40 | 2015-09-03 09:51:59 +0200 | [diff] [blame] | 28 |                                 universal_newlines=True) | 
 | 29 |         version = proc.communicate()[0] | 
 | 30 |     except OSError: | 
 | 31 |         # This is what "no gdb" looks like.  There may, however, be other | 
 | 32 |         # errors that manifest this way too. | 
 | 33 |         raise unittest.SkipTest("Couldn't find gdb on the path") | 
 | 34 |  | 
 | 35 |     # Regex to parse: | 
 | 36 |     # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 | 
 | 37 |     # 'GNU gdb (GDB) Fedora 7.9.1-17.fc22\n' -> 7.9 | 
| Victor Stinner | df11d7c | 2015-09-15 00:19:47 +0200 | [diff] [blame] | 38 |     # 'GNU gdb 6.1.1 [FreeBSD]\n' -> 6.1 | 
 | 39 |     # 'GNU gdb (GDB) Fedora (7.5.1-37.fc18)\n' -> 7.5 | 
 | 40 |     match = re.search(r"^GNU gdb.*?\b(\d+)\.(\d+)", version) | 
| Victor Stinner | 3c5ce40 | 2015-09-03 09:51:59 +0200 | [diff] [blame] | 41 |     if match is None: | 
 | 42 |         raise Exception("unable to parse GDB version: %r" % version) | 
 | 43 |     return (version, int(match.group(1)), int(match.group(2))) | 
 | 44 |  | 
 | 45 | gdb_version, gdb_major_version, gdb_minor_version = get_gdb_version() | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 46 | if gdb_major_version < 7: | 
| Victor Stinner | 3c5ce40 | 2015-09-03 09:51:59 +0200 | [diff] [blame] | 47 |     raise unittest.SkipTest("gdb versions before 7.0 didn't support python " | 
 | 48 |                             "embedding. Saw %s.%s:\n%s" | 
 | 49 |                             % (gdb_major_version, gdb_minor_version, | 
 | 50 |                                gdb_version)) | 
 | 51 |  | 
| Benjamin Peterson | 51f461f | 2014-11-23 22:34:04 -0600 | [diff] [blame] | 52 | if sys.platform.startswith("sunos"): | 
| Benjamin Peterson | 0636a4b | 2014-11-23 22:02:47 -0600 | [diff] [blame] | 53 |     raise unittest.SkipTest("test doesn't work very well on Solaris") | 
 | 54 |  | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 55 |  | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 56 | # Location of custom hooks file in a repository checkout. | 
 | 57 | checkout_hook_path = os.path.join(os.path.dirname(sys.executable), | 
 | 58 |                                   'python-gdb.py') | 
 | 59 |  | 
 | 60 | def run_gdb(*args, **env_vars): | 
| Victor Stinner | 8bd3415 | 2014-08-16 14:31:02 +0200 | [diff] [blame] | 61 |     """Runs gdb in batch mode with the additional arguments given by *args. | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 62 |  | 
 | 63 |     Returns its (stdout, stderr) | 
 | 64 |     """ | 
 | 65 |     if env_vars: | 
 | 66 |         env = os.environ.copy() | 
 | 67 |         env.update(env_vars) | 
 | 68 |     else: | 
 | 69 |         env = None | 
| Victor Stinner | 8bd3415 | 2014-08-16 14:31:02 +0200 | [diff] [blame] | 70 |     # -nx: Do not execute commands from any .gdbinit initialization files | 
 | 71 |     #      (issue #22188) | 
 | 72 |     base_cmd = ('gdb', '--batch', '-nx') | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 73 |     if (gdb_major_version, gdb_minor_version) >= (7, 4): | 
 | 74 |         base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) | 
 | 75 |     out, err = subprocess.Popen(base_cmd + args, | 
| Martin Panter | 2179b2e | 2016-01-16 05:07:35 +0000 | [diff] [blame] | 76 |         # Redirect stdin to prevent GDB from messing with terminal settings | 
 | 77 |         stdin=subprocess.PIPE, | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 78 |         stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, | 
 | 79 |         ).communicate() | 
 | 80 |     return out, err | 
 | 81 |  | 
| Zachary Ware | d833c77 | 2016-08-24 11:14:34 -0500 | [diff] [blame] | 82 | if not sysconfig.is_python_build(): | 
 | 83 |     raise unittest.SkipTest("test_gdb only works on source builds at the moment.") | 
 | 84 |  | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 85 | # Verify that "gdb" was built with the embedded python support enabled: | 
| Antoine Pitrou | 358da5b | 2013-11-23 17:40:36 +0100 | [diff] [blame] | 86 | gdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_info)") | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 87 | if not gdbpy_version: | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 88 |     raise unittest.SkipTest("gdb not built with embedded python support") | 
 | 89 |  | 
| Nick Coghlan | 254a377 | 2013-09-22 19:36:09 +1000 | [diff] [blame] | 90 | # Verify that "gdb" can load our custom hooks, as OS security settings may | 
 | 91 | # disallow this without a customised .gdbinit. | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 92 | cmd = ['--args', sys.executable] | 
 | 93 | _, gdbpy_errors = run_gdb('--args', sys.executable) | 
 | 94 | if "auto-loading has been declined" in gdbpy_errors: | 
 | 95 |     msg = "gdb security settings prevent use of custom hooks: " | 
| Nick Coghlan | 254a377 | 2013-09-22 19:36:09 +1000 | [diff] [blame] | 96 |     raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) | 
| Nick Coghlan | a093312 | 2012-06-17 19:03:39 +1000 | [diff] [blame] | 97 |  | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 98 | def python_is_optimized(): | 
 | 99 |     cflags = sysconfig.get_config_vars()['PY_CFLAGS'] | 
 | 100 |     final_opt = "" | 
 | 101 |     for opt in cflags.split(): | 
 | 102 |         if opt.startswith('-O'): | 
 | 103 |             final_opt = opt | 
| Victor Stinner | 582265f | 2015-03-27 15:44:13 +0100 | [diff] [blame] | 104 |     return final_opt not in ('', '-O0', '-Og') | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 105 |  | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 106 | def gdb_has_frame_select(): | 
 | 107 |     # Does this build of gdb have gdb.Frame.select ? | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 108 |     stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))") | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 109 |     m = re.match(r'.*\[(.*)\].*', stdout) | 
 | 110 |     if not m: | 
 | 111 |         raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test") | 
 | 112 |     gdb_frame_dir = m.group(1).split(', ') | 
 | 113 |     return "'select'" in gdb_frame_dir | 
 | 114 |  | 
 | 115 | HAS_PYUP_PYDOWN = gdb_has_frame_select() | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 116 |  | 
 | 117 | class DebuggerTests(unittest.TestCase): | 
 | 118 |  | 
 | 119 |     """Test that the debugger can debug Python.""" | 
 | 120 |  | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 121 |     def get_stack_trace(self, source=None, script=None, | 
 | 122 |                         breakpoint='PyObject_Print', | 
 | 123 |                         cmds_after_breakpoint=None, | 
 | 124 |                         import_site=False): | 
 | 125 |         ''' | 
 | 126 |         Run 'python -c SOURCE' under gdb with a breakpoint. | 
 | 127 |  | 
 | 128 |         Support injecting commands after the breakpoint is reached | 
 | 129 |  | 
 | 130 |         Returns the stdout from gdb | 
 | 131 |  | 
 | 132 |         cmds_after_breakpoint: if provided, a list of strings: gdb commands | 
 | 133 |         ''' | 
 | 134 |         # We use "set breakpoint pending yes" to avoid blocking with a: | 
 | 135 |         #   Function "foo" not defined. | 
 | 136 |         #   Make breakpoint pending on future shared library load? (y or [n]) | 
 | 137 |         # error, which typically happens python is dynamically linked (the | 
 | 138 |         # breakpoints of interest are to be found in the shared library) | 
 | 139 |         # When this happens, we still get: | 
 | 140 |         #   Function "PyObject_Print" not defined. | 
 | 141 |         # emitted to stderr each time, alas. | 
 | 142 |  | 
 | 143 |         # Initially I had "--eval-command=continue" here, but removed it to | 
 | 144 |         # avoid repeated print breakpoints when traversing hierarchical data | 
 | 145 |         # structures | 
 | 146 |  | 
 | 147 |         # Generate a list of commands in gdb's language: | 
 | 148 |         commands = ['set breakpoint pending yes', | 
 | 149 |                     'break %s' % breakpoint, | 
| Serhiy Storchaka | 73bcde2 | 2015-01-31 11:48:36 +0200 | [diff] [blame] | 150 |  | 
| Serhiy Storchaka | 73bcde2 | 2015-01-31 11:48:36 +0200 | [diff] [blame] | 151 |                     # The tests assume that the first frame of printed | 
 | 152 |                     #  backtrace will not contain program counter, | 
 | 153 |                     #  that is however not guaranteed by gdb | 
 | 154 |                     #  therefore we need to use 'set print address off' to | 
 | 155 |                     #  make sure the counter is not there. For example: | 
 | 156 |                     # #0 in PyObject_Print ... | 
 | 157 |                     #  is assumed, but sometimes this can be e.g. | 
 | 158 |                     # #0 0x00003fffb7dd1798 in PyObject_Print ... | 
 | 159 |                     'set print address off', | 
 | 160 |  | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 161 |                     'run'] | 
| Serhiy Storchaka | dd8430f | 2015-02-06 08:36:14 +0200 | [diff] [blame] | 162 |  | 
 | 163 |         # GDB as of 7.4 onwards can distinguish between the | 
 | 164 |         # value of a variable at entry vs current value: | 
 | 165 |         #   http://sourceware.org/gdb/onlinedocs/gdb/Variables.html | 
 | 166 |         # which leads to the selftests failing with errors like this: | 
 | 167 |         #   AssertionError: 'v@entry=()' != '()' | 
 | 168 |         # Disable this: | 
 | 169 |         if (gdb_major_version, gdb_minor_version) >= (7, 4): | 
 | 170 |             commands += ['set print entry-values no'] | 
 | 171 |  | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 172 |         if cmds_after_breakpoint: | 
 | 173 |             commands += cmds_after_breakpoint | 
 | 174 |         else: | 
 | 175 |             commands += ['backtrace'] | 
 | 176 |  | 
 | 177 |         # print commands | 
 | 178 |  | 
 | 179 |         # Use "commands" to generate the arguments with which to invoke "gdb": | 
| Victor Stinner | 8bd3415 | 2014-08-16 14:31:02 +0200 | [diff] [blame] | 180 |         args = ["gdb", "--batch", "-nx"] | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 181 |         args += ['--eval-command=%s' % cmd for cmd in commands] | 
 | 182 |         args += ["--args", | 
 | 183 |                  sys.executable] | 
 | 184 |  | 
 | 185 |         if not import_site: | 
 | 186 |             # -S suppresses the default 'import site' | 
 | 187 |             args += ["-S"] | 
 | 188 |  | 
 | 189 |         if source: | 
 | 190 |             args += ["-c", source] | 
 | 191 |         elif script: | 
 | 192 |             args += [script] | 
 | 193 |  | 
 | 194 |         # print args | 
 | 195 |         # print ' '.join(args) | 
 | 196 |  | 
 | 197 |         # Use "args" to invoke gdb, capturing stdout, stderr: | 
| R David Murray | 3e66f0d | 2012-10-27 13:47:49 -0400 | [diff] [blame] | 198 |         out, err = run_gdb(*args, PYTHONHASHSEED='0') | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 199 |  | 
| Antoine Pitrou | b996e04 | 2013-05-01 00:15:44 +0200 | [diff] [blame] | 200 |         errlines = err.splitlines() | 
 | 201 |         unexpected_errlines = [] | 
 | 202 |  | 
 | 203 |         # Ignore some benign messages on stderr. | 
 | 204 |         ignore_patterns = ( | 
 | 205 |             'Function "%s" not defined.' % breakpoint, | 
| Antoine Pitrou | b996e04 | 2013-05-01 00:15:44 +0200 | [diff] [blame] | 206 |             'Do you need "set solib-search-path" or ' | 
 | 207 |             '"set sysroot"?', | 
| Victor Stinner | 8420cd2 | 2017-02-10 14:14:04 +0100 | [diff] [blame] | 208 |             # BFD: /usr/lib/debug/(...): unable to initialize decompress | 
 | 209 |             # status for section .debug_aranges | 
 | 210 |             'BFD: ', | 
 | 211 |             # ignore all warnings | 
 | 212 |             'warning: ', | 
| Antoine Pitrou | b996e04 | 2013-05-01 00:15:44 +0200 | [diff] [blame] | 213 |             ) | 
 | 214 |         for line in errlines: | 
| Victor Stinner | 8420cd2 | 2017-02-10 14:14:04 +0100 | [diff] [blame] | 215 |             if not line: | 
 | 216 |                 continue | 
| Antoine Pitrou | b996e04 | 2013-05-01 00:15:44 +0200 | [diff] [blame] | 217 |             if not line.startswith(ignore_patterns): | 
 | 218 |                 unexpected_errlines.append(line) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 219 |  | 
 | 220 |         # Ensure no unexpected error messages: | 
| Antoine Pitrou | b996e04 | 2013-05-01 00:15:44 +0200 | [diff] [blame] | 221 |         self.assertEqual(unexpected_errlines, []) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 222 |         return out | 
 | 223 |  | 
 | 224 |     def get_gdb_repr(self, source, | 
 | 225 |                      cmds_after_breakpoint=None, | 
 | 226 |                      import_site=False): | 
 | 227 |         # Given an input python source representation of data, | 
 | 228 |         # run "python -c'print DATA'" under gdb with a breakpoint on | 
 | 229 |         # PyObject_Print and scrape out gdb's representation of the "op" | 
 | 230 |         # parameter, and verify that the gdb displays the same string | 
 | 231 |         # | 
 | 232 |         # For a nested structure, the first time we hit the breakpoint will | 
 | 233 |         # give us the top-level structure | 
 | 234 |         gdb_output = self.get_stack_trace(source, breakpoint='PyObject_Print', | 
 | 235 |                                           cmds_after_breakpoint=cmds_after_breakpoint, | 
 | 236 |                                           import_site=import_site) | 
| R. David Murray | 0c08009 | 2010-04-05 16:28:49 +0000 | [diff] [blame] | 237 |         # gdb can insert additional '\n' and space characters in various places | 
 | 238 |         # in its output, depending on the width of the terminal it's connected | 
 | 239 |         # to (using its "wrap_here" function) | 
 | 240 |         m = re.match('.*#0\s+PyObject_Print\s+\(\s*op\=\s*(.*?),\s+fp=.*\).*', | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 241 |                      gdb_output, re.DOTALL) | 
| R. David Murray | 0c08009 | 2010-04-05 16:28:49 +0000 | [diff] [blame] | 242 |         if not m: | 
 | 243 |             self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 244 |         return m.group(1), gdb_output | 
 | 245 |  | 
 | 246 |     def assertEndsWith(self, actual, exp_end): | 
 | 247 |         '''Ensure that the given "actual" string ends with "exp_end"''' | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 248 |         self.assertTrue(actual.endswith(exp_end), | 
 | 249 |                         msg='%r did not end with %r' % (actual, exp_end)) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 250 |  | 
 | 251 |     def assertMultilineMatches(self, actual, pattern): | 
 | 252 |         m = re.match(pattern, actual, re.DOTALL) | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 253 |         self.assertTrue(m, msg='%r did not match %r' % (actual, pattern)) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 254 |  | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 255 |     def get_sample_script(self): | 
 | 256 |         return findfile('gdb_sample.py') | 
 | 257 |  | 
| Gregory P. Smith | 77ba596 | 2016-09-08 21:50:44 -0700 | [diff] [blame] | 258 |  | 
 | 259 | @unittest.skipIf(python_is_optimized(), | 
 | 260 |                  "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 261 | class PrettyPrintTests(DebuggerTests): | 
 | 262 |     def test_getting_backtrace(self): | 
 | 263 |         gdb_output = self.get_stack_trace('print 42') | 
 | 264 |         self.assertTrue('PyObject_Print' in gdb_output) | 
 | 265 |  | 
 | 266 |     def assertGdbRepr(self, val, cmds_after_breakpoint=None): | 
 | 267 |         # Ensure that gdb's rendering of the value in a debugged process | 
 | 268 |         # matches repr(value) in this process: | 
 | 269 |         gdb_repr, gdb_output = self.get_gdb_repr('print ' + repr(val), | 
 | 270 |                                                  cmds_after_breakpoint) | 
| Antoine Pitrou | 358da5b | 2013-11-23 17:40:36 +0100 | [diff] [blame] | 271 |         self.assertEqual(gdb_repr, repr(val)) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 272 |  | 
 | 273 |     def test_int(self): | 
 | 274 |         'Verify the pretty-printing of various "int" values' | 
 | 275 |         self.assertGdbRepr(42) | 
 | 276 |         self.assertGdbRepr(0) | 
 | 277 |         self.assertGdbRepr(-7) | 
 | 278 |         self.assertGdbRepr(sys.maxint) | 
 | 279 |         self.assertGdbRepr(-sys.maxint) | 
 | 280 |  | 
 | 281 |     def test_long(self): | 
 | 282 |         'Verify the pretty-printing of various "long" values' | 
 | 283 |         self.assertGdbRepr(0L) | 
 | 284 |         self.assertGdbRepr(1000000000000L) | 
 | 285 |         self.assertGdbRepr(-1L) | 
 | 286 |         self.assertGdbRepr(-1000000000000000L) | 
 | 287 |  | 
 | 288 |     def test_singletons(self): | 
 | 289 |         'Verify the pretty-printing of True, False and None' | 
 | 290 |         self.assertGdbRepr(True) | 
 | 291 |         self.assertGdbRepr(False) | 
 | 292 |         self.assertGdbRepr(None) | 
 | 293 |  | 
 | 294 |     def test_dicts(self): | 
 | 295 |         'Verify the pretty-printing of dictionaries' | 
 | 296 |         self.assertGdbRepr({}) | 
 | 297 |         self.assertGdbRepr({'foo': 'bar'}) | 
| Benjamin Peterson | 11fa11b | 2012-02-20 21:55:32 -0500 | [diff] [blame] | 298 |         self.assertGdbRepr("{'foo': 'bar', 'douglas':42}") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 299 |  | 
 | 300 |     def test_lists(self): | 
 | 301 |         'Verify the pretty-printing of lists' | 
 | 302 |         self.assertGdbRepr([]) | 
 | 303 |         self.assertGdbRepr(range(5)) | 
 | 304 |  | 
 | 305 |     def test_strings(self): | 
 | 306 |         'Verify the pretty-printing of strings' | 
 | 307 |         self.assertGdbRepr('') | 
 | 308 |         self.assertGdbRepr('And now for something hopefully the same') | 
 | 309 |         self.assertGdbRepr('string with embedded NUL here \0 and then some more text') | 
 | 310 |         self.assertGdbRepr('this is byte 255:\xff and byte 128:\x80') | 
 | 311 |  | 
 | 312 |     def test_tuples(self): | 
 | 313 |         'Verify the pretty-printing of tuples' | 
 | 314 |         self.assertGdbRepr(tuple()) | 
 | 315 |         self.assertGdbRepr((1,)) | 
 | 316 |         self.assertGdbRepr(('foo', 'bar', 'baz')) | 
 | 317 |  | 
 | 318 |     def test_unicode(self): | 
 | 319 |         'Verify the pretty-printing of unicode values' | 
 | 320 |         # Test the empty unicode string: | 
 | 321 |         self.assertGdbRepr(u'') | 
 | 322 |  | 
 | 323 |         self.assertGdbRepr(u'hello world') | 
 | 324 |  | 
 | 325 |         # Test printing a single character: | 
 | 326 |         #    U+2620 SKULL AND CROSSBONES | 
 | 327 |         self.assertGdbRepr(u'\u2620') | 
 | 328 |  | 
 | 329 |         # Test printing a Japanese unicode string | 
 | 330 |         # (I believe this reads "mojibake", using 3 characters from the CJK | 
 | 331 |         # Unified Ideographs area, followed by U+3051 HIRAGANA LETTER KE) | 
 | 332 |         self.assertGdbRepr(u'\u6587\u5b57\u5316\u3051') | 
 | 333 |  | 
 | 334 |         # Test a character outside the BMP: | 
 | 335 |         #    U+1D121 MUSICAL SYMBOL C CLEF | 
 | 336 |         # This is: | 
 | 337 |         # UTF-8: 0xF0 0x9D 0x84 0xA1 | 
 | 338 |         # UTF-16: 0xD834 0xDD21 | 
| Victor Stinner | b1556c5 | 2010-05-20 11:29:45 +0000 | [diff] [blame] | 339 |         # This will only work on wide-unicode builds: | 
 | 340 |         self.assertGdbRepr(u"\U0001D121") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 341 |  | 
 | 342 |     def test_sets(self): | 
 | 343 |         'Verify the pretty-printing of sets' | 
 | 344 |         self.assertGdbRepr(set()) | 
| Benjamin Peterson | e39ccef | 2012-02-21 09:07:40 -0500 | [diff] [blame] | 345 |         rep = self.get_gdb_repr("print set(['a', 'b'])")[0] | 
 | 346 |         self.assertTrue(rep.startswith("set([")) | 
 | 347 |         self.assertTrue(rep.endswith("])")) | 
 | 348 |         self.assertEqual(eval(rep), {'a', 'b'}) | 
 | 349 |         rep = self.get_gdb_repr("print set([4, 5])")[0] | 
 | 350 |         self.assertTrue(rep.startswith("set([")) | 
 | 351 |         self.assertTrue(rep.endswith("])")) | 
 | 352 |         self.assertEqual(eval(rep), {4, 5}) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 353 |  | 
 | 354 |         # Ensure that we handled sets containing the "dummy" key value, | 
 | 355 |         # which happens on deletion: | 
 | 356 |         gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b']) | 
 | 357 | s.pop() | 
 | 358 | print s''') | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 359 |         self.assertEqual(gdb_repr, "set(['b'])") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 360 |  | 
 | 361 |     def test_frozensets(self): | 
 | 362 |         'Verify the pretty-printing of frozensets' | 
 | 363 |         self.assertGdbRepr(frozenset()) | 
| Benjamin Peterson | e39ccef | 2012-02-21 09:07:40 -0500 | [diff] [blame] | 364 |         rep = self.get_gdb_repr("print frozenset(['a', 'b'])")[0] | 
 | 365 |         self.assertTrue(rep.startswith("frozenset([")) | 
 | 366 |         self.assertTrue(rep.endswith("])")) | 
 | 367 |         self.assertEqual(eval(rep), {'a', 'b'}) | 
 | 368 |         rep = self.get_gdb_repr("print frozenset([4, 5])")[0] | 
 | 369 |         self.assertTrue(rep.startswith("frozenset([")) | 
 | 370 |         self.assertTrue(rep.endswith("])")) | 
 | 371 |         self.assertEqual(eval(rep), {4, 5}) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 372 |  | 
 | 373 |     def test_exceptions(self): | 
 | 374 |         # Test a RuntimeError | 
 | 375 |         gdb_repr, gdb_output = self.get_gdb_repr(''' | 
 | 376 | try: | 
 | 377 |     raise RuntimeError("I am an error") | 
 | 378 | except RuntimeError, e: | 
 | 379 |     print e | 
 | 380 | ''') | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 381 |         self.assertEqual(gdb_repr, | 
 | 382 |                          "exceptions.RuntimeError('I am an error',)") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 383 |  | 
 | 384 |  | 
 | 385 |         # Test division by zero: | 
 | 386 |         gdb_repr, gdb_output = self.get_gdb_repr(''' | 
 | 387 | try: | 
 | 388 |     a = 1 / 0 | 
 | 389 | except ZeroDivisionError, e: | 
 | 390 |     print e | 
 | 391 | ''') | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 392 |         self.assertEqual(gdb_repr, | 
 | 393 |                          "exceptions.ZeroDivisionError('integer division or modulo by zero',)") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 394 |  | 
 | 395 |     def test_classic_class(self): | 
 | 396 |         'Verify the pretty-printing of classic class instances' | 
 | 397 |         gdb_repr, gdb_output = self.get_gdb_repr(''' | 
 | 398 | class Foo: | 
 | 399 |     pass | 
 | 400 | foo = Foo() | 
 | 401 | foo.an_int = 42 | 
 | 402 | print foo''') | 
 | 403 |         m = re.match(r'<Foo\(an_int=42\) at remote 0x[0-9a-f]+>', gdb_repr) | 
 | 404 |         self.assertTrue(m, | 
 | 405 |                         msg='Unexpected classic-class rendering %r' % gdb_repr) | 
 | 406 |  | 
 | 407 |     def test_modern_class(self): | 
 | 408 |         'Verify the pretty-printing of new-style class instances' | 
 | 409 |         gdb_repr, gdb_output = self.get_gdb_repr(''' | 
 | 410 | class Foo(object): | 
 | 411 |     pass | 
 | 412 | foo = Foo() | 
 | 413 | foo.an_int = 42 | 
 | 414 | print foo''') | 
 | 415 |         m = re.match(r'<Foo\(an_int=42\) at remote 0x[0-9a-f]+>', gdb_repr) | 
 | 416 |         self.assertTrue(m, | 
 | 417 |                         msg='Unexpected new-style class rendering %r' % gdb_repr) | 
 | 418 |  | 
 | 419 |     def test_subclassing_list(self): | 
 | 420 |         'Verify the pretty-printing of an instance of a list subclass' | 
 | 421 |         gdb_repr, gdb_output = self.get_gdb_repr(''' | 
 | 422 | class Foo(list): | 
 | 423 |     pass | 
 | 424 | foo = Foo() | 
 | 425 | foo += [1, 2, 3] | 
 | 426 | foo.an_int = 42 | 
 | 427 | print foo''') | 
 | 428 |         m = re.match(r'<Foo\(an_int=42\) at remote 0x[0-9a-f]+>', gdb_repr) | 
 | 429 |         self.assertTrue(m, | 
 | 430 |                         msg='Unexpected new-style class rendering %r' % gdb_repr) | 
 | 431 |  | 
 | 432 |     def test_subclassing_tuple(self): | 
 | 433 |         'Verify the pretty-printing of an instance of a tuple subclass' | 
 | 434 |         # This should exercise the negative tp_dictoffset code in the | 
 | 435 |         # new-style class support | 
 | 436 |         gdb_repr, gdb_output = self.get_gdb_repr(''' | 
 | 437 | class Foo(tuple): | 
 | 438 |     pass | 
 | 439 | foo = Foo((1, 2, 3)) | 
 | 440 | foo.an_int = 42 | 
 | 441 | print foo''') | 
 | 442 |         m = re.match(r'<Foo\(an_int=42\) at remote 0x[0-9a-f]+>', gdb_repr) | 
 | 443 |         self.assertTrue(m, | 
 | 444 |                         msg='Unexpected new-style class rendering %r' % gdb_repr) | 
 | 445 |  | 
| Martin v. Löwis | 7f7765c | 2010-04-12 05:18:16 +0000 | [diff] [blame] | 446 |     def assertSane(self, source, corruption, expvalue=None, exptype=None): | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 447 |         '''Run Python under gdb, corrupting variables in the inferior process | 
 | 448 |         immediately before taking a backtrace. | 
 | 449 |  | 
 | 450 |         Verify that the variable's representation is the expected failsafe | 
 | 451 |         representation''' | 
 | 452 |         if corruption: | 
 | 453 |             cmds_after_breakpoint=[corruption, 'backtrace'] | 
 | 454 |         else: | 
 | 455 |             cmds_after_breakpoint=['backtrace'] | 
 | 456 |  | 
 | 457 |         gdb_repr, gdb_output = \ | 
 | 458 |             self.get_gdb_repr(source, | 
 | 459 |                               cmds_after_breakpoint=cmds_after_breakpoint) | 
| Martin v. Löwis | 7f7765c | 2010-04-12 05:18:16 +0000 | [diff] [blame] | 460 |  | 
 | 461 |         if expvalue: | 
 | 462 |             if gdb_repr == repr(expvalue): | 
 | 463 |                 # gdb managed to print the value in spite of the corruption; | 
 | 464 |                 # this is good (see http://bugs.python.org/issue8330) | 
 | 465 |                 return | 
 | 466 |  | 
 | 467 |         if exptype: | 
 | 468 |             pattern = '<' + exptype + ' at remote 0x[0-9a-f]+>' | 
 | 469 |         else: | 
 | 470 |             # Match anything for the type name; 0xDEADBEEF could point to | 
 | 471 |             # something arbitrary (see  http://bugs.python.org/issue8330) | 
 | 472 |             pattern = '<.* at remote 0x[0-9a-f]+>' | 
 | 473 |  | 
 | 474 |         m = re.match(pattern, gdb_repr) | 
 | 475 |         if not m: | 
 | 476 |             self.fail('Unexpected gdb representation: %r\n%s' % \ | 
 | 477 |                           (gdb_repr, gdb_output)) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 478 |  | 
 | 479 |     def test_NULL_ptr(self): | 
 | 480 |         'Ensure that a NULL PyObject* is handled gracefully' | 
 | 481 |         gdb_repr, gdb_output = ( | 
 | 482 |             self.get_gdb_repr('print 42', | 
 | 483 |                               cmds_after_breakpoint=['set variable op=0', | 
| R. David Murray | 0c08009 | 2010-04-05 16:28:49 +0000 | [diff] [blame] | 484 |                                                      'backtrace']) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 485 |             ) | 
 | 486 |  | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 487 |         self.assertEqual(gdb_repr, '0x0') | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 488 |  | 
 | 489 |     def test_NULL_ob_type(self): | 
 | 490 |         'Ensure that a PyObject* with NULL ob_type is handled gracefully' | 
 | 491 |         self.assertSane('print 42', | 
 | 492 |                         'set op->ob_type=0') | 
 | 493 |  | 
 | 494 |     def test_corrupt_ob_type(self): | 
 | 495 |         'Ensure that a PyObject* with a corrupt ob_type is handled gracefully' | 
 | 496 |         self.assertSane('print 42', | 
| Martin v. Löwis | 7f7765c | 2010-04-12 05:18:16 +0000 | [diff] [blame] | 497 |                         'set op->ob_type=0xDEADBEEF', | 
 | 498 |                         expvalue=42) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 499 |  | 
 | 500 |     def test_corrupt_tp_flags(self): | 
 | 501 |         'Ensure that a PyObject* with a type with corrupt tp_flags is handled' | 
 | 502 |         self.assertSane('print 42', | 
 | 503 |                         'set op->ob_type->tp_flags=0x0', | 
| Martin v. Löwis | 7f7765c | 2010-04-12 05:18:16 +0000 | [diff] [blame] | 504 |                         expvalue=42) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 505 |  | 
 | 506 |     def test_corrupt_tp_name(self): | 
 | 507 |         'Ensure that a PyObject* with a type with corrupt tp_name is handled' | 
 | 508 |         self.assertSane('print 42', | 
| Martin v. Löwis | 7f7765c | 2010-04-12 05:18:16 +0000 | [diff] [blame] | 509 |                         'set op->ob_type->tp_name=0xDEADBEEF', | 
 | 510 |                         expvalue=42) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 511 |  | 
 | 512 |     def test_NULL_instance_dict(self): | 
 | 513 |         'Ensure that a PyInstanceObject with with a NULL in_dict is handled' | 
 | 514 |         self.assertSane(''' | 
 | 515 | class Foo: | 
 | 516 |     pass | 
 | 517 | foo = Foo() | 
 | 518 | foo.an_int = 42 | 
 | 519 | print foo''', | 
 | 520 |                         'set ((PyInstanceObject*)op)->in_dict = 0', | 
| Martin v. Löwis | 7f7765c | 2010-04-12 05:18:16 +0000 | [diff] [blame] | 521 |                         exptype='Foo') | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 522 |  | 
 | 523 |     def test_builtins_help(self): | 
 | 524 |         'Ensure that the new-style class _Helper in site.py can be handled' | 
 | 525 |         # (this was the issue causing tracebacks in | 
 | 526 |         #  http://bugs.python.org/issue8032#msg100537 ) | 
 | 527 |  | 
 | 528 |         gdb_repr, gdb_output = self.get_gdb_repr('print __builtins__.help', import_site=True) | 
 | 529 |         m = re.match(r'<_Helper at remote 0x[0-9a-f]+>', gdb_repr) | 
 | 530 |         self.assertTrue(m, | 
 | 531 |                         msg='Unexpected rendering %r' % gdb_repr) | 
 | 532 |  | 
 | 533 |     def test_selfreferential_list(self): | 
 | 534 |         '''Ensure that a reference loop involving a list doesn't lead proxyval | 
 | 535 |         into an infinite loop:''' | 
 | 536 |         gdb_repr, gdb_output = \ | 
 | 537 |             self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; print a") | 
 | 538 |  | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 539 |         self.assertEqual(gdb_repr, '[3, 4, 5, [...]]') | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 540 |  | 
 | 541 |         gdb_repr, gdb_output = \ | 
 | 542 |             self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; print a") | 
 | 543 |  | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 544 |         self.assertEqual(gdb_repr, '[3, 4, 5, [[...]]]') | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 545 |  | 
 | 546 |     def test_selfreferential_dict(self): | 
 | 547 |         '''Ensure that a reference loop involving a dict doesn't lead proxyval | 
 | 548 |         into an infinite loop:''' | 
 | 549 |         gdb_repr, gdb_output = \ | 
 | 550 |             self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; print a") | 
 | 551 |  | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 552 |         self.assertEqual(gdb_repr, "{'foo': {'bar': {...}}}") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 553 |  | 
 | 554 |     def test_selfreferential_old_style_instance(self): | 
 | 555 |         gdb_repr, gdb_output = \ | 
 | 556 |             self.get_gdb_repr(''' | 
 | 557 | class Foo: | 
 | 558 |     pass | 
 | 559 | foo = Foo() | 
 | 560 | foo.an_attr = foo | 
 | 561 | print foo''') | 
 | 562 |         self.assertTrue(re.match('<Foo\(an_attr=<\.\.\.>\) at remote 0x[0-9a-f]+>', | 
 | 563 |                                  gdb_repr), | 
 | 564 |                         'Unexpected gdb representation: %r\n%s' % \ | 
 | 565 |                             (gdb_repr, gdb_output)) | 
 | 566 |  | 
 | 567 |     def test_selfreferential_new_style_instance(self): | 
 | 568 |         gdb_repr, gdb_output = \ | 
 | 569 |             self.get_gdb_repr(''' | 
 | 570 | class Foo(object): | 
 | 571 |     pass | 
 | 572 | foo = Foo() | 
 | 573 | foo.an_attr = foo | 
 | 574 | print foo''') | 
 | 575 |         self.assertTrue(re.match('<Foo\(an_attr=<\.\.\.>\) at remote 0x[0-9a-f]+>', | 
 | 576 |                                  gdb_repr), | 
 | 577 |                         'Unexpected gdb representation: %r\n%s' % \ | 
 | 578 |                             (gdb_repr, gdb_output)) | 
 | 579 |  | 
 | 580 |         gdb_repr, gdb_output = \ | 
 | 581 |             self.get_gdb_repr(''' | 
 | 582 | class Foo(object): | 
 | 583 |     pass | 
 | 584 | a = Foo() | 
 | 585 | b = Foo() | 
 | 586 | a.an_attr = b | 
 | 587 | b.an_attr = a | 
 | 588 | print a''') | 
 | 589 |         self.assertTrue(re.match('<Foo\(an_attr=<Foo\(an_attr=<\.\.\.>\) at remote 0x[0-9a-f]+>\) at remote 0x[0-9a-f]+>', | 
 | 590 |                                  gdb_repr), | 
 | 591 |                         'Unexpected gdb representation: %r\n%s' % \ | 
 | 592 |                             (gdb_repr, gdb_output)) | 
 | 593 |  | 
 | 594 |     def test_truncation(self): | 
 | 595 |         'Verify that very long output is truncated' | 
 | 596 |         gdb_repr, gdb_output = self.get_gdb_repr('print range(1000)') | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 597 |         self.assertEqual(gdb_repr, | 
 | 598 |                          "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " | 
 | 599 |                          "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, " | 
 | 600 |                          "27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, " | 
 | 601 |                          "40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, " | 
 | 602 |                          "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, " | 
 | 603 |                          "66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, " | 
 | 604 |                          "79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, " | 
 | 605 |                          "92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, " | 
 | 606 |                          "104, 105, 106, 107, 108, 109, 110, 111, 112, 113, " | 
 | 607 |                          "114, 115, 116, 117, 118, 119, 120, 121, 122, 123, " | 
 | 608 |                          "124, 125, 126, 127, 128, 129, 130, 131, 132, 133, " | 
 | 609 |                          "134, 135, 136, 137, 138, 139, 140, 141, 142, 143, " | 
 | 610 |                          "144, 145, 146, 147, 148, 149, 150, 151, 152, 153, " | 
 | 611 |                          "154, 155, 156, 157, 158, 159, 160, 161, 162, 163, " | 
 | 612 |                          "164, 165, 166, 167, 168, 169, 170, 171, 172, 173, " | 
 | 613 |                          "174, 175, 176, 177, 178, 179, 180, 181, 182, 183, " | 
 | 614 |                          "184, 185, 186, 187, 188, 189, 190, 191, 192, 193, " | 
 | 615 |                          "194, 195, 196, 197, 198, 199, 200, 201, 202, 203, " | 
 | 616 |                          "204, 205, 206, 207, 208, 209, 210, 211, 212, 213, " | 
 | 617 |                          "214, 215, 216, 217, 218, 219, 220, 221, 222, 223, " | 
 | 618 |                          "224, 225, 226...(truncated)") | 
 | 619 |         self.assertEqual(len(gdb_repr), | 
 | 620 |                          1024 + len('...(truncated)')) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 621 |  | 
 | 622 |     def test_builtin_function(self): | 
 | 623 |         gdb_repr, gdb_output = self.get_gdb_repr('print len') | 
| Ezio Melotti | 2623a37 | 2010-11-21 13:34:58 +0000 | [diff] [blame] | 624 |         self.assertEqual(gdb_repr, '<built-in function len>') | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 625 |  | 
 | 626 |     def test_builtin_method(self): | 
 | 627 |         gdb_repr, gdb_output = self.get_gdb_repr('import sys; print sys.stdout.readlines') | 
 | 628 |         self.assertTrue(re.match('<built-in method readlines of file object at remote 0x[0-9a-f]+>', | 
 | 629 |                                  gdb_repr), | 
 | 630 |                         'Unexpected gdb representation: %r\n%s' % \ | 
 | 631 |                             (gdb_repr, gdb_output)) | 
 | 632 |  | 
 | 633 |     def test_frames(self): | 
 | 634 |         gdb_output = self.get_stack_trace(''' | 
 | 635 | def foo(a, b, c): | 
 | 636 |     pass | 
 | 637 |  | 
 | 638 | foo(3, 4, 5) | 
 | 639 | print foo.__code__''', | 
 | 640 |                                           breakpoint='PyObject_Print', | 
 | 641 |                                           cmds_after_breakpoint=['print (PyFrameObject*)(((PyCodeObject*)op)->co_zombieframe)'] | 
 | 642 |                                           ) | 
| R. David Murray | 0c08009 | 2010-04-05 16:28:49 +0000 | [diff] [blame] | 643 |         self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x[0-9a-f]+, for file <string>, line 3, in foo \(\)\s+.*', | 
 | 644 |                                  gdb_output, | 
 | 645 |                                  re.DOTALL), | 
 | 646 |                         'Unexpected gdb representation: %r\n%s' % (gdb_output, gdb_output)) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 647 |  | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 648 | @unittest.skipIf(python_is_optimized(), | 
 | 649 |                  "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 650 | class PyListTests(DebuggerTests): | 
 | 651 |     def assertListing(self, expected, actual): | 
 | 652 |         self.assertEndsWith(actual, expected) | 
 | 653 |  | 
 | 654 |     def test_basic_command(self): | 
 | 655 |         'Verify that the "py-list" command works' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 656 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 657 |                                   cmds_after_breakpoint=['py-list']) | 
 | 658 |  | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 659 |         self.assertListing('   5    \n' | 
 | 660 |                            '   6    def bar(a, b, c):\n' | 
 | 661 |                            '   7        baz(a, b, c)\n' | 
 | 662 |                            '   8    \n' | 
 | 663 |                            '   9    def baz(*args):\n' | 
 | 664 |                            ' >10        print(42)\n' | 
 | 665 |                            '  11    \n' | 
 | 666 |                            '  12    foo(1, 2, 3)\n', | 
 | 667 |                            bt) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 668 |  | 
 | 669 |     def test_one_abs_arg(self): | 
 | 670 |         'Verify the "py-list" command with one absolute argument' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 671 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 672 |                                   cmds_after_breakpoint=['py-list 9']) | 
 | 673 |  | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 674 |         self.assertListing('   9    def baz(*args):\n' | 
 | 675 |                            ' >10        print(42)\n' | 
 | 676 |                            '  11    \n' | 
 | 677 |                            '  12    foo(1, 2, 3)\n', | 
 | 678 |                            bt) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 679 |  | 
 | 680 |     def test_two_abs_args(self): | 
 | 681 |         'Verify the "py-list" command with two absolute arguments' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 682 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 683 |                                   cmds_after_breakpoint=['py-list 1,3']) | 
 | 684 |  | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 685 |         self.assertListing('   1    # Sample script for use by test_gdb.py\n' | 
 | 686 |                            '   2    \n' | 
 | 687 |                            '   3    def foo(a, b, c):\n', | 
 | 688 |                            bt) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 689 |  | 
 | 690 | class StackNavigationTests(DebuggerTests): | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 691 |     @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 692 |     @unittest.skipIf(python_is_optimized(), | 
 | 693 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 694 |     def test_pyup_command(self): | 
 | 695 |         'Verify that the "py-up" command works' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 696 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 697 |                                   cmds_after_breakpoint=['py-up']) | 
 | 698 |         self.assertMultilineMatches(bt, | 
 | 699 |                                     r'''^.* | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 700 | #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 701 |     baz\(a, b, c\) | 
 | 702 | $''') | 
 | 703 |  | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 704 |     @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 705 |     def test_down_at_bottom(self): | 
 | 706 |         'Verify handling of "py-down" at the bottom of the stack' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 707 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 708 |                                   cmds_after_breakpoint=['py-down']) | 
 | 709 |         self.assertEndsWith(bt, | 
 | 710 |                             'Unable to find a newer python frame\n') | 
 | 711 |  | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 712 |     @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") | 
| Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D) | cb20a21 | 2016-09-08 21:51:26 +0000 | [diff] [blame] | 713 |     @unittest.skipIf(python_is_optimized(), | 
 | 714 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 715 |     def test_up_at_top(self): | 
 | 716 |         'Verify handling of "py-up" at the top of the stack' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 717 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 718 |                                   cmds_after_breakpoint=['py-up'] * 4) | 
 | 719 |         self.assertEndsWith(bt, | 
 | 720 |                             'Unable to find an older python frame\n') | 
 | 721 |  | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 722 |     @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 723 |     @unittest.skipIf(python_is_optimized(), | 
 | 724 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 725 |     def test_up_then_down(self): | 
 | 726 |         'Verify "py-up" followed by "py-down"' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 727 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 728 |                                   cmds_after_breakpoint=['py-up', 'py-down']) | 
 | 729 |         self.assertMultilineMatches(bt, | 
 | 730 |                                     r'''^.* | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 731 | #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 732 |     baz\(a, b, c\) | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 733 | #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 10, in baz \(args=\(1, 2, 3\)\) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 734 |     print\(42\) | 
 | 735 | $''') | 
 | 736 |  | 
 | 737 | class PyBtTests(DebuggerTests): | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 738 |     @unittest.skipIf(python_is_optimized(), | 
 | 739 |                      "Python was compiled with optimizations") | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 740 |     def test_bt(self): | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 741 |         'Verify that the "py-bt" command works' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 742 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 743 |                                   cmds_after_breakpoint=['py-bt']) | 
 | 744 |         self.assertMultilineMatches(bt, | 
 | 745 |                                     r'''^.* | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 746 | Traceback \(most recent call first\): | 
 | 747 |   File ".*gdb_sample.py", line 10, in baz | 
 | 748 |     print\(42\) | 
 | 749 |   File ".*gdb_sample.py", line 7, in bar | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 750 |     baz\(a, b, c\) | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 751 |   File ".*gdb_sample.py", line 4, in foo | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 752 |     bar\(a, b, c\) | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 753 |   File ".*gdb_sample.py", line 12, in <module> | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 754 |     foo\(1, 2, 3\) | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 755 | ''') | 
 | 756 |  | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 757 |     @unittest.skipIf(python_is_optimized(), | 
 | 758 |                      "Python was compiled with optimizations") | 
 | 759 |     def test_bt_full(self): | 
 | 760 |         'Verify that the "py-bt-full" command works' | 
 | 761 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
 | 762 |                                   cmds_after_breakpoint=['py-bt-full']) | 
 | 763 |         self.assertMultilineMatches(bt, | 
 | 764 |                                     r'''^.* | 
 | 765 | #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) | 
 | 766 |     baz\(a, b, c\) | 
 | 767 | #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) | 
 | 768 |     bar\(a, b, c\) | 
 | 769 | #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in <module> \(\) | 
 | 770 |     foo\(1, 2, 3\) | 
 | 771 | ''') | 
 | 772 |  | 
 | 773 |     @unittest.skipUnless(thread, | 
 | 774 |                          "Python was compiled without thread support") | 
| Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D) | cb20a21 | 2016-09-08 21:51:26 +0000 | [diff] [blame] | 775 |     @unittest.skipIf(python_is_optimized(), | 
 | 776 |                      "Python was compiled with optimizations") | 
| Victor Stinner | cc1db4b | 2015-09-03 10:17:28 +0200 | [diff] [blame] | 777 |     def test_threads(self): | 
 | 778 |         'Verify that "py-bt" indicates threads that are waiting for the GIL' | 
 | 779 |         cmd = ''' | 
 | 780 | from threading import Thread | 
 | 781 |  | 
 | 782 | class TestThread(Thread): | 
 | 783 |     # These threads would run forever, but we'll interrupt things with the | 
 | 784 |     # debugger | 
 | 785 |     def run(self): | 
 | 786 |         i = 0 | 
 | 787 |         while 1: | 
 | 788 |              i += 1 | 
 | 789 |  | 
 | 790 | t = {} | 
 | 791 | for i in range(4): | 
 | 792 |    t[i] = TestThread() | 
 | 793 |    t[i].start() | 
 | 794 |  | 
 | 795 | # Trigger a breakpoint on the main thread | 
 | 796 | print 42 | 
 | 797 |  | 
 | 798 | ''' | 
 | 799 |         # Verify with "py-bt": | 
 | 800 |         gdb_output = self.get_stack_trace(cmd, | 
 | 801 |                                           cmds_after_breakpoint=['thread apply all py-bt']) | 
 | 802 |         self.assertIn('Waiting for the GIL', gdb_output) | 
 | 803 |  | 
 | 804 |         # Verify with "py-bt-full": | 
 | 805 |         gdb_output = self.get_stack_trace(cmd, | 
 | 806 |                                           cmds_after_breakpoint=['thread apply all py-bt-full']) | 
 | 807 |         self.assertIn('Waiting for the GIL', gdb_output) | 
 | 808 |  | 
 | 809 |     @unittest.skipIf(python_is_optimized(), | 
 | 810 |                      "Python was compiled with optimizations") | 
 | 811 |     # Some older versions of gdb will fail with | 
 | 812 |     #  "Cannot find new threads: generic error" | 
 | 813 |     # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround | 
 | 814 |     @unittest.skipUnless(thread, | 
 | 815 |                          "Python was compiled without thread support") | 
 | 816 |     def test_gc(self): | 
 | 817 |         'Verify that "py-bt" indicates if a thread is garbage-collecting' | 
 | 818 |         cmd = ('from gc import collect\n' | 
 | 819 |                'print 42\n' | 
 | 820 |                'def foo():\n' | 
 | 821 |                '    collect()\n' | 
 | 822 |                'def bar():\n' | 
 | 823 |                '    foo()\n' | 
 | 824 |                'bar()\n') | 
 | 825 |         # Verify with "py-bt": | 
 | 826 |         gdb_output = self.get_stack_trace(cmd, | 
 | 827 |                                           cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'], | 
 | 828 |                                           ) | 
 | 829 |         self.assertIn('Garbage-collecting', gdb_output) | 
 | 830 |  | 
 | 831 |         # Verify with "py-bt-full": | 
 | 832 |         gdb_output = self.get_stack_trace(cmd, | 
 | 833 |                                           cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'], | 
 | 834 |                                           ) | 
 | 835 |         self.assertIn('Garbage-collecting', gdb_output) | 
 | 836 |  | 
 | 837 |     @unittest.skipIf(python_is_optimized(), | 
 | 838 |                      "Python was compiled with optimizations") | 
 | 839 |     # Some older versions of gdb will fail with | 
 | 840 |     #  "Cannot find new threads: generic error" | 
 | 841 |     # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround | 
 | 842 |     @unittest.skipUnless(thread, | 
 | 843 |                          "Python was compiled without thread support") | 
 | 844 |     def test_pycfunction(self): | 
 | 845 |         'Verify that "py-bt" displays invocations of PyCFunction instances' | 
 | 846 |         # Tested function must not be defined with METH_NOARGS or METH_O, | 
 | 847 |         # otherwise call_function() doesn't call PyCFunction_Call() | 
 | 848 |         cmd = ('from time import gmtime\n' | 
 | 849 |                'def foo():\n' | 
 | 850 |                '    gmtime(1)\n' | 
 | 851 |                'def bar():\n' | 
 | 852 |                '    foo()\n' | 
 | 853 |                'bar()\n') | 
 | 854 |         # Verify with "py-bt": | 
 | 855 |         gdb_output = self.get_stack_trace(cmd, | 
 | 856 |                                           breakpoint='time_gmtime', | 
 | 857 |                                           cmds_after_breakpoint=['bt', 'py-bt'], | 
 | 858 |                                           ) | 
 | 859 |         self.assertIn('<built-in function gmtime', gdb_output) | 
 | 860 |  | 
 | 861 |         # Verify with "py-bt-full": | 
 | 862 |         gdb_output = self.get_stack_trace(cmd, | 
 | 863 |                                           breakpoint='time_gmtime', | 
 | 864 |                                           cmds_after_breakpoint=['py-bt-full'], | 
 | 865 |                                           ) | 
 | 866 |         self.assertIn('#0 <built-in function gmtime', gdb_output) | 
 | 867 |  | 
 | 868 |  | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 869 | class PyPrintTests(DebuggerTests): | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 870 |     @unittest.skipIf(python_is_optimized(), | 
 | 871 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 872 |     def test_basic_command(self): | 
 | 873 |         'Verify that the "py-print" command works' | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 874 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 875 |                                   cmds_after_breakpoint=['py-print args']) | 
 | 876 |         self.assertMultilineMatches(bt, | 
 | 877 |                                     r".*\nlocal 'args' = \(1, 2, 3\)\n.*") | 
 | 878 |  | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 879 |     @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 880 |     @unittest.skipIf(python_is_optimized(), | 
 | 881 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 882 |     def test_print_after_up(self): | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 883 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 884 |                                   cmds_after_breakpoint=['py-up', 'py-print c', 'py-print b', 'py-print a']) | 
 | 885 |         self.assertMultilineMatches(bt, | 
 | 886 |                                     r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*") | 
 | 887 |  | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 888 |     @unittest.skipIf(python_is_optimized(), | 
 | 889 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 890 |     def test_printing_global(self): | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 891 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 892 |                                   cmds_after_breakpoint=['py-print __name__']) | 
 | 893 |         self.assertMultilineMatches(bt, | 
 | 894 |                                     r".*\nglobal '__name__' = '__main__'\n.*") | 
 | 895 |  | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 896 |     @unittest.skipIf(python_is_optimized(), | 
 | 897 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 898 |     def test_printing_builtin(self): | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 899 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 900 |                                   cmds_after_breakpoint=['py-print len']) | 
 | 901 |         self.assertMultilineMatches(bt, | 
 | 902 |                                     r".*\nbuiltin 'len' = <built-in function len>\n.*") | 
 | 903 |  | 
 | 904 | class PyLocalsTests(DebuggerTests): | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 905 |     @unittest.skipIf(python_is_optimized(), | 
 | 906 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 907 |     def test_basic_command(self): | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 908 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 909 |                                   cmds_after_breakpoint=['py-locals']) | 
 | 910 |         self.assertMultilineMatches(bt, | 
 | 911 |                                     r".*\nargs = \(1, 2, 3\)\n.*") | 
 | 912 |  | 
| Victor Stinner | a92e81b | 2010-04-20 22:28:31 +0000 | [diff] [blame] | 913 |     @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") | 
| Victor Stinner | 99cff3f | 2011-12-19 13:59:58 +0100 | [diff] [blame] | 914 |     @unittest.skipIf(python_is_optimized(), | 
 | 915 |                      "Python was compiled with optimizations") | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 916 |     def test_locals_after_up(self): | 
| Martin v. Löwis | 24f09fd | 2010-04-17 22:40:40 +0000 | [diff] [blame] | 917 |         bt = self.get_stack_trace(script=self.get_sample_script(), | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 918 |                                   cmds_after_breakpoint=['py-up', 'py-locals']) | 
 | 919 |         self.assertMultilineMatches(bt, | 
 | 920 |                                     r".*\na = 1\nb = 2\nc = 3\n.*") | 
 | 921 |  | 
 | 922 | def test_main(): | 
| Victor Stinner | 3c5ce40 | 2015-09-03 09:51:59 +0200 | [diff] [blame] | 923 |     if test_support.verbose: | 
 | 924 |         print("GDB version %s.%s:" % (gdb_major_version, gdb_minor_version)) | 
 | 925 |         for line in gdb_version.splitlines(): | 
 | 926 |             print(" " * 4 + line) | 
| Martin v. Löwis | 5a96543 | 2010-04-12 05:22:25 +0000 | [diff] [blame] | 927 |     run_unittest(PrettyPrintTests, | 
 | 928 |                  PyListTests, | 
 | 929 |                  StackNavigationTests, | 
 | 930 |                  PyBtTests, | 
 | 931 |                  PyPrintTests, | 
 | 932 |                  PyLocalsTests | 
| Martin v. Löwis | bf0dfb3 | 2010-04-01 07:40:51 +0000 | [diff] [blame] | 933 |                  ) | 
 | 934 |  | 
 | 935 | if __name__ == "__main__": | 
 | 936 |     test_main() |