Mirror of the gdb mailing list
 help / color / mirror / Atom feed
From: Zack Weinberg <zackw@panix.com>
To: libc-alpha@sourceware.org,	gdb@sourceware.org
Cc: joseph@codesourcery.com,	fweimer@redhat.com,	tom@tromey.com,
	siddhesh@gotplt.org
Subject: [PATCH 1/3] Improve testing of GDB pretty-printers.
Date: Thu, 22 Jun 2017 22:45:00 -0000	[thread overview]
Message-ID: <20170622224456.1358-2-zackw@panix.com> (raw)
In-Reply-To: <20170622224456.1358-1-zackw@panix.com>

The C programs used to test GDB pretty-printers were being compiled
with -DMODULE_NAME=libc (!) which causes many problems, such as
failure to link if they refer to errno.  Now they are compiled with
-DMODULE_NAME=testsuite instead.

test_printers_common.py was testing for expected output in a clumsy
way which meant the pexpect timeout had to expire before it could
report a failure, even if the regexp was never going to match.  This
slows down debugging a test quite a bit.  Rewrote that logic so it
doesn't do that anymore.  Note that as a side effect, test() fails the
test by calling exit() rather than throwing an exception -- that could
change if people think it's a bad idea.

Add an 'unsupported_pattern' argument to test(); if the normal
'pattern' fails to match, but an 'unsupported_pattern' was supplied
and it matches, then the test fails as unsupported, not as a normal
failure.  This feature is used in part 2.

Tighten up the code to honor TIMEOUTFACTOR, and add another
environment variable TEST_PRINTERS_LOG; if this is set to a pathname,
all of the dialogue with the gdb subprocess will be logged to that
file.

	* Rules: Set MODULE_NAME=testsuite for everything in tests-printers.
	* scripts/test_printers_common.py (TIMEOUTFACTOR): Tighten up handling.
	(TEST_PRINTERS_LOG): New env variable; if set, pexpect will log all
	dialogue with the gdb subprocess to the file it names.
	(send_command): New function broken out of test.
	(test): Add 'unsupported_pattern' argument and improve
	handling of 'pattern' argument; match failures no longer have to
	wait for the timeout.
---
 Rules                           |  4 ++
 scripts/test_printers_common.py | 84 ++++++++++++++++++++++-------------------
 2 files changed, 50 insertions(+), 38 deletions(-)

diff --git a/Rules b/Rules
index 168cf508d7..85b77a00e8 100644
--- a/Rules
+++ b/Rules
@@ -265,6 +265,10 @@ endif	# tests
 ifdef PYTHON
 ifneq "$(strip $(tests-printers))" ""
 
+cpp-srcs-left := $(tests-printers)
+lib := testsuite
+include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
+
 # Static pattern rule for building the test programs for the pretty printers.
 $(tests-printers-programs): %: %.o $(tests-printers-libs) \
   $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \
diff --git a/scripts/test_printers_common.py b/scripts/test_printers_common.py
index fe88f36366..aabb9da83e 100644
--- a/scripts/test_printers_common.py
+++ b/scripts/test_printers_common.py
@@ -54,11 +54,7 @@ if not pexpect.which(gdb_bin):
     print('gdb 7.8 or newer must be installed to test the pretty printers.')
     exit(UNSUPPORTED)
 
-timeout = 5
-TIMEOUTFACTOR = os.environ.get('TIMEOUTFACTOR')
-
-if TIMEOUTFACTOR:
-    timeout = int(TIMEOUTFACTOR)
+timeout = int(os.environ.get('TIMEOUTFACTOR', '5'))
 
 try:
     # Check the gdb version.
@@ -93,15 +89,39 @@ try:
     # If everything's ok, spawn the gdb process we'll use for testing.
     gdb = pexpect.spawn(gdb_invocation, echo=False, timeout=timeout,
                         encoding=encoding)
-    gdb_prompt = u'\(gdb\)'
+    logfile = os.environ.get("TEST_PRINTERS_LOG")
+    if logfile is not None:
+        gdb.logfile = open(logfile, "wt")
+
+    gdb_prompt = u'(?:\A|\r\n)\(gdb\) '
     gdb.expect(gdb_prompt)
 
 except pexpect.ExceptionPexpect as exception:
     print('Error: {0}'.format(exception))
     exit(FAIL)
 
-def test(command, pattern=None):
-    """Sends 'command' to gdb and expects the given 'pattern'.
+def send_command(command):
+    """Sends 'command' to gdb, and returns all output up to but not
+    including the next gdb prompt.  If a gdb prompt is not detected
+    in a timely fashion, raises pexpect.TIMEOUT.
+
+    Args:
+        command (string): The command we'll send to gdb.
+    """
+
+    gdb.sendline(command)
+
+    # PExpect does a non-greedy match for '+' and '*', since it can't
+    # look ahead on the gdb output stream.  Therefore, we must include
+    # the gdb prompt in the match to ensure that all of the output of
+    # the command is captured.
+    gdb.expect(u'(.*?){}'.format(gdb_prompt))
+    return gdb.match.group(1)
+
+
+def test(command, pattern=None, unsupported_pattern=None):
+    """Sends 'command' to gdb and expects the given 'pattern'.  If
+       the match fails, the test fails.
 
     If 'pattern' is None, simply consumes everything up to and including
     the gdb prompt.
@@ -109,43 +129,31 @@ def test(command, pattern=None):
     Args:
         command (string): The command we'll send to gdb.
         pattern (raw string): A pattern the gdb output should match.
+        unsupported_pattern (raw string): If the gdb output fails to
+            match 'pattern', but it _does_ match this, then the test
+            is marked unsupported rather than failing outright.
 
     Returns:
         string: The string that matched 'pattern', or an empty string if
             'pattern' was None.
     """
+    output = send_command(command)
+    if pattern is None:
+        return None
 
-    match = ''
+    match = re.search(pattern, output, re.DOTALL)
+    if not match:
+        if (unsupported_pattern is not None
+            and re.search(unsupported_pattern, output, re.DOTALL)):
+            exit(UNSUPPORTED)
+        else:
+            print('Response does not match the expected pattern.\n'
+                  'Command: {0}\n'
+                  'Expected pattern: {1}\n'
+                  'Response: {2}'.format(command, pattern, output))
+            exit(FAIL)
 
-    gdb.sendline(command)
-
-    if pattern:
-        # PExpect does a non-greedy match for '+' and '*'.  Since it can't look
-        # ahead on the gdb output stream, if 'pattern' ends with a '+' or a '*'
-        # we may end up matching only part of the required output.
-        # To avoid this, we'll consume 'pattern' and anything that follows it
-        # up to and including the gdb prompt, then extract 'pattern' later.
-        index = gdb.expect([u'{0}.+{1}'.format(pattern, gdb_prompt),
-                            pexpect.TIMEOUT])
-
-        if index == 0:
-            # gdb.after now contains the whole match.  Extract the text that
-            # matches 'pattern'.
-            match = re.match(pattern, gdb.after, re.DOTALL).group()
-        elif index == 1:
-            # We got a timeout exception.  Print information on what caused it
-            # and bail out.
-            error = ('Response does not match the expected pattern.\n'
-                     'Command: {0}\n'
-                     'Expected pattern: {1}\n'
-                     'Response: {2}'.format(command, pattern, gdb.before))
-
-            raise pexpect.TIMEOUT(error)
-    else:
-        # Consume just the the gdb prompt.
-        gdb.expect(gdb_prompt)
-
-    return match
+    return match.group(0)
 
 def init_test(test_bin, printer_files, printer_names):
     """Loads the test binary file and the required pretty printers to gdb.
-- 
2.11.0


  reply	other threads:[~2017-06-22 22:45 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-22 22:45 [RFC PATCH 0/3] Pretty-printing for errno Zack Weinberg
2017-06-22 22:45 ` Zack Weinberg [this message]
2017-06-22 22:46 ` [PATCH 2/3] Make error_t always int; make __errno_location return an __error_t Zack Weinberg
2017-06-22 22:46 ` [PATCH 3/3] Add pretty-printer for errno Zack Weinberg
2017-06-29 15:48 ` [RFC PATCH 0/3] Pretty-printing " Phil Muldoon
2017-06-29 16:53   ` Pedro Alves
2017-06-29 17:02     ` Pedro Alves
2017-06-29 17:28       ` Pedro Alves
2017-06-30  0:28         ` Zack Weinberg
2017-06-30 16:38           ` Pedro Alves
2017-06-30 16:47             ` Pedro Alves
2017-06-30 17:27             ` Zack Weinberg
2017-06-30 18:11               ` Pedro Alves
2017-07-01 11:56                 ` Pedro Alves
2017-07-13  2:30                 ` Pedro Alves
2017-09-04 21:25                   ` Pedro Alves
2017-09-05 21:15                     ` Zack Weinberg
2017-09-05 22:32                       ` Pedro Alves
2017-09-06 13:05                         ` Zack Weinberg
2017-09-06 13:32                           ` Pedro Alves
2017-09-06 21:03                             ` Zack Weinberg
     [not found]                               ` <2432779a-f146-1612-236e-84dde15c5d01@redhat.com>
2017-09-13 11:22                                 ` Using libthread_db.so with single-threaded programs, for TLS access (was: Re: [RFC PATCH 0/3] Pretty-printing for errno) Pedro Alves
2017-09-13 19:27                                   ` Philippe Waroquiers
2017-09-14  0:02                                   ` Using libthread_db.so with single-threaded programs, for TLS access Pedro Alves
2017-09-18 13:17                                     ` Carlos O'Donell
2017-09-18 14:28                                       ` Pedro Alves
2017-07-01 14:35               ` [RFC PATCH 0/3] Pretty-printing for errno Siddhesh Poyarekar
2017-07-04 15:54                 ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170622224456.1358-2-zackw@panix.com \
    --to=zackw@panix.com \
    --cc=fweimer@redhat.com \
    --cc=gdb@sourceware.org \
    --cc=joseph@codesourcery.com \
    --cc=libc-alpha@sourceware.org \
    --cc=siddhesh@gotplt.org \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox