From c376209f35331b358e59c79ed3537a2ed920d677 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 10 Nov 2018 14:11:47 -0500 Subject: Canonicalize the XML output https://bugs.python.org/issue34160 added retaining the user's attribute order to the XML output, which removed the sorting that used to happen. This broke our XML tests, which compare against saved gold files. This adds in a rough-and-ready canonicalization to avoid the problem. Maybe the core devs will eventually support a sort_attributes option, and I can get rid of this. --- coverage/xmlreport.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'coverage/xmlreport.py') diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py index 5148b54a..6c07337a 100644 --- a/coverage/xmlreport.py +++ b/coverage/xmlreport.py @@ -1,3 +1,4 @@ +# coding: utf-8 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt @@ -5,6 +6,7 @@ import os import os.path +import re import sys import time import xml.dom.minidom @@ -124,11 +126,8 @@ class XmlReporter(Reporter): xcoverage.setAttribute("branch-rate", "0") xcoverage.setAttribute("complexity", "0") - # Use the DOM to write the output file. - out = self.xml_out.toprettyxml() - if env.PY2: - out = out.encode("utf8") - outfile.write(out) + # Write the output file. + outfile.write(serialize_xml(self.xml_out)) # Return the total percentage. denom = lnum_tot + bnum_tot @@ -219,3 +218,23 @@ class XmlReporter(Reporter): package[2] += class_lines package[3] += class_br_hits package[4] += class_branches + + +def serialize_xml(dom): + """Serialize a minidom node to XML.""" + out = dom.toprettyxml() + if env.PY2: + out = out.encode("utf8") + # In Python 3.8, minidom lost the sorting of attributes: https://bugs.python.org/issue34160 + # For the limited kinds of XML we produce, this re-sorts them. + if env.PYVERSION >= (3, 8): + rx_attr = r' [\w-]+="[^"]*"' + rx_attrs = r'(' + rx_attr + ')+' + fixed_lines = [] + for line in out.splitlines(True): + hollow_line = re.sub(rx_attrs, u"☺", line) + attrs = sorted(re.findall(rx_attr, line)) + new_line = hollow_line.replace(u"☺", "".join(attrs)) + fixed_lines.append(new_line) + out = "".join(fixed_lines) + return out -- cgit v1.2.1