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 minutes
, seconds
= divmod(t
, 60)
20 hours
, minutes
= divmod(minutes
, 60)
25 ret
+= "%dm" % minutes
26 ret
+= "%ds" % seconds
30 class PlainFormatter(object):
32 def __init__(self
, summaryfile
, verbose
, immediate
, statistics
,
34 self
.verbose
= verbose
35 self
.immediate
= immediate
36 self
.statistics
= statistics
37 self
.start_time
= None
39 self
.suitesfailed
= []
42 self
.summaryfile
= summaryfile
45 self
._progress
_level
= 0
46 self
.totalsuites
= totaltests
48 def progress(self
, offset
, whence
):
49 if whence
== subunit
.PROGRESS_POP
:
50 self
._progress
_level
-= 1
51 elif whence
== subunit
.PROGRESS_PUSH
:
52 self
._progress
_level
+= 1
53 elif whence
== subunit
.PROGRESS_SET
:
54 if self
._progress
_level
== 0:
55 self
.totalsuites
= offset
56 elif whence
== subunit
.PROGRESS_CUR
:
57 raise NotImplementedError
59 def report_time(self
, time
):
60 if self
.start_time
is None:
61 self
.start_time
= time
64 def start_testsuite(self
, name
):
67 testsuite_start_time
= self
.last_time
69 duration
= testsuite_start_time
- self
.start_time
72 self
.test_output
[name
] = ""
74 out
= "[%d" % self
.index
75 if self
.totalsuites
is not None:
76 out
+= "/%d" % self
.totalsuites
77 out
+= " in " + format_time(duration
)
79 out
+= ", %d errors" % (len(self
.suitesfailed
),)
82 sys
.stdout
.write(out
+ "\n")
84 sys
.stdout
.write(out
+ ": ")
86 def output_msg(self
, output
):
88 sys
.stdout
.write(output
)
89 elif self
.name
is not None:
90 self
.test_output
[self
.name
] += output
92 sys
.stdout
.write(output
)
94 def control_msg(self
, output
):
95 #$self->output_msg($output)
98 def end_testsuite(self
, name
, result
, reason
):
102 if not name
in self
.test_output
:
103 print "no output for name[%s]" % name
105 if result
in ("success", "xfail"):
108 self
.output_msg("ERROR: Testsuite[%s]\n" % name
)
109 if reason
is not None:
110 self
.output_msg("REASON: %s\n" % (reason
,))
111 self
.suitesfailed
.append(name
)
112 if self
.immediate
and not self
.verbose
and name
in self
.test_output
:
113 out
+= self
.test_output
[name
]
116 if not self
.immediate
:
120 out
+= " " + result
.upper() + "\n"
122 sys
.stdout
.write(out
)
124 def start_test(self
, testname
):
127 def end_test(self
, testname
, result
, unexpected
, reason
=None):
129 self
.test_output
[self
.name
] = ""
130 if not self
.immediate
:
135 'success': '.'}.get(result
, "?(%s)" % result
))
138 self
.test_output
[self
.name
] += "UNEXPECTED(%s): %s\n" % (result
, testname
)
139 if reason
is not None:
140 self
.test_output
[self
.name
] += "REASON: %s\n" % (reason
.strip(),)
142 if self
.immediate
and not self
.verbose
:
143 print self
.test_output
[self
.name
]
144 self
.test_output
[self
.name
] = ""
146 if not self
.immediate
:
150 'success': 'S'}.get(result
, "?"))
153 f
= open(self
.summaryfile
, 'w+')
155 if self
.suitesfailed
:
156 f
.write("= Failed tests =\n")
158 for suite
in self
.suitesfailed
:
159 f
.write("== %s ==\n" % suite
)
160 if suite
in self
.test_output
:
161 f
.write(self
.test_output
[suite
]+"\n\n")
165 if not self
.immediate
and not self
.verbose
:
166 for suite
in self
.suitesfailed
:
168 print "FAIL: %s" % suite
169 if suite
in self
.test_output
:
170 print self
.test_output
[suite
]
173 f
.write("= Skipped tests =\n")
174 for reason
in self
.skips
.keys():
175 f
.write(reason
+ "\n")
176 for name
in self
.skips
[reason
]:
177 f
.write("\t%s\n" % name
)
181 print "\nA summary with detailed information can be found in:"
182 print " %s" % self
.summaryfile
184 if not self
.suitesfailed
:
185 ok
= (self
.statistics
['TESTS_EXPECTED_OK'] +
186 self
.statistics
['TESTS_EXPECTED_FAIL'])
187 print "\nALL OK (%d tests in %d testsuites)" % (ok
, self
.suites_ok
)
189 print "\nFAILED (%d failures and %d errors in %d testsuites)" % (
190 self
.statistics
['TESTS_UNEXPECTED_FAIL'],
191 self
.statistics
['TESTS_ERROR'],
192 len(self
.suitesfailed
))
194 def skip_testsuite(self
, name
, reason
="UNKNOWN"):
195 self
.skips
.setdefault(reason
, []).append(name
)
199 parser
= optparse
.OptionParser("format-subunit [options]")
200 parser
.add_option("--verbose", action
="store_true",
202 parser
.add_option("--immediate", action
="store_true",
203 help="Show failures immediately, don't wait until test run has finished")
204 parser
.add_option("--prefix", type="string", default
=".",
205 help="Prefix to write summary to")
207 opts
, args
= parser
.parse_args()
211 'TESTS_UNEXPECTED_OK': 0,
212 'TESTS_EXPECTED_OK': 0,
213 'TESTS_UNEXPECTED_FAIL': 0,
214 'TESTS_EXPECTED_FAIL': 0,
219 def handle_sigint(sig
, stack
):
221 signal
.signal(signal
.SIGINT
, handle_sigint
)
223 msg_ops
= PlainFormatter(os
.path
.join(opts
.prefix
, "summary"), opts
.verbose
,
224 opts
.immediate
, statistics
)
226 expected_ret
= subunithelper
.parse_results(msg_ops
, statistics
, sys
.stdin
)
230 sys
.exit(expected_ret
)