Merge remote-tracking branch 'origin/master' into issue_7295
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()}}:"
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user