xUnit test formatter: add options for ignoring skipped tests

Skipped tests can be dropped from xUnit reports if either
the name or the skip reason matches one of a given set of
regular expression patterns (via re.search(), not re.match()).
New formatter option for the xunit formatter:
--ignore-skip-matching-reason and
--ignore-skip-matching-name

Both are results-formatter options.

llvm-svn: 248247
This commit is contained in:
Todd Fiala 2015-09-22 06:32:50 +00:00
parent 844deef50f
commit 132c2c4bc7
1 changed files with 68 additions and 1 deletions

View File

@ -456,6 +456,7 @@ class ResultsFormatter(object):
terminate_event = EventBuilder.bare_event("terminate")
self.handle_event(terminate_event)
class XunitFormatter(ResultsFormatter):
"""Provides xUnit-style formatted output.
"""
@ -536,6 +537,20 @@ class XunitFormatter(ResultsFormatter):
action="store_true",
help=('cause unknown test events to generate '
'a python assert. Default is to ignore.'))
parser.add_argument(
"--ignore-skip-matching-name",
action="store",
help=('one or more comma-separated python regex patterns, where '
'any skipped test with a test method name where regex '
'matches (via search) will be ignored for xUnit test '
'result purposes.'))
parser.add_argument(
"--ignore-skip-matching-reason",
action="store",
help=('one or more comma-separated python regex patterns, where '
'any skipped test with a skip reason where the regex '
'matches (via search) will be ignored for xUnit test '
'result purposes.'))
parser.add_argument(
"--xpass", action="store", choices=results_mapping_choices,
default=XunitFormatter.RM_FAILURE,
@ -548,6 +563,22 @@ class XunitFormatter(ResultsFormatter):
'result type'))
return parser
@staticmethod
def _build_regex_list_from_option(option):
"""Builds a list of compiled regexes from option value.
@param option string containing a comma-separated list of regex
patterns. Zero-length or None will produce an empty regex list.
@return list of compiled regular expressions, empty if no
patterns provided.
"""
regex_list = []
if option is not None and len(option) > 0:
for pattern in option.split(","):
regex_list.append(re.compile(pattern))
return regex_list
def __init__(self, out_file, options):
"""Initializes the XunitFormatter instance.
@param out_file file-like object where formatted output is written.
@ -558,8 +589,13 @@ class XunitFormatter(ResultsFormatter):
super(XunitFormatter, self).__init__(out_file, options)
self.text_encoding = "UTF-8"
self.invalid_xml_re = XunitFormatter._build_illegal_xml_regex()
self.total_test_count = 0
self.ignore_skip_name_regexes = (
XunitFormatter._build_regex_list_from_option(
options.ignore_skip_matching_name))
self.ignore_skip_reason_regexes = (
XunitFormatter._build_regex_list_from_option(
options.ignore_skip_matching_reason))
self.elements = {
"successes": [],
@ -648,10 +684,40 @@ class XunitFormatter(ResultsFormatter):
with self.lock:
self.elements["errors"].append(result)
@staticmethod
def _ignore_based_on_regex_list(test_event, test_key, regex_list):
"""Returns whether to ignore a test event based on patterns.
@param test_event the test event dictionary to check.
@param test_key the key within the dictionary to check.
@param regex_list a list of zero or more regexes. May contain
zero or more compiled regexes.
@return True if any o the regex list match based on the
re.search() method; false otherwise.
"""
for regex in regex_list:
match = regex.search(test_event.get(test_key, ''))
if match:
return True
return False
def _handle_skip(self, test_event):
"""Handles a skipped test.
@param test_event the test event to handle.
"""
# Are we ignoring this test based on test name?
if XunitFormatter._ignore_based_on_regex_list(
test_event, 'test_name', self.ignore_skip_name_regexes):
return
# Are we ignoring this test based on skip reason?
if XunitFormatter._ignore_based_on_regex_list(
test_event, 'skip_reason', self.ignore_skip_reason_regexes):
return
# We're not ignoring this test. Process the skip.
reason = self._replace_invalid_xml(test_event.get("skip_reason", ""))
result = self._common_add_testcase_entry(
test_event,
@ -857,6 +923,7 @@ class XunitFormatter(ResultsFormatter):
self.out_file.write('</testsuite></testsuites>\n')
def _finish_output(self):
"""Finish writing output as all incoming events have arrived."""
with self.lock:
self._finish_output_no_lock()