220 lines
7.8 KiB
Python
220 lines
7.8 KiB
Python
import py
|
|
import sys
|
|
from py.__.test import event
|
|
from py.__.test.report.base import BaseReporter
|
|
from py.__.test.report.base import getrelpath, repr_pythonversion
|
|
|
|
class TerminalReporter(BaseReporter):
|
|
def __init__(self, config, file=None, bus=None):
|
|
super(TerminalReporter, self).__init__(bus=bus)
|
|
self.config = config
|
|
self.curdir = py.path.local()
|
|
if file is None:
|
|
file = py.std.sys.stdout
|
|
self._tw = py.io.TerminalWriter(file)
|
|
|
|
def _reset(self):
|
|
self.currentfspath = None
|
|
super(TerminalReporter, self)._reset()
|
|
|
|
def write_fspath_result(self, fspath, res):
|
|
if fspath != self.currentfspath:
|
|
self._tw.line()
|
|
relpath = getrelpath(self.curdir, fspath)
|
|
self._tw.write(relpath + " ")
|
|
self.currentfspath = fspath
|
|
self._tw.write(res)
|
|
|
|
def write_ensure_prefix(self, prefix, extra=""):
|
|
if self.currentfspath != prefix:
|
|
self._tw.line()
|
|
self.currentfspath = prefix
|
|
self._tw.write(prefix)
|
|
if extra:
|
|
self._tw.write(extra)
|
|
self.currentfspath = -2
|
|
|
|
def ensure_newline(self):
|
|
if self.currentfspath:
|
|
self._tw.line()
|
|
self.currentfspath = None
|
|
|
|
def write_line(self, line, **markup):
|
|
line = str(line)
|
|
self.ensure_newline()
|
|
self._tw.line(line, **markup)
|
|
|
|
def write_sep(self, sep, title=None, **markup):
|
|
self.ensure_newline()
|
|
self._tw.sep(sep, title, **markup)
|
|
|
|
def getoutcomeletter(self, item):
|
|
return item.outcome.shortrepr
|
|
|
|
def getoutcomeword(self, item):
|
|
if item.passed: return self._tw.markup("PASS", green=True)
|
|
elif item.failed: return self._tw.markup("FAIL", red=True)
|
|
elif item.skipped: return "SKIP"
|
|
else: return self._tw.markup("???", red=True)
|
|
|
|
def getcollectoutcome(self, item):
|
|
if item.skipped:
|
|
return str(item.outcome.longrepr.message)
|
|
else:
|
|
return str(item.outcome.longrepr.reprcrash.message)
|
|
|
|
def rep_InternalException(self, ev):
|
|
for line in str(ev.repr).split("\n"):
|
|
self.write_line("InternalException: " + line)
|
|
|
|
def rep_HostGatewayReady(self, ev):
|
|
if self.config.option.verbose:
|
|
self.write_line("HostGatewayReady: %s" %(ev.host,))
|
|
|
|
def rep_HostUp(self, ev):
|
|
d = ev.platinfo.copy()
|
|
d['hostid'] = ev.host.hostid
|
|
d['version'] = repr_pythonversion(d['sys.version_info'])
|
|
self.write_line("HOSTUP: %(hostid)s %(sys.platform)s "
|
|
"%(sys.executable)s - Python %(version)s" %
|
|
d)
|
|
|
|
def rep_HostDown(self, ev):
|
|
host = ev.host
|
|
error = ev.error
|
|
if error:
|
|
self.write_line("HostDown %s: %s" %(host.hostid, error))
|
|
|
|
def rep_ItemStart(self, ev):
|
|
if self.config.option.verbose:
|
|
info = ev.item.repr_metainfo()
|
|
line = info.verboseline(basedir=self.curdir) + " "
|
|
extra = ""
|
|
if ev.host:
|
|
extra = "-> " + ev.host.hostid
|
|
self.write_ensure_prefix(line, extra)
|
|
else:
|
|
# ensure that the path is printed before the 1st test of
|
|
# a module starts running
|
|
fspath = ev.item.fspath
|
|
self.write_fspath_result(fspath, "")
|
|
|
|
def rep_RescheduleItems(self, ev):
|
|
if self.config.option.debug:
|
|
self.write_sep("!", "RESCHEDULING %s " %(ev.items,))
|
|
|
|
def rep_ItemTestReport(self, ev):
|
|
super(TerminalReporter, self).rep_ItemTestReport(ev)
|
|
fspath = ev.colitem.fspath
|
|
if not self.config.option.verbose:
|
|
self.write_fspath_result(fspath, self.getoutcomeletter(ev))
|
|
else:
|
|
info = ev.colitem.repr_metainfo()
|
|
line = info.verboseline(basedir=self.curdir) + " "
|
|
word = self.getoutcomeword(ev)
|
|
self.write_ensure_prefix(line, word)
|
|
|
|
def rep_CollectionReport(self, ev):
|
|
super(TerminalReporter, self).rep_CollectionReport(ev)
|
|
fspath = ev.colitem.fspath
|
|
if ev.failed or ev.skipped:
|
|
msg = self.getcollectoutcome(ev)
|
|
self.write_fspath_result(fspath, "- " + msg)
|
|
|
|
def rep_TestrunStart(self, ev):
|
|
super(TerminalReporter, self).rep_TestrunStart(ev)
|
|
self.write_sep("=", "test session starts", bold=True)
|
|
self._sessionstarttime = py.std.time.time()
|
|
#self.out_hostinfo()
|
|
|
|
def rep_TestrunFinish(self, ev):
|
|
self._tw.line("")
|
|
if ev.exitstatus in (0, 1, 2):
|
|
self.summary_failures()
|
|
self.summary_skips()
|
|
if ev.excrepr is not None:
|
|
self.summary_final_exc(ev.excrepr)
|
|
if ev.exitstatus == 2:
|
|
self.write_sep("!", "KEYBOARD INTERRUPT")
|
|
self.summary_deselected()
|
|
self.summary_stats()
|
|
|
|
def rep_LooponfailingInfo(self, ev):
|
|
if ev.failreports:
|
|
self.write_sep("#", "LOOPONFAILING", red=True)
|
|
for report in ev.failreports:
|
|
try:
|
|
loc = report.outcome.longrepr.reprcrash
|
|
except AttributeError:
|
|
loc = str(report.outcome.longrepr)[:50]
|
|
self.write_line(loc, red=True)
|
|
self.write_sep("#", "waiting for changes")
|
|
for rootdir in ev.rootdirs:
|
|
self.write_line("### Watching: %s" %(rootdir,), bold=True)
|
|
|
|
if 0:
|
|
print "#" * 60
|
|
print "# looponfailing: mode: %d failures args" % len(failures)
|
|
for ev in failurereports:
|
|
name = "/".join(ev.colitem.listnames()) # XXX
|
|
print "Failure at: %r" % (name,)
|
|
print "# watching py files below %s" % rootdir
|
|
print "# ", "^" * len(str(rootdir))
|
|
failures = [ev.colitem for ev in failurereports]
|
|
if not failures:
|
|
failures = colitems
|
|
|
|
#
|
|
# summaries for TestrunFinish
|
|
#
|
|
|
|
def summary_failures(self):
|
|
if self._failed and self.config.option.tbstyle != "no":
|
|
self.write_sep("=", "FAILURES")
|
|
for ev in self._failed:
|
|
self.write_sep("_")
|
|
ev.toterminal(self._tw)
|
|
|
|
def summary_stats(self):
|
|
session_duration = py.std.time.time() - self._sessionstarttime
|
|
numfailed = len(self._failed)
|
|
numskipped = len(self._skipped)
|
|
numpassed = len(self._passed)
|
|
sum = numfailed + numpassed
|
|
self.write_sep("=", "%d/%d passed + %d skips in %.2f seconds" %
|
|
(numpassed, sum, numskipped, session_duration), bold=True)
|
|
if numfailed == 0:
|
|
self.write_sep("=", "failures: no failures :)", green=True)
|
|
else:
|
|
self.write_sep("=", "failures: %d" %(numfailed), red=True)
|
|
|
|
def summary_deselected(self):
|
|
if not self._deselected:
|
|
return
|
|
self.write_sep("=", "%d tests deselected by %r" %(
|
|
len(self._deselected), self.config.option.keyword), bold=True)
|
|
|
|
|
|
def summary_skips(self):
|
|
if not self._failed or self.config.option.showskipsummary:
|
|
folded_skips = self._folded_skips()
|
|
if folded_skips:
|
|
self.write_sep("_", "skipped test summary")
|
|
for num, fspath, lineno, reason in folded_skips:
|
|
self._tw.line("%s:%d: [%d] %s" %(fspath, lineno, num, reason))
|
|
|
|
def summary_final_exc(self, excrepr):
|
|
self.write_sep("!")
|
|
if self.config.option.verbose:
|
|
excrepr.toterminal(self._tw)
|
|
else:
|
|
excrepr.reprcrash.toterminal(self._tw)
|
|
|
|
def out_hostinfo(self):
|
|
self._tw.line("host 0: %s %s - Python %s" %
|
|
(py.std.sys.platform,
|
|
py.std.sys.executable,
|
|
repr_pythonversion()))
|
|
|
|
Reporter = TerminalReporter
|