3 # Pretty-format subunit output
4 # Copyright (C) 2008-2010 Jelmer Vernooij <jelmer@samba.org>
5 # Published under the GNU GPL, v3 or later
12 sys
.path
.insert(0, os
.path
.join(os
.path
.dirname(__file__
), "../lib/subunit/python"))
13 sys
.path
.insert(0, os
.path
.join(os
.path
.dirname(__file__
), "../lib/testtools"))
19 def format_time(delta
):
20 minutes
, seconds
= divmod(delta
.seconds
, 60)
21 hours
, minutes
= divmod(minutes
, 60)
26 ret
+= "%dm" % minutes
27 ret
+= "%ds" % seconds
31 class PlainFormatter(subunithelper
.TestsuiteEnabledTestResult
):
33 def __init__(self
, summaryfile
, verbose
, immediate
, statistics
,
35 super(PlainFormatter
, self
).__init
__()
36 self
.verbose
= verbose
37 self
.immediate
= immediate
38 self
.statistics
= statistics
39 self
.start_time
= None
41 self
.suitesfailed
= []
44 self
.summaryfile
= summaryfile
47 self
._progress
_level
= 0
48 self
.totalsuites
= totaltests
51 def progress(self
, offset
, whence
):
52 if whence
== subunit
.PROGRESS_POP
:
53 self
._progress
_level
-= 1
54 elif whence
== subunit
.PROGRESS_PUSH
:
55 self
._progress
_level
+= 1
56 elif whence
== subunit
.PROGRESS_SET
:
57 if self
._progress
_level
== 0:
58 self
.totalsuites
= offset
59 elif whence
== subunit
.PROGRESS_CUR
:
60 raise NotImplementedError
63 if self
.start_time
is None:
67 def start_testsuite(self
, name
):
72 self
.test_output
[name
] = ""
74 out
= "[%d" % self
.index
75 if self
.totalsuites
is not None:
76 out
+= "/%d" % self
.totalsuites
77 if self
.start_time
is not None:
78 out
+= " in " + format_time(self
.last_time
- self
.start_time
)
80 out
+= ", %d errors" % (len(self
.suitesfailed
),)
83 sys
.stdout
.write(out
+ "\n")
85 sys
.stdout
.write(out
+ ": ")
87 def output_msg(self
, output
):
89 sys
.stdout
.write(output
)
90 elif self
.name
is not None:
91 self
.test_output
[self
.name
] += output
93 sys
.stdout
.write(output
)
95 def control_msg(self
, output
):
96 #$self->output_msg($output)
99 def end_testsuite(self
, name
, result
, reason
):
103 if not name
in self
.test_output
:
104 print "no output for name[%s]" % name
106 if result
in ("success", "xfail"):
109 self
.output_msg("ERROR: Testsuite[%s]\n" % name
)
110 if reason
is not None:
111 self
.output_msg("REASON: %s\n" % (reason
,))
112 self
.suitesfailed
.append(name
)
113 if self
.immediate
and not self
.verbose
and name
in self
.test_output
:
114 out
+= self
.test_output
[name
]
117 if not self
.immediate
:
121 out
+= " " + result
.upper() + "\n"
123 sys
.stdout
.write(out
)
125 def startTest(self
, test
):
128 def addSuccess(self
, test
):
129 self
.end_test(test
.id(), "success", False)
131 def addError(self
, test
, details
=None):
132 self
.end_test(test
.id(), "error", True, details
)
134 def addFailure(self
, test
, details
=None):
135 self
.end_test(test
.id(), "failure", True, details
)
137 def addSkip(self
, test
, details
=None):
138 self
.end_test(test
.id(), "skip", False, details
)
140 def addExpectedFail(self
, test
, details
=None):
141 self
.end_test(test
.id(), "xfail", False, details
)
143 def end_test(self
, testname
, result
, unexpected
, reason
=None):
145 self
.test_output
[self
.name
] = ""
146 if not self
.immediate
:
151 'success': '.'}.get(result
, "?(%s)" % result
))
154 if not self
.name
in self
.test_output
:
155 self
.test_output
[self
.name
] = ""
157 self
.test_output
[self
.name
] += "UNEXPECTED(%s): %s\n" % (result
, testname
)
158 if reason
is not None:
159 self
.test_output
[self
.name
] += "REASON: %s\n" % (reason
[1].message
.encode("utf-8").strip(),)
161 if self
.immediate
and not self
.verbose
:
162 print self
.test_output
[self
.name
]
163 self
.test_output
[self
.name
] = ""
165 if not self
.immediate
:
169 'success': 'S'}.get(result
, "?"))
172 f
= open(self
.summaryfile
, 'w+')
174 if self
.suitesfailed
:
175 f
.write("= Failed tests =\n")
177 for suite
in self
.suitesfailed
:
178 f
.write("== %s ==\n" % suite
)
179 if suite
in self
.test_output
:
180 f
.write(self
.test_output
[suite
]+"\n\n")
184 if not self
.immediate
and not self
.verbose
:
185 for suite
in self
.suitesfailed
:
187 print "FAIL: %s" % suite
188 if suite
in self
.test_output
:
189 print self
.test_output
[suite
]
192 f
.write("= Skipped tests =\n")
193 for reason
in self
.skips
.keys():
194 f
.write(reason
+ "\n")
195 for name
in self
.skips
[reason
]:
196 f
.write("\t%s\n" % name
)
200 print "\nA summary with detailed information can be found in:"
201 print " %s" % self
.summaryfile
203 if not self
.suitesfailed
:
204 ok
= (self
.statistics
['TESTS_EXPECTED_OK'] +
205 self
.statistics
['TESTS_EXPECTED_FAIL'])
206 print "\nALL OK (%d tests in %d testsuites)" % (ok
, self
.suites_ok
)
208 print "\nFAILED (%d failures and %d errors in %d testsuites)" % (
209 self
.statistics
['TESTS_UNEXPECTED_FAIL'],
210 self
.statistics
['TESTS_ERROR'],
211 len(self
.suitesfailed
))
213 def skip_testsuite(self
, name
, reason
="UNKNOWN"):
214 self
.skips
.setdefault(reason
, []).append(name
)
218 parser
= optparse
.OptionParser("format-subunit [options]")
219 parser
.add_option("--verbose", action
="store_true",
221 parser
.add_option("--immediate", action
="store_true",
222 help="Show failures immediately, don't wait until test run has finished")
223 parser
.add_option("--prefix", type="string", default
=".",
224 help="Prefix to write summary to")
226 opts
, args
= parser
.parse_args()
230 'TESTS_UNEXPECTED_OK': 0,
231 'TESTS_EXPECTED_OK': 0,
232 'TESTS_UNEXPECTED_FAIL': 0,
233 'TESTS_EXPECTED_FAIL': 0,
238 def handle_sigint(sig
, stack
):
240 signal
.signal(signal
.SIGINT
, handle_sigint
)
242 msg_ops
= PlainFormatter(os
.path
.join(opts
.prefix
, "summary"), opts
.verbose
,
243 opts
.immediate
, statistics
)
245 expected_ret
= subunithelper
.parse_results(msg_ops
, statistics
, sys
.stdin
)
249 sys
.exit(expected_ret
)