Release 5.1.0 (#5748)

Release 5.1.0
This commit is contained in:
Bruno Oliveira
2019-08-15 22:35:59 -03:00
committed by GitHub
99 changed files with 2056 additions and 1274 deletions

View File

@@ -4,12 +4,11 @@ import textwrap
import types
import attr
import importlib_metadata
import py
import pytest
from _pytest.compat import importlib_metadata
from _pytest.main import ExitCode
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
def prepend_pythonpath(*dirs):
@@ -343,7 +342,7 @@ class TestGeneralUsage:
"""
)
p = testdir.makepyfile("""def test_func(x): pass""")
res = testdir.runpytest(p, SHOW_PYTEST_WARNINGS_ARG)
res = testdir.runpytest(p)
assert res.ret == 0
res.stdout.fnmatch_lines(["*1 skipped*"])
@@ -356,9 +355,7 @@ class TestGeneralUsage:
pass
"""
)
res = testdir.runpytest(
p.basename + "::" + "test_func[1]", SHOW_PYTEST_WARNINGS_ARG
)
res = testdir.runpytest(p.basename + "::" + "test_func[1]")
assert res.ret == 0
res.stdout.fnmatch_lines(["*1 passed*"])

View File

@@ -58,7 +58,7 @@ class TWMock:
fullwidth = 80
def test_excinfo_simple():
def test_excinfo_simple() -> None:
try:
raise ValueError
except ValueError:
@@ -66,6 +66,14 @@ def test_excinfo_simple():
assert info.type == ValueError
def test_excinfo_from_exc_info_simple():
try:
raise ValueError
except ValueError as e:
info = _pytest._code.ExceptionInfo.from_exc_info((type(e), e, e.__traceback__))
assert info.type == ValueError
def test_excinfo_getstatement():
def g():
raise ValueError

View File

@@ -1,39 +1,5 @@
import os
import pytest
from _pytest import deprecated
from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
pytestmark = pytest.mark.pytester_example_path("deprecated")
def test_pytest_setup_cfg_unsupported(testdir):
testdir.makefile(
".cfg",
setup="""
[pytest]
addopts = --verbose
""",
)
with pytest.raises(pytest.fail.Exception):
testdir.runpytest()
def test_pytest_custom_cfg_unsupported(testdir):
testdir.makefile(
".cfg",
custom="""
[pytest]
addopts = --verbose
""",
)
with pytest.raises(pytest.fail.Exception):
testdir.runpytest("-c", "custom.cfg")
def test_getfuncargvalue_is_deprecated(request):
pytest.deprecated_call(request.getfuncargvalue, "tmpdir")
@pytest.mark.filterwarnings("default")
@@ -78,142 +44,3 @@ def test_external_plugins_integrated(testdir, plugin):
with pytest.warns(pytest.PytestConfigWarning):
testdir.parseconfig("-p", plugin)
def test_raises_message_argument_deprecated():
with pytest.warns(pytest.PytestDeprecationWarning):
with pytest.raises(RuntimeError, message="foobar"):
raise RuntimeError
def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir):
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
testdir.makepyfile(
**{
"subdirectory/conftest.py": """
pytest_plugins=['capture']
"""
}
)
testdir.makepyfile(
"""
def test_func():
pass
"""
)
res = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG)
assert res.ret == 2
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
res.stdout.fnmatch_lines(
["*{msg}*".format(msg=msg), "*subdirectory{sep}conftest.py*".format(sep=os.sep)]
)
@pytest.mark.parametrize("use_pyargs", [True, False])
def test_pytest_plugins_in_non_top_level_conftest_unsupported_pyargs(
testdir, use_pyargs
):
"""When using --pyargs, do not emit the warning about non-top-level conftest warnings (#4039, #4044)"""
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
files = {
"src/pkg/__init__.py": "",
"src/pkg/conftest.py": "",
"src/pkg/test_root.py": "def test(): pass",
"src/pkg/sub/__init__.py": "",
"src/pkg/sub/conftest.py": "pytest_plugins=['capture']",
"src/pkg/sub/test_bar.py": "def test(): pass",
}
testdir.makepyfile(**files)
testdir.syspathinsert(testdir.tmpdir.join("src"))
args = ("--pyargs", "pkg") if use_pyargs else ()
args += (SHOW_PYTEST_WARNINGS_ARG,)
res = testdir.runpytest(*args)
assert res.ret == (0 if use_pyargs else 2)
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
if use_pyargs:
assert msg not in res.stdout.str()
else:
res.stdout.fnmatch_lines(["*{msg}*".format(msg=msg)])
def test_pytest_plugins_in_non_top_level_conftest_unsupported_no_top_level_conftest(
testdir
):
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
subdirectory = testdir.tmpdir.join("subdirectory")
subdirectory.mkdir()
testdir.makeconftest(
"""
pytest_plugins=['capture']
"""
)
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
testdir.makepyfile(
"""
def test_func():
pass
"""
)
res = testdir.runpytest_subprocess()
assert res.ret == 2
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
res.stdout.fnmatch_lines(
["*{msg}*".format(msg=msg), "*subdirectory{sep}conftest.py*".format(sep=os.sep)]
)
def test_pytest_plugins_in_non_top_level_conftest_unsupported_no_false_positives(
testdir
):
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
subdirectory = testdir.tmpdir.join("subdirectory")
subdirectory.mkdir()
testdir.makeconftest(
"""
pass
"""
)
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
testdir.makeconftest(
"""
import warnings
warnings.filterwarnings('always', category=DeprecationWarning)
pytest_plugins=['capture']
"""
)
testdir.makepyfile(
"""
def test_func():
pass
"""
)
res = testdir.runpytest_subprocess()
assert res.ret == 0
msg = str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
assert msg not in res.stdout.str()
def test_fixture_named_request(testdir):
testdir.copy_example()
result = testdir.runpytest()
result.stdout.fnmatch_lines(
[
"*'request' is a reserved name for fixtures and will raise an error in future versions"
]
)
def test_pytest_warns_unknown_kwargs():
with pytest.warns(
PytestDeprecationWarning,
match=r"pytest.warns\(\) got unexpected keyword arguments: \['foo'\]",
):
pytest.warns(UserWarning, foo="hello")

View File

@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
The MIT License (MIT)
Copyright (c) 2014, Gregory Boissinot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="SUREFIRE_TIME">
<xs:restriction base="xs:string">
<xs:pattern value="(([0-9]{0,3},)*[0-9]{3}|[0-9]{0,3})*(\.[0-9]{0,3})?"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="rerunType" mixed="true"> <!-- mixed (XML contains text) to be compatible with version previous than 2.22.1 -->
<xs:sequence>
<xs:element name="stackTrace" type="xs:string" minOccurs="0" /> <!-- optional to be compatible with version previous than 2.22.1 -->
<xs:element name="system-out" type="xs:string" minOccurs="0" />
<xs:element name="system-err" type="xs:string" minOccurs="0" />
</xs:sequence>
<xs:attribute name="message" type="xs:string" />
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
<xs:element name="failure">
<xs:complexType mixed="true">
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="message" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="error">
<xs:complexType mixed="true">
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="message" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="skipped">
<xs:complexType mixed="true">
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="message" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="properties">
<xs:complexType>
<xs:sequence>
<xs:element ref="property" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="property">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="value" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="system-err" type="xs:string"/>
<xs:element name="system-out" type="xs:string"/>
<xs:element name="rerunFailure" type="rerunType"/>
<xs:element name="rerunError" type="rerunType"/>
<xs:element name="flakyFailure" type="rerunType"/>
<xs:element name="flakyError" type="rerunType"/>
<xs:element name="testcase">
<xs:complexType>
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="skipped"/>
<xs:element ref="error"/>
<xs:element ref="failure"/>
<xs:element ref="rerunFailure" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="rerunError" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="flakyFailure" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="flakyError" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="system-out"/>
<xs:element ref="system-err"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="time" type="xs:string"/>
<xs:attribute name="classname" type="xs:string"/>
<xs:attribute name="group" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="testsuite">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="testsuite"/>
<xs:element ref="properties"/>
<xs:element ref="testcase"/>
<xs:element ref="system-out"/>
<xs:element ref="system-err"/>
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="tests" type="xs:string" use="required"/>
<xs:attribute name="failures" type="xs:string" use="required"/>
<xs:attribute name="errors" type="xs:string" use="required"/>
<xs:attribute name="group" type="xs:string" />
<xs:attribute name="time" type="SUREFIRE_TIME"/>
<xs:attribute name="skipped" type="xs:string" />
<xs:attribute name="timestamp" type="xs:string" />
<xs:attribute name="hostname" type="xs:string" />
<xs:attribute name="id" type="xs:string" />
<xs:attribute name="package" type="xs:string" />
<xs:attribute name="file" type="xs:string"/>
<xs:attribute name="log" type="xs:string"/>
<xs:attribute name="url" type="xs:string"/>
<xs:attribute name="version" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="testsuites">
<xs:complexType>
<xs:sequence>
<xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="time" type="SUREFIRE_TIME"/>
<xs:attribute name="tests" type="xs:string" />
<xs:attribute name="failures" type="xs:string" />
<xs:attribute name="errors" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -45,10 +45,21 @@ def test_exceptions():
assert "unknown" in s2
def test_buggy_builtin_repr():
# Simulate a case where a repr for a builtin raises.
# reprlib dispatches by type name, so use "int".
class int:
def __repr__(self):
raise ValueError("Buggy repr!")
assert "Buggy" in saferepr(int())
def test_big_repr():
from _pytest._io.saferepr import SafeRepr
assert len(saferepr(range(1000))) <= len("[" + SafeRepr().maxlist * "1000" + "]")
assert len(saferepr(range(1000))) <= len("[" + SafeRepr(0).maxlist * "1000" + "]")
def test_repr_on_newstyle():

View File

@@ -946,7 +946,7 @@ def test_collection_collect_only_live_logging(testdir, verbose):
expected_lines.extend(
[
"*test_collection_collect_only_live_logging.py::test_simple*",
"no tests ran in * seconds",
"no tests ran in 0.[0-9][0-9]s",
]
)
elif verbose == "-qq":

View File

@@ -7,7 +7,6 @@ from _pytest.fixtures import FixtureLookupError
from _pytest.fixtures import FixtureRequest
from _pytest.pathlib import Path
from _pytest.pytester import get_public_names
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
def test_getfuncargnames_functions():
@@ -639,8 +638,7 @@ class TestRequestBasic:
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 2 passed in *"])
@pytest.mark.parametrize("getfixmethod", ("getfixturevalue", "getfuncargvalue"))
def test_getfixturevalue(self, testdir, getfixmethod):
def test_getfixturevalue(self, testdir):
item = testdir.getitem(
"""
import pytest
@@ -653,35 +651,22 @@ class TestRequestBasic:
def test_func(something): pass
"""
)
import contextlib
if getfixmethod == "getfuncargvalue":
warning_expectation = pytest.warns(DeprecationWarning)
else:
# see #1830 for a cleaner way to accomplish this
@contextlib.contextmanager
def expecting_no_warning():
yield
warning_expectation = expecting_no_warning()
req = item._request
with warning_expectation:
fixture_fetcher = getattr(req, getfixmethod)
with pytest.raises(FixtureLookupError):
fixture_fetcher("notexists")
val = fixture_fetcher("something")
assert val == 1
val = fixture_fetcher("something")
assert val == 1
val2 = fixture_fetcher("other")
assert val2 == 2
val2 = fixture_fetcher("other") # see about caching
assert val2 == 2
pytest._fillfuncargs(item)
assert item.funcargs["something"] == 1
assert len(get_public_names(item.funcargs)) == 2
assert "request" in item.funcargs
with pytest.raises(FixtureLookupError):
req.getfixturevalue("notexists")
val = req.getfixturevalue("something")
assert val == 1
val = req.getfixturevalue("something")
assert val == 1
val2 = req.getfixturevalue("other")
assert val2 == 2
val2 = req.getfixturevalue("other") # see about caching
assert val2 == 2
pytest._fillfuncargs(item)
assert item.funcargs["something"] == 1
assert len(get_public_names(item.funcargs)) == 2
assert "request" in item.funcargs
def test_request_addfinalizer(self, testdir):
item = testdir.getitem(
@@ -1181,21 +1166,6 @@ class TestFixtureUsages:
values = reprec.getfailedcollections()
assert len(values) == 1
def test_request_can_be_overridden(self, testdir):
testdir.makepyfile(
"""
import pytest
@pytest.fixture()
def request(request):
request.a = 1
return request
def test_request(request):
assert request.a == 1
"""
)
reprec = testdir.inline_run("-Wignore::pytest.PytestDeprecationWarning")
reprec.assertoutcome(passed=1)
def test_usefixtures_marker(self, testdir):
testdir.makepyfile(
"""
@@ -2240,7 +2210,7 @@ class TestFixtureMarker:
pass
"""
)
result = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest()
assert result.ret != 0
result.stdout.fnmatch_lines(
["*ScopeMismatch*You tried*function*session*request*"]
@@ -4028,3 +3998,14 @@ def test_fixture_param_shadowing(testdir):
result.stdout.fnmatch_lines(["*::test_normal_fixture[[]a[]]*"])
result.stdout.fnmatch_lines(["*::test_normal_fixture[[]b[]]*"])
result.stdout.fnmatch_lines(["*::test_indirect[[]1[]]*"])
def test_fixture_named_request(testdir):
testdir.copy_example("fixtures/test_fixture_named_request.py")
result = testdir.runpytest()
result.stdout.fnmatch_lines(
[
"*'request' is a reserved word for fixtures, use another name:",
" *test_fixture_named_request.py:5",
]
)

View File

@@ -9,7 +9,6 @@ from hypothesis import strategies
import pytest
from _pytest import fixtures
from _pytest import python
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
class TestMetafunc:
@@ -600,6 +599,17 @@ class TestMetafunc:
assert metafunc._calls[0].funcargs == dict(x="a", y="b")
assert metafunc._calls[0].params == {}
def test_parametrize_indirect_wrong_type(self):
def func(x, y):
pass
metafunc = self.Metafunc(func)
with pytest.raises(
pytest.fail.Exception,
match="In func: expected Sequence or boolean for indirect, got dict",
):
metafunc.parametrize("x, y", [("a", "b")], indirect={})
def test_parametrize_indirect_list_functional(self, testdir):
"""
#714
@@ -915,7 +925,7 @@ class TestMetafuncFunctional:
assert metafunc.cls == TestClass
"""
)
result = testdir.runpytest(p, "-v", SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest(p, "-v")
result.assert_outcomes(passed=2)
def test_two_functions(self, testdir):
@@ -931,7 +941,7 @@ class TestMetafuncFunctional:
assert arg1 in (10, 20)
"""
)
result = testdir.runpytest("-v", p, SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines(
[
"*test_func1*0*PASS*",
@@ -967,7 +977,7 @@ class TestMetafuncFunctional:
assert hello == "world"
"""
)
result = testdir.runpytest("-v", p, SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines(["*test_myfunc*hello*PASS*", "*1 passed*"])
def test_two_functions_not_same_instance(self, testdir):
@@ -982,7 +992,7 @@ class TestMetafuncFunctional:
self.x = 1
"""
)
result = testdir.runpytest("-v", p, SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest("-v", p)
result.stdout.fnmatch_lines(
["*test_func*0*PASS*", "*test_func*1*PASS*", "*2 pass*"]
)
@@ -1000,7 +1010,7 @@ class TestMetafuncFunctional:
self.val = 1
"""
)
result = testdir.runpytest(p, SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest(p)
result.assert_outcomes(passed=1)
def test_parametrize_functional2(self, testdir):
@@ -1522,7 +1532,7 @@ class TestMarkersWithParametrization:
assert n + 1 == expected
"""
testdir.makepyfile(s)
rec = testdir.inline_run("-m", "foo", SHOW_PYTEST_WARNINGS_ARG)
rec = testdir.inline_run("-m", "foo")
passed, skipped, fail = rec.listoutcomes()
assert len(passed) == 1
assert len(skipped) == 0
@@ -1562,7 +1572,7 @@ class TestMarkersWithParametrization:
assert n + 1 == expected
"""
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
# xfail is skip??
reprec.assertoutcome(passed=2, skipped=1)
@@ -1579,7 +1589,7 @@ class TestMarkersWithParametrization:
assert n % 2 == 0
"""
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2, skipped=1)
def test_xfail_with_arg(self, testdir):
@@ -1595,7 +1605,7 @@ class TestMarkersWithParametrization:
assert n + 1 == expected
"""
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2, skipped=1)
def test_xfail_with_kwarg(self, testdir):
@@ -1611,7 +1621,7 @@ class TestMarkersWithParametrization:
assert n + 1 == expected
"""
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2, skipped=1)
def test_xfail_with_arg_and_kwarg(self, testdir):
@@ -1627,7 +1637,7 @@ class TestMarkersWithParametrization:
assert n + 1 == expected
"""
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2, skipped=1)
@pytest.mark.parametrize("strict", [True, False])
@@ -1648,7 +1658,7 @@ class TestMarkersWithParametrization:
strict=strict
)
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
passed, failed = (2, 1) if strict else (3, 0)
reprec.assertoutcome(passed=passed, failed=failed)
@@ -1672,7 +1682,7 @@ class TestMarkersWithParametrization:
assert n + 1 == expected
"""
testdir.makepyfile(s)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2, skipped=2)
def test_parametrize_ID_generation_string_int_works(self, testdir):

View File

@@ -2,35 +2,20 @@ import sys
import pytest
from _pytest.outcomes import Failed
from _pytest.warning_types import PytestDeprecationWarning
class TestRaises:
def test_check_callable(self):
with pytest.raises(TypeError, match=r".* must be callable"):
pytest.raises(RuntimeError, "int('qwe')")
def test_raises(self):
source = "int('qwe')"
with pytest.warns(PytestDeprecationWarning):
excinfo = pytest.raises(ValueError, source)
code = excinfo.traceback[-1].frame.code
s = str(code.fullsource)
assert s == source
def test_raises_exec(self):
with pytest.warns(PytestDeprecationWarning) as warninfo:
pytest.raises(ValueError, "a,x = []")
assert warninfo[0].filename == __file__
def test_raises_exec_correct_filename(self):
with pytest.warns(PytestDeprecationWarning):
excinfo = pytest.raises(ValueError, 'int("s")')
assert __file__ in excinfo.traceback[-1].path
def test_raises_syntax_error(self):
with pytest.warns(PytestDeprecationWarning) as warninfo:
pytest.raises(SyntaxError, "qwe qwe qwe")
assert warninfo[0].filename == __file__
excinfo = pytest.raises(ValueError, int, "qwe")
assert "invalid literal" in str(excinfo.value)
def test_raises_function(self):
pytest.raises(ValueError, int, "hello")
excinfo = pytest.raises(ValueError, int, "hello")
assert "invalid literal" in str(excinfo.value)
def test_raises_callable_no_exception(self):
class A:
@@ -169,17 +154,6 @@ class TestRaises:
else:
assert False, "Expected pytest.raises.Exception"
def test_custom_raise_message(self):
message = "TEST_MESSAGE"
try:
with pytest.warns(PytestDeprecationWarning):
with pytest.raises(ValueError, message=message):
pass
except pytest.raises.Exception as e:
assert e.msg == message
else:
assert False, "Expected pytest.raises.Exception"
@pytest.mark.parametrize("method", ["function", "with"])
def test_raises_cyclic_reference(self, method):
"""
@@ -274,3 +248,9 @@ class TestRaises:
with pytest.raises(CrappyClass()):
pass
assert "via __class__" in excinfo.value.args[0]
def test_raises_context_manager_with_kwargs(self):
with pytest.raises(TypeError) as excinfo:
with pytest.raises(Exception, foo="bar"):
pass
assert "Unexpected keyword arguments" in str(excinfo.value)

View File

@@ -172,7 +172,8 @@ class TestImportHookInstallation:
return check
""",
"mainwrapper.py": """\
import pytest, importlib_metadata
import pytest
from _pytest.compat import importlib_metadata
class DummyEntryPoint(object):
name = 'spam'

View File

@@ -200,6 +200,16 @@ class TestAssertionRewrite:
else:
assert msg == ["assert cls == 42"]
def test_assertrepr_compare_same_width(self, request):
"""Should use same width/truncation with same initial width."""
def f():
assert "1234567890" * 5 + "A" == "1234567890" * 5 + "B"
assert getmsg(f).splitlines()[0] == (
"assert '123456789012...901234567890A' == '123456789012...901234567890B'"
)
def test_dont_rewrite_if_hasattr_fails(self, request):
class Y:
""" A class whos getattr fails, but not with `AttributeError` """

View File

@@ -1,10 +1,11 @@
import os
import sys
import textwrap
import importlib_metadata
from pathlib import Path
import _pytest._code
import pytest
from _pytest.compat import importlib_metadata
from _pytest.config import _iter_rewritable_modules
from _pytest.config.exceptions import UsageError
from _pytest.config.findpaths import determine_setup
@@ -446,7 +447,7 @@ class TestConfigFromdictargs:
assert config.option.capture == "no"
assert config.args == args
def test_origargs(self, _sys_snapshot):
def test_invocation_params_args(self, _sys_snapshot):
"""Show that fromdictargs can handle args in their "orig" format"""
from _pytest.config import Config
@@ -455,7 +456,7 @@ class TestConfigFromdictargs:
config = Config.fromdictargs(option_dict, args)
assert config.args == ["a", "b"]
assert config._origargs == args
assert config.invocation_params.args == args
assert config.option.verbose == 4
assert config.option.capture == "no"
@@ -1205,6 +1206,29 @@ def test_config_does_not_load_blocked_plugin_from_args(testdir):
assert result.ret == ExitCode.USAGE_ERROR
def test_invocation_args(testdir):
"""Ensure that Config.invocation_* arguments are correctly defined"""
class DummyPlugin:
pass
p = testdir.makepyfile("def test(): pass")
plugin = DummyPlugin()
rec = testdir.inline_run(p, "-v", plugins=[plugin])
calls = rec.getcalls("pytest_runtest_protocol")
assert len(calls) == 1
call = calls[0]
config = call.item.config
assert config.invocation_params.args == [p, "-v"]
assert config.invocation_params.dir == Path(str(testdir.tmpdir))
plugins = config.invocation_params.plugins
assert len(plugins) == 2
assert plugins[0] is plugin
assert type(plugins[1]).__name__ == "Collect" # installed by testdir.inline_run()
@pytest.mark.parametrize(
"plugin",
[
@@ -1248,3 +1272,140 @@ def test_config_blocked_default_plugins(testdir, plugin):
result.stdout.fnmatch_lines(["* 1 failed in *"])
else:
assert result.stdout.lines == [""]
class TestSetupCfg:
def test_pytest_setup_cfg_unsupported(self, testdir):
testdir.makefile(
".cfg",
setup="""
[pytest]
addopts = --verbose
""",
)
with pytest.raises(pytest.fail.Exception):
testdir.runpytest()
def test_pytest_custom_cfg_unsupported(self, testdir):
testdir.makefile(
".cfg",
custom="""
[pytest]
addopts = --verbose
""",
)
with pytest.raises(pytest.fail.Exception):
testdir.runpytest("-c", "custom.cfg")
class TestPytestPluginsVariable:
def test_pytest_plugins_in_non_top_level_conftest_unsupported(self, testdir):
testdir.makepyfile(
**{
"subdirectory/conftest.py": """
pytest_plugins=['capture']
"""
}
)
testdir.makepyfile(
"""
def test_func():
pass
"""
)
res = testdir.runpytest()
assert res.ret == 2
msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported"
res.stdout.fnmatch_lines(
[
"*{msg}*".format(msg=msg),
"*subdirectory{sep}conftest.py*".format(sep=os.sep),
]
)
@pytest.mark.parametrize("use_pyargs", [True, False])
def test_pytest_plugins_in_non_top_level_conftest_unsupported_pyargs(
self, testdir, use_pyargs
):
"""When using --pyargs, do not emit the warning about non-top-level conftest warnings (#4039, #4044)"""
files = {
"src/pkg/__init__.py": "",
"src/pkg/conftest.py": "",
"src/pkg/test_root.py": "def test(): pass",
"src/pkg/sub/__init__.py": "",
"src/pkg/sub/conftest.py": "pytest_plugins=['capture']",
"src/pkg/sub/test_bar.py": "def test(): pass",
}
testdir.makepyfile(**files)
testdir.syspathinsert(testdir.tmpdir.join("src"))
args = ("--pyargs", "pkg") if use_pyargs else ()
res = testdir.runpytest(*args)
assert res.ret == (0 if use_pyargs else 2)
msg = (
msg
) = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported"
if use_pyargs:
assert msg not in res.stdout.str()
else:
res.stdout.fnmatch_lines(["*{msg}*".format(msg=msg)])
def test_pytest_plugins_in_non_top_level_conftest_unsupported_no_top_level_conftest(
self, testdir
):
subdirectory = testdir.tmpdir.join("subdirectory")
subdirectory.mkdir()
testdir.makeconftest(
"""
pytest_plugins=['capture']
"""
)
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
testdir.makepyfile(
"""
def test_func():
pass
"""
)
res = testdir.runpytest_subprocess()
assert res.ret == 2
msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported"
res.stdout.fnmatch_lines(
[
"*{msg}*".format(msg=msg),
"*subdirectory{sep}conftest.py*".format(sep=os.sep),
]
)
def test_pytest_plugins_in_non_top_level_conftest_unsupported_no_false_positives(
self, testdir
):
subdirectory = testdir.tmpdir.join("subdirectory")
subdirectory.mkdir()
testdir.makeconftest(
"""
pass
"""
)
testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py"))
testdir.makeconftest(
"""
import warnings
warnings.filterwarnings('always', category=DeprecationWarning)
pytest_plugins=['capture']
"""
)
testdir.makepyfile(
"""
def test_func():
pass
"""
)
res = testdir.runpytest_subprocess()
assert res.ret == 0
msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported"
assert msg not in res.stdout.str()

View File

@@ -3,6 +3,7 @@ import textwrap
import pytest
from _pytest.compat import MODULE_NOT_FOUND_ERROR
from _pytest.doctest import _get_checker
from _pytest.doctest import _is_mocked
from _pytest.doctest import _patch_unwrap_mock_aware
from _pytest.doctest import DoctestItem
@@ -838,6 +839,154 @@ class TestLiterals:
reprec = testdir.inline_run()
reprec.assertoutcome(failed=1)
def test_number_re(self):
for s in [
"1.",
"+1.",
"-1.",
".1",
"+.1",
"-.1",
"0.1",
"+0.1",
"-0.1",
"1e5",
"+1e5",
"1e+5",
"+1e+5",
"1e-5",
"+1e-5",
"-1e-5",
"1.2e3",
"-1.2e-3",
]:
print(s)
m = _get_checker()._number_re.match(s)
assert m is not None
assert float(m.group()) == pytest.approx(float(s))
for s in ["1", "abc"]:
print(s)
assert _get_checker()._number_re.match(s) is None
@pytest.mark.parametrize("config_mode", ["ini", "comment"])
def test_number_precision(self, testdir, config_mode):
"""Test the NUMBER option."""
if config_mode == "ini":
testdir.makeini(
"""
[pytest]
doctest_optionflags = NUMBER
"""
)
comment = ""
else:
comment = "#doctest: +NUMBER"
testdir.maketxtfile(
test_doc="""
Scalars:
>>> import math
>>> math.pi {comment}
3.141592653589793
>>> math.pi {comment}
3.1416
>>> math.pi {comment}
3.14
>>> -math.pi {comment}
-3.14
>>> math.pi {comment}
3.
>>> 3. {comment}
3.0
>>> 3. {comment}
3.
>>> 3. {comment}
3.01
>>> 3. {comment}
2.99
>>> .299 {comment}
.3
>>> .301 {comment}
.3
>>> 951. {comment}
1e3
>>> 1049. {comment}
1e3
>>> -1049. {comment}
-1e3
>>> 1e3 {comment}
1e3
>>> 1e3 {comment}
1000.
Lists:
>>> [3.1415, 0.097, 13.1, 7, 8.22222e5, 0.598e-2] {comment}
[3.14, 0.1, 13., 7, 8.22e5, 6.0e-3]
>>> [[0.333, 0.667], [0.999, 1.333]] {comment}
[[0.33, 0.667], [0.999, 1.333]]
>>> [[[0.101]]] {comment}
[[[0.1]]]
Doesn't barf on non-numbers:
>>> 'abc' {comment}
'abc'
>>> None {comment}
""".format(
comment=comment
)
)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
@pytest.mark.parametrize(
"expression,output",
[
# ints shouldn't match floats:
("3.0", "3"),
("3e0", "3"),
("1e3", "1000"),
("3", "3.0"),
# Rounding:
("3.1", "3.0"),
("3.1", "3.2"),
("3.1", "4.0"),
("8.22e5", "810000.0"),
# Only the actual output is rounded up, not the expected output:
("3.0", "2.98"),
("1e3", "999"),
# The current implementation doesn't understand that numbers inside
# strings shouldn't be treated as numbers:
pytest.param("'3.1416'", "'3.14'", marks=pytest.mark.xfail),
],
)
def test_number_non_matches(self, testdir, expression, output):
testdir.maketxtfile(
test_doc="""
>>> {expression} #doctest: +NUMBER
{output}
""".format(
expression=expression, output=output
)
)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=0, failed=1)
def test_number_and_allow_unicode(self, testdir):
testdir.maketxtfile(
test_doc="""
>>> from collections import namedtuple
>>> T = namedtuple('T', 'a b c')
>>> T(a=0.2330000001, b=u'str', c=b'bytes') # doctest: +ALLOW_UNICODE, +ALLOW_BYTES, +NUMBER
T(a=0.233, b=u'str', c='bytes')
"""
)
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
class TestDoctestSkips:
"""

View File

@@ -1,4 +1,4 @@
import importlib_metadata
from _pytest.compat import importlib_metadata
def test_pytest_entry_points_are_identical():

View File

@@ -1,18 +1,47 @@
import os
import platform
from datetime import datetime
from pathlib import Path
from xml.dom import minidom
import py
import xmlschema
import pytest
from _pytest.junitxml import LogXML
from _pytest.reports import BaseReport
def runandparse(testdir, *args):
resultpath = testdir.tmpdir.join("junit.xml")
result = testdir.runpytest("--junitxml=%s" % resultpath, *args)
xmldoc = minidom.parse(str(resultpath))
return result, DomNode(xmldoc)
@pytest.fixture(scope="session")
def schema():
"""Returns a xmlschema.XMLSchema object for the junit-10.xsd file"""
fn = Path(__file__).parent / "example_scripts/junit-10.xsd"
with fn.open() as f:
return xmlschema.XMLSchema(f)
@pytest.fixture
def run_and_parse(testdir, schema):
"""
Fixture that returns a function that can be used to execute pytest and return
the parsed ``DomNode`` of the root xml node.
The ``family`` parameter is used to configure the ``junit_family`` of the written report.
"xunit2" is also automatically validated against the schema.
"""
def run(*args, family="xunit1"):
if family:
args = ("-o", "junit_family=" + family) + args
xml_path = testdir.tmpdir.join("junit.xml")
result = testdir.runpytest("--junitxml=%s" % xml_path, *args)
if family == "xunit2":
with xml_path.open() as f:
schema.validate(f)
xmldoc = minidom.parse(str(xml_path))
return result, DomNode(xmldoc)
return run
def assert_attr(node, **kwargs):
@@ -41,6 +70,16 @@ class DomNode:
def _by_tag(self, tag):
return self.__node.getElementsByTagName(tag)
@property
def children(self):
return [type(self)(x) for x in self.__node.childNodes]
@property
def get_unique_child(self):
children = self.children
assert len(children) == 1
return children[0]
def find_nth_by_tag(self, tag, n):
items = self._by_tag(tag)
try:
@@ -75,12 +114,16 @@ class DomNode:
return self.__node.tagName
@property
def next_siebling(self):
def next_sibling(self):
return type(self)(self.__node.nextSibling)
parametrize_families = pytest.mark.parametrize("xunit_family", ["xunit1", "xunit2"])
class TestPython:
def test_summing_simple(self, testdir):
@parametrize_families
def test_summing_simple(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -98,12 +141,13 @@ class TestPython:
assert 1
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(name="pytest", errors=0, failures=1, skipped=2, tests=5)
def test_summing_simple_with_errors(self, testdir):
@parametrize_families
def test_summing_simple_with_errors(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -124,12 +168,38 @@ class TestPython:
assert True
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(name="pytest", errors=1, failures=2, skipped=1, tests=5)
def test_timing_function(self, testdir):
@parametrize_families
def test_hostname_in_xml(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
def test_pass():
pass
"""
)
result, dom = run_and_parse(family=xunit_family)
node = dom.find_first_by_tag("testsuite")
node.assert_attr(hostname=platform.node())
@parametrize_families
def test_timestamp_in_xml(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
def test_pass():
pass
"""
)
start_time = datetime.now()
result, dom = run_and_parse(family=xunit_family)
node = dom.find_first_by_tag("testsuite")
timestamp = datetime.strptime(node["timestamp"], "%Y-%m-%dT%H:%M:%S.%f")
assert start_time <= timestamp < datetime.now()
def test_timing_function(self, testdir, run_and_parse):
testdir.makepyfile(
"""
import time, pytest
@@ -141,14 +211,16 @@ class TestPython:
time.sleep(0.01)
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
val = tnode["time"]
assert round(float(val), 2) >= 0.03
@pytest.mark.parametrize("duration_report", ["call", "total"])
def test_junit_duration_report(self, testdir, monkeypatch, duration_report):
def test_junit_duration_report(
self, testdir, monkeypatch, duration_report, run_and_parse
):
# mock LogXML.node_reporter so it always sets a known duration to each test report object
original_node_reporter = LogXML.node_reporter
@@ -166,8 +238,8 @@ class TestPython:
pass
"""
)
result, dom = runandparse(
testdir, "-o", "junit_duration_report={}".format(duration_report)
result, dom = run_and_parse(
"-o", "junit_duration_report={}".format(duration_report)
)
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
@@ -178,7 +250,8 @@ class TestPython:
assert duration_report == "call"
assert val == 1.0
def test_setup_error(self, testdir):
@parametrize_families
def test_setup_error(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -190,7 +263,7 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, tests=1)
@@ -200,7 +273,8 @@ class TestPython:
fnode.assert_attr(message="test setup failure")
assert "ValueError" in fnode.toxml()
def test_teardown_error(self, testdir):
@parametrize_families
def test_teardown_error(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -213,7 +287,7 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
@@ -222,7 +296,8 @@ class TestPython:
fnode.assert_attr(message="test teardown failure")
assert "ValueError" in fnode.toxml()
def test_call_failure_teardown_error(self, testdir):
@parametrize_families
def test_call_failure_teardown_error(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -235,7 +310,7 @@ class TestPython:
raise Exception("Call Exception")
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, failures=1, tests=1)
@@ -247,7 +322,8 @@ class TestPython:
snode = second.find_first_by_tag("error")
snode.assert_attr(message="test teardown failure")
def test_skip_contains_name_reason(self, testdir):
@parametrize_families
def test_skip_contains_name_reason(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -255,7 +331,7 @@ class TestPython:
pytest.skip("hello23")
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=1)
@@ -264,7 +340,8 @@ class TestPython:
snode = tnode.find_first_by_tag("skipped")
snode.assert_attr(type="pytest.skip", message="hello23")
def test_mark_skip_contains_name_reason(self, testdir):
@parametrize_families
def test_mark_skip_contains_name_reason(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -273,7 +350,7 @@ class TestPython:
assert True
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=1)
@@ -284,7 +361,10 @@ class TestPython:
snode = tnode.find_first_by_tag("skipped")
snode.assert_attr(type="pytest.skip", message="hello24")
def test_mark_skipif_contains_name_reason(self, testdir):
@parametrize_families
def test_mark_skipif_contains_name_reason(
self, testdir, run_and_parse, xunit_family
):
testdir.makepyfile(
"""
import pytest
@@ -294,7 +374,7 @@ class TestPython:
assert True
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=1)
@@ -305,7 +385,10 @@ class TestPython:
snode = tnode.find_first_by_tag("skipped")
snode.assert_attr(type="pytest.skip", message="hello25")
def test_mark_skip_doesnt_capture_output(self, testdir):
@parametrize_families
def test_mark_skip_doesnt_capture_output(
self, testdir, run_and_parse, xunit_family
):
testdir.makepyfile(
"""
import pytest
@@ -314,12 +397,13 @@ class TestPython:
print("bar!")
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node_xml = dom.find_first_by_tag("testsuite").toxml()
assert "bar!" not in node_xml
def test_classname_instance(self, testdir):
@parametrize_families
def test_classname_instance(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
class TestClass(object):
@@ -327,7 +411,7 @@ class TestPython:
assert 0
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1)
@@ -336,20 +420,22 @@ class TestPython:
classname="test_classname_instance.TestClass", name="test_method"
)
def test_classname_nested_dir(self, testdir):
@parametrize_families
def test_classname_nested_dir(self, testdir, run_and_parse, xunit_family):
p = testdir.tmpdir.ensure("sub", "test_hello.py")
p.write("def test_func(): 0/0")
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(classname="sub.test_hello", name="test_func")
def test_internal_error(self, testdir):
@parametrize_families
def test_internal_error(self, testdir, run_and_parse, xunit_family):
testdir.makeconftest("def pytest_runtest_protocol(): 0 / 0")
testdir.makepyfile("def test_function(): pass")
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, tests=1)
@@ -360,7 +446,10 @@ class TestPython:
assert "Division" in fnode.toxml()
@pytest.mark.parametrize("junit_logging", ["no", "system-out", "system-err"])
def test_failure_function(self, testdir, junit_logging):
@parametrize_families
def test_failure_function(
self, testdir, junit_logging, run_and_parse, xunit_family
):
testdir.makepyfile(
"""
import logging
@@ -375,7 +464,9 @@ class TestPython:
"""
)
result, dom = runandparse(testdir, "-o", "junit_logging=%s" % junit_logging)
result, dom = run_and_parse(
"-o", "junit_logging=%s" % junit_logging, family=xunit_family
)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1, tests=1)
@@ -384,11 +475,11 @@ class TestPython:
fnode = tnode.find_first_by_tag("failure")
fnode.assert_attr(message="ValueError: 42")
assert "ValueError" in fnode.toxml()
systemout = fnode.next_siebling
systemout = fnode.next_sibling
assert systemout.tag == "system-out"
assert "hello-stdout" in systemout.toxml()
assert "info msg" not in systemout.toxml()
systemerr = systemout.next_siebling
systemerr = systemout.next_sibling
assert systemerr.tag == "system-err"
assert "hello-stderr" in systemerr.toxml()
assert "info msg" not in systemerr.toxml()
@@ -403,7 +494,8 @@ class TestPython:
assert "warning msg" not in systemout.toxml()
assert "warning msg" not in systemerr.toxml()
def test_failure_verbose_message(self, testdir):
@parametrize_families
def test_failure_verbose_message(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import sys
@@ -411,14 +503,14 @@ class TestPython:
assert 0, "An error"
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
fnode = tnode.find_first_by_tag("failure")
fnode.assert_attr(message="AssertionError: An error assert 0")
def test_failure_escape(self, testdir):
@parametrize_families
def test_failure_escape(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -428,7 +520,7 @@ class TestPython:
assert 0
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=3, tests=3)
@@ -443,7 +535,8 @@ class TestPython:
text = sysout.text
assert text == "%s\n" % char
def test_junit_prefixing(self, testdir):
@parametrize_families
def test_junit_prefixing(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
def test_func():
@@ -453,7 +546,7 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir, "--junitprefix=xyz")
result, dom = run_and_parse("--junitprefix=xyz", family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1, tests=2)
@@ -464,7 +557,8 @@ class TestPython:
classname="xyz.test_junit_prefixing.TestHello", name="test_hello"
)
def test_xfailure_function(self, testdir):
@parametrize_families
def test_xfailure_function(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -472,7 +566,7 @@ class TestPython:
pytest.xfail("42")
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert not result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=1, tests=1)
@@ -480,9 +574,9 @@ class TestPython:
tnode.assert_attr(classname="test_xfailure_function", name="test_xfail")
fnode = tnode.find_first_by_tag("skipped")
fnode.assert_attr(type="pytest.xfail", message="42")
# assert "ValueError" in fnode.toxml()
def test_xfailure_marker(self, testdir):
@parametrize_families
def test_xfailure_marker(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -491,7 +585,7 @@ class TestPython:
assert False
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert not result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=1, tests=1)
@@ -500,7 +594,7 @@ class TestPython:
fnode = tnode.find_first_by_tag("skipped")
fnode.assert_attr(type="pytest.xfail", message="42")
def test_xfail_captures_output_once(self, testdir):
def test_xfail_captures_output_once(self, testdir, run_and_parse):
testdir.makepyfile(
"""
import sys
@@ -513,13 +607,14 @@ class TestPython:
assert 0
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
assert len(tnode.find_by_tag("system-err")) == 1
assert len(tnode.find_by_tag("system-out")) == 1
def test_xfailure_xpass(self, testdir):
@parametrize_families
def test_xfailure_xpass(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -528,14 +623,15 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
# assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=0, tests=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(classname="test_xfailure_xpass", name="test_xpass")
def test_xfailure_xpass_strict(self, testdir):
@parametrize_families
def test_xfailure_xpass_strict(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
import pytest
@@ -544,7 +640,7 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
# assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skipped=0, tests=1)
@@ -553,9 +649,10 @@ class TestPython:
fnode = tnode.find_first_by_tag("failure")
fnode.assert_attr(message="[XPASS(strict)] This needs to fail!")
def test_collect_error(self, testdir):
@parametrize_families
def test_collect_error(self, testdir, run_and_parse, xunit_family):
testdir.makepyfile("syntax error")
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, tests=1)
@@ -564,7 +661,7 @@ class TestPython:
fnode.assert_attr(message="collection failure")
assert "SyntaxError" in fnode.toxml()
def test_unicode(self, testdir):
def test_unicode(self, testdir, run_and_parse):
value = "hx\xc4\x85\xc4\x87\n"
testdir.makepyfile(
"""\
@@ -575,14 +672,14 @@ class TestPython:
"""
% value
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
assert result.ret == 1
tnode = dom.find_first_by_tag("testcase")
fnode = tnode.find_first_by_tag("failure")
assert "hx" in fnode.toxml()
def test_assertion_binchars(self, testdir):
"""this test did fail when the escaping wasn't strict"""
def test_assertion_binchars(self, testdir, run_and_parse):
"""this test did fail when the escaping wasnt strict"""
testdir.makepyfile(
"""
@@ -593,23 +690,23 @@ class TestPython:
assert M1 == M2
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
print(dom.toxml())
def test_pass_captures_stdout(self, testdir):
def test_pass_captures_stdout(self, testdir, run_and_parse):
testdir.makepyfile(
"""
def test_pass():
print('hello-stdout')
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-out")
assert "hello-stdout" in systemout.toxml()
def test_pass_captures_stderr(self, testdir):
def test_pass_captures_stderr(self, testdir, run_and_parse):
testdir.makepyfile(
"""
import sys
@@ -617,13 +714,13 @@ class TestPython:
sys.stderr.write('hello-stderr')
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-err")
assert "hello-stderr" in systemout.toxml()
def test_setup_error_captures_stdout(self, testdir):
def test_setup_error_captures_stdout(self, testdir, run_and_parse):
testdir.makepyfile(
"""
import pytest
@@ -636,13 +733,13 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-out")
assert "hello-stdout" in systemout.toxml()
def test_setup_error_captures_stderr(self, testdir):
def test_setup_error_captures_stderr(self, testdir, run_and_parse):
testdir.makepyfile(
"""
import sys
@@ -656,13 +753,13 @@ class TestPython:
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-err")
assert "hello-stderr" in systemout.toxml()
def test_avoid_double_stdout(self, testdir):
def test_avoid_double_stdout(self, testdir, run_and_parse):
testdir.makepyfile(
"""
import sys
@@ -677,7 +774,7 @@ class TestPython:
sys.stdout.write('hello-stdout call')
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-out")
@@ -720,7 +817,8 @@ def test_dont_configure_on_slaves(tmpdir):
class TestNonPython:
def test_summing_simple(self, testdir):
@parametrize_families
def test_summing_simple(self, testdir, run_and_parse, xunit_family):
testdir.makeconftest(
"""
import pytest
@@ -738,7 +836,7 @@ class TestNonPython:
"""
)
testdir.tmpdir.join("myfile.xyz").write("hello")
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=0, failures=1, skipped=0, tests=1)
@@ -786,8 +884,8 @@ def test_nullbyte_replace(testdir):
def test_invalid_xml_escape():
# Test some more invalid xml chars, the full range should be
# tested really but let's just thest the edges of the ranges
# intead.
# tested really but let's just test the edges of the ranges
# instead.
# XXX This only tests low unicode character points for now as
# there are some issues with the testing infrastructure for
# the higher ones.
@@ -871,7 +969,7 @@ def test_logxml_check_isdir(testdir):
result.stderr.fnmatch_lines(["*--junitxml must be a filename*"])
def test_escaped_parametrized_names_xml(testdir):
def test_escaped_parametrized_names_xml(testdir, run_and_parse):
testdir.makepyfile(
"""\
import pytest
@@ -880,13 +978,13 @@ def test_escaped_parametrized_names_xml(testdir):
assert char
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
assert result.ret == 0
node = dom.find_first_by_tag("testcase")
node.assert_attr(name="test_func[\\x00]")
def test_double_colon_split_function_issue469(testdir):
def test_double_colon_split_function_issue469(testdir, run_and_parse):
testdir.makepyfile(
"""
import pytest
@@ -895,14 +993,14 @@ def test_double_colon_split_function_issue469(testdir):
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
assert result.ret == 0
node = dom.find_first_by_tag("testcase")
node.assert_attr(classname="test_double_colon_split_function_issue469")
node.assert_attr(name="test_func[double::colon]")
def test_double_colon_split_method_issue469(testdir):
def test_double_colon_split_method_issue469(testdir, run_and_parse):
testdir.makepyfile(
"""
import pytest
@@ -912,7 +1010,7 @@ def test_double_colon_split_method_issue469(testdir):
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
assert result.ret == 0
node = dom.find_first_by_tag("testcase")
node.assert_attr(classname="test_double_colon_split_method_issue469.TestClass")
@@ -948,7 +1046,7 @@ def test_unicode_issue368(testdir):
log.pytest_sessionfinish()
def test_record_property(testdir):
def test_record_property(testdir, run_and_parse):
testdir.makepyfile(
"""
import pytest
@@ -960,7 +1058,7 @@ def test_record_property(testdir):
record_property("foo", "<1");
"""
)
result, dom = runandparse(testdir, "-rwv")
result, dom = run_and_parse("-rwv")
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
psnode = tnode.find_first_by_tag("properties")
@@ -969,7 +1067,7 @@ def test_record_property(testdir):
pnodes[1].assert_attr(name="foo", value="<1")
def test_record_property_same_name(testdir):
def test_record_property_same_name(testdir, run_and_parse):
testdir.makepyfile(
"""
def test_record_with_same_name(record_property):
@@ -977,7 +1075,7 @@ def test_record_property_same_name(testdir):
record_property("foo", "baz")
"""
)
result, dom = runandparse(testdir, "-rw")
result, dom = run_and_parse("-rw")
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
psnode = tnode.find_first_by_tag("properties")
@@ -1001,7 +1099,7 @@ def test_record_fixtures_without_junitxml(testdir, fixture_name):
@pytest.mark.filterwarnings("default")
def test_record_attribute(testdir):
def test_record_attribute(testdir, run_and_parse):
testdir.makeini(
"""
[pytest]
@@ -1019,7 +1117,7 @@ def test_record_attribute(testdir):
record_xml_attribute("foo", "<1");
"""
)
result, dom = runandparse(testdir, "-rw")
result, dom = run_and_parse("-rw")
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(bar="1")
@@ -1031,7 +1129,7 @@ def test_record_attribute(testdir):
@pytest.mark.filterwarnings("default")
@pytest.mark.parametrize("fixture_name", ["record_xml_attribute", "record_property"])
def test_record_fixtures_xunit2(testdir, fixture_name):
def test_record_fixtures_xunit2(testdir, fixture_name, run_and_parse):
"""Ensure record_xml_attribute and record_property drop values when outside of legacy family
"""
testdir.makeini(
@@ -1054,7 +1152,7 @@ def test_record_fixtures_xunit2(testdir, fixture_name):
)
)
result, dom = runandparse(testdir, "-rw")
result, dom = run_and_parse("-rw", family=None)
expected_lines = []
if fixture_name == "record_xml_attribute":
expected_lines.append(
@@ -1069,7 +1167,7 @@ def test_record_fixtures_xunit2(testdir, fixture_name):
result.stdout.fnmatch_lines(expected_lines)
def test_random_report_log_xdist(testdir, monkeypatch):
def test_random_report_log_xdist(testdir, monkeypatch, run_and_parse):
"""xdist calls pytest_runtest_logreport as they are executed by the slaves,
with nodes from several nodes overlapping, so junitxml must cope with that
to produce correct reports. #1064
@@ -1084,7 +1182,7 @@ def test_random_report_log_xdist(testdir, monkeypatch):
assert i != 22
"""
)
_, dom = runandparse(testdir, "-n2")
_, dom = run_and_parse("-n2")
suite_node = dom.find_first_by_tag("testsuite")
failed = []
for case_node in suite_node.find_by_tag("testcase"):
@@ -1094,7 +1192,22 @@ def test_random_report_log_xdist(testdir, monkeypatch):
assert failed == ["test_x[22]"]
def test_runs_twice(testdir):
@parametrize_families
def test_root_testsuites_tag(testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
def test_x():
pass
"""
)
_, dom = run_and_parse(family=xunit_family)
root = dom.get_unique_child
assert root.tag == "testsuites"
suite_node = root.get_unique_child
assert suite_node.tag == "testsuite"
def test_runs_twice(testdir, run_and_parse):
f = testdir.makepyfile(
"""
def test_pass():
@@ -1102,14 +1215,13 @@ def test_runs_twice(testdir):
"""
)
result, dom = runandparse(testdir, f, f)
result, dom = run_and_parse(f, f)
assert "INTERNALERROR" not in result.stdout.str()
first, second = [x["classname"] for x in dom.find_by_tag("testcase")]
assert first == second
@pytest.mark.xfail(reason="hangs", run=False)
def test_runs_twice_xdist(testdir):
def test_runs_twice_xdist(testdir, run_and_parse):
pytest.importorskip("xdist")
f = testdir.makepyfile(
"""
@@ -1118,13 +1230,13 @@ def test_runs_twice_xdist(testdir):
"""
)
result, dom = runandparse(testdir, f, "--dist", "each", "--tx", "2*popen")
result, dom = run_and_parse(f, "--dist", "each", "--tx", "2*popen")
assert "INTERNALERROR" not in result.stdout.str()
first, second = [x["classname"] for x in dom.find_by_tag("testcase")]
assert first == second
def test_fancy_items_regression(testdir):
def test_fancy_items_regression(testdir, run_and_parse):
# issue 1259
testdir.makeconftest(
"""
@@ -1157,7 +1269,7 @@ def test_fancy_items_regression(testdir):
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse()
assert "INTERNALERROR" not in result.stdout.str()
@@ -1176,9 +1288,10 @@ def test_fancy_items_regression(testdir):
]
def test_global_properties(testdir):
@parametrize_families
def test_global_properties(testdir, xunit_family):
path = testdir.tmpdir.join("test_global_properties.xml")
log = LogXML(str(path), None)
log = LogXML(str(path), None, family=xunit_family)
class Report(BaseReport):
sections = []
@@ -1236,7 +1349,8 @@ def test_url_property(testdir):
), "The URL did not get written to the xml"
def test_record_testsuite_property(testdir):
@parametrize_families
def test_record_testsuite_property(testdir, run_and_parse, xunit_family):
testdir.makepyfile(
"""
def test_func1(record_testsuite_property):
@@ -1246,7 +1360,7 @@ def test_record_testsuite_property(testdir):
record_testsuite_property("stats", 10)
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node = dom.find_first_by_tag("testsuite")
properties_node = node.find_first_by_tag("properties")
@@ -1284,14 +1398,16 @@ def test_record_testsuite_property_type_checking(testdir, junit):
@pytest.mark.parametrize("suite_name", ["my_suite", ""])
def test_set_suite_name(testdir, suite_name):
@parametrize_families
def test_set_suite_name(testdir, suite_name, run_and_parse, xunit_family):
if suite_name:
testdir.makeini(
"""
[pytest]
junit_suite_name={}
junit_suite_name={suite_name}
junit_family={family}
""".format(
suite_name
suite_name=suite_name, family=xunit_family
)
)
expected = suite_name
@@ -1305,13 +1421,13 @@ def test_set_suite_name(testdir, suite_name):
pass
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node = dom.find_first_by_tag("testsuite")
node.assert_attr(name=expected)
def test_escaped_skipreason_issue3533(testdir):
def test_escaped_skipreason_issue3533(testdir, run_and_parse):
testdir.makepyfile(
"""
import pytest
@@ -1320,20 +1436,26 @@ def test_escaped_skipreason_issue3533(testdir):
pass
"""
)
_, dom = runandparse(testdir)
_, dom = run_and_parse()
node = dom.find_first_by_tag("testcase")
snode = node.find_first_by_tag("skipped")
assert "1 <> 2" in snode.text
snode.assert_attr(message="1 <> 2")
def test_logging_passing_tests_disabled_does_not_log_test_output(testdir):
@parametrize_families
def test_logging_passing_tests_disabled_does_not_log_test_output(
testdir, run_and_parse, xunit_family
):
testdir.makeini(
"""
[pytest]
junit_log_passing_tests=False
junit_logging=system-out
"""
junit_family={family}
""".format(
family=xunit_family
)
)
testdir.makepyfile(
"""
@@ -1347,7 +1469,7 @@ def test_logging_passing_tests_disabled_does_not_log_test_output(testdir):
logging.warning('hello')
"""
)
result, dom = runandparse(testdir)
result, dom = run_and_parse(family=xunit_family)
assert result.ret == 0
node = dom.find_first_by_tag("testcase")
assert len(node.find_by_tag("system-err")) == 0

View File

@@ -8,12 +8,6 @@ from _pytest.mark import EMPTY_PARAMETERSET_OPTION
from _pytest.mark import MarkGenerator as Mark
from _pytest.nodes import Collector
from _pytest.nodes import Node
from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
ignore_markinfo = pytest.mark.filterwarnings(
"ignore:MarkInfo objects:pytest.RemovedInPytest4Warning"
)
class TestMark:
@@ -25,7 +19,8 @@ class TestMark:
def test_pytest_mark_notcallable(self):
mark = Mark()
pytest.raises((AttributeError, TypeError), mark)
with pytest.raises(TypeError):
mark()
def test_mark_with_param(self):
def some_function(abc):
@@ -625,7 +620,6 @@ class TestFunctional:
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
@ignore_markinfo
def test_keyword_added_for_session(self, testdir):
testdir.makeconftest(
"""
@@ -651,7 +645,7 @@ class TestFunctional:
assert marker.kwargs == {}
"""
)
reprec = testdir.inline_run("-m", "mark1", SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run("-m", "mark1")
reprec.assertoutcome(passed=1)
def assert_markers(self, items, **expected):
@@ -689,7 +683,7 @@ class TestFunctional:
assert True
"""
)
reprec = testdir.inline_run(SHOW_PYTEST_WARNINGS_ARG)
reprec = testdir.inline_run()
reprec.assertoutcome(skipped=1)
@@ -989,7 +983,7 @@ def test_markers_from_parametrize(testdir):
"""
)
result = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest()
result.assert_outcomes(passed=4)
@@ -1003,15 +997,3 @@ def test_pytest_param_id_requires_string():
@pytest.mark.parametrize("s", (None, "hello world"))
def test_pytest_param_id_allows_none_or_string(s):
assert pytest.param(id=s)
def test_pytest_param_warning_on_unknown_kwargs():
with pytest.warns(PytestDeprecationWarning) as warninfo:
# typo, should be marks=
pytest.param(1, 2, mark=pytest.mark.xfail())
assert warninfo[0].filename == __file__
msg, = warninfo[0].message.args
assert msg == (
"pytest.param() got unexpected keyword arguments: ['mark'].\n"
"This will be an error in future versions."
)

View File

@@ -72,8 +72,7 @@ def test_make_hook_recorder(testdir):
def test_parseconfig(testdir):
config1 = testdir.parseconfig()
config2 = testdir.parseconfig()
assert config2 != config1
assert config1 != pytest.config
assert config2 is not config1
def test_testdir_runs_with_plugin(testdir):
@@ -279,7 +278,7 @@ def test_assert_outcomes_after_pytest_error(testdir):
testdir.makepyfile("def test_foo(): assert True")
result = testdir.runpytest("--unexpected-argument")
with pytest.raises(ValueError, match="Pytest terminal report not found"):
with pytest.raises(ValueError, match="Pytest terminal summary report not found"):
result.assert_outcomes(passed=0)

View File

@@ -3,7 +3,6 @@ import warnings
import pytest
from _pytest.recwarn import WarningsRecorder
from _pytest.warning_types import PytestDeprecationWarning
def test_recwarn_stacklevel(recwarn):
@@ -206,22 +205,17 @@ class TestDeprecatedCall:
class TestWarns:
def test_strings(self):
def test_check_callable(self):
source = "warnings.warn('w1', RuntimeWarning)"
with pytest.raises(TypeError, match=r".* must be callable"):
pytest.warns(RuntimeWarning, source)
def test_several_messages(self):
# different messages, b/c Python suppresses multiple identical warnings
source1 = "warnings.warn('w1', RuntimeWarning)"
source2 = "warnings.warn('w2', RuntimeWarning)"
source3 = "warnings.warn('w3', RuntimeWarning)"
with pytest.warns(PytestDeprecationWarning) as warninfo: # yo dawg
pytest.warns(RuntimeWarning, source1)
pytest.raises(
pytest.fail.Exception, lambda: pytest.warns(UserWarning, source2)
)
pytest.warns(RuntimeWarning, source3)
assert len(warninfo) == 3
for w in warninfo:
assert w.filename == __file__
msg, = w.message.args
assert msg.startswith("warns(..., 'code(as_a_string)') is deprecated")
pytest.warns(RuntimeWarning, lambda: warnings.warn("w1", RuntimeWarning))
with pytest.raises(pytest.fail.Exception):
pytest.warns(UserWarning, lambda: warnings.warn("w2", RuntimeWarning))
pytest.warns(RuntimeWarning, lambda: warnings.warn("w3", RuntimeWarning))
def test_function(self):
pytest.warns(
@@ -380,3 +374,9 @@ class TestWarns:
assert f() == 10
assert pytest.warns(UserWarning, f) == 10
assert pytest.warns(UserWarning, f) == 10
def test_warns_context_manager_with_kwargs(self):
with pytest.raises(TypeError) as excinfo:
with pytest.warns(UserWarning, foo="bar"):
pass
assert "Unexpected keyword arguments" in str(excinfo.value)

View File

@@ -617,7 +617,7 @@ class TestTerminalFunctional:
pluggy.__version__,
),
"*test_header_trailer_info.py .*",
"=* 1 passed*in *.[0-9][0-9] seconds *=",
"=* 1 passed*in *.[0-9][0-9]s *=",
]
)
if request.config.pluginmanager.list_plugin_distinfo():
@@ -1678,3 +1678,20 @@ def test_line_with_reprcrash(monkeypatch):
check("😄😄😄😄😄\n2nd line", 41, "FAILED nodeid::😄::withunicode - 😄😄...")
check("😄😄😄😄😄\n2nd line", 42, "FAILED nodeid::😄::withunicode - 😄😄😄...")
check("😄😄😄😄😄\n2nd line", 80, "FAILED nodeid::😄::withunicode - 😄😄😄😄😄")
@pytest.mark.parametrize(
"seconds, expected",
[
(10.0, "10.00s"),
(10.34, "10.34s"),
(59.99, "59.99s"),
(60.55, "60.55s (0:01:00)"),
(123.55, "123.55s (0:02:03)"),
(60 * 60 + 0.5, "3600.50s (1:00:00)"),
],
)
def test_format_session_duration(seconds, expected):
from _pytest.terminal import format_session_duration
assert format_session_duration(seconds) == expected

View File

@@ -7,7 +7,6 @@ import attr
import pytest
from _pytest import pathlib
from _pytest.pathlib import Path
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
def test_tmpdir_fixture(testdir):
@@ -16,13 +15,6 @@ def test_tmpdir_fixture(testdir):
results.stdout.fnmatch_lines(["*1 passed*"])
def test_ensuretemp(recwarn):
d1 = pytest.ensuretemp("hello")
d2 = pytest.ensuretemp("hello")
assert d1 == d2
assert d1.check(dir=1)
@attr.s
class FakeConfig:
basetemp = attr.ib()
@@ -87,12 +79,13 @@ def test_basetemp(testdir):
p = testdir.makepyfile(
"""
import pytest
def test_1():
pytest.ensuretemp("hello")
def test_1(tmpdir_factory):
tmpdir_factory.mktemp('hello', numbered=False)
"""
)
result = testdir.runpytest(p, "--basetemp=%s" % mytemp, SHOW_PYTEST_WARNINGS_ARG)
result = testdir.runpytest(p, "--basetemp=%s" % mytemp)
assert result.ret == 0
print(mytemp)
assert mytemp.join("hello").check()

View File

@@ -939,9 +939,7 @@ def test_class_method_containing_test_issue1558(testdir):
reprec.assertoutcome(passed=1)
@pytest.mark.parametrize(
"base", ["builtins.object", "unittest.TestCase", "unittest2.TestCase"]
)
@pytest.mark.parametrize("base", ["builtins.object", "unittest.TestCase"])
def test_usefixtures_marker_on_unittest(base, testdir):
"""#3498"""
module = base.rsplit(".", 1)[0]

View File

@@ -498,38 +498,15 @@ class TestDeprecationWarningsByDefault:
@pytest.mark.parametrize("change_default", [None, "ini", "cmdline"])
def test_removed_in_pytest4_warning_as_error(testdir, change_default):
testdir.makepyfile(
"""
import warnings, pytest
def test():
warnings.warn(pytest.RemovedInPytest4Warning("some warning"))
"""
)
if change_default == "ini":
testdir.makeini(
"""
[pytest]
filterwarnings =
ignore::pytest.RemovedInPytest4Warning
"""
)
args = (
("-Wignore::pytest.RemovedInPytest4Warning",)
if change_default == "cmdline"
else ()
)
result = testdir.runpytest(*args)
if change_default is None:
result.stdout.fnmatch_lines(["* 1 failed in *"])
else:
assert change_default in ("ini", "cmdline")
result.stdout.fnmatch_lines(["* 1 passed in *"])
@pytest.mark.parametrize("change_default", [None, "ini", "cmdline"])
@pytest.mark.skip(
reason="This test should be enabled again before pytest 6.0 is released"
)
def test_deprecation_warning_as_error(testdir, change_default):
"""This ensures that PytestDeprecationWarnings raised by pytest are turned into errors.
This test should be enabled as part of each major release, and skipped again afterwards
to ensure our deprecations are turning into warnings as expected.
"""
testdir.makepyfile(
"""
import warnings, pytest