Merge pull request #6521 from blueyed/harden-nose-raises
tests: improve test for `nose.raises`
This commit is contained in:
commit
6b13379f37
|
@ -307,7 +307,7 @@ def get_real_method(obj, holder):
|
|||
return obj
|
||||
|
||||
|
||||
def getfslineno(obj):
|
||||
def getfslineno(obj) -> Tuple[Union[str, py.path.local], int]:
|
||||
# xxx let decorators etc specify a sane ordering
|
||||
obj = get_real_func(obj)
|
||||
if hasattr(obj, "place_as"):
|
||||
|
|
|
@ -82,8 +82,8 @@ class Parser:
|
|||
|
||||
self.optparser = self._getparser()
|
||||
try_argcomplete(self.optparser)
|
||||
args = [str(x) if isinstance(x, py.path.local) else x for x in args]
|
||||
return self.optparser.parse_args(args, namespace=namespace)
|
||||
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args]
|
||||
return self.optparser.parse_args(strargs, namespace=namespace)
|
||||
|
||||
def _getparser(self) -> "MyOptionParser":
|
||||
from _pytest._argcomplete import filescompleter
|
||||
|
@ -124,8 +124,8 @@ class Parser:
|
|||
the remaining arguments unknown at this point.
|
||||
"""
|
||||
optparser = self._getparser()
|
||||
args = [str(x) if isinstance(x, py.path.local) else x for x in args]
|
||||
return optparser.parse_known_args(args, namespace=namespace)
|
||||
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args]
|
||||
return optparser.parse_known_args(strargs, namespace=namespace)
|
||||
|
||||
def addini(self, name, help, type=None, default=None):
|
||||
""" register an ini-file option.
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import os
|
||||
from typing import Any
|
||||
from typing import Iterable
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
|
||||
import py
|
||||
|
||||
|
@ -60,7 +63,7 @@ def getcfg(args, config=None):
|
|||
return None, None, None
|
||||
|
||||
|
||||
def get_common_ancestor(paths):
|
||||
def get_common_ancestor(paths: Iterable[py.path.local]) -> py.path.local:
|
||||
common_ancestor = None
|
||||
for path in paths:
|
||||
if not path.exists():
|
||||
|
@ -113,7 +116,7 @@ def determine_setup(
|
|||
args: List[str],
|
||||
rootdir_cmd_arg: Optional[str] = None,
|
||||
config: Optional["Config"] = None,
|
||||
):
|
||||
) -> Tuple[py.path.local, Optional[str], Any]:
|
||||
dirs = get_dirs_from_args(args)
|
||||
if inifile:
|
||||
iniconfig = py.iniconfig.IniConfig(inifile)
|
||||
|
|
|
@ -308,7 +308,7 @@ class DoctestItem(pytest.Item):
|
|||
else:
|
||||
return super().repr_failure(excinfo)
|
||||
|
||||
def reportinfo(self) -> Tuple[str, int, str]:
|
||||
def reportinfo(self) -> Tuple[py.path.local, int, str]:
|
||||
return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name
|
||||
|
||||
|
||||
|
|
|
@ -351,7 +351,7 @@ class FixtureRequest:
|
|||
self.fixturename = None
|
||||
#: Scope string, one of "function", "class", "module", "session"
|
||||
self.scope = "function"
|
||||
self._fixture_defs = {} # argname -> FixtureDef
|
||||
self._fixture_defs = {} # type: Dict[str, FixtureDef]
|
||||
fixtureinfo = pyfuncitem._fixtureinfo
|
||||
self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
|
||||
self._arg2index = {}
|
||||
|
@ -426,7 +426,8 @@ class FixtureRequest:
|
|||
@scopeproperty()
|
||||
def fspath(self) -> py.path.local:
|
||||
""" the file system path of the test module which collected this test. """
|
||||
return self._pyfuncitem.fspath
|
||||
# TODO: Remove ignore once _pyfuncitem is properly typed.
|
||||
return self._pyfuncitem.fspath # type: ignore
|
||||
|
||||
@property
|
||||
def keywords(self):
|
||||
|
@ -549,7 +550,9 @@ class FixtureRequest:
|
|||
source_lineno = frameinfo.lineno
|
||||
source_path = py.path.local(source_path)
|
||||
if source_path.relto(funcitem.config.rootdir):
|
||||
source_path = source_path.relto(funcitem.config.rootdir)
|
||||
source_path_str = source_path.relto(funcitem.config.rootdir)
|
||||
else:
|
||||
source_path_str = str(source_path)
|
||||
msg = (
|
||||
"The requested fixture has no parameter defined for test:\n"
|
||||
" {}\n\n"
|
||||
|
@ -558,7 +561,7 @@ class FixtureRequest:
|
|||
funcitem.nodeid,
|
||||
fixturedef.argname,
|
||||
getlocation(fixturedef.func, funcitem.config.rootdir),
|
||||
source_path,
|
||||
source_path_str,
|
||||
source_lineno,
|
||||
)
|
||||
)
|
||||
|
|
|
@ -376,9 +376,9 @@ class Failed(Exception):
|
|||
|
||||
@attr.s
|
||||
class _bestrelpath_cache(dict):
|
||||
path = attr.ib()
|
||||
path = attr.ib(type=py.path.local)
|
||||
|
||||
def __missing__(self, path: str) -> str:
|
||||
def __missing__(self, path: py.path.local) -> str:
|
||||
r = self.path.bestrelpath(path) # type: str
|
||||
self[path] = r
|
||||
return r
|
||||
|
@ -412,7 +412,7 @@ class Session(nodes.FSCollector):
|
|||
|
||||
self._bestrelpathcache = _bestrelpath_cache(
|
||||
config.rootdir
|
||||
) # type: Dict[str, str]
|
||||
) # type: Dict[py.path.local, str]
|
||||
|
||||
self.config.pluginmanager.register(self, name="session")
|
||||
|
||||
|
@ -425,7 +425,7 @@ class Session(nodes.FSCollector):
|
|||
self.testscollected,
|
||||
)
|
||||
|
||||
def _node_location_to_relpath(self, node_path: str) -> str:
|
||||
def _node_location_to_relpath(self, node_path: py.path.local) -> str:
|
||||
# bestrelpath is a quite slow function
|
||||
return self._bestrelpathcache[node_path]
|
||||
|
||||
|
|
|
@ -462,6 +462,10 @@ class Item(Node):
|
|||
@cached_property
|
||||
def location(self) -> Tuple[str, Optional[int], str]:
|
||||
location = self.reportinfo()
|
||||
fspath = self.session._node_location_to_relpath(location[0])
|
||||
if isinstance(location[0], py.path.local):
|
||||
fspath = location[0]
|
||||
else:
|
||||
fspath = py.path.local(location[0])
|
||||
relfspath = self.session._node_location_to_relpath(fspath)
|
||||
assert type(location[2]) is str
|
||||
return (fspath, location[1], location[2])
|
||||
return (relfspath, location[1], location[2])
|
||||
|
|
|
@ -12,6 +12,7 @@ from functools import partial
|
|||
from textwrap import dedent
|
||||
from typing import List
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
import py
|
||||
|
||||
|
@ -280,15 +281,16 @@ class PyobjMixin(PyobjContext):
|
|||
parts.reverse()
|
||||
return ".".join(parts)
|
||||
|
||||
def reportinfo(self) -> Tuple[str, int, str]:
|
||||
def reportinfo(self) -> Tuple[Union[py.path.local, str], int, str]:
|
||||
# XXX caching?
|
||||
obj = self.obj
|
||||
compat_co_firstlineno = getattr(obj, "compat_co_firstlineno", None)
|
||||
if isinstance(compat_co_firstlineno, int):
|
||||
# nose compatibility
|
||||
fspath = sys.modules[obj.__module__].__file__
|
||||
if fspath.endswith(".pyc"):
|
||||
fspath = fspath[:-1]
|
||||
file_path = sys.modules[obj.__module__].__file__
|
||||
if file_path.endswith(".pyc"):
|
||||
file_path = file_path[:-1]
|
||||
fspath = file_path # type: Union[py.path.local, str]
|
||||
lineno = compat_co_firstlineno
|
||||
else:
|
||||
fspath, lineno = getfslineno(obj)
|
||||
|
@ -367,7 +369,12 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
|||
if not isinstance(res, list):
|
||||
res = [res]
|
||||
values.extend(res)
|
||||
values.sort(key=lambda item: item.reportinfo()[:2])
|
||||
|
||||
def sort_key(item):
|
||||
fspath, lineno, _ = item.reportinfo()
|
||||
return (str(fspath), lineno)
|
||||
|
||||
values.sort(key=sort_key)
|
||||
return values
|
||||
|
||||
def _makeitem(self, name, obj):
|
||||
|
|
|
@ -377,15 +377,48 @@ def test_skip_test_with_unicode(testdir):
|
|||
result.stdout.fnmatch_lines(["* 1 skipped *"])
|
||||
|
||||
|
||||
def test_issue_6517(testdir):
|
||||
def test_raises(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
from nose.tools import raises
|
||||
|
||||
@raises(RuntimeError)
|
||||
def test_fail_without_tcp():
|
||||
def test_raises_runtimeerror():
|
||||
raise RuntimeError
|
||||
|
||||
@raises(Exception)
|
||||
def test_raises_baseexception_not_caught():
|
||||
raise BaseException
|
||||
|
||||
@raises(BaseException)
|
||||
def test_raises_baseexception_caught():
|
||||
raise BaseException
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(["* 1 passed *"])
|
||||
result = testdir.runpytest("-vv")
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"test_raises.py::test_raises_runtimeerror PASSED*",
|
||||
"test_raises.py::test_raises_baseexception_not_caught FAILED*",
|
||||
"test_raises.py::test_raises_baseexception_caught PASSED*",
|
||||
"*= FAILURES =*",
|
||||
"*_ test_raises_baseexception_not_caught _*",
|
||||
"",
|
||||
"arg = (), kw = {}",
|
||||
"",
|
||||
" def newfunc(*arg, **kw):",
|
||||
" try:",
|
||||
"> func(*arg, **kw)",
|
||||
"",
|
||||
"*/nose/*: ",
|
||||
"_ _ *",
|
||||
"",
|
||||
" @raises(Exception)",
|
||||
" def test_raises_baseexception_not_caught():",
|
||||
"> raise BaseException",
|
||||
"E BaseException",
|
||||
"",
|
||||
"test_raises.py:9: BaseException",
|
||||
"* 1 failed, 2 passed *",
|
||||
]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue