17
18
return junitxml.tests.test_suite()
21
class LocalTimezone(datetime.tzinfo):
26
# It seems that the minimal possible implementation is to just return all
27
# None for every function, but then it breaks...
28
def utcoffset(self, dt):
29
if self._offset is None:
30
t = 1260423030 # arbitrary, but doesn't handle dst very well
31
dt = datetime.datetime
32
self._offset = (dt.fromtimestamp(t) - dt.utcfromtimestamp(t))
36
return datetime.timedelta(0)
20
43
class JUnitXmlResult(unittest.TestResult):
21
44
"""A TestResult which outputs JUnit compatible XML."""
27
50
nature of JUnit XML output, nnothing will be written to the stream
28
51
until stopTestRun() is called.
30
super(JUnitXmlResult, self).__init__()
53
self.__super = super(JUnitXmlResult, self)
54
self.__super.__init__()
31
55
self._stream = stream
33
57
self._set_time = None
34
58
self._test_start = None
35
59
self._run_start = None
38
return super(JUnitXmlResult, self)
40
62
def startTestRun(self):
41
63
"""Start a test run."""
42
64
self._run_start = self._now()
66
def _get_tzinfo(self):
67
if self._tz_info is None:
68
self._tz_info = LocalTimezone()
45
72
if self._set_time is not None:
46
73
return self._set_time
48
return datetime.datetime.utcnow()
75
return datetime.datetime.now(self._get_tzinfo())
50
77
def time(self, a_datetime):
51
78
self._set_time = a_datetime
79
if (self._run_start is not None and
80
self._run_start > a_datetime):
81
self._run_start = a_datetime
53
83
def startTest(self, test):
84
self.__super.startTest(test)
54
85
self._test_start = self._now()
56
87
def _duration(self, from_datetime):
57
delta = self._now() - from_datetime
89
delta = self._now() - from_datetime
92
print n, self._set_time, from_datetime
93
delta = datetime.timedelta(-1)
58
94
seconds = delta.days * 3600*24 + delta.seconds
59
95
return seconds + 0.000001 * delta.microseconds
79
115
duration = self._duration(self._run_start)
80
self._stream.write('<testsuite errors="%d" failures="%d" name="" tests="0" time="%0.3f">\n' % (len(self.errors), len(self.failures), duration))
116
self._stream.write('<testsuite errors="%d" failures="%d" name="" '
117
'tests="%d" time="%0.3f">\n' % (len(self.errors),
118
len(self.failures), self.testsRun, duration))
81
119
self._stream.write(''.join(self._results))
82
120
self._stream.write('</testsuite>\n')
84
122
def addError(self, test, error):
85
self._super().addError(test, error)
123
self.__super.addError(test, error)
86
124
self._test_case_string(test)
87
125
self._results.append('>\n')
88
126
self._results.append('<error type="%s.%s">%s</error>\n</testcase>\n'% (escape(error[0].__module__), escape(error[0].__name__), escape(self._exc_info_to_string(error, test))))
90
128
def addFailure(self, test, error):
91
self._super().addFailure(test, error)
129
self.__super.addFailure(test, error)
92
130
self._test_case_string(test)
93
131
self._results.append('>\n')
94
132
self._results.append('<failure type="%s.%s">%s</failure>\n</testcase>\n'% (escape(error[0].__module__), escape(error[0].__name__), escape(self._exc_info_to_string(error, test))))
96
134
def addSuccess(self, test):
97
self._super().addSuccess(test)
135
self.__super.addSuccess(test)
98
136
self._test_case_string(test)
99
137
self._results.append(' />\n')
101
139
def addSkip(self, test, reason):
103
self._super().addSkip(test, reason)
141
self.__super.addSkip(test, reason)
104
142
except AttributeError:
105
143
# Python < 2.7|3.1
109
147
self._results.append('<skip>%s</skip>\n</testcase>\n'% escape(reason))
111
149
def addUnexpectedSuccess(self, test):
112
self._super().addUnexpectedSuccess(test, error)
150
self.__super.addUnexpectedSuccess(test, error)
113
151
self._test_case_string(test)
114
152
self._results.append(' />\n')
116
154
def addExpectedFailure(self, test, error):
117
self._super().addExpectedFailure(test, error)
155
self.__super.addExpectedFailure(test, error)
118
156
self._test_case_string(test)
119
157
self._results.append('>\n')
120
158
self._results.append('<failure type="%s.%s">%s</failure>\n</testcase>\n'% (escape(error[0].__module__), escape(error[0].__name__), escape(self._exc_info_to_string(error, test))))