11be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#!/usr/bin/env python 21be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# 31be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# Copyright 2006, Google Inc. 41be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# All rights reserved. 51be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# 61be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# Redistribution and use in source and binary forms, with or without 71be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# modification, are permitted provided that the following conditions are 81be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# met: 91be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# 101be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# * Redistributions of source code must retain the above copyright 111be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# notice, this list of conditions and the following disclaimer. 121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# * Redistributions in binary form must reproduce the above 131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# copyright notice, this list of conditions and the following disclaimer 141be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# in the documentation and/or other materials provided with the 151be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# distribution. 161be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# * Neither the name of Google Inc. nor the names of its 171be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# contributors may be used to endorse or promote products derived from 181be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# this software without specific prior written permission. 191be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# 201be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 211be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 221be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 231be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 241be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 251be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 261be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 271be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 281be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 291be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania"""Unit test utilities for gtest_xml_output""" 331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania__author__ = 'eefacm@gmail.com (Sean Mcafee)' 351be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 361be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniaimport re 371be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniafrom xml.dom import minidom, Node 381be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 3941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotimport gtest_test_utils 4041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 4141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 421be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaGTEST_OUTPUT_FLAG = "--gtest_output" 431be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaGTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml" 441be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 4541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotclass GTestXMLTestCase(gtest_test_utils.TestCase): 461be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 471be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania Base class for tests of Google Test's XML output functionality. 481be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 491be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 501be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 511be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania def AssertEquivalentNodes(self, expected_node, actual_node): 521be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 531be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania Asserts that actual_node (a DOM node object) is equivalent to 541be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania expected_node (another DOM node object), in that either both of 551be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania them are CDATA nodes and have the same value, or both are DOM 561be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania elements and actual_node meets all of the following conditions: 571be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 581be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * It has the same tag name as expected_node. 591be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * It has the same set of attributes as expected_node, each with 601be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania the same value as the corresponding attribute of expected_node. 6141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot Exceptions are any attribute named "time", which needs only be 6241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot convertible to a floating-point number and any attribute named 6341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot "type_param" which only has to be non-empty. 641be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * It has an equivalent set of child nodes (including elements and 651be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania CDATA sections) as expected_node. Note that we ignore the 661be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania order of the children as they are not guaranteed to be in any 671be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania particular order. 681be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 691be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 701be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if expected_node.nodeType == Node.CDATA_SECTION_NODE: 711be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType) 721be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assertEquals(expected_node.nodeValue, actual_node.nodeValue) 731be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return 741be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 751be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType) 761be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType) 771be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assertEquals(expected_node.tagName, actual_node.tagName) 781be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 791be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania expected_attributes = expected_node.attributes 801be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania actual_attributes = actual_node .attributes 8141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot self.assertEquals( 8241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot expected_attributes.length, actual_attributes.length, 8341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot "attribute numbers differ in element " + actual_node.tagName) 841be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania for i in range(expected_attributes.length): 851be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania expected_attr = expected_attributes.item(i) 861be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania actual_attr = actual_attributes.get(expected_attr.name) 8741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot self.assert_( 8841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot actual_attr is not None, 8941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot "expected attribute %s not found in element %s" % 9041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot (expected_attr.name, actual_node.tagName)) 9141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot self.assertEquals(expected_attr.value, actual_attr.value, 9241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot " values of attribute %s in element %s differ" % 9341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot (expected_attr.name, actual_node.tagName)) 941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania expected_children = self._GetChildren(expected_node) 961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania actual_children = self._GetChildren(actual_node) 9741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot self.assertEquals( 9841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot len(expected_children), len(actual_children), 9941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot "number of child elements differ in element " + actual_node.tagName) 1001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania for child_id, child in expected_children.iteritems(): 1011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assert_(child_id in actual_children, 10241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot '<%s> is not in <%s> (in element %s)' % 10341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot (child_id, actual_children, actual_node.tagName)) 1041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.AssertEquivalentNodes(child, actual_children[child_id]) 1051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania identifying_attribute = { 10741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot "testsuites": "name", 1081be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania "testsuite": "name", 1091be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania "testcase": "name", 1101be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania "failure": "message", 1111be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 1121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania def _GetChildren(self, element): 1141be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 1151be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania Fetches all of the child nodes of element, a DOM Element object. 1161be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania Returns them as the values of a dictionary keyed by the IDs of the 11741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot children. For <testsuites>, <testsuite> and <testcase> elements, the ID 11841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot is the value of their "name" attribute; for <failure> elements, it is 11941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot the value of the "message" attribute; CDATA sections and non-whitespace 12041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot text nodes are concatenated into a single CDATA section with ID 12141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot "detail". An exception is raised if any element other than the above 12241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot four is encountered, if two child elements with the same identifying 12341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot attributes are encountered, or if any other type of node is encountered. 1241be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 1251be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1261be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania children = {} 1271be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania for child in element.childNodes: 1281be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if child.nodeType == Node.ELEMENT_NODE: 1291be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assert_(child.tagName in self.identifying_attribute, 1301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania "Encountered unknown element <%s>" % child.tagName) 1311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania childID = child.getAttribute(self.identifying_attribute[child.tagName]) 1321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.assert_(childID not in children) 1331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania children[childID] = child 13441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: 13541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if "detail" not in children: 13641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (child.nodeType == Node.CDATA_SECTION_NODE or 13741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot not child.nodeValue.isspace()): 13841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot children["detail"] = child.ownerDocument.createCDATASection( 13941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot child.nodeValue) 14041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot else: 14141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot children["detail"].nodeValue += child.nodeValue 1421be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania else: 1431be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.fail("Encountered unexpected node type %d" % child.nodeType) 1441be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return children 1451be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1461be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania def NormalizeXml(self, element): 1471be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 1481be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania Normalizes Google Test's XML output to eliminate references to transient 1491be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania information that may change from run to run. 1501be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 15141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * The "time" attribute of <testsuites>, <testsuite> and <testcase> 15241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot elements is replaced with a single asterisk, if it contains 15341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot only digit characters. 15441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * The "type_param" attribute of <testcase> elements is replaced with a 15541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot single asterisk (if it sn non-empty) as it is the type name returned 15641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot by the compiler and is platform dependent. 1571be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * The line number reported in the first line of the "message" 1581be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania attribute of <failure> elements is replaced with a single asterisk. 1591be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * The directory names in file paths are removed. 1601be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * The stack traces are removed. 1611be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania """ 1621be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 16341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if element.tagName in ("testsuites", "testsuite", "testcase"): 1641be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania time = element.getAttributeNode("time") 1651be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value) 16641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot type_param = element.getAttributeNode("type_param") 16741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if type_param and type_param.value: 16841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot type_param.value = "*" 1691be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania elif element.tagName == "failure": 1701be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania for child in element.childNodes: 1711be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if child.nodeType == Node.CDATA_SECTION_NODE: 1721be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania # Removes the source line number. 17341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot cdata = re.sub(r"^.*[/\\](.*:)\d+\n", "\\1*\n", child.nodeValue) 1741be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania # Removes the actual stack trace. 1751be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania child.nodeValue = re.sub(r"\nStack trace:\n(.|\n)*", 1761be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania "", cdata) 1771be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania for child in element.childNodes: 1781be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if child.nodeType == Node.ELEMENT_NODE: 1791be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania self.NormalizeXml(child) 180