[gdb/testsuite] Reimplement gdb.gdb/python-interrupts.exp as unittest
authorTom de Vries <tdevries@suse.de>
Tue, 19 Oct 2021 21:50:50 +0000 (23:50 +0200)
committerTom de Vries <tdevries@suse.de>
Tue, 19 Oct 2021 21:50:50 +0000 (23:50 +0200)
The test-case gdb.gdb/python-interrupts.exp:
- runs to captured_command_loop
- sets a breakpoint at set_active_ext_lang
- calls a python command
- verifies the command triggers the breakpoint
- sends a signal and verifies the result

The test-case is fragile, because (f.i. with -flto) it cannot be guaranteed
that captured_command_loop and set_active_ext_lang are available for setting
breakpoints.

Reimplement the test-case as unittest, using:
- execute_command_to_string to capture the output
- try/catch to catch the "Error while executing Python code" exception
- a new hook selftests::hook_set_active_ext_lang to raise the signal

Tested on x86_64-linux.

gdb/extension.c
gdb/extension.h
gdb/python/python.c
gdb/testsuite/gdb.gdb/python-interrupts.exp [deleted file]

index 27dce9befa0f7de3d6d6f4da827e1a0d875670e7..89ab29f3d1c97b16735b5d4e8200daffe25bf273 100644 (file)
@@ -682,6 +682,12 @@ install_gdb_sigint_handler (struct signal_handler *previous)
     previous->handler_saved = 0;
 }
 
+#if GDB_SELF_TEST
+namespace selftests {
+void (*hook_set_active_ext_lang) () = nullptr;
+}
+#endif
+
 /* Set the currently active extension language to NOW_ACTIVE.
    The result is a pointer to a malloc'd block of memory to pass to
    restore_active_ext_lang.
@@ -708,6 +714,11 @@ install_gdb_sigint_handler (struct signal_handler *previous)
 struct active_ext_lang_state *
 set_active_ext_lang (const struct extension_language_defn *now_active)
 {
+#if GDB_SELF_TEST
+  if (selftests::hook_set_active_ext_lang)
+    selftests::hook_set_active_ext_lang ();
+#endif
+
   struct active_ext_lang_state *previous
     = XCNEW (struct active_ext_lang_state);
 
index 56f57560de306a2073c7bb024da7508eb891e006..2f2ca3e77433aa9c726426be28f4cfd536f98c83 100644 (file)
@@ -319,4 +319,10 @@ extern void get_matching_xmethod_workers
 extern gdb::optional<std::string> ext_lang_colorize
   (const std::string &filename, const std::string &contents);
 
+#if GDB_SELF_TEST
+namespace selftests {
+extern void (*hook_set_active_ext_lang) ();
+}
+#endif
+
 #endif /* EXTENSION_H */
index 264f7c88ed66c4f4f4bdb19d425e238fcbd07d67..44ec4b7094cdada6c10a9af20a6c4ffdcf72736d 100644 (file)
@@ -1933,21 +1933,46 @@ test_python ()
   output.clear ();
 
   bool saw_exception = false;
-  scoped_restore reset_gdb_python_initialized
-    = make_scoped_restore (&gdb_python_initialized, 0);
-  try
-    {
-      CMD (output);
-    }
-  catch (const gdb_exception &e)
-    {
-      saw_exception = true;
-      SELF_CHECK (e.reason == RETURN_ERROR);
-      SELF_CHECK (e.error == GENERIC_ERROR);
-      SELF_CHECK (*e.message == "Python not initialized");
-    }
-  SELF_CHECK (saw_exception);
-  SELF_CHECK (output.empty ());
+  {
+    scoped_restore reset_gdb_python_initialized
+      = make_scoped_restore (&gdb_python_initialized, 0);
+    try
+      {
+       CMD (output);
+      }
+    catch (const gdb_exception &e)
+      {
+       saw_exception = true;
+       SELF_CHECK (e.reason == RETURN_ERROR);
+       SELF_CHECK (e.error == GENERIC_ERROR);
+       SELF_CHECK (*e.message == "Python not initialized");
+      }
+    SELF_CHECK (saw_exception);
+    SELF_CHECK (output.empty ());
+  }
+
+  saw_exception = false;
+  {
+    scoped_restore save_hook
+      = make_scoped_restore (&hook_set_active_ext_lang,
+                            []() { raise (SIGINT); });
+    try
+      {
+       CMD (output);
+      }
+    catch (const gdb_exception &e)
+      {
+       saw_exception = true;
+       SELF_CHECK (e.reason == RETURN_ERROR);
+       SELF_CHECK (e.error == GENERIC_ERROR);
+       SELF_CHECK (*e.message == "Error while executing Python code.");
+      }
+    SELF_CHECK (saw_exception);
+    std::string ref_output("Traceback (most recent call last):\n"
+                          "  File \"<string>\", line 1, in <module>\n"
+                          "KeyboardInterrupt\n");
+    SELF_CHECK (output == ref_output);
+  }
 
 #undef CMD
 }
diff --git a/gdb/testsuite/gdb.gdb/python-interrupts.exp b/gdb/testsuite/gdb.gdb/python-interrupts.exp
deleted file mode 100644 (file)
index 33cf1ef..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2014-2021 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# Test Python SIGINT handling.
-# This is easiest if we can send SIGINT when gdb is at particular points.
-
-load_lib selftest-support.exp
-load_lib gdb-python.exp
-
-proc test_python_interrupts {} {
-    if {[skip_python_tests]} {
-       return -1
-    }
-
-    gdb_breakpoint set_active_ext_lang temporary
-    gdb_test "call catch_command_errors(execute_command, \"python print(5)\", 0, true)" \
-       "Temporary breakpoint.*silently stop."
-    gdb_test "signal SIGINT" \
-       "KeyboardInterrupt.*Error while executing Python code."
-    return 0
-}
-
-do_self_tests captured_command_loop test_python_interrupts