~ubuntu-branches/ubuntu/precise/ceph/precise-proposed

« back to all changes in this revision

Viewing changes to src/gtest/test/gtest_xml_test_utils.py

  • Committer: Bazaar Package Importer
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2011-04-25 10:09:05 UTC
  • mfrom: (1.1.3 upstream) (0.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110425100905-exm7dfvi2v5ick02
Tags: 0.27-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# Copyright 2006, Google Inc.
 
4
# All rights reserved.
 
5
#
 
6
# Redistribution and use in source and binary forms, with or without
 
7
# modification, are permitted provided that the following conditions are
 
8
# met:
 
9
#
 
10
#     * Redistributions of source code must retain the above copyright
 
11
# notice, this list of conditions and the following disclaimer.
 
12
#     * Redistributions in binary form must reproduce the above
 
13
# copyright notice, this list of conditions and the following disclaimer
 
14
# in the documentation and/or other materials provided with the
 
15
# distribution.
 
16
#     * Neither the name of Google Inc. nor the names of its
 
17
# contributors may be used to endorse or promote products derived from
 
18
# this software without specific prior written permission.
 
19
#
 
20
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
21
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
22
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
23
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
24
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
25
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
26
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
27
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
28
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
29
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
30
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
31
 
 
32
"""Unit test utilities for gtest_xml_output"""
 
33
 
 
34
__author__ = 'eefacm@gmail.com (Sean Mcafee)'
 
35
 
 
36
import re
 
37
from xml.dom import minidom, Node
 
38
 
 
39
import gtest_test_utils
 
40
 
 
41
 
 
42
GTEST_OUTPUT_FLAG         = "--gtest_output"
 
43
GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
 
44
 
 
45
class GTestXMLTestCase(gtest_test_utils.TestCase):
 
46
  """
 
47
  Base class for tests of Google Test's XML output functionality.
 
48
  """
 
49
 
 
50
 
 
51
  def AssertEquivalentNodes(self, expected_node, actual_node):
 
52
    """
 
53
    Asserts that actual_node (a DOM node object) is equivalent to
 
54
    expected_node (another DOM node object), in that either both of
 
55
    them are CDATA nodes and have the same value, or both are DOM
 
56
    elements and actual_node meets all of the following conditions:
 
57
 
 
58
    *  It has the same tag name as expected_node.
 
59
    *  It has the same set of attributes as expected_node, each with
 
60
       the same value as the corresponding attribute of expected_node.
 
61
       An exception is any attribute named "time", which needs only be
 
62
       convertible to a floating-point number.
 
63
    *  It has an equivalent set of child nodes (including elements and
 
64
       CDATA sections) as expected_node.  Note that we ignore the
 
65
       order of the children as they are not guaranteed to be in any
 
66
       particular order.
 
67
    """
 
68
 
 
69
    if expected_node.nodeType == Node.CDATA_SECTION_NODE:
 
70
      self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType)
 
71
      self.assertEquals(expected_node.nodeValue, actual_node.nodeValue)
 
72
      return
 
73
 
 
74
    self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType)
 
75
    self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType)
 
76
    self.assertEquals(expected_node.tagName, actual_node.tagName)
 
77
 
 
78
    expected_attributes = expected_node.attributes
 
79
    actual_attributes   = actual_node  .attributes
 
80
    self.assertEquals(
 
81
        expected_attributes.length, actual_attributes.length,
 
82
        "attribute numbers differ in element " + actual_node.tagName)
 
83
    for i in range(expected_attributes.length):
 
84
      expected_attr = expected_attributes.item(i)
 
85
      actual_attr   = actual_attributes.get(expected_attr.name)
 
86
      self.assert_(
 
87
          actual_attr is not None,
 
88
          "expected attribute %s not found in element %s" %
 
89
          (expected_attr.name, actual_node.tagName))
 
90
      self.assertEquals(expected_attr.value, actual_attr.value,
 
91
                        " values of attribute %s in element %s differ" %
 
92
                        (expected_attr.name, actual_node.tagName))
 
93
 
 
94
    expected_children = self._GetChildren(expected_node)
 
95
    actual_children = self._GetChildren(actual_node)
 
96
    self.assertEquals(
 
97
        len(expected_children), len(actual_children),
 
98
        "number of child elements differ in element " + actual_node.tagName)
 
99
    for child_id, child in expected_children.iteritems():
 
100
      self.assert_(child_id in actual_children,
 
101
                   '<%s> is not in <%s> (in element %s)' %
 
102
                   (child_id, actual_children, actual_node.tagName))
 
103
      self.AssertEquivalentNodes(child, actual_children[child_id])
 
104
 
 
105
  identifying_attribute = {
 
106
    "testsuites": "name",
 
107
    "testsuite": "name",
 
108
    "testcase":  "name",
 
109
    "failure":   "message",
 
110
    }
 
111
 
 
112
  def _GetChildren(self, element):
 
113
    """
 
114
    Fetches all of the child nodes of element, a DOM Element object.
 
115
    Returns them as the values of a dictionary keyed by the IDs of the
 
116
    children.  For <testsuites>, <testsuite> and <testcase> elements, the ID
 
117
    is the value of their "name" attribute; for <failure> elements, it is
 
118
    the value of the "message" attribute; CDATA sections and non-whitespace
 
119
    text nodes are concatenated into a single CDATA section with ID
 
120
    "detail".  An exception is raised if any element other than the above
 
121
    four is encountered, if two child elements with the same identifying
 
122
    attributes are encountered, or if any other type of node is encountered.
 
123
    """
 
124
 
 
125
    children = {}
 
126
    for child in element.childNodes:
 
127
      if child.nodeType == Node.ELEMENT_NODE:
 
128
        self.assert_(child.tagName in self.identifying_attribute,
 
129
                     "Encountered unknown element <%s>" % child.tagName)
 
130
        childID = child.getAttribute(self.identifying_attribute[child.tagName])
 
131
        self.assert_(childID not in children)
 
132
        children[childID] = child
 
133
      elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]:
 
134
        if "detail" not in children:
 
135
          if (child.nodeType == Node.CDATA_SECTION_NODE or
 
136
              not child.nodeValue.isspace()):
 
137
            children["detail"] = child.ownerDocument.createCDATASection(
 
138
                child.nodeValue)
 
139
        else:
 
140
          children["detail"].nodeValue += child.nodeValue
 
141
      else:
 
142
        self.fail("Encountered unexpected node type %d" % child.nodeType)
 
143
    return children
 
144
 
 
145
  def NormalizeXml(self, element):
 
146
    """
 
147
    Normalizes Google Test's XML output to eliminate references to transient
 
148
    information that may change from run to run.
 
149
 
 
150
    *  The "time" attribute of <testsuites>, <testsuite> and <testcase>
 
151
       elements is replaced with a single asterisk, if it contains
 
152
       only digit characters.
 
153
    *  The line number reported in the first line of the "message"
 
154
       attribute of <failure> elements is replaced with a single asterisk.
 
155
    *  The directory names in file paths are removed.
 
156
    *  The stack traces are removed.
 
157
    """
 
158
 
 
159
    if element.tagName in ("testsuites", "testsuite", "testcase"):
 
160
      time = element.getAttributeNode("time")
 
161
      time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value)
 
162
    elif element.tagName == "failure":
 
163
      for child in element.childNodes:
 
164
        if child.nodeType == Node.CDATA_SECTION_NODE:
 
165
          # Removes the source line number.
 
166
          cdata = re.sub(r"^.*[/\\](.*:)\d+\n", "\\1*\n", child.nodeValue)
 
167
          # Removes the actual stack trace.
 
168
          child.nodeValue = re.sub(r"\nStack trace:\n(.|\n)*",
 
169
                                   "", cdata)
 
170
    for child in element.childNodes:
 
171
      if child.nodeType == Node.ELEMENT_NODE:
 
172
        self.NormalizeXml(child)