[Lldb-commits] [lldb] r247998 - xUnit test output: implemented proper xml escaping
Todd Fiala via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 18 09:00:52 PDT 2015
Author: tfiala
Date: Fri Sep 18 11:00:52 2015
New Revision: 247998
URL: http://llvm.org/viewvc/llvm-project?rev=247998&view=rev
Log:
xUnit test output: implemented proper xml escaping
Now does proper Unicode code region scanning for invalid XML
characters. Strips out XML-invalid characters.
Does this for:
failure result: message, backtrace
error result: message, backtrace
skipped test: skip reason
pexpect timeouts were still generating characters that would break
XML readers (correctly so).
Modified:
lldb/trunk/test/test_results.py
Modified: lldb/trunk/test/test_results.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/test_results.py?rev=247998&r1=247997&r2=247998&view=diff
==============================================================================
--- lldb/trunk/test/test_results.py (original)
+++ lldb/trunk/test/test_results.py Fri Sep 18 11:00:52 2015
@@ -12,6 +12,7 @@ import argparse
import cPickle
import inspect
import os
+import re
import sys
import threading
import time
@@ -418,6 +419,31 @@ class XunitFormatter(ResultsFormatter):
RM_PASSTHRU = 'passthru'
@staticmethod
+ def _build_illegal_xml_regex():
+ # Construct the range pairs of invalid unicode chareacters.
+ illegal_chars_u = [
+ (0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0x7F, 0x84),
+ (0x86, 0x9F), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF)]
+
+ # For wide builds, we have more.
+ if sys.maxunicode >= 0x10000:
+ illegal_chars_u.extend(
+ [(0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF),
+ (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF),
+ (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF),
+ (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF),
+ (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF),
+ (0x10FFFE, 0x10FFFF)])
+
+ # Build up an array of range expressions.
+ illegal_ranges = [
+ "%s-%s" % (unichr(low), unichr(high))
+ for (low, high) in illegal_chars_u]
+
+ # Compile the regex
+ return re.compile(u'[%s]' % u''.join(illegal_ranges))
+
+ @staticmethod
def _quote_attribute(text):
"""Returns the given text in a manner safe for usage in an XML attribute.
@@ -426,6 +452,14 @@ class XunitFormatter(ResultsFormatter):
"""
return xml.sax.saxutils.quoteattr(text)
+ def _replace_invalid_xml(self, str_or_unicode):
+ # Get the content into unicode
+ if isinstance(str_or_unicode, str):
+ unicode_content = str_or_unicode.decode('utf-8')
+ else:
+ unicode_content = str_or_unicode
+ return self.invalid_xml_re.sub(u'?', unicode_content).encode('utf-8')
+
@classmethod
def arg_parser(cls):
"""@return arg parser used to parse formatter-specific options."""
@@ -458,6 +492,7 @@ class XunitFormatter(ResultsFormatter):
# Initialize the parent
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
@@ -513,16 +548,17 @@ class XunitFormatter(ResultsFormatter):
"""Handles a test failure.
@param test_event the test event to handle.
"""
- message_summary = test_event["issue_message"].splitlines()[0]
- backtrace = "".join(test_event.get("issue_backtrace", []))
+ message = self._replace_invalid_xml(test_event["issue_message"])
+ backtrace = self._replace_invalid_xml(
+ "".join(test_event.get("issue_backtrace", [])))
result = self._common_add_testcase_entry(
test_event,
- inner_content=('<failure type={} message={}><![CDATA[message: {}\nbacktrace:\n{}]]></failure>'.format(
- XunitFormatter._quote_attribute(test_event["issue_class"]),
- XunitFormatter._quote_attribute(message_summary),
- test_event["issue_message"],
- backtrace)
+ inner_content=(
+ '<failure type={} message={}><![CDATA[{}]]></failure>'.format(
+ XunitFormatter._quote_attribute(test_event["issue_class"]),
+ XunitFormatter._quote_attribute(message),
+ backtrace)
))
with self.lock:
self.elements["failures"].append(result)
@@ -531,19 +567,17 @@ class XunitFormatter(ResultsFormatter):
"""Handles a test error.
@param test_event the test event to handle.
"""
-
- # Limit the message summary attribute to the first line of the
- # issue message.
- message_summary = test_event["issue_message"].splitlines()[0]
- backtrace = "".join(test_event.get("issue_backtrace", []))
+ message = self._replace_invalid_xml(test_event["issue_message"])
+ backtrace = self._replace_invalid_xml(
+ "".join(test_event.get("issue_backtrace", [])))
result = self._common_add_testcase_entry(
test_event,
- inner_content=('<error type={} message={}><![CDATA[message: {}\nbacktrace:\n{}]]></error>'.format(
- XunitFormatter._quote_attribute(test_event["issue_class"]),
- XunitFormatter._quote_attribute(message_summary),
- test_event["issue_message"],
- backtrace)
+ inner_content=(
+ '<error type={} message={}><![CDATA[{}]]></error>'.format(
+ XunitFormatter._quote_attribute(test_event["issue_class"]),
+ XunitFormatter._quote_attribute(message),
+ backtrace)
))
with self.lock:
self.elements["errors"].append(result)
@@ -552,10 +586,11 @@ class XunitFormatter(ResultsFormatter):
"""Handles a skipped test.
@param test_event the test event to handle.
"""
+ reason = self._replace_invalid_xml(test_event.get("skip_reason", ""))
result = self._common_add_testcase_entry(
test_event,
inner_content='<skipped message={} />'.format(
- XunitFormatter._quote_attribute(test_event["skip_reason"])))
+ XunitFormatter._quote_attribute(reason)))
with self.lock:
self.elements["skips"].append(result)
More information about the lldb-commits
mailing list