You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							194 lines
						
					
					
						
							8.7 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							194 lines
						
					
					
						
							8.7 KiB
						
					
					
				
								#!/usr/bin/env python
							 | 
						|
								#
							 | 
						|
								# Copyright 2006, Google Inc.
							 | 
						|
								# All rights reserved.
							 | 
						|
								#
							 | 
						|
								# Redistribution and use in source and binary forms, with or without
							 | 
						|
								# modification, are permitted provided that the following conditions are
							 | 
						|
								# met:
							 | 
						|
								#
							 | 
						|
								#     * Redistributions of source code must retain the above copyright
							 | 
						|
								# notice, this list of conditions and the following disclaimer.
							 | 
						|
								#     * Redistributions in binary form must reproduce the above
							 | 
						|
								# copyright notice, this list of conditions and the following disclaimer
							 | 
						|
								# in the documentation and/or other materials provided with the
							 | 
						|
								# distribution.
							 | 
						|
								#     * Neither the name of Google Inc. nor the names of its
							 | 
						|
								# contributors may be used to endorse or promote products derived from
							 | 
						|
								# this software without specific prior written permission.
							 | 
						|
								#
							 | 
						|
								# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
							 | 
						|
								# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
							 | 
						|
								# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
							 | 
						|
								# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
							 | 
						|
								# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
							 | 
						|
								# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
							 | 
						|
								# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
							 | 
						|
								# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
							 | 
						|
								# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
							 | 
						|
								# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
							 | 
						|
								# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
							 | 
						|
								
							 | 
						|
								"""Unit test utilities for gtest_xml_output"""
							 | 
						|
								
							 | 
						|
								__author__ = 'eefacm@gmail.com (Sean Mcafee)'
							 | 
						|
								
							 | 
						|
								import re
							 | 
						|
								from xml.dom import minidom, Node
							 | 
						|
								
							 | 
						|
								import gtest_test_utils
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								GTEST_OUTPUT_FLAG         = '--gtest_output'
							 | 
						|
								GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.xml'
							 | 
						|
								
							 | 
						|
								class GTestXMLTestCase(gtest_test_utils.TestCase):
							 | 
						|
								  """
							 | 
						|
								  Base class for tests of Google Test's XML output functionality.
							 | 
						|
								  """
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  def AssertEquivalentNodes(self, expected_node, actual_node):
							 | 
						|
								    """
							 | 
						|
								    Asserts that actual_node (a DOM node object) is equivalent to
							 | 
						|
								    expected_node (another DOM node object), in that either both of
							 | 
						|
								    them are CDATA nodes and have the same value, or both are DOM
							 | 
						|
								    elements and actual_node meets all of the following conditions:
							 | 
						|
								
							 | 
						|
								    *  It has the same tag name as expected_node.
							 | 
						|
								    *  It has the same set of attributes as expected_node, each with
							 | 
						|
								       the same value as the corresponding attribute of expected_node.
							 | 
						|
								       Exceptions are any attribute named "time", which needs only be
							 | 
						|
								       convertible to a floating-point number and any attribute named
							 | 
						|
								       "type_param" which only has to be non-empty.
							 | 
						|
								    *  It has an equivalent set of child nodes (including elements and
							 | 
						|
								       CDATA sections) as expected_node.  Note that we ignore the
							 | 
						|
								       order of the children as they are not guaranteed to be in any
							 | 
						|
								       particular order.
							 | 
						|
								    """
							 | 
						|
								
							 | 
						|
								    if expected_node.nodeType == Node.CDATA_SECTION_NODE:
							 | 
						|
								      self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType)
							 | 
						|
								      self.assertEquals(expected_node.nodeValue, actual_node.nodeValue)
							 | 
						|
								      return
							 | 
						|
								
							 | 
						|
								    self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType)
							 | 
						|
								    self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType)
							 | 
						|
								    self.assertEquals(expected_node.tagName, actual_node.tagName)
							 | 
						|
								
							 | 
						|
								    expected_attributes = expected_node.attributes
							 | 
						|
								    actual_attributes   = actual_node  .attributes
							 | 
						|
								    self.assertEquals(
							 | 
						|
								        expected_attributes.length, actual_attributes.length,
							 | 
						|
								        'attribute numbers differ in element %s:\nExpected: %r\nActual: %r' % (
							 | 
						|
								            actual_node.tagName, expected_attributes.keys(),
							 | 
						|
								            actual_attributes.keys()))
							 | 
						|
								    for i in range(expected_attributes.length):
							 | 
						|
								      expected_attr = expected_attributes.item(i)
							 | 
						|
								      actual_attr   = actual_attributes.get(expected_attr.name)
							 | 
						|
								      self.assert_(
							 | 
						|
								          actual_attr is not None,
							 | 
						|
								          'expected attribute %s not found in element %s' %
							 | 
						|
								          (expected_attr.name, actual_node.tagName))
							 | 
						|
								      self.assertEquals(
							 | 
						|
								          expected_attr.value, actual_attr.value,
							 | 
						|
								          ' values of attribute %s in element %s differ: %s vs %s' %
							 | 
						|
								          (expected_attr.name, actual_node.tagName,
							 | 
						|
								           expected_attr.value, actual_attr.value))
							 | 
						|
								
							 | 
						|
								    expected_children = self._GetChildren(expected_node)
							 | 
						|
								    actual_children = self._GetChildren(actual_node)
							 | 
						|
								    self.assertEquals(
							 | 
						|
								        len(expected_children), len(actual_children),
							 | 
						|
								        'number of child elements differ in element ' + actual_node.tagName)
							 | 
						|
								    for child_id, child in expected_children.iteritems():
							 | 
						|
								      self.assert_(child_id in actual_children,
							 | 
						|
								                   '<%s> is not in <%s> (in element %s)' %
							 | 
						|
								                   (child_id, actual_children, actual_node.tagName))
							 | 
						|
								      self.AssertEquivalentNodes(child, actual_children[child_id])
							 | 
						|
								
							 | 
						|
								  identifying_attribute = {
							 | 
						|
								    'testsuites': 'name',
							 | 
						|
								    'testsuite': 'name',
							 | 
						|
								    'testcase':  'name',
							 | 
						|
								    'failure':   'message',
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								  def _GetChildren(self, element):
							 | 
						|
								    """
							 | 
						|
								    Fetches all of the child nodes of element, a DOM Element object.
							 | 
						|
								    Returns them as the values of a dictionary keyed by the IDs of the
							 | 
						|
								    children.  For <testsuites>, <testsuite> and <testcase> elements, the ID
							 | 
						|
								    is the value of their "name" attribute; for <failure> elements, it is
							 | 
						|
								    the value of the "message" attribute; CDATA sections and non-whitespace
							 | 
						|
								    text nodes are concatenated into a single CDATA section with ID
							 | 
						|
								    "detail".  An exception is raised if any element other than the above
							 | 
						|
								    four is encountered, if two child elements with the same identifying
							 | 
						|
								    attributes are encountered, or if any other type of node is encountered.
							 | 
						|
								    """
							 | 
						|
								
							 | 
						|
								    children = {}
							 | 
						|
								    for child in element.childNodes:
							 | 
						|
								      if child.nodeType == Node.ELEMENT_NODE:
							 | 
						|
								        self.assert_(child.tagName in self.identifying_attribute,
							 | 
						|
								                     'Encountered unknown element <%s>' % child.tagName)
							 | 
						|
								        childID = child.getAttribute(self.identifying_attribute[child.tagName])
							 | 
						|
								        self.assert_(childID not in children)
							 | 
						|
								        children[childID] = child
							 | 
						|
								      elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]:
							 | 
						|
								        if 'detail' not in children:
							 | 
						|
								          if (child.nodeType == Node.CDATA_SECTION_NODE or
							 | 
						|
								              not child.nodeValue.isspace()):
							 | 
						|
								            children['detail'] = child.ownerDocument.createCDATASection(
							 | 
						|
								                child.nodeValue)
							 | 
						|
								        else:
							 | 
						|
								          children['detail'].nodeValue += child.nodeValue
							 | 
						|
								      else:
							 | 
						|
								        self.fail('Encountered unexpected node type %d' % child.nodeType)
							 | 
						|
								    return children
							 | 
						|
								
							 | 
						|
								  def NormalizeXml(self, element):
							 | 
						|
								    """
							 | 
						|
								    Normalizes Google Test's XML output to eliminate references to transient
							 | 
						|
								    information that may change from run to run.
							 | 
						|
								
							 | 
						|
								    *  The "time" attribute of <testsuites>, <testsuite> and <testcase>
							 | 
						|
								       elements is replaced with a single asterisk, if it contains
							 | 
						|
								       only digit characters.
							 | 
						|
								    *  The "timestamp" attribute of <testsuites> elements is replaced with a
							 | 
						|
								       single asterisk, if it contains a valid ISO8601 datetime value.
							 | 
						|
								    *  The "type_param" attribute of <testcase> elements is replaced with a
							 | 
						|
								       single asterisk (if it sn non-empty) as it is the type name returned
							 | 
						|
								       by the compiler and is platform dependent.
							 | 
						|
								    *  The line info reported in the first line of the "message"
							 | 
						|
								       attribute and CDATA section of <failure> elements is replaced with the
							 | 
						|
								       file's basename and a single asterisk for the line number.
							 | 
						|
								    *  The directory names in file paths are removed.
							 | 
						|
								    *  The stack traces are removed.
							 | 
						|
								    """
							 | 
						|
								
							 | 
						|
								    if element.tagName == 'testsuites':
							 | 
						|
								      timestamp = element.getAttributeNode('timestamp')
							 | 
						|
								      timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d$',
							 | 
						|
								                               '*', timestamp.value)
							 | 
						|
								    if element.tagName in ('testsuites', 'testsuite', 'testcase'):
							 | 
						|
								      time = element.getAttributeNode('time')
							 | 
						|
								      time.value = re.sub(r'^\d+(\.\d+)?$', '*', time.value)
							 | 
						|
								      type_param = element.getAttributeNode('type_param')
							 | 
						|
								      if type_param and type_param.value:
							 | 
						|
								        type_param.value = '*'
							 | 
						|
								    elif element.tagName == 'failure':
							 | 
						|
								      source_line_pat = r'^.*[/\\](.*:)\d+\n'
							 | 
						|
								      # Replaces the source line information with a normalized form.
							 | 
						|
								      message = element.getAttributeNode('message')
							 | 
						|
								      message.value = re.sub(source_line_pat, '\\1*\n', message.value)
							 | 
						|
								      for child in element.childNodes:
							 | 
						|
								        if child.nodeType == Node.CDATA_SECTION_NODE:
							 | 
						|
								          # Replaces the source line information with a normalized form.
							 | 
						|
								          cdata = re.sub(source_line_pat, '\\1*\n', child.nodeValue)
							 | 
						|
								          # Removes the actual stack trace.
							 | 
						|
								          child.nodeValue = re.sub(r'\nStack trace:\n(.|\n)*',
							 | 
						|
								                                   '', cdata)
							 | 
						|
								    for child in element.childNodes:
							 | 
						|
								      if child.nodeType == Node.ELEMENT_NODE:
							 | 
						|
								        self.NormalizeXml(child)
							 |