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
next prev parent 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