[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