[py-svn] r61298 - in py/branch/pytestplugin/py/test: . plugin plugin/testing testing
hpk at codespeak.net
hpk at codespeak.net
Sat Jan 24 13:25:30 CET 2009
Author: hpk
Date: Sat Jan 24 13:25:29 2009
New Revision: 61298
Modified:
py/branch/pytestplugin/py/test/event.py
py/branch/pytestplugin/py/test/plugin/pytest_resultlog.py
py/branch/pytestplugin/py/test/plugin/pytest_terminal.py
py/branch/pytestplugin/py/test/plugin/testing/test_resultlog.py
py/branch/pytestplugin/py/test/plugin/testing/test_terminal.py
py/branch/pytestplugin/py/test/runner.py
py/branch/pytestplugin/py/test/testing/suptest.py
py/branch/pytestplugin/py/test/testing/test_collect.py
py/branch/pytestplugin/py/test/testing/test_session.py
Log:
* start un-tangling handling of CollectionReports and ItemTestReports
* refactor resultlog plugin tests to depend less on py.test internal details
* fix suptest to properly handle plugins
* somewhat intermediate checkin
* all tests pass
Modified: py/branch/pytestplugin/py/test/event.py
==============================================================================
--- py/branch/pytestplugin/py/test/event.py (original)
+++ py/branch/pytestplugin/py/test/event.py Sat Jan 24 13:25:29 2009
@@ -99,9 +99,30 @@
class CollectionReport(BaseReport):
""" Collection Report. """
- def __init__(self, colitem, result, **kwargs):
- super(CollectionReport, self).__init__(colitem, **kwargs)
- self.result = result
+ skipped = failed = passed = False
+
+ def __init__(self, colitem, result, excinfo=None, when=None, outerr=None):
+ self.colitem = colitem
+ if not excinfo:
+ self.passed = True
+ self.result = result
+ else:
+ self.when = when
+ self.outerr = outerr
+ if excinfo.errisinstance(Skipped):
+ self.skipped = True
+ self.reason = str(excinfo.value)
+ self.longrepr = excinfo._getreprcrash()
+ else:
+ self.longrepr = self.colitem._repr_failure_py(excinfo, outerr)
+ self.failed = True
+
+ def toterminal(self, out):
+ longrepr = self.longrepr
+ if hasattr(longrepr, 'toterminal'):
+ longrepr.toterminal(out)
+ else:
+ out.line(str(longrepr))
class LooponfailingInfo(BaseEvent):
def __init__(self, failreports, rootdirs):
Modified: py/branch/pytestplugin/py/test/plugin/pytest_resultlog.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/pytest_resultlog.py (original)
+++ py/branch/pytestplugin/py/test/plugin/pytest_resultlog.py Sat Jan 24 13:25:29 2009
@@ -55,10 +55,28 @@
for line in longrepr.splitlines():
print >>self.logfile, " %s" % line
+ def getoutcomecodes(self, ev):
+ if isinstance(ev, ev.CollectionReport):
+ # encode pass/fail/skip indepedent of terminal reporting semantics
+ # XXX handle collection and item reports more uniformly
+ if ev.passed:
+ code = "."
+ else:
+ if ev.failed:
+ code = "F"
+ elif ev.skipped:
+ code = "S"
+ longrepr = str(ev.longrepr)
+ else:
+ assert isinstance(ev, ev.ItemTestReport)
+ code = ev.outcome.shortrepr # XXX make independent from reporting
+ longrepr = str(ev.outcome.longrepr)
+ return code, longrepr
+
def log_outcome(self, ev):
- outcome = ev.outcome
gpath = generic_path(ev.colitem)
- self.write_log_entry(outcome.shortrepr, gpath, str(outcome.longrepr))
+ shortrepr, longrepr = self.getoutcomecodes(ev)
+ self.write_log_entry(shortrepr, gpath, longrepr)
def log_event_to_file(self, ev):
if isinstance(ev, ev.ItemTestReport):
Modified: py/branch/pytestplugin/py/test/plugin/pytest_terminal.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/pytest_terminal.py (original)
+++ py/branch/pytestplugin/py/test/plugin/pytest_terminal.py Sat Jan 24 13:25:29 2009
@@ -74,7 +74,10 @@
def _folded_skips(self):
d = {}
for event in self._skipped:
- longrepr = event.outcome.longrepr
+ if isinstance(event, event.CollectionReport):
+ longrepr = event.longrepr
+ else:
+ longrepr = event.outcome.longrepr
key = longrepr.path, longrepr.lineno, longrepr.message
d.setdefault(key, []).append(event)
l = []
@@ -136,12 +139,6 @@
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)
@@ -195,10 +192,15 @@
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)
+ if not ev.passed:
+ if ev.failed:
+ msg = ev.longrepr.reprcrash.message
+ elif ev.skipped:
+ msg = "Skipped:" + ev.reason
+ else:
+ msg = None
+ if msg is not None:
+ self.write_fspath_result(ev.colitem.fspath, "- " + msg)
def rep_TestrunStart(self, ev):
super(TerminalReporter, self).rep_TestrunStart(ev)
@@ -324,9 +326,9 @@
def rep_CollectionReport(self, ev):
super(CollectonlyReporter, self).rep_CollectionReport(ev)
if ev.failed:
- self.outindent("!!! %s !!!" % ev.outcome.longrepr.reprcrash.message)
+ self.outindent("!!! %s !!!" % ev.longrepr.reprcrash.message)
elif ev.skipped:
- self.outindent("!!! %s !!!" % ev.outcome.longrepr.message)
+ self.outindent("!!! %s !!!" % ev.longrepr.message)
self.indent = self.indent[:-len(self.INDENT)]
def rep_TestrunFinish(self, session):
Modified: py/branch/pytestplugin/py/test/plugin/testing/test_resultlog.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/testing/test_resultlog.py (original)
+++ py/branch/pytestplugin/py/test/plugin/testing/test_resultlog.py Sat Jan 24 13:25:29 2009
@@ -2,31 +2,17 @@
test module for result log plugin
-XXX try to avoid low-level construction of items (see make_item) or move
- functionality to some place where other tests use it as well.
-
-
"""
import os, StringIO
import py
import py.__.test.plugin.pytest_resultlog as resultlog
-from py.__.test.testing import plugintester
-
+from py.__.test.testing import plugintester, suptest
from py.__.test import event
-from py.__.test.session import Session
-from py.__.test.testing import suptest
-from py.__.test.config import Config
-from py.__.test.collect import Node, Item, FSCollector
-from py.__.test.runner import OutcomeRepr
-
-class Fake(object):
- def __init__(self, **kwds):
- self.__dict__.update(kwds)
-
def test_generic_path():
+ from py.__.test.collect import Node, Item, FSCollector
p1 = Node('a', config='dummy')
assert p1.fspath is None
p2 = Node('B', parent=p1)
@@ -46,19 +32,6 @@
res = resultlog.generic_path(item)
assert res == 'test/a:B().c[1]'
-
-def make_item(*names):
- node = None
- config = "dummy"
- for name in names[:-1]:
- if '/' in name:
- node = FSCollector(name, parent=node, config=config)
- else:
- node = Node(name, parent=node, config=config)
- if names[-1] is None:
- return node
- return Item(names[-1], parent=node)
-
def test_generic():
plugintester.nocalls("py.__.test.plugin.pytest_resultlog")
tmpdir = plugintester.functional("py.__.test.plugin.pytest_resultlog",
@@ -71,109 +44,95 @@
"s *:test_skip",
])
-class TestResultLog(object):
- def test_write_log_entry(self):
- reslog = resultlog.ResultLog(None)
- reslog.logfile = StringIO.StringIO()
- reslog.write_log_entry('.', 'name', '')
- entry = reslog.logfile.getvalue()
- assert entry[-1] == '\n'
- entry_lines = entry.splitlines()
- assert len(entry_lines) == 1
- assert entry_lines[0] == '. name'
-
- reslog.logfile = StringIO.StringIO()
- reslog.write_log_entry('s', 'name', 'Skipped')
- entry = reslog.logfile.getvalue()
- assert entry[-1] == '\n'
- entry_lines = entry.splitlines()
- assert len(entry_lines) == 2
- assert entry_lines[0] == 's name'
- assert entry_lines[1] == ' Skipped'
-
- reslog.logfile = StringIO.StringIO()
- reslog.write_log_entry('s', 'name', 'Skipped\n')
- entry = reslog.logfile.getvalue()
- assert entry[-1] == '\n'
- entry_lines = entry.splitlines()
- assert len(entry_lines) == 2
- assert entry_lines[0] == 's name'
- assert entry_lines[1] == ' Skipped'
-
- reslog.logfile = StringIO.StringIO()
- longrepr = ' tb1\n tb 2\nE tb3\nSome Error'
- reslog.write_log_entry('F', 'name', longrepr)
- entry = reslog.logfile.getvalue()
- assert entry[-1] == '\n'
- entry_lines = entry.splitlines()
- assert len(entry_lines) == 5
- assert entry_lines[0] == 'F name'
- assert entry_lines[1:] == [' '+line for line in longrepr.splitlines()]
+def test_write_log_entry():
+ reslog = resultlog.ResultLog(None)
+ reslog.logfile = StringIO.StringIO()
+ reslog.write_log_entry('.', 'name', '')
+ entry = reslog.logfile.getvalue()
+ assert entry[-1] == '\n'
+ entry_lines = entry.splitlines()
+ assert len(entry_lines) == 1
+ assert entry_lines[0] == '. name'
+
+ reslog.logfile = StringIO.StringIO()
+ reslog.write_log_entry('s', 'name', 'Skipped')
+ entry = reslog.logfile.getvalue()
+ assert entry[-1] == '\n'
+ entry_lines = entry.splitlines()
+ assert len(entry_lines) == 2
+ assert entry_lines[0] == 's name'
+ assert entry_lines[1] == ' Skipped'
+
+ reslog.logfile = StringIO.StringIO()
+ reslog.write_log_entry('s', 'name', 'Skipped\n')
+ entry = reslog.logfile.getvalue()
+ assert entry[-1] == '\n'
+ entry_lines = entry.splitlines()
+ assert len(entry_lines) == 2
+ assert entry_lines[0] == 's name'
+ assert entry_lines[1] == ' Skipped'
+
+ reslog.logfile = StringIO.StringIO()
+ longrepr = ' tb1\n tb 2\nE tb3\nSome Error'
+ reslog.write_log_entry('F', 'name', longrepr)
+ entry = reslog.logfile.getvalue()
+ assert entry[-1] == '\n'
+ entry_lines = entry.splitlines()
+ assert len(entry_lines) == 5
+ assert entry_lines[0] == 'F name'
+ assert entry_lines[1:] == [' '+line for line in longrepr.splitlines()]
- def test_log_outcome(self):
- reslog = resultlog.ResultLog(StringIO.StringIO())
-
- colitem = make_item('some', 'path', 'a', 'b')
-
- try:
- raise ValueError
- except ValueError:
- the_repr = py.code.ExceptionInfo().getrepr()
-
- outcome=OutcomeRepr('execute', 'F', the_repr)
- ev = Fake(colitem=colitem, outcome=outcome)
-
- reslog.log_outcome(ev)
-
- entry = reslog.logfile.getvalue()
- entry_lines = entry.splitlines()
-
- assert entry_lines[0] == 'F some.path.a.b'
- assert entry_lines[-1][0] == ' '
- assert 'ValueError' in entry
-
- def test_item_test_passed(self):
- bus = event.EventBus()
- reslog = resultlog.ResultLog(StringIO.StringIO())
- bus.subscribe(reslog.log_event_to_file)
-
- colitem = make_item('proj/test', 'proj/test/mod', 'a', 'b')
-
- outcome=OutcomeRepr('execute', '.', '')
- rep_ev = event.ItemTestReport(colitem, passed=outcome)
-
- bus.notify(rep_ev)
-
- lines = reslog.logfile.getvalue().splitlines()
- assert len(lines) == 1
- line = lines[0]
- assert line.startswith(". ")
- assert line[2:] == 'test/mod:a.b'
-
+class TestWithFunctionIntegration(suptest.InlineSession):
+ # XXX (hpk) i think that the resultlog plugin should
+ # provide a Parser object so that one can remain
+ # ignorant regarding formatting details.
+ def getresultlog(self, args):
+ resultlog = self.tmpdir.join("resultlog")
+ self.parse_and_run("--resultlog=%s" % resultlog, args)
+ return filter(None, resultlog.readlines(cr=0))
+
def test_collection_report(self):
- bus = event.EventBus()
- reslog = resultlog.ResultLog(None)
- bus.subscribe(reslog.log_event_to_file)
-
- reslog.logfile = StringIO.StringIO()
- colitem = make_item('proj/test', 'proj/test/mod', 'A', None)
- outcome=OutcomeRepr('execute', '', '')
- rep_ev = event.CollectionReport(colitem, object(), passed=outcome)
-
- bus.notify(rep_ev)
-
- entry = reslog.logfile.getvalue()
- assert not entry
-
- reslog.logfile = StringIO.StringIO()
- outcome=OutcomeRepr('execute', 'F', 'Some Error')
- rep_ev = event.CollectionReport(colitem, object(), failed=outcome)
+ ok = self.makepyfile(test_collection_ok="")
+ skip = self.makepyfile(test_collection_skip="import py ; py.test.skip('hello')")
+ fail = self.makepyfile(test_collection_fail="XXX")
- bus.notify(rep_ev)
+ lines = self.getresultlog(ok)
+ assert not lines
- lines = reslog.logfile.getvalue().splitlines()
+ lines = self.getresultlog(skip)
assert len(lines) == 2
- assert lines[0] == 'F test/mod:A'
+ assert lines[0].startswith("S ")
+ assert lines[0].endswith("test_collection_skip.py")
+ assert lines[1].startswith(" ")
+ assert lines[1].endswith("test_collection_skip.py:1: Skipped: 'hello'")
+
+ lines = self.getresultlog(fail)
+ assert lines
+ assert lines[0].startswith("F ")
+ assert lines[0].endswith("test_collection_fail.py"), lines[0]
+ for x in lines[1:]:
+ assert x.startswith(" ")
+ assert "XXX" in "".join(lines[1:])
+
+ def test_log_test_outcomes(self):
+ mod = self.makepyfile(test_mod="""
+ import py
+ def test_pass(): pass
+ def test_skip(): py.test.skip("hello")
+ def test_fail(): raise ValueError("val")
+ """)
+ lines = self.getresultlog(mod)
+ assert len(lines) >= 3
+ assert lines[0].startswith(". ")
+ assert lines[0].endswith("test_pass")
+ assert lines[1].startswith("s "), lines[1]
+ assert lines[1].endswith("test_skip")
+ assert lines[2].find("hello") != -1
+
+ assert lines[3].startswith("F ")
+ assert lines[3].endswith("test_fail")
+ tb = "".join(lines[4:])
+ assert tb.find("ValueError") != -1
def test_internal_exception(self):
# they are produced for example by a teardown failing
Modified: py/branch/pytestplugin/py/test/plugin/testing/test_terminal.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/testing/test_terminal.py (original)
+++ py/branch/pytestplugin/py/test/plugin/testing/test_terminal.py Sat Jan 24 13:25:29 2009
@@ -260,7 +260,7 @@
rep.processevent(event.ItemStart(item))
s = popvalue(stringio)
assert s.find("Function 'test_func'") != -1
- rep.processevent(event.CollectionReport(modcol, [], passed=""))
+ rep.processevent(event.CollectionReport(modcol, [], excinfo=None))
assert rep.indent == indent
def test_collectonly_skipped_module(self):
@@ -322,23 +322,28 @@
rep.processevent(ev)
assert getattr(rep, '_' + outcome) == [ev]
- def test_CollectionReport(self):
+ def test_CollectionReport_events_are_counted(self):
for outcome in 'skipped failed'.split():
rep = BaseReporter()
- ev = event.CollectionReport(None, None, **{outcome:True})
+ ev = event.CollectionReport(None, None)
+ setattr(ev, outcome, True)
rep.processevent(ev)
assert getattr(rep, '_' + outcome) == [ev]
- def test_skip_reasons(self):
- from py.__.test.runner import OutcomeRepr
+ def test_skip_reasons_folding(self):
rep = BaseReporter()
class longrepr:
path = 'xyz'
lineno = 3
message = "justso"
- out1 = OutcomeRepr(None, None, longrepr)
+
+ ev1 = event.CollectionReport(None, None)
+ ev1.when = "execute"
+ ev1.skipped = True
+ ev1.longrepr = longrepr
+
+ from py.__.test.runner import OutcomeRepr
out2 = OutcomeRepr(None, None, longrepr)
- ev1 = event.CollectionReport(None, None, skipped=out1)
ev2 = event.ItemTestReport(None, skipped=out2)
rep.processevent(ev1)
rep.processevent(ev2)
Modified: py/branch/pytestplugin/py/test/runner.py
==============================================================================
--- py/branch/pytestplugin/py/test/runner.py (original)
+++ py/branch/pytestplugin/py/test/runner.py Sat Jan 24 13:25:29 2009
@@ -95,11 +95,13 @@
def execute(self):
return self.colitem._memocollect()
def makereport(self, res, when, excinfo, outerr):
- if excinfo:
- kw = self.getkw(when, excinfo, outerr)
- else:
- kw = {'passed': OutcomeRepr(when, '', "")}
- return event.CollectionReport(self.colitem, res, **kw)
+ return event.CollectionReport(self.colitem, res, excinfo, when, outerr)
+
+# if excinfo:
+# kw = self.getkw(when, excinfo, outerr)
+# else:
+# kw = {'passed': OutcomeRepr(when, '', "")}
+# return event.CollectionReport(self.colitem, res, **kw)
NORESULT = object()
#
Modified: py/branch/pytestplugin/py/test/testing/suptest.py
==============================================================================
--- py/branch/pytestplugin/py/test/testing/suptest.py (original)
+++ py/branch/pytestplugin/py/test/testing/suptest.py Sat Jan 24 13:25:29 2009
@@ -213,9 +213,11 @@
class InlineSession(InlineCollection):
def parse_and_run(self, *args):
config = self.parseconfig(*args)
+ config.pluginmanager.configure(config)
session = config.initsession()
sorter = EventSorter(config, session)
session.main()
+ config.pluginmanager.unconfigure(config)
return sorter
def popvalue(stringio):
Modified: py/branch/pytestplugin/py/test/testing/test_collect.py
==============================================================================
--- py/branch/pytestplugin/py/test/testing/test_collect.py (original)
+++ py/branch/pytestplugin/py/test/testing/test_collect.py Sat Jan 24 13:25:29 2009
@@ -489,7 +489,7 @@
and x.failed]
assert len(failures) == 1
ev = failures[0]
- assert ev.outcome.longrepr.reprcrash.message.startswith("SyntaxError")
+ assert ev.longrepr.reprcrash.message.startswith("SyntaxError")
def test_example_items1(self):
self.tmp.ensure("test_example.py").write(py.code.Source('''
Modified: py/branch/pytestplugin/py/test/testing/test_session.py
==============================================================================
--- py/branch/pytestplugin/py/test/testing/test_session.py (original)
+++ py/branch/pytestplugin/py/test/testing/test_session.py Sat Jan 24 13:25:29 2009
@@ -122,7 +122,7 @@
sorter = self.events_from_cmdline()
l = sorter.getfailedcollections()
assert len(l) == 1
- out = l[0].outcome.longrepr.reprcrash.message
+ out = l[0].longrepr.reprcrash.message
assert out.find('does_not_work') != -1
def test_raises_output(self):
@@ -145,7 +145,7 @@
yield None
""")
failures = sorter.getfailedcollections()
- out = failures[0].outcome.longrepr.reprcrash.message
+ out = failures[0].longrepr.reprcrash.message
i = out.find('TypeError')
assert i != -1
@@ -153,7 +153,7 @@
sorter = self.events_from_runsource("this is really not python")
l = sorter.getfailedcollections()
assert len(l) == 1
- out = l[0].outcome.longrepr.reprcrash.message
+ out = l[0].longrepr.reprcrash.message
assert out.find(str('not python')) != -1
def test_exit_first_problem(self):
More information about the pytest-commit
mailing list