fix issue30 - better handling and reporting of errors in xfail expressions

This commit is contained in:
holger krekel 2011-03-03 12:19:17 +01:00
parent 6f3b84da9f
commit 682773e0cb
4 changed files with 70 additions and 15 deletions

View File

@ -1,10 +1,13 @@
Changes between 2.0.1 and 2.0.2
----------------------------------------------
- fix issue30 - better handling and error reporting for errors in xfail
expressions
- fix issue28 - setup_method and pytest_generate_tests work together
- fix issue24 - pytest_assertrepr_compare produces an in-line
exception on python3
- fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP
(which apparently starts to offer os.symlink now)
- fixed some typos in the docs (thanks Victor)

View File

@ -1,6 +1,7 @@
""" support for skip/xfail functions and markers. """
import py, pytest
import sys
def pytest_addoption(parser):
group = parser.getgroup("general")
@ -32,7 +33,28 @@ class MarkEvaluator:
return bool(self.holder)
__nonzero__ = __bool__
def wasvalid(self):
return not hasattr(self, 'exc')
def istrue(self):
try:
return self._istrue()
except KeyboardInterrupt:
raise
except:
self.exc = sys.exc_info()
if isinstance(self.exc[1], SyntaxError):
msg = [" " * (self.exc[1].offset + 4) + "^",]
msg.append("SyntaxError: invalid syntax")
else:
msg = py.std.traceback.format_exception_only(*self.exc[:2])
pytest.fail("Error evaluating %r expression\n"
" %s\n"
"%s"
%(self.name, self.expr, "\n".join(msg)),
pytrace=False)
def _istrue(self):
if self.holder:
d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config}
if self.holder.args:
@ -99,16 +121,17 @@ def pytest_runtest_makereport(__multicall__, item, call):
return rep
rep = __multicall__.execute()
evalxfail = item._evalxfail
if not item.config.option.runxfail and evalxfail.istrue():
if call.excinfo:
rep.outcome = "skipped"
rep.keywords['xfail'] = evalxfail.getexplanation()
elif call.when == "call":
rep.outcome = "failed"
rep.keywords['xfail'] = evalxfail.getexplanation()
else:
if 'xfail' in rep.keywords:
del rep.keywords['xfail']
if not item.config.option.runxfail:
if evalxfail.wasvalid() and evalxfail.istrue():
if call.excinfo:
rep.outcome = "skipped"
rep.keywords['xfail'] = evalxfail.getexplanation()
elif call.when == "call":
rep.outcome = "failed"
rep.keywords['xfail'] = evalxfail.getexplanation()
return rep
if 'xfail' in rep.keywords:
del rep.keywords['xfail']
return rep
# called by terminalreporter progress reporting
@ -179,7 +202,8 @@ def cached_eval(config, expr, d):
except KeyError:
#import sys
#print >>sys.stderr, ("cache-miss: %r" % expr)
config._evalcache[expr] = x = eval(expr, d)
exprcode = py.code.compile(expr, mode="eval")
config._evalcache[expr] = x = eval(exprcode, d)
return x

View File

@ -29,7 +29,7 @@ def main():
author='holger krekel, Guido Wesdorp, Carl Friedrich Bolz, Armin Rigo, Maciej Fijalkowski & others',
author_email='holger at merlinux.eu',
entry_points= make_entry_points(),
install_requires=['py>1.4.0'],
install_requires=['py>1.4.1'],
classifiers=['Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
@ -67,4 +67,4 @@ def make_entry_points():
return {'console_scripts': l}
if __name__ == '__main__':
main()
main()

View File

@ -470,3 +470,31 @@ def test_reportchars(testdir):
"XPASS*test_3*",
"SKIP*four*",
])
def test_errors_in_xfail_skip_expressions(testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.skipif("asd")
def test_nameerror():
pass
@pytest.mark.xfail("syntax error")
def test_syntax():
pass
def test_func():
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*ERROR*test_nameerror*",
"*evaluating*skipif*expression*",
"*asd*",
"*ERROR*test_syntax*",
"*evaluating*xfail*expression*",
" syntax error",
" ^",
"SyntaxError: invalid syntax",
"*1 pass*2 error*",
])