Merge remote-tracking branch 'origin/master' into issue_7295

This commit is contained in:
Gleb Nikonorov
2020-06-23 23:21:36 -04:00
31 changed files with 587 additions and 423 deletions

View File

@@ -585,11 +585,11 @@ class TestInvocationVariants:
# Type ignored because `py.test` is not and will not be typed.
assert pytest.main == py.test.cmdline.main # type: ignore[attr-defined]
def test_invoke_with_invalid_type(self):
def test_invoke_with_invalid_type(self) -> None:
with pytest.raises(
TypeError, match="expected to be a list of strings, got: '-h'"
):
pytest.main("-h")
pytest.main("-h") # type: ignore[arg-type]
def test_invoke_with_path(self, tmpdir, capsys):
retcode = pytest.main(tmpdir)

View File

@@ -372,7 +372,7 @@ def test_excinfo_no_python_sourcecode(tmpdir):
for item in excinfo.traceback:
print(item) # XXX: for some reason jinja.Template.render is printed in full
item.source # shouldn't fail
if item.path.basename == "test.txt":
if isinstance(item.path, py.path.local) and item.path.basename == "test.txt":
assert str(item.source) == "{{ h()}}:"

View File

@@ -11,6 +11,7 @@ import py.path
import _pytest._code
import pytest
from _pytest.compat import importlib_metadata
from _pytest.config import _get_plugin_specs_as_list
from _pytest.config import _iter_rewritable_modules
from _pytest.config import Config
from _pytest.config import ConftestImportFailure
@@ -1119,21 +1120,17 @@ def test_load_initial_conftest_last_ordering(_config_for_test):
assert [x.function.__module__ for x in values] == expected
def test_get_plugin_specs_as_list():
from _pytest.config import _get_plugin_specs_as_list
def exp_match(val):
def test_get_plugin_specs_as_list() -> None:
def exp_match(val: object) -> str:
return (
"Plugin specs must be a ','-separated string"
" or a list/tuple of strings for plugin names. Given: {}".format(
re.escape(repr(val))
)
"Plugins may be specified as a sequence or a ','-separated string of plugin names. Got: %s"
% re.escape(repr(val))
)
with pytest.raises(pytest.UsageError, match=exp_match({"foo"})):
_get_plugin_specs_as_list({"foo"})
_get_plugin_specs_as_list({"foo"}) # type: ignore[arg-type]
with pytest.raises(pytest.UsageError, match=exp_match({})):
_get_plugin_specs_as_list(dict())
_get_plugin_specs_as_list(dict()) # type: ignore[arg-type]
assert _get_plugin_specs_as_list(None) == []
assert _get_plugin_specs_as_list("") == []
@@ -1782,5 +1779,7 @@ def test_conftest_import_error_repr(tmpdir):
):
try:
raise RuntimeError("some error")
except Exception:
raise ConftestImportFailure(path, sys.exc_info())
except Exception as exc:
assert exc.__traceback__ is not None
exc_info = (type(exc), exc, exc.__traceback__)
raise ConftestImportFailure(path, exc_info) from exc

View File

@@ -266,7 +266,7 @@ class TestPython:
@pytest.fixture
def arg(request):
raise ValueError()
raise ValueError("Error reason")
def test_function(arg):
pass
"""
@@ -278,7 +278,7 @@ class TestPython:
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(classname="test_setup_error", name="test_function")
fnode = tnode.find_first_by_tag("error")
fnode.assert_attr(message="test setup failure")
fnode.assert_attr(message='failed on setup with "ValueError: Error reason"')
assert "ValueError" in fnode.toxml()
@parametrize_families
@@ -290,7 +290,7 @@ class TestPython:
@pytest.fixture
def arg():
yield
raise ValueError()
raise ValueError('Error reason')
def test_function(arg):
pass
"""
@@ -301,7 +301,7 @@ class TestPython:
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(classname="test_teardown_error", name="test_function")
fnode = tnode.find_first_by_tag("error")
fnode.assert_attr(message="test teardown failure")
fnode.assert_attr(message='failed on teardown with "ValueError: Error reason"')
assert "ValueError" in fnode.toxml()
@parametrize_families
@@ -328,7 +328,9 @@ class TestPython:
fnode = first.find_first_by_tag("failure")
fnode.assert_attr(message="Exception: Call Exception")
snode = second.find_first_by_tag("error")
snode.assert_attr(message="test teardown failure")
snode.assert_attr(
message='failed on teardown with "Exception: Teardown Exception"'
)
@parametrize_families
def test_skip_contains_name_reason(self, testdir, run_and_parse, xunit_family):

View File

@@ -534,8 +534,8 @@ def test_outcomeexception_passes_except_Exception() -> None:
with pytest.raises(outcomes.OutcomeException):
try:
raise outcomes.OutcomeException("test")
except Exception:
raise NotImplementedError()
except Exception as e:
raise NotImplementedError from e
def test_pytest_exit() -> None:

View File

@@ -2,68 +2,74 @@ import sys
import pytest
from _pytest.runner import runtestprotocol
from _pytest.skipping import MarkEvaluator
from _pytest.skipping import evaluate_skip_marks
from _pytest.skipping import evaluate_xfail_marks
from _pytest.skipping import pytest_runtest_setup
class TestEvaluator:
class TestEvaluation:
def test_no_marker(self, testdir):
item = testdir.getitem("def test_func(): pass")
evalskipif = MarkEvaluator(item, "skipif")
assert not evalskipif
assert not evalskipif.istrue()
skipped = evaluate_skip_marks(item)
assert not skipped
def test_marked_no_args(self, testdir):
def test_marked_xfail_no_args(self, testdir):
item = testdir.getitem(
"""
import pytest
@pytest.mark.xyz
@pytest.mark.xfail
def test_func():
pass
"""
)
ev = MarkEvaluator(item, "xyz")
assert ev
assert ev.istrue()
expl = ev.getexplanation()
assert expl == ""
assert not ev.get("run", False)
xfailed = evaluate_xfail_marks(item)
assert xfailed
assert xfailed.reason == ""
assert xfailed.run
def test_marked_skipif_no_args(self, testdir):
item = testdir.getitem(
"""
import pytest
@pytest.mark.skipif
def test_func():
pass
"""
)
skipped = evaluate_skip_marks(item)
assert skipped
assert skipped.reason == ""
def test_marked_one_arg(self, testdir):
item = testdir.getitem(
"""
import pytest
@pytest.mark.xyz("hasattr(os, 'sep')")
@pytest.mark.skipif("hasattr(os, 'sep')")
def test_func():
pass
"""
)
ev = MarkEvaluator(item, "xyz")
assert ev
assert ev.istrue()
expl = ev.getexplanation()
assert expl == "condition: hasattr(os, 'sep')"
skipped = evaluate_skip_marks(item)
assert skipped
assert skipped.reason == "condition: hasattr(os, 'sep')"
def test_marked_one_arg_with_reason(self, testdir):
item = testdir.getitem(
"""
import pytest
@pytest.mark.xyz("hasattr(os, 'sep')", attr=2, reason="hello world")
@pytest.mark.skipif("hasattr(os, 'sep')", attr=2, reason="hello world")
def test_func():
pass
"""
)
ev = MarkEvaluator(item, "xyz")
assert ev
assert ev.istrue()
expl = ev.getexplanation()
assert expl == "hello world"
assert ev.get("attr") == 2
skipped = evaluate_skip_marks(item)
assert skipped
assert skipped.reason == "hello world"
def test_marked_one_arg_twice(self, testdir):
lines = [
"""@pytest.mark.skipif("not hasattr(os, 'murks')")""",
"""@pytest.mark.skipif("hasattr(os, 'murks')")""",
"""@pytest.mark.skipif(condition="hasattr(os, 'murks')")""",
]
for i in range(0, 2):
item = testdir.getitem(
@@ -76,11 +82,9 @@ class TestEvaluator:
"""
% (lines[i], lines[(i + 1) % 2])
)
ev = MarkEvaluator(item, "skipif")
assert ev
assert ev.istrue()
expl = ev.getexplanation()
assert expl == "condition: not hasattr(os, 'murks')"
skipped = evaluate_skip_marks(item)
assert skipped
assert skipped.reason == "condition: not hasattr(os, 'murks')"
def test_marked_one_arg_twice2(self, testdir):
item = testdir.getitem(
@@ -92,13 +96,11 @@ class TestEvaluator:
pass
"""
)
ev = MarkEvaluator(item, "skipif")
assert ev
assert ev.istrue()
expl = ev.getexplanation()
assert expl == "condition: not hasattr(os, 'murks')"
skipped = evaluate_skip_marks(item)
assert skipped
assert skipped.reason == "condition: not hasattr(os, 'murks')"
def test_marked_skip_with_not_string(self, testdir) -> None:
def test_marked_skipif_with_boolean_without_reason(self, testdir) -> None:
item = testdir.getitem(
"""
import pytest
@@ -107,14 +109,34 @@ class TestEvaluator:
pass
"""
)
ev = MarkEvaluator(item, "skipif")
exc = pytest.raises(pytest.fail.Exception, ev.istrue)
assert exc.value.msg is not None
with pytest.raises(pytest.fail.Exception) as excinfo:
evaluate_skip_marks(item)
assert excinfo.value.msg is not None
assert (
"""Failed: you need to specify reason=STRING when using booleans as conditions."""
in exc.value.msg
"""Error evaluating 'skipif': you need to specify reason=STRING when using booleans as conditions."""
in excinfo.value.msg
)
def test_marked_skipif_with_invalid_boolean(self, testdir) -> None:
item = testdir.getitem(
"""
import pytest
class InvalidBool:
def __bool__(self):
raise TypeError("INVALID")
@pytest.mark.skipif(InvalidBool(), reason="xxx")
def test_func():
pass
"""
)
with pytest.raises(pytest.fail.Exception) as excinfo:
evaluate_skip_marks(item)
assert excinfo.value.msg is not None
assert "Error evaluating 'skipif' condition as a boolean" in excinfo.value.msg
assert "INVALID" in excinfo.value.msg
def test_skipif_class(self, testdir):
(item,) = testdir.getitems(
"""
@@ -126,10 +148,9 @@ class TestEvaluator:
"""
)
item.config._hackxyz = 3
ev = MarkEvaluator(item, "skipif")
assert ev.istrue()
expl = ev.getexplanation()
assert expl == "condition: config._hackxyz"
skipped = evaluate_skip_marks(item)
assert skipped
assert skipped.reason == "condition: config._hackxyz"
class TestXFail:
@@ -895,10 +916,10 @@ def test_errors_in_xfail_skip_expressions(testdir) -> None:
result.stdout.fnmatch_lines(
[
"*ERROR*test_nameerror*",
"*evaluating*skipif*expression*",
"*evaluating*skipif*condition*",
"*asd*",
"*ERROR*test_syntax*",
"*evaluating*xfail*expression*",
"*evaluating*xfail*condition*",
" syntax error",
markline,
"SyntaxError: invalid syntax",
@@ -924,25 +945,12 @@ def test_xfail_skipif_with_globals(testdir):
result.stdout.fnmatch_lines(["*SKIP*x == 3*", "*XFAIL*test_boolean*", "*x == 3*"])
def test_direct_gives_error(testdir):
testdir.makepyfile(
"""
import pytest
@pytest.mark.skipif(True)
def test_skip1():
pass
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*1 error*"])
def test_default_markers(testdir):
result = testdir.runpytest("--markers")
result.stdout.fnmatch_lines(
[
"*skipif(*condition)*skip*",
"*xfail(*condition, reason=None, run=True, raises=None, strict=False)*expected failure*",
"*skipif(condition, ..., [*], reason=...)*skip*",
"*xfail(condition, ..., [*], reason=..., run=True, raises=None, strict=xfail_strict)*expected failure*",
]
)
@@ -1137,7 +1145,9 @@ def test_mark_xfail_item(testdir):
class MyItem(pytest.Item):
nodeid = 'foo'
def setup(self):
marker = pytest.mark.xfail(True, reason="Expected failure")
marker = pytest.mark.xfail("1 == 2", reason="Expected failure - false")
self.add_marker(marker)
marker = pytest.mark.xfail(True, reason="Expected failure - true")
self.add_marker(marker)
def runtest(self):
assert False