From f3bc197afbe9201ea8b867e151499520d55678eb Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 12 Jul 2011 23:09:03 +0200 Subject: [PATCH] fix #59: provide better Jenkins stdout and stderr sections --- CHANGELOG | 1 + _pytest/__init__.py | 2 +- _pytest/capture.py | 5 +---- _pytest/junitxml.py | 12 ++++++++++-- _pytest/runner.py | 10 ++++++++-- _pytest/terminal.py | 12 ++++++++++-- setup.py | 4 ++-- testing/test_junitxml.py | 13 ++++++++++++- testing/test_terminal.py | 11 +++++++---- 9 files changed, 52 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d6364592d..6e58daac3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Changes between 2.1.0 and 2.1.1.DEV ---------------------------------------------- +- fix issue59: provide system-out/err tags for junitxml output - fix assertion rewriting on boolean operations with 3 or more operands Changes between 2.0.3 and 2.1.0.DEV diff --git a/_pytest/__init__.py b/_pytest/__init__.py index c6fa1adc5..3238a6f70 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.1.1.dev1' +__version__ = '2.1.1.dev2' diff --git a/_pytest/capture.py b/_pytest/capture.py index b7594be31..f26e31731 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -12,12 +12,9 @@ def pytest_addoption(parser): help="shortcut for --capture=no.") def addouterr(rep, outerr): - repr = getattr(rep, 'longrepr', None) - if not hasattr(repr, 'addsection'): - return for secname, content in zip(["out", "err"], outerr): if content: - repr.addsection("Captured std%s" % secname, content.rstrip()) + rep.sections.append(("Captured std%s" % secname, content)) def pytest_unconfigure(config): # registered in config.py during early conftest.py loading diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index c7a089cce..31aeb2343 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -114,8 +114,16 @@ class LogXML(object): '') self.skipped += 1 else: - self.appendlog('%s', - report.longrepr) + sec = dict(report.sections) + fmt = '%s' + args = [report.longrepr] + for name in ('out', 'err'): + content = sec.get("Captured std%s" % name) + if content: + fmt += "%%s" % (name, name) + args.append(content) + fmt += "" + self.appendlog(fmt, *args) self.failed += 1 self._closetestcase() diff --git a/_pytest/runner.py b/_pytest/runner.py index c1b73e94c..be34bb72c 100644 --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -167,7 +167,7 @@ class TestReport(BaseReport): they fail). """ def __init__(self, nodeid, location, - keywords, outcome, longrepr, when): + keywords, outcome, longrepr, when, sections=()): #: normalized collection node id self.nodeid = nodeid @@ -189,6 +189,10 @@ class TestReport(BaseReport): #: one of 'setup', 'call', 'teardown' to indicate runtest phase. self.when = when + #: list of (secname, data) extra information which needs to + #: marshallable + self.sections = list(sections) + def __repr__(self): return "" % ( self.nodeid, self.when, self.outcome) @@ -198,6 +202,7 @@ class TeardownErrorReport(BaseReport): when = "teardown" def __init__(self, longrepr): self.longrepr = longrepr + self.sections = [] def pytest_make_collect_report(collector): call = CallInfo(collector._memocollect, "memocollect") @@ -219,11 +224,12 @@ def pytest_make_collect_report(collector): getattr(call, 'result', None)) class CollectReport(BaseReport): - def __init__(self, nodeid, outcome, longrepr, result): + def __init__(self, nodeid, outcome, longrepr, result, sections=()): self.nodeid = nodeid self.outcome = outcome self.longrepr = longrepr self.result = result or [] + self.sections = list(sections) @property def location(self): diff --git a/_pytest/terminal.py b/_pytest/terminal.py index 03b6e8c83..f8b3244ff 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -393,7 +393,7 @@ class TerminalReporter: else: msg = self._getfailureheadline(rep) self.write_sep("_", msg) - rep.toterminal(self._tw) + self._outrep_summary(rep) def summary_errors(self): if self.config.option.tbstyle != "no": @@ -411,7 +411,15 @@ class TerminalReporter: elif rep.when == "teardown": msg = "ERROR at teardown of " + msg self.write_sep("_", msg) - rep.toterminal(self._tw) + self._outrep_summary(rep) + + def _outrep_summary(self, rep): + rep.toterminal(self._tw) + for secname, content in rep.sections: + self._tw.sep("-", secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) def summary_stats(self): session_duration = py.std.time.time() - self._sessionstarttime diff --git a/setup.py b/setup.py index 1a2e3e6f2..fd5688ad8 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.1.1.dev1', + version='2.1.1.dev2', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], @@ -32,7 +32,7 @@ def main(): author_email='holger at merlinux.eu', entry_points= make_entry_points(), # the following should be enabled for release - install_requires=['py>=1.4.4'], + install_requires=['py>=1.4.5.dev1'], classifiers=['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 8ca6c01ce..96efb6fca 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -131,7 +131,14 @@ class TestPython: assert "Division" in fnode.toxml() def test_failure_function(self, testdir): - testdir.makepyfile("def test_fail(): raise ValueError(42)") + testdir.makepyfile(""" + import sys + def test_fail(): + print ("hello-stdout") + sys.stderr.write("hello-stderr\\n") + raise ValueError(42) + """) + result, dom = runandparse(testdir) assert result.ret node = dom.getElementsByTagName("testsuite")[0] @@ -143,6 +150,10 @@ class TestPython: fnode = tnode.getElementsByTagName("failure")[0] assert_attr(fnode, message="test failure") assert "ValueError" in fnode.toxml() + systemout = fnode.getElementsByTagName("system-out")[0] + assert "hello-stdout" in systemout.toxml() + systemerr = fnode.getElementsByTagName("system-err")[0] + assert "hello-stderr" in systemerr.toxml() def test_failure_escape(self, testdir): testdir.makepyfile(""" diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 317f2e932..584faf94c 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -258,10 +258,13 @@ class TestCollectonly: def test_repr_python_version(monkeypatch): - monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0)) - assert repr_pythonversion() == "2.5.1-final-0" - py.std.sys.version_info = x = (2,3) - assert repr_pythonversion() == str(x) + try: + monkeypatch.setattr(sys, 'version_info', (2, 5, 1, 'final', 0)) + assert repr_pythonversion() == "2.5.1-final-0" + py.std.sys.version_info = x = (2,3) + assert repr_pythonversion() == str(x) + finally: + monkeypatch.undo() # do this early as pytest can get confused class TestFixtureReporting: def test_setup_fixture_error(self, testdir):