Issue #8437: Fix test_gdb failures, patch written by Dave Malcolm
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index b01efcb..907d6ef 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -31,6 +31,19 @@
 if gdbpy_version == '':
     raise unittest.SkipTest("gdb not built with embedded python support")
 
+def gdb_has_frame_select():
+    # Does this build of gdb have gdb.Frame.select ?
+    cmd = "--eval-command=python print(dir(gdb.Frame))"
+    p = subprocess.Popen(["gdb", "--batch", cmd],
+                         stdout=subprocess.PIPE)
+    stdout, _ = p.communicate()
+    m = re.match(r'.*\[(.*)\].*', stdout)
+    if not m:
+        raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test")
+    gdb_frame_dir = m.group(1).split(', ')
+    return "'select'" in gdb_frame_dir
+
+HAS_PYUP_PYDOWN = gdb_has_frame_select()
 
 class DebuggerTests(unittest.TestCase):
 
@@ -569,6 +582,7 @@
                            bt)
 
 class StackNavigationTests(DebuggerTests):
+    @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
     def test_pyup_command(self):
         'Verify that the "py-up" command works'
         bt = self.get_stack_trace(script=self.get_sample_script(),
@@ -579,6 +593,7 @@
     baz\(a, b, c\)
 $''')
 
+    @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
     def test_down_at_bottom(self):
         'Verify handling of "py-down" at the bottom of the stack'
         bt = self.get_stack_trace(script=self.get_sample_script(),
@@ -586,6 +601,7 @@
         self.assertEndsWith(bt,
                             'Unable to find a newer python frame\n')
 
+    @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
     def test_up_at_top(self):
         'Verify handling of "py-up" at the top of the stack'
         bt = self.get_stack_trace(script=self.get_sample_script(),
@@ -593,6 +609,7 @@
         self.assertEndsWith(bt,
                             'Unable to find an older python frame\n')
 
+    @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
     def test_up_then_down(self):
         'Verify "py-up" followed by "py-down"'
         bt = self.get_stack_trace(script=self.get_sample_script(),
@@ -628,6 +645,7 @@
         self.assertMultilineMatches(bt,
                                     r".*\nlocal 'args' = \(1, 2, 3\)\n.*")
 
+    @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
     def test_print_after_up(self):
         bt = self.get_stack_trace(script=self.get_sample_script(),
                                   cmds_after_breakpoint=['py-up', 'py-print c', 'py-print b', 'py-print a'])
@@ -653,6 +671,7 @@
         self.assertMultilineMatches(bt,
                                     r".*\nargs = \(1, 2, 3\)\n.*")
 
+    @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
     def test_locals_after_up(self):
         bt = self.get_stack_trace(script=self.get_sample_script(),
                                   cmds_after_breakpoint=['py-up', 'py-locals'])