1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver"""
2324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverXML Test Runner for PyUnit
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver"""
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# Written by Sebastian Rittau <srittau@jroger.in-berlin.de> and placed in
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# the Public Domain. With contributions by Paolo Borelli.
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver__revision__ = "$Id: /private/python/stdlib/xmlrunner.py 16654 2007-11-12T12:46:35.368945Z srittau  $"
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport os.path
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport re
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport sys
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport time
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport traceback
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport unittest
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverfrom StringIO import StringIO
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverfrom xml.sax.saxutils import escape
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverfrom StringIO import StringIO
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass _TestInfo(object):
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    """Information about a particular test.
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    Used by _XMLTestResult.
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    """
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def __init__(self, test, time):
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        (self._class, self._method) = test.id().rsplit(".", 1)
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._time = time
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._error = None
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._failure = None
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @staticmethod
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def create_success(test, time):
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Create a _TestInfo instance for a successful test."""
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return _TestInfo(test, time)
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @staticmethod
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def create_failure(test, time, failure):
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Create a _TestInfo instance for a failed test."""
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        info = _TestInfo(test, time)
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        info._failure = failure
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return info
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @staticmethod
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def create_error(test, time, error):
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Create a _TestInfo instance for an erroneous test."""
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        info = _TestInfo(test, time)
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        info._error = error
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return info
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def print_report(self, stream):
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Print information about this test case in XML format to the
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        supplied stream.
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('  <testcase classname="%(class)s" name="%(method)s" time="%(time).4f">' % \
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                "class": self._class,
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                "method": self._method,
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                "time": self._time,
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            })
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if self._failure != None:
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            self._print_error(stream, 'failure', self._failure)
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if self._error != None:
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            self._print_error(stream, 'error', self._error)
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('</testcase>\n')
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def _print_error(self, stream, tagname, error):
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Print information from a failure or error to the supplied stream."""
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        text = escape(str(error[1]))
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('\n')
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('    <%s type="%s">%s\n' \
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            % (tagname, str(error[0]), text))
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        tb_stream = StringIO()
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        traceback.print_tb(error[2], None, tb_stream)
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write(escape(tb_stream.getvalue()))
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('    </%s>\n' % tagname)
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('  ')
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass _XMLTestResult(unittest.TestResult):
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    """A test result class that stores result as XML.
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    Used by XMLTestRunner.
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    """
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def __init__(self, classname):
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        unittest.TestResult.__init__(self)
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._test_name = classname
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._start_time = None
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._tests = []
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._error = None
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._failure = None
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def startTest(self, test):
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        unittest.TestResult.startTest(self, test)
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._error = None
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._failure = None
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._start_time = time.time()
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def stopTest(self, test):
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        time_taken = time.time() - self._start_time
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        unittest.TestResult.stopTest(self, test)
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if self._error:
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            info = _TestInfo.create_error(test, time_taken, self._error)
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        elif self._failure:
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            info = _TestInfo.create_failure(test, time_taken, self._failure)
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        else:
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            info = _TestInfo.create_success(test, time_taken)
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._tests.append(info)
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def addError(self, test, err):
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        unittest.TestResult.addError(self, test, err)
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._error = err
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def addFailure(self, test, err):
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        unittest.TestResult.addFailure(self, test, err)
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._failure = err
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def print_report(self, stream, time_taken, out, err):
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Prints the XML report to the supplied stream.
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        The time the tests took to perform as well as the captured standard
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        output and standard error streams must be passed in.a
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('<testsuite errors="%(e)d" failures="%(f)d" ' % \
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            { "e": len(self.errors), "f": len(self.failures) })
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('name="%(n)s" tests="%(t)d" time="%(time).3f">\n' % \
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                "n": self._test_name,
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                "t": self.testsRun,
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                "time": time_taken,
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            })
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        for info in self._tests:
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            info.print_report(stream)
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('  <system-out><![CDATA[%s]]></system-out>\n' % out)
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('  <system-err><![CDATA[%s]]></system-err>\n' % err)
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        stream.write('</testsuite>\n')
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass XMLTestRunner(object):
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    """A test runner that stores results in XML format compatible with JUnit.
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    XMLTestRunner(stream=None) -> XML test runner
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    The XML file is written to the supplied stream. If stream is None, the
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    results are stored in a file called TEST-<module>.<class>.xml in the
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    current working directory (if not overridden with the path property),
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    where <module> and <class> are the module and class name of the test class.
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    """
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def __init__(self, stream=None):
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._stream = stream
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._path = "."
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def run(self, test):
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Run the given test case or test suite."""
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class_ = test.__class__
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        classname = class_.__module__ + "." + class_.__name__
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if self._stream == None:
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            filename = "TEST-%s.xml" % classname
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            stream = file(os.path.join(self._path, filename), "w")
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            stream.write('<?xml version="1.0" encoding="utf-8"?>\n')
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        else:
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            stream = self._stream
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        result = _XMLTestResult(classname)
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        start_time = time.time()
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # TODO: Python 2.5: Use the with statement
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        old_stdout = sys.stdout
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        old_stderr = sys.stderr
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        sys.stdout = StringIO()
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        sys.stderr = StringIO()
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        try:
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            test(result)
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            try:
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                out_s = sys.stdout.getvalue()
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            except AttributeError:
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                out_s = ""
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            try:
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                err_s = sys.stderr.getvalue()
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            except AttributeError:
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                err_s = ""
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        finally:
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            sys.stdout = old_stdout
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            sys.stderr = old_stderr
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        time_taken = time.time() - start_time
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        result.print_report(stream, time_taken, out_s, err_s)
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if self._stream == None:
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            stream.close()
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return result
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def _set_path(self, path):
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._path = path
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    path = property(lambda self: self._path, _set_path, None,
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            """The path where the XML files are stored.
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            This property is ignored when the XML file is written to a file
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            stream.""")
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass XMLTestRunnerTest(unittest.TestCase):
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def setUp(self):
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._stream = StringIO()
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def _try_test_run(self, test_class, expected):
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Run the test suite against the supplied test class and compare the
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        XML result against the expected XML string. Fail if the expected
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        string doesn't match the actual string. All time attribute in the
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        expected string should have the value "0.000". All error and failure
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        messages are reduced to "Foobar".
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        runner = XMLTestRunner(self._stream)
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        runner.run(unittest.makeSuite(test_class))
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        got = self._stream.getvalue()
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # Replace all time="X.YYY" attributes by time="0.000" to enable a
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # simple string comparison.
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got)
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # Likewise, replace all failure and error messages by a simple "Foobar"
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        # string.
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        got = re.sub(r'(?s)<failure (.*?)>.*?</failure>', r'<failure \1>Foobar</failure>', got)
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        got = re.sub(r'(?s)<error (.*?)>.*?</error>', r'<error \1>Foobar</error>', got)
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self.assertEqual(expected, got)
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_no_tests(self):
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Regression test: Check whether a test run without any tests
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        matches a previous run.
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            pass
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="0" time="0.000">
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-out><![CDATA[]]></system-out>
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-err><![CDATA[]]></system-err>
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver</testsuite>
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver""")
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_success(self):
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Regression test: Check whether a test run with a successful test
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        matches a previous run.
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                pass
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-out><![CDATA[]]></system-out>
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-err><![CDATA[]]></system-err>
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver</testsuite>
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver""")
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_failure(self):
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Regression test: Check whether a test run with a failing test
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        matches a previous run.
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                self.assert_(False)
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._try_test_run(TestTest, """<testsuite errors="0" failures="1" name="unittest.TestSuite" tests="1" time="0.000">
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    <failure type="exceptions.AssertionError">Foobar</failure>
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  </testcase>
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-out><![CDATA[]]></system-out>
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-err><![CDATA[]]></system-err>
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver</testsuite>
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver""")
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_error(self):
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Regression test: Check whether a test run with a erroneous test
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        matches a previous run.
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                raise IndexError()
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._try_test_run(TestTest, """<testsuite errors="1" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    <error type="exceptions.IndexError">Foobar</error>
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  </testcase>
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-out><![CDATA[]]></system-out>
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-err><![CDATA[]]></system-err>
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver</testsuite>
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver""")
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_stdout_capture(self):
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Regression test: Check whether a test run with output to stdout
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        matches a previous run.
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                print "Test"
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-out><![CDATA[Test
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver]]></system-out>
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-err><![CDATA[]]></system-err>
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver</testsuite>
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver""")
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_stderr_capture(self):
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Regression test: Check whether a test run with output to stderr
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        matches a previous run.
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                print >>sys.stderr, "Test"
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-out><![CDATA[]]></system-out>
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  <system-err><![CDATA[Test
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver]]></system-err>
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver</testsuite>
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver""")
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    class NullStream(object):
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """A file-like object that discards everything written to it."""
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        def write(self, buffer):
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            pass
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_unittests_changing_stdout(self):
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Check whether the XMLTestRunner recovers gracefully from unit tests
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        that change stdout, but don't change it back properly.
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                sys.stdout = XMLTestRunnerTest.NullStream()
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        runner = XMLTestRunner(self._stream)
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        runner.run(unittest.makeSuite(TestTest))
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def test_unittests_changing_stderr(self):
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """Check whether the XMLTestRunner recovers gracefully from unit tests
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        that change stderr, but don't change it back properly.
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        """
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class TestTest(unittest.TestCase):
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            def test_foo(self):
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                sys.stderr = XMLTestRunnerTest.NullStream()
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        runner = XMLTestRunner(self._stream)
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        runner.run(unittest.makeSuite(TestTest))
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass XMLTestProgram(unittest.TestProgram):
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def runTests(self):
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        if self.testRunner is None:
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            self.testRunner = XMLTestRunner()
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        unittest.TestProgram.runTests(self)
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermain = XMLTestProgram
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverif __name__ == "__main__":
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    main(module=None)
379