2024-01-28 21:12:42 +08:00
|
|
|
# mypy: allow-untyped-defs
|
2020-12-19 20:06:17 +08:00
|
|
|
from pathlib import Path
|
2022-02-08 21:32:21 +08:00
|
|
|
import re
|
2020-12-14 21:54:59 +08:00
|
|
|
from typing import cast
|
2020-11-21 21:49:17 +08:00
|
|
|
from typing import Type
|
2022-02-08 21:32:21 +08:00
|
|
|
import warnings
|
2020-10-24 07:09:28 +08:00
|
|
|
|
2017-10-24 00:49:49 +08:00
|
|
|
from _pytest import nodes
|
2021-08-31 20:12:11 +08:00
|
|
|
from _pytest.outcomes import OutcomeException
|
2020-10-31 04:34:05 +08:00
|
|
|
from _pytest.pytester import Pytester
|
2020-11-21 21:49:17 +08:00
|
|
|
from _pytest.warning_types import PytestWarning
|
2017-10-23 20:26:42 +08:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
2020-05-01 19:40:17 +08:00
|
|
|
def test_node_from_parent_disallowed_arguments() -> None:
|
2020-01-01 03:20:28 +08:00
|
|
|
with pytest.raises(TypeError, match="session is"):
|
2020-07-10 14:44:14 +08:00
|
|
|
nodes.Node.from_parent(None, session=None) # type: ignore[arg-type]
|
2020-01-01 03:20:28 +08:00
|
|
|
with pytest.raises(TypeError, match="config is"):
|
2020-07-10 14:44:14 +08:00
|
|
|
nodes.Node.from_parent(None, config=None) # type: ignore[arg-type]
|
2020-01-01 03:20:28 +08:00
|
|
|
|
|
|
|
|
2021-08-31 20:12:11 +08:00
|
|
|
def test_node_direct_construction_deprecated() -> None:
|
|
|
|
with pytest.raises(
|
|
|
|
OutcomeException,
|
|
|
|
match=(
|
|
|
|
"Direct construction of _pytest.nodes.Node has been deprecated, please "
|
|
|
|
"use _pytest.nodes.Node.from_parent.\nSee "
|
|
|
|
"https://docs.pytest.org/en/stable/deprecations.html#node-construction-changed-to-node-from-parent"
|
|
|
|
" for more details."
|
|
|
|
),
|
|
|
|
):
|
|
|
|
nodes.Node(None, session=None) # type: ignore[arg-type]
|
|
|
|
|
|
|
|
|
2021-06-24 17:45:32 +08:00
|
|
|
def test_subclassing_both_item_and_collector_deprecated(
|
|
|
|
request, tmp_path: Path
|
|
|
|
) -> None:
|
|
|
|
"""
|
2022-02-08 21:32:21 +08:00
|
|
|
Verifies we warn on diamond inheritance as well as correctly managing legacy
|
|
|
|
inheritance constructors with missing args as found in plugins.
|
2021-06-24 17:45:32 +08:00
|
|
|
"""
|
2022-02-08 21:32:21 +08:00
|
|
|
# We do not expect any warnings messages to issued during class definition.
|
|
|
|
with warnings.catch_warnings():
|
|
|
|
warnings.simplefilter("error")
|
2021-06-24 17:45:32 +08:00
|
|
|
|
2021-11-08 22:51:04 +08:00
|
|
|
class SoWrong(nodes.Item, nodes.File):
|
2024-01-01 22:45:17 +08:00
|
|
|
def __init__(self, path, parent):
|
2021-06-24 17:45:32 +08:00
|
|
|
"""Legacy ctor with legacy call # don't wana see"""
|
2024-01-01 22:45:17 +08:00
|
|
|
super().__init__(parent, path)
|
2021-06-24 17:45:32 +08:00
|
|
|
|
2023-12-07 00:27:17 +08:00
|
|
|
def collect(self):
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def runtest(self):
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2022-02-08 21:32:21 +08:00
|
|
|
with pytest.warns(PytestWarning) as rec:
|
2024-01-01 22:45:17 +08:00
|
|
|
SoWrong.from_parent(request.session, path=tmp_path / "broken.txt", wrong=10)
|
2022-02-08 21:32:21 +08:00
|
|
|
messages = [str(x.message) for x in rec]
|
|
|
|
assert any(
|
|
|
|
re.search(".*SoWrong.* not using a cooperative constructor.*", x)
|
|
|
|
for x in messages
|
|
|
|
)
|
|
|
|
assert any(
|
|
|
|
re.search("(?m)SoWrong .* should not be a collector", x) for x in messages
|
|
|
|
)
|
2021-06-24 17:45:32 +08:00
|
|
|
|
|
|
|
|
2020-11-21 21:49:17 +08:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"warn_type, msg", [(DeprecationWarning, "deprecated"), (PytestWarning, "pytest")]
|
|
|
|
)
|
|
|
|
def test_node_warn_is_no_longer_only_pytest_warnings(
|
|
|
|
pytester: Pytester, warn_type: Type[Warning], msg: str
|
|
|
|
) -> None:
|
|
|
|
items = pytester.getitems(
|
|
|
|
"""
|
|
|
|
def test():
|
|
|
|
pass
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
with pytest.warns(warn_type, match=msg):
|
|
|
|
items[0].warn(warn_type(msg))
|
|
|
|
|
|
|
|
|
|
|
|
def test_node_warning_enforces_warning_types(pytester: Pytester) -> None:
|
2020-10-31 04:34:05 +08:00
|
|
|
items = pytester.getitems(
|
2018-09-05 01:20:42 +08:00
|
|
|
"""
|
|
|
|
def test():
|
|
|
|
pass
|
|
|
|
"""
|
|
|
|
)
|
2020-11-21 21:49:17 +08:00
|
|
|
with pytest.raises(
|
|
|
|
ValueError, match="warning must be an instance of Warning or subclass"
|
|
|
|
):
|
|
|
|
items[0].warn(Exception("ok")) # type: ignore[arg-type]
|
2018-11-09 03:35:53 +08:00
|
|
|
|
|
|
|
|
2020-05-01 19:40:17 +08:00
|
|
|
def test__check_initialpaths_for_relpath() -> None:
|
2018-11-09 03:35:53 +08:00
|
|
|
"""Ensure that it handles dirs, and does not always use dirname."""
|
2020-12-19 20:06:17 +08:00
|
|
|
cwd = Path.cwd()
|
2018-11-09 03:35:53 +08:00
|
|
|
|
2020-05-01 19:40:17 +08:00
|
|
|
class FakeSession1:
|
2020-12-19 20:06:17 +08:00
|
|
|
_initialpaths = frozenset({cwd})
|
2018-11-09 03:35:53 +08:00
|
|
|
|
2020-12-14 21:54:59 +08:00
|
|
|
session = cast(pytest.Session, FakeSession1)
|
|
|
|
|
2021-03-15 22:01:58 +08:00
|
|
|
assert nodes._check_initialpaths_for_relpath(session, cwd) == ""
|
2018-11-09 03:35:53 +08:00
|
|
|
|
2020-12-19 20:06:17 +08:00
|
|
|
sub = cwd / "file"
|
2018-11-09 03:35:53 +08:00
|
|
|
|
2020-05-01 19:40:17 +08:00
|
|
|
class FakeSession2:
|
2020-12-19 20:06:17 +08:00
|
|
|
_initialpaths = frozenset({cwd})
|
2018-11-09 03:35:53 +08:00
|
|
|
|
2020-12-14 21:54:59 +08:00
|
|
|
session = cast(pytest.Session, FakeSession2)
|
|
|
|
|
2021-03-15 22:01:58 +08:00
|
|
|
assert nodes._check_initialpaths_for_relpath(session, sub) == "file"
|
2018-11-09 03:35:53 +08:00
|
|
|
|
2021-06-22 19:25:52 +08:00
|
|
|
outside = Path("/outside-this-does-not-exist")
|
2020-12-14 21:54:59 +08:00
|
|
|
assert nodes._check_initialpaths_for_relpath(session, outside) is None
|
2020-05-16 22:36:22 +08:00
|
|
|
|
|
|
|
|
2020-10-31 04:34:05 +08:00
|
|
|
def test_failure_with_changed_cwd(pytester: Pytester) -> None:
|
2020-05-16 22:36:22 +08:00
|
|
|
"""
|
|
|
|
Test failure lines should use absolute paths if cwd has changed since
|
|
|
|
invocation, so the path is correct (#6428).
|
|
|
|
"""
|
2020-10-31 04:34:05 +08:00
|
|
|
p = pytester.makepyfile(
|
2020-05-16 22:36:22 +08:00
|
|
|
"""
|
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def private_dir():
|
|
|
|
out_dir = 'ddd'
|
|
|
|
os.mkdir(out_dir)
|
|
|
|
old_dir = os.getcwd()
|
|
|
|
os.chdir(out_dir)
|
|
|
|
yield out_dir
|
|
|
|
os.chdir(old_dir)
|
|
|
|
|
|
|
|
def test_show_wrong_path(private_dir):
|
|
|
|
assert False
|
|
|
|
"""
|
|
|
|
)
|
2020-10-31 04:34:05 +08:00
|
|
|
result = pytester.runpytest()
|
2020-05-16 22:36:22 +08:00
|
|
|
result.stdout.fnmatch_lines([str(p) + ":*: AssertionError", "*1 failed in *"])
|