[py-svn] r34885 - in py/dist/py/test: . rsession rsession/testing
guido at codespeak.net
guido at codespeak.net
Thu Nov 23 11:43:28 CET 2006
Author: guido
Date: Thu Nov 23 11:43:24 2006
New Revision: 34885
Modified:
py/dist/py/test/defaultconftest.py
py/dist/py/test/rsession/rest.py
py/dist/py/test/rsession/testing/test_rest.py
Log:
Added link writer mechanism to create links for paths in the ReST, added code
to display exceptions and signals.
Modified: py/dist/py/test/defaultconftest.py
==============================================================================
--- py/dist/py/test/defaultconftest.py (original)
+++ py/dist/py/test/defaultconftest.py Thu Nov 23 11:43:24 2006
@@ -10,6 +10,8 @@
additionalinfo = None
+linkwriter = py.test.rest.RelLinkWriter()
+
def adddefaultoptions():
Option = py.test.Config.Option
py.test.Config.addoptions('general options',
Modified: py/dist/py/test/rsession/rest.py
==============================================================================
--- py/dist/py/test/rsession/rest.py (original)
+++ py/dist/py/test/rsession/rest.py Thu Nov 23 11:43:24 2006
@@ -6,9 +6,21 @@
import sys
from StringIO import StringIO
from py.__.test.rsession.reporter import AbstractReporter
+from py.__.test.rsession import report
from py.__.rest.rst import *
class RestReporter(AbstractReporter):
+ linkwriter = None
+
+ def __init__(self, *args, **kwargs):
+ super(RestReporter, self).__init__(*args, **kwargs)
+ self.rest = Rest()
+
+ def get_linkwriter(self):
+ if self.linkwriter is None:
+ self.linkwriter = self.config.getinitialvalue('linkwriter')
+ return self.linkwriter
+
def report_unknown(self, what):
self.add_rest(Paragraph("Unknown report: %s" % what))
@@ -41,10 +53,21 @@
item = event.item
if isinstance(item, py.test.collect.Module):
lgt = len(list(item.tryiter()))
- lns = item.listnames()
+ lns = item.listnames()[1:]
name = "/".join(lns)
+ link = self.get_linkwriter().get_link(self.get_rootpath(item),
+ item.fspath)
+ if link:
+ name = Link(name, link)
txt = 'Testing module %s (%d items)' % (name, lgt)
- self.add_rest(Title(txt, belowchar='-'))
+ self.add_rest(Title('Testing module', name, '(%d items)' % (lgt,),
+ belowchar='-'))
+
+ def get_rootpath(self, item):
+ root = item.parent
+ while root.parent is not None:
+ root = root.parent
+ return root.fspath
def print_summary(self, total, skipped_str, failed_str):
txt = "%d tests run%s%s in %.2fs (rsync: %.2f)" % \
@@ -52,6 +75,13 @@
self.timersync - self.timestart)
self.add_rest(Title(txt, belowchar='-'))
+ self.skips()
+ self.failures()
+
+ # since we're rendering each item, the links haven't been rendered
+ # yet
+ self.out.write(self.rest.render_links())
+
def report_ReceivedItemOutcome(self, event):
host = self.get_host(event)
if event.outcome.passed:
@@ -66,20 +96,159 @@
self.failed[host] += 1
self.failed_tests_outcome.append(event)
# we'll take care of them later
- lns = event.item.listnames()[1:]
- for i, ln in enumerate(lns):
- if i > 0 and ln != '()':
- lns[i] = '/%s' % (ln,)
- itempath = ''.join(lns)
+ itempath = self.get_path_from_item(event.item)
self.add_rest(ListItem(Text("%10s:" % (host[:10],)), Strong(status),
Text(itempath)))
- if event.outcome.excinfo:
- excinfo = event.outcome.excinfo
- self.add_rest(Paragraph('exception:', Strong(excinfo.typename)))
- self.add_rest(LiteralBlock(excinfo.value))
- self.add_rest(LiteralBlock('\n'.join([str(x) for x in
- excinfo.traceback])))
+
+ def skips(self):
+ # XXX hrmph, copied code
+ texts = {}
+ for event in self.skipped_tests_outcome:
+ colitem = event.item
+ if isinstance(event, report.ReceivedItemOutcome):
+ outcome = event.outcome
+ text = outcome.skipped
+ itemname = self.get_item_name(event, colitem)
+ elif isinstance(event, report.SkippedTryiter):
+ text = str(event.excinfo.value)
+ itemname = "/".join(colitem.listnames())
+ if text not in texts:
+ texts[text] = [itemname]
+ else:
+ texts[text].append(itemname)
+ if texts:
+ self.add_rest(Title('Reasons for skipped tests:', belowchar='+'))
+ for text, items in texts.items():
+ for item in items:
+ self.add_rest(ListItem('%s: %s' % (item, text)))
+
+ def failures(self):
+ tbstyle = self.config.option.tbstyle
+ if self.failed_tests_outcome:
+ self.add_rest(Title('Exceptions:', belowchar='+'))
+ for i, event in enumerate(self.failed_tests_outcome):
+ if i > 0:
+ self.add_rest(Transition())
+ if isinstance(event, report.ReceivedItemOutcome):
+ host = self.get_host(event)
+ itempath = self.get_path_from_item(event.item)
+ root = self.get_rootpath(event.item)
+ link = self.get_linkwriter().get_link(root, event.item.fspath)
+ t = Title(belowchar='+')
+ if link:
+ t.add(Link(itempath, link))
+ else:
+ t.add(Text(itempath))
+ t.add(Text('on %s' % (host,)))
+ self.add_rest(t)
+ if event.outcome.signal:
+ self.repr_signal(event.item, event.outcome)
+ else:
+ self.repr_failure(event.item, event.outcome, tbstyle)
+ else:
+ itempath = self.get_path_from_item(event.item)
+ root = self.get_rootpath(event.item)
+ link = self.get_linkwriter().get_link(root, event.item.fspath)
+ t = Title(abovechar='+', belowchar='+')
+ if link:
+ t.add(Link(itempath, link))
+ else:
+ t.add(Text(itempath))
+ out = outcome.Outcome(excinfo=event.excinfo)
+ self.repr_failure(event.item,
+ outcome.ReprOutcome(out.make_repr()),
+ tbstyle)
+
+ def repr_signal(self, item, outcome):
+ signal = outcome.signal
+ self.add_rest(Title('Received signal: %d' % (outcome.signal,),
+ abovechar='+', belowchar='+'))
+ if outcome.stdout.strip():
+ self.add_rest(Paragraph('Captured process stdout:'))
+ self.add_rest(LiteralBlock(outcome.stdout))
+ if outcome.stderr.strip():
+ self.add_rest(Paragraph('Captured process stderr:'))
+ self.add_rest(LiteralBlock(outcome.stderr))
+
+ def repr_failure(self, item, outcome, style):
+ excinfo = outcome.excinfo
+ traceback = excinfo.traceback
+ if not traceback:
+ self.add_rest(Paragraph('empty traceback from item %r' % (item,)))
+ return
+ self.repr_traceback(item, excinfo, traceback, style)
+ if outcome.stdout:
+ self.add_rest(Title('Captured process stdout:', abovechar='+',
+ belowchar='+'))
+ self.add_rest(LiteralBlock(outcome.stdout))
+ if outcome.stderr:
+ self.add_rest(Title('Captured process stderr:', abovechar='+',
+ belowchar='+'))
+ self.add_rest(LiteralBlock(outcome.stderr))
+
+ def repr_traceback(self, item, excinfo, traceback, style):
+ root = self.get_rootpath(item)
+ if style == 'long':
+ for entry in traceback:
+ link = self.get_linkwriter().get_link(root,
+ py.path.local(entry.path))
+ if link:
+ self.add_rest(Title(Link(entry.path, link),
+ 'line %d' % (entry.lineno,),
+ belowchar='+', abovechar='+'))
+ else:
+ self.add_rest(Title('%s line %d' % (entry.path,
+ entry.lineno,),
+ belowchar='+', abovechar='+'))
+ self.add_rest(LiteralBlock(self.prepare_source(entry.relline,
+ entry.source)))
+ elif style == 'short':
+ text = []
+ for entry in traceback:
+ text.append('%s line %d' % (entry.path, entry.lineno))
+ text.append(' %s' % (entry.source.strip(),))
+ self.add_rest(LiteralBlock('\n'.join(text)))
+ self.add_rest(Title(excinfo.typename, belowchar='+'))
+ self.add_rest(LiteralBlock(excinfo.value))
+
+ def prepare_source(self, relline, source):
+ text = []
+ for num, line in enumerate(source.split('\n')):
+ if num == relline:
+ text.append('>>> %s' % (line,))
+ else:
+ text.append(' %s' % (line,))
+ return '\n'.join(text)
def add_rest(self, item):
+ self.rest.add(item)
self.out.write('%s\n\n' % (item.text(),))
+ def get_path_from_item(self, item):
+ lns = item.listnames()[1:]
+ for i, ln in enumerate(lns):
+ if i > 0 and ln != '()':
+ lns[i] = '/%s' % (ln,)
+ itempath = ''.join(lns)
+ return itempath
+
+class AbstractLinkWriter(object):
+ def get_link(self, base, path):
+ pass
+
+class NoLinkWriter(AbstractLinkWriter):
+ def get_link(self, base, path):
+ return ''
+
+class LinkWriter(AbstractLinkWriter):
+ def __init__(self, baseurl):
+ self.baseurl = baseurl
+
+ def get_link(self, base, path):
+ relpath = path.relto(base)
+ return self.baseurl + relpath
+
+class RelLinkWriter(AbstractLinkWriter):
+ def get_link(self, base, path):
+ return path.relto(base)
+
Modified: py/dist/py/test/rsession/testing/test_rest.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rest.py (original)
+++ py/dist/py/test/rsession/testing/test_rest.py Thu Nov 23 11:43:24 2006
@@ -4,7 +4,8 @@
import py
from py.__.test.rsession.testing.test_reporter import AbstractTestReporter
-from py.__.test.rsession.rest import RestReporter
+from py.__.test.rsession import report
+from py.__.test.rsession.rest import RestReporter, NoLinkWriter
from py.__.rest.rst import *
class RestTestReporter(RestReporter):
@@ -16,6 +17,12 @@
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
+class FakeOutcome(Container, report.ReceivedItemOutcome):
+ pass
+
+class FakeTryiter(Container, report.SkippedTryiter):
+ pass
+
class TestRestUnits(object):
def setup_method(self, method):
config, args = py.test.Config.parse(["some_sub"])
@@ -24,6 +31,7 @@
['localhost'])
method.im_func.func_globals['stdout'] = s = py.std.StringIO.StringIO()
r.out = s # XXX will need to become a real reporter some time perhaps?
+ r.linkwriter = NoLinkWriter()
def test_report_unknown(self):
reporter.report_unknown('foo')
@@ -63,13 +71,15 @@
def test_report_ItemStart(self):
class FakeModule(py.test.collect.Module):
- def __init__(self):
- pass
+ def __init__(self, parent):
+ self.parent = parent
+ self.fspath = py.path.local('.')
def tryiter(self):
return ['test_foo', 'test_bar']
def listnames(self):
- return ['foo', 'bar.py']
- event = Container(item=FakeModule())
+ return ['package', 'foo', 'bar.py']
+ parent = Container(parent=None, fspath=py.path.local('.'))
+ event = Container(item=FakeModule(parent))
reporter.report_ItemStart(event)
assert stdout.getvalue() == """\
Testing module foo/bar.py (2 items)
@@ -105,31 +115,148 @@
'foo.py/bar()/baz\n\n')
def test_ReceivedItemOutcome_FAILED(self):
- excinfo = Container(typename='FooError', value='a foo has occurred',
- traceback=[' in foo in line 1, in foo:',
- ' bar()',
- ' in bar in line 4, in bar:',
- (' raise FooError("a foo has '
- 'occurred")')])
- outcome = Container(passed=False, skipped=False, excinfo=excinfo)
+ outcome = Container(passed=False, skipped=False)
item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'])
event = Container(channel=False, outcome=outcome, item=item)
reporter.report_ReceivedItemOutcome(event)
assert stdout.getvalue() == """\
* localhost\: **FAILED** foo.py/bar()/baz
-exception\: **FooError**
+"""
+
+ def test_skips(self):
+ reporter.skips()
+ assert stdout.getvalue() == ''
+ reporter.skipped_tests_outcome = [
+ FakeOutcome(outcome=Container(skipped='problem X'),
+ item=Container(listnames=lambda: ['foo', 'bar.py'])),
+ FakeTryiter(excinfo=Container(value='problem Y'),
+ item=Container(listnames=lambda: ['foo', 'baz.py']))]
+ reporter.skips()
+ assert stdout.getvalue() == """\
+Reasons for skipped tests\:
++++++++++++++++++++++++++++
+
+* foo/bar.py\: problem X
+
+* foo/baz.py\: problem Y
+
+"""
+
+ def test_failures(self):
+ parent = Container(parent=None, fspath=py.path.local('.'))
+ reporter.failed_tests_outcome = [
+ FakeOutcome(
+ outcome=Container(
+ signal=False,
+ excinfo=Container(
+ typename='FooError',
+ value='A foo has occurred',
+ traceback=[
+ Container(
+ path='foo/bar.py',
+ lineno=1,
+ relline=1,
+ source='foo()',
+ ),
+ Container(
+ path='foo/baz.py',
+ lineno=4,
+ relline=1,
+ source='raise FooError("A foo has occurred")',
+ ),
+ ]
+ ),
+ stdout='',
+ stderr='',
+ ),
+ item=Container(
+ listnames=lambda: ['package', 'foo', 'bar.py',
+ 'baz', '()'],
+ parent=parent,
+ fspath=py.path.local('.'),
+ ),
+ channel=None,
+ ),
+ ]
+ reporter.config.option.tbstyle = 'no'
+ reporter.failures()
+ assert stdout.getvalue() == """\
+Exceptions\:
+++++++++++++
+
+foo/bar.py/baz() on localhost
++++++++++++++++++++++++++++++
+
+FooError
+++++++++
::
- a foo has occurred
+ A foo has occurred
+
+"""
+
+ reporter.config.option.tbstyle = 'short'
+ stdout.seek(0)
+ stdout.truncate()
+ reporter.failures()
+ assert stdout.getvalue() == """\
+Exceptions\:
+++++++++++++
+
+foo/bar.py/baz() on localhost
++++++++++++++++++++++++++++++
+
+::
+
+ foo/bar.py line 1
+ foo()
+ foo/baz.py line 4
+ raise FooError("A foo has occurred")
+
+FooError
+++++++++
::
- in foo in line 1, in foo:
- bar()
- in bar in line 4, in bar:
- raise FooError("a foo has occurred")
+ A foo has occurred
+
+"""
+
+ reporter.config.option.tbstyle = 'long'
+ stdout.seek(0)
+ stdout.truncate()
+ reporter.failures()
+ stdout.getvalue() == """\
+Exceptions\:
+++++++++++++
+
+foo/bar.py/baz() on localhost
++++++++++++++++++++++++++++++
+
++++++++++++++++++
+foo/bar.py line 1
++++++++++++++++++
+
+::
+
+ foo()
+
++++++++++++++++++
+foo/baz.py line 4
++++++++++++++++++
+
+::
+
+ raise FooError("A foo has occurred")
+
+FooError
+++++++++
+
+::
+
+ A foo has occurred
"""
@@ -141,34 +268,16 @@
def test_report_received_item_outcome(self):
val = self.report_received_item_outcome()
- expected = """- localhost\\: FAILED py test rsession testing test\\_slave.py funcpass
-- localhost\\: SKIPPED py test rsession testing test\\_slave.py funcpass
-- localhost\\: FAILED py test rsession testing test\\_slave.py funcpass
-- localhost\\: PASSED py test rsession testing test\\_slave.py funcpass
-"""
- print repr(val)
- expected_start = """\
+ expected = """\
* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass
* localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass
* localhost\: **FAILED** py/test/rsession/testing/test\_slave.py/funcpass
-exception\\: **ZeroDivisionError**
-
-::
-
- integer division or modulo by zero
-
-::
-
-"""
-
- expected_end = """
-
* localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass
"""
- assert val.startswith(expected_start)
- assert val.endswith(expected_end)
+ print val
+ assert val == expected
More information about the pytest-commit
mailing list