@@ -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*"])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
147
testing/example_scripts/junit-10.xsd
Normal file
147
testing/example_scripts/junit-10.xsd
Normal 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>
|
||||
@@ -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():
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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` """
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import importlib_metadata
|
||||
from _pytest.compat import importlib_metadata
|
||||
|
||||
|
||||
def test_pytest_entry_points_are_identical():
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user