Migrate test_assertrewrite.py from testdir to pytester (#7952)

This commit is contained in:
Christine Mecklenborg 2020-10-29 02:54:34 -05:00 committed by GitHub
parent b95991aeea
commit efe470bf1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 210 additions and 193 deletions

View File

@ -29,7 +29,7 @@ from _pytest.assertion.rewrite import PYTEST_TAG
from _pytest.assertion.rewrite import rewrite_asserts from _pytest.assertion.rewrite import rewrite_asserts
from _pytest.config import ExitCode from _pytest.config import ExitCode
from _pytest.pathlib import make_numbered_dir from _pytest.pathlib import make_numbered_dir
from _pytest.pytester import Testdir from _pytest.pytester import Pytester
def rewrite(src: str) -> ast.Module: def rewrite(src: str) -> ast.Module:
@ -66,7 +66,7 @@ def getmsg(
class TestAssertionRewrite: class TestAssertionRewrite:
def test_place_initial_imports(self): def test_place_initial_imports(self) -> None:
s = """'Doc string'\nother = stuff""" s = """'Doc string'\nother = stuff"""
m = rewrite(s) m = rewrite(s)
assert isinstance(m.body[0], ast.Expr) assert isinstance(m.body[0], ast.Expr)
@ -115,19 +115,19 @@ class TestAssertionRewrite:
assert isinstance(m.body[1], ast.Assert) assert isinstance(m.body[1], ast.Assert)
assert m.body[1].msg is None assert m.body[1].msg is None
def test_dont_rewrite_plugin(self, testdir): def test_dont_rewrite_plugin(self, pytester: Pytester) -> None:
contents = { contents = {
"conftest.py": "pytest_plugins = 'plugin'; import plugin", "conftest.py": "pytest_plugins = 'plugin'; import plugin",
"plugin.py": "'PYTEST_DONT_REWRITE'", "plugin.py": "'PYTEST_DONT_REWRITE'",
"test_foo.py": "def test_foo(): pass", "test_foo.py": "def test_foo(): pass",
} }
testdir.makepyfile(**contents) pytester.makepyfile(**contents)
result = testdir.runpytest_subprocess() result = pytester.runpytest_subprocess()
assert "warning" not in "".join(result.outlines) assert "warning" not in "".join(result.outlines)
def test_rewrites_plugin_as_a_package(self, testdir): def test_rewrites_plugin_as_a_package(self, pytester: Pytester) -> None:
pkgdir = testdir.mkpydir("plugin") pkgdir = pytester.mkpydir("plugin")
pkgdir.join("__init__.py").write( pkgdir.joinpath("__init__.py").write_text(
"import pytest\n" "import pytest\n"
"@pytest.fixture\n" "@pytest.fixture\n"
"def special_asserter():\n" "def special_asserter():\n"
@ -135,26 +135,27 @@ class TestAssertionRewrite:
" assert x == y\n" " assert x == y\n"
" return special_assert\n" " return special_assert\n"
) )
testdir.makeconftest('pytest_plugins = ["plugin"]') pytester.makeconftest('pytest_plugins = ["plugin"]')
testdir.makepyfile("def test(special_asserter): special_asserter(1, 2)\n") pytester.makepyfile("def test(special_asserter): special_asserter(1, 2)\n")
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*assert 1 == 2*"]) result.stdout.fnmatch_lines(["*assert 1 == 2*"])
def test_honors_pep_235(self, testdir, monkeypatch): def test_honors_pep_235(self, pytester: Pytester, monkeypatch) -> None:
# note: couldn't make it fail on macos with a single `sys.path` entry # note: couldn't make it fail on macos with a single `sys.path` entry
# note: these modules are named `test_*` to trigger rewriting # note: these modules are named `test_*` to trigger rewriting
testdir.tmpdir.join("test_y.py").write("x = 1") pytester.makepyfile(test_y="x = 1")
xdir = testdir.tmpdir.join("x").ensure_dir() xdir = pytester.mkdir("x")
xdir.join("test_Y").ensure_dir().join("__init__.py").write("x = 2") pytester.mkpydir(str(xdir.joinpath("test_Y")))
testdir.makepyfile( xdir.joinpath("test_Y").joinpath("__init__.py").write_text("x = 2")
pytester.makepyfile(
"import test_y\n" "import test_y\n"
"import test_Y\n" "import test_Y\n"
"def test():\n" "def test():\n"
" assert test_y.x == 1\n" " assert test_y.x == 1\n"
" assert test_Y.x == 2\n" " assert test_Y.x == 2\n"
) )
monkeypatch.syspath_prepend(xdir) monkeypatch.syspath_prepend(str(xdir))
testdir.runpytest().assert_outcomes(passed=1) pytester.runpytest().assert_outcomes(passed=1)
def test_name(self, request) -> None: def test_name(self, request) -> None:
def f1() -> None: def f1() -> None:
@ -260,78 +261,78 @@ class TestAssertionRewrite:
" + where Y = cls()", " + where Y = cls()",
] ]
def test_assert_already_has_message(self): def test_assert_already_has_message(self) -> None:
def f(): def f():
assert False, "something bad!" assert False, "something bad!"
assert getmsg(f) == "AssertionError: something bad!\nassert False" assert getmsg(f) == "AssertionError: something bad!\nassert False"
def test_assertion_message(self, testdir): def test_assertion_message(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_foo(): def test_foo():
assert 1 == 2, "The failure message" assert 1 == 2, "The failure message"
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
["*AssertionError*The failure message*", "*assert 1 == 2*"] ["*AssertionError*The failure message*", "*assert 1 == 2*"]
) )
def test_assertion_message_multiline(self, testdir): def test_assertion_message_multiline(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_foo(): def test_foo():
assert 1 == 2, "A multiline\\nfailure message" assert 1 == 2, "A multiline\\nfailure message"
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
["*AssertionError*A multiline*", "*failure message*", "*assert 1 == 2*"] ["*AssertionError*A multiline*", "*failure message*", "*assert 1 == 2*"]
) )
def test_assertion_message_tuple(self, testdir): def test_assertion_message_tuple(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_foo(): def test_foo():
assert 1 == 2, (1, 2) assert 1 == 2, (1, 2)
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
["*AssertionError*%s*" % repr((1, 2)), "*assert 1 == 2*"] ["*AssertionError*%s*" % repr((1, 2)), "*assert 1 == 2*"]
) )
def test_assertion_message_expr(self, testdir): def test_assertion_message_expr(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_foo(): def test_foo():
assert 1 == 2, 1 + 2 assert 1 == 2, 1 + 2
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines(["*AssertionError*3*", "*assert 1 == 2*"]) result.stdout.fnmatch_lines(["*AssertionError*3*", "*assert 1 == 2*"])
def test_assertion_message_escape(self, testdir): def test_assertion_message_escape(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_foo(): def test_foo():
assert 1 == 2, 'To be escaped: %' assert 1 == 2, 'To be escaped: %'
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
["*AssertionError: To be escaped: %", "*assert 1 == 2"] ["*AssertionError: To be escaped: %", "*assert 1 == 2"]
) )
def test_assertion_messages_bytes(self, testdir): def test_assertion_messages_bytes(self, pytester: Pytester) -> None:
testdir.makepyfile("def test_bytes_assertion():\n assert False, b'ohai!'\n") pytester.makepyfile("def test_bytes_assertion():\n assert False, b'ohai!'\n")
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines(["*AssertionError: b'ohai!'", "*assert False"]) result.stdout.fnmatch_lines(["*AssertionError: b'ohai!'", "*assert False"])
@ -475,8 +476,8 @@ class TestAssertionRewrite:
assert getmsg(f2) == "assert (False or (4 % 2))" assert getmsg(f2) == "assert (False or (4 % 2))"
def test_at_operator_issue1290(self, testdir): def test_at_operator_issue1290(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
class Matrix(object): class Matrix(object):
def __init__(self, num): def __init__(self, num):
@ -487,11 +488,11 @@ class TestAssertionRewrite:
def test_multmat_operator(): def test_multmat_operator():
assert Matrix(2) @ Matrix(3) == 6""" assert Matrix(2) @ Matrix(3) == 6"""
) )
testdir.runpytest().assert_outcomes(passed=1) pytester.runpytest().assert_outcomes(passed=1)
def test_starred_with_side_effect(self, testdir): def test_starred_with_side_effect(self, pytester: Pytester) -> None:
"""See #4412""" """See #4412"""
testdir.makepyfile( pytester.makepyfile(
"""\ """\
def test(): def test():
f = lambda x: x f = lambda x: x
@ -499,7 +500,7 @@ class TestAssertionRewrite:
assert 2 * next(x) == f(*[next(x)]) assert 2 * next(x) == f(*[next(x)])
""" """
) )
testdir.runpytest().assert_outcomes(passed=1) pytester.runpytest().assert_outcomes(passed=1)
def test_call(self) -> None: def test_call(self) -> None:
def g(a=42, *args, **kwargs) -> bool: def g(a=42, *args, **kwargs) -> bool:
@ -629,7 +630,7 @@ class TestAssertionRewrite:
getmsg(f5, must_pass=True) getmsg(f5, must_pass=True)
def test_len(self, request): def test_len(self, request) -> None:
def f(): def f():
values = list(range(10)) values = list(range(10))
assert len(values) == 11 assert len(values) == 11
@ -727,31 +728,31 @@ class TestAssertionRewrite:
class TestRewriteOnImport: class TestRewriteOnImport:
def test_pycache_is_a_file(self, testdir): def test_pycache_is_a_file(self, pytester: Pytester) -> None:
testdir.tmpdir.join("__pycache__").write("Hello") pytester.path.joinpath("__pycache__").write_text("Hello")
testdir.makepyfile( pytester.makepyfile(
""" """
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals()""" assert "@py_builtins" in globals()"""
) )
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
def test_pycache_is_readonly(self, testdir): def test_pycache_is_readonly(self, pytester: Pytester) -> None:
cache = testdir.tmpdir.mkdir("__pycache__") cache = pytester.mkdir("__pycache__")
old_mode = cache.stat().mode old_mode = cache.stat().st_mode
cache.chmod(old_mode ^ stat.S_IWRITE) cache.chmod(old_mode ^ stat.S_IWRITE)
testdir.makepyfile( pytester.makepyfile(
""" """
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals()""" assert "@py_builtins" in globals()"""
) )
try: try:
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
finally: finally:
cache.chmod(old_mode) cache.chmod(old_mode)
def test_zipfile(self, testdir): def test_zipfile(self, pytester: Pytester) -> None:
z = testdir.tmpdir.join("myzip.zip") z = pytester.path.joinpath("myzip.zip")
z_fn = str(z) z_fn = str(z)
f = zipfile.ZipFile(z_fn, "w") f = zipfile.ZipFile(z_fn, "w")
try: try:
@ -760,35 +761,34 @@ class TestRewriteOnImport:
finally: finally:
f.close() f.close()
z.chmod(256) z.chmod(256)
testdir.makepyfile( pytester.makepyfile(
""" """
import sys import sys
sys.path.append(%r) sys.path.append(%r)
import test_gum.test_lizard""" import test_gum.test_lizard"""
% (z_fn,) % (z_fn,)
) )
assert testdir.runpytest().ret == ExitCode.NO_TESTS_COLLECTED assert pytester.runpytest().ret == ExitCode.NO_TESTS_COLLECTED
def test_readonly(self, testdir): def test_readonly(self, pytester: Pytester) -> None:
sub = testdir.mkdir("testing") sub = pytester.mkdir("testing")
sub.join("test_readonly.py").write( sub.joinpath("test_readonly.py").write_bytes(
b""" b"""
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals() assert "@py_builtins" in globals()
""", """,
"wb",
) )
old_mode = sub.stat().mode old_mode = sub.stat().st_mode
sub.chmod(320) sub.chmod(320)
try: try:
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
finally: finally:
sub.chmod(old_mode) sub.chmod(old_mode)
def test_dont_write_bytecode(self, testdir, monkeypatch): def test_dont_write_bytecode(self, pytester: Pytester, monkeypatch) -> None:
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False) monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
testdir.makepyfile( pytester.makepyfile(
""" """
import os import os
def test_no_bytecode(): def test_no_bytecode():
@ -797,20 +797,20 @@ def test_rewritten():
assert not os.path.exists(os.path.dirname(__cached__))""" assert not os.path.exists(os.path.dirname(__cached__))"""
) )
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
assert testdir.runpytest_subprocess().ret == 0 assert pytester.runpytest_subprocess().ret == 0
def test_orphaned_pyc_file(self, testdir, monkeypatch): def test_orphaned_pyc_file(self, pytester: Pytester, monkeypatch) -> None:
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False) monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
monkeypatch.setattr(sys, "pycache_prefix", None, raising=False) monkeypatch.setattr(sys, "pycache_prefix", None, raising=False)
testdir.makepyfile( pytester.makepyfile(
""" """
import orphan import orphan
def test_it(): def test_it():
assert orphan.value == 17 assert orphan.value == 17
""" """
) )
testdir.makepyfile( pytester.makepyfile(
orphan=""" orphan="""
value = 17 value = 17
""" """
@ -826,19 +826,21 @@ def test_rewritten():
assert len(pycs) == 1 assert len(pycs) == 1
os.rename(pycs[0], "orphan.pyc") os.rename(pycs[0], "orphan.pyc")
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
def test_cached_pyc_includes_pytest_version(self, testdir, monkeypatch): def test_cached_pyc_includes_pytest_version(
self, pytester: Pytester, monkeypatch
) -> None:
"""Avoid stale caches (#1671)""" """Avoid stale caches (#1671)"""
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False) monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
testdir.makepyfile( pytester.makepyfile(
test_foo=""" test_foo="""
def test_foo(): def test_foo():
assert True assert True
""" """
) )
result = testdir.runpytest_subprocess() result = pytester.runpytest_subprocess()
assert result.ret == 0 assert result.ret == 0
found_names = glob.glob(f"__pycache__/*-pytest-{pytest.__version__}.pyc") found_names = glob.glob(f"__pycache__/*-pytest-{pytest.__version__}.pyc")
assert found_names, "pyc with expected tag not found in names: {}".format( assert found_names, "pyc with expected tag not found in names: {}".format(
@ -846,81 +848,83 @@ def test_rewritten():
) )
@pytest.mark.skipif('"__pypy__" in sys.modules') @pytest.mark.skipif('"__pypy__" in sys.modules')
def test_pyc_vs_pyo(self, testdir, monkeypatch): def test_pyc_vs_pyo(self, pytester: Pytester, monkeypatch) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
def test_optimized(): def test_optimized():
"hello" "hello"
assert test_optimized.__doc__ is None""" assert test_optimized.__doc__ is None"""
) )
p = make_numbered_dir(root=Path(testdir.tmpdir), prefix="runpytest-") p = make_numbered_dir(root=Path(pytester.path), prefix="runpytest-")
tmp = "--basetemp=%s" % p tmp = "--basetemp=%s" % p
monkeypatch.setenv("PYTHONOPTIMIZE", "2") monkeypatch.setenv("PYTHONOPTIMIZE", "2")
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False) monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
assert testdir.runpytest_subprocess(tmp).ret == 0 assert pytester.runpytest_subprocess(tmp).ret == 0
tagged = "test_pyc_vs_pyo." + PYTEST_TAG tagged = "test_pyc_vs_pyo." + PYTEST_TAG
assert tagged + ".pyo" in os.listdir("__pycache__") assert tagged + ".pyo" in os.listdir("__pycache__")
monkeypatch.undo() monkeypatch.undo()
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False) monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
assert testdir.runpytest_subprocess(tmp).ret == 1 assert pytester.runpytest_subprocess(tmp).ret == 1
assert tagged + ".pyc" in os.listdir("__pycache__") assert tagged + ".pyc" in os.listdir("__pycache__")
def test_package(self, testdir): def test_package(self, pytester: Pytester) -> None:
pkg = testdir.tmpdir.join("pkg") pkg = pytester.path.joinpath("pkg")
pkg.mkdir() pkg.mkdir()
pkg.join("__init__.py").ensure() pkg.joinpath("__init__.py")
pkg.join("test_blah.py").write( pkg.joinpath("test_blah.py").write_text(
""" """
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals()""" assert "@py_builtins" in globals()"""
) )
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
def test_translate_newlines(self, testdir): def test_translate_newlines(self, pytester: Pytester) -> None:
content = "def test_rewritten():\r\n assert '@py_builtins' in globals()" content = "def test_rewritten():\r\n assert '@py_builtins' in globals()"
b = content.encode("utf-8") b = content.encode("utf-8")
testdir.tmpdir.join("test_newlines.py").write(b, "wb") pytester.path.joinpath("test_newlines.py").write_bytes(b)
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
def test_package_without__init__py(self, testdir): def test_package_without__init__py(self, pytester: Pytester) -> None:
pkg = testdir.mkdir("a_package_without_init_py") pkg = pytester.mkdir("a_package_without_init_py")
pkg.join("module.py").ensure() pkg.joinpath("module.py").touch()
testdir.makepyfile("import a_package_without_init_py.module") pytester.makepyfile("import a_package_without_init_py.module")
assert testdir.runpytest().ret == ExitCode.NO_TESTS_COLLECTED assert pytester.runpytest().ret == ExitCode.NO_TESTS_COLLECTED
def test_rewrite_warning(self, testdir): def test_rewrite_warning(self, pytester: Pytester) -> None:
testdir.makeconftest( pytester.makeconftest(
""" """
import pytest import pytest
pytest.register_assert_rewrite("_pytest") pytest.register_assert_rewrite("_pytest")
""" """
) )
# needs to be a subprocess because pytester explicitly disables this warning # needs to be a subprocess because pytester explicitly disables this warning
result = testdir.runpytest_subprocess() result = pytester.runpytest_subprocess()
result.stdout.fnmatch_lines(["*Module already imported*: _pytest"]) result.stdout.fnmatch_lines(["*Module already imported*: _pytest"])
def test_rewrite_module_imported_from_conftest(self, testdir): def test_rewrite_module_imported_from_conftest(self, pytester: Pytester) -> None:
testdir.makeconftest( pytester.makeconftest(
""" """
import test_rewrite_module_imported import test_rewrite_module_imported
""" """
) )
testdir.makepyfile( pytester.makepyfile(
test_rewrite_module_imported=""" test_rewrite_module_imported="""
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals() assert "@py_builtins" in globals()
""" """
) )
assert testdir.runpytest_subprocess().ret == 0 assert pytester.runpytest_subprocess().ret == 0
def test_remember_rewritten_modules(self, pytestconfig, testdir, monkeypatch): def test_remember_rewritten_modules(
self, pytestconfig, pytester: Pytester, monkeypatch
) -> None:
"""`AssertionRewriteHook` should remember rewritten modules so it """`AssertionRewriteHook` should remember rewritten modules so it
doesn't give false positives (#2005).""" doesn't give false positives (#2005)."""
monkeypatch.syspath_prepend(testdir.tmpdir) monkeypatch.syspath_prepend(pytester.path)
testdir.makepyfile(test_remember_rewritten_modules="") pytester.makepyfile(test_remember_rewritten_modules="")
warnings = [] warnings = []
hook = AssertionRewritingHook(pytestconfig) hook = AssertionRewritingHook(pytestconfig)
monkeypatch.setattr( monkeypatch.setattr(
@ -934,8 +938,8 @@ def test_rewritten():
hook.mark_rewrite("test_remember_rewritten_modules") hook.mark_rewrite("test_remember_rewritten_modules")
assert warnings == [] assert warnings == []
def test_rewrite_warning_using_pytest_plugins(self, testdir): def test_rewrite_warning_using_pytest_plugins(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
**{ **{
"conftest.py": "pytest_plugins = ['core', 'gui', 'sci']", "conftest.py": "pytest_plugins = ['core', 'gui', 'sci']",
"core.py": "", "core.py": "",
@ -944,14 +948,16 @@ def test_rewritten():
"test_rewrite_warning_pytest_plugins.py": "def test(): pass", "test_rewrite_warning_pytest_plugins.py": "def test(): pass",
} }
) )
testdir.chdir() pytester.chdir()
result = testdir.runpytest_subprocess() result = pytester.runpytest_subprocess()
result.stdout.fnmatch_lines(["*= 1 passed in *=*"]) result.stdout.fnmatch_lines(["*= 1 passed in *=*"])
result.stdout.no_fnmatch_line("*pytest-warning summary*") result.stdout.no_fnmatch_line("*pytest-warning summary*")
def test_rewrite_warning_using_pytest_plugins_env_var(self, testdir, monkeypatch): def test_rewrite_warning_using_pytest_plugins_env_var(
self, pytester: Pytester, monkeypatch
) -> None:
monkeypatch.setenv("PYTEST_PLUGINS", "plugin") monkeypatch.setenv("PYTEST_PLUGINS", "plugin")
testdir.makepyfile( pytester.makepyfile(
**{ **{
"plugin.py": "", "plugin.py": "",
"test_rewrite_warning_using_pytest_plugins_env_var.py": """ "test_rewrite_warning_using_pytest_plugins_env_var.py": """
@ -962,29 +968,30 @@ def test_rewritten():
""", """,
} }
) )
testdir.chdir() pytester.chdir()
result = testdir.runpytest_subprocess() result = pytester.runpytest_subprocess()
result.stdout.fnmatch_lines(["*= 1 passed in *=*"]) result.stdout.fnmatch_lines(["*= 1 passed in *=*"])
result.stdout.no_fnmatch_line("*pytest-warning summary*") result.stdout.no_fnmatch_line("*pytest-warning summary*")
class TestAssertionRewriteHookDetails: class TestAssertionRewriteHookDetails:
def test_sys_meta_path_munged(self, testdir): def test_sys_meta_path_munged(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_meta_path(): def test_meta_path():
import sys; sys.meta_path = []""" import sys; sys.meta_path = []"""
) )
assert testdir.runpytest().ret == 0 assert pytester.runpytest().ret == 0
def test_write_pyc(self, testdir: Testdir, tmpdir, monkeypatch) -> None: def test_write_pyc(self, pytester: Pytester, tmp_path, monkeypatch) -> None:
from _pytest.assertion.rewrite import _write_pyc from _pytest.assertion.rewrite import _write_pyc
from _pytest.assertion import AssertionState from _pytest.assertion import AssertionState
config = testdir.parseconfig() config = pytester.parseconfig()
state = AssertionState(config, "rewrite") state = AssertionState(config, "rewrite")
source_path = str(tmpdir.ensure("source.py")) tmp_path.joinpath("source.py").touch()
pycpath = tmpdir.join("pyc").strpath source_path = str(tmp_path)
pycpath = tmp_path.joinpath("pyc")
co = compile("1", "f.py", "single") co = compile("1", "f.py", "single")
assert _write_pyc(state, co, os.stat(source_path), pycpath) assert _write_pyc(state, co, os.stat(source_path), pycpath)
@ -1010,7 +1017,7 @@ class TestAssertionRewriteHookDetails:
assert not _write_pyc(state, co, os.stat(source_path), pycpath) assert not _write_pyc(state, co, os.stat(source_path), pycpath)
def test_resources_provider_for_loader(self, testdir): def test_resources_provider_for_loader(self, pytester: Pytester) -> None:
""" """
Attempts to load resources from a package should succeed normally, Attempts to load resources from a package should succeed normally,
even when the AssertionRewriteHook is used to load the modules. even when the AssertionRewriteHook is used to load the modules.
@ -1019,7 +1026,7 @@ class TestAssertionRewriteHookDetails:
""" """
pytest.importorskip("pkg_resources") pytest.importorskip("pkg_resources")
testdir.mkpydir("testpkg") pytester.mkpydir("testpkg")
contents = { contents = {
"testpkg/test_pkg": """ "testpkg/test_pkg": """
import pkg_resources import pkg_resources
@ -1034,10 +1041,10 @@ class TestAssertionRewriteHookDetails:
assert res == 'Load me please.' assert res == 'Load me please.'
""" """
} }
testdir.makepyfile(**contents) pytester.makepyfile(**contents)
testdir.maketxtfile(**{"testpkg/resource": "Load me please."}) pytester.maketxtfile(**{"testpkg/resource": "Load me please."})
result = testdir.runpytest_subprocess() result = pytester.runpytest_subprocess()
result.assert_outcomes(passed=1) result.assert_outcomes(passed=1)
def test_read_pyc(self, tmp_path: Path) -> None: def test_read_pyc(self, tmp_path: Path) -> None:
@ -1062,15 +1069,15 @@ class TestAssertionRewriteHookDetails:
assert _read_pyc(source, pyc) is None # no error assert _read_pyc(source, pyc) is None # no error
def test_reload_is_same_and_reloads(self, testdir: Testdir) -> None: def test_reload_is_same_and_reloads(self, pytester: Pytester) -> None:
"""Reloading a (collected) module after change picks up the change.""" """Reloading a (collected) module after change picks up the change."""
testdir.makeini( pytester.makeini(
""" """
[pytest] [pytest]
python_files = *.py python_files = *.py
""" """
) )
testdir.makepyfile( pytester.makepyfile(
file=""" file="""
def reloaded(): def reloaded():
return False return False
@ -1091,13 +1098,13 @@ class TestAssertionRewriteHookDetails:
assert file.reloaded() assert file.reloaded()
""", """,
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["* 1 passed*"]) result.stdout.fnmatch_lines(["* 1 passed*"])
def test_get_data_support(self, testdir): def test_get_data_support(self, pytester: Pytester) -> None:
"""Implement optional PEP302 api (#808).""" """Implement optional PEP302 api (#808)."""
path = testdir.mkpydir("foo") path = pytester.mkpydir("foo")
path.join("test_foo.py").write( path.joinpath("test_foo.py").write_text(
textwrap.dedent( textwrap.dedent(
"""\ """\
class Test(object): class Test(object):
@ -1108,13 +1115,13 @@ class TestAssertionRewriteHookDetails:
""" """
) )
) )
path.join("data.txt").write("Hey") path.joinpath("data.txt").write_text("Hey")
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*1 passed*"]) result.stdout.fnmatch_lines(["*1 passed*"])
def test_issue731(testdir): def test_issue731(pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
class LongReprWithBraces(object): class LongReprWithBraces(object):
def __repr__(self): def __repr__(self):
@ -1128,45 +1135,45 @@ def test_issue731(testdir):
assert obj.some_method() assert obj.some_method()
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.no_fnmatch_line("*unbalanced braces*") result.stdout.no_fnmatch_line("*unbalanced braces*")
class TestIssue925: class TestIssue925:
def test_simple_case(self, testdir): def test_simple_case(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_ternary_display(): def test_ternary_display():
assert (False == False) == False assert (False == False) == False
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*E*assert (False == False) == False"]) result.stdout.fnmatch_lines(["*E*assert (False == False) == False"])
def test_long_case(self, testdir): def test_long_case(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_ternary_display(): def test_ternary_display():
assert False == (False == True) == True assert False == (False == True) == True
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*E*assert (False == True) == True"]) result.stdout.fnmatch_lines(["*E*assert (False == True) == True"])
def test_many_brackets(self, testdir): def test_many_brackets(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
""" """
def test_ternary_display(): def test_ternary_display():
assert True == ((False == True) == True) assert True == ((False == True) == True)
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*E*assert True == ((False == True) == True)"]) result.stdout.fnmatch_lines(["*E*assert True == ((False == True) == True)"])
class TestIssue2121: class TestIssue2121:
def test_rewrite_python_files_contain_subdirs(self, testdir): def test_rewrite_python_files_contain_subdirs(self, pytester: Pytester) -> None:
testdir.makepyfile( pytester.makepyfile(
**{ **{
"tests/file.py": """ "tests/file.py": """
def test_simple_failure(): def test_simple_failure():
@ -1174,13 +1181,13 @@ class TestIssue2121:
""" """
} }
) )
testdir.makeini( pytester.makeini(
""" """
[pytest] [pytest]
python_files = tests/**.py python_files = tests/**.py
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["*E*assert (1 + 1) == 3"]) result.stdout.fnmatch_lines(["*E*assert (1 + 1) == 3"])
@ -1188,7 +1195,7 @@ class TestIssue2121:
sys.maxsize <= (2 ** 31 - 1), reason="Causes OverflowError on 32bit systems" sys.maxsize <= (2 ** 31 - 1), reason="Causes OverflowError on 32bit systems"
) )
@pytest.mark.parametrize("offset", [-1, +1]) @pytest.mark.parametrize("offset", [-1, +1])
def test_source_mtime_long_long(testdir, offset): def test_source_mtime_long_long(pytester: Pytester, offset) -> None:
"""Support modification dates after 2038 in rewritten files (#4903). """Support modification dates after 2038 in rewritten files (#4903).
pytest would crash with: pytest would crash with:
@ -1196,7 +1203,7 @@ def test_source_mtime_long_long(testdir, offset):
fp.write(struct.pack("<ll", mtime, size)) fp.write(struct.pack("<ll", mtime, size))
E struct.error: argument out of range E struct.error: argument out of range
""" """
p = testdir.makepyfile( p = pytester.makepyfile(
""" """
def test(): pass def test(): pass
""" """
@ -1206,19 +1213,21 @@ def test_source_mtime_long_long(testdir, offset):
# +1 offset also tests masking of 0xFFFFFFFF # +1 offset also tests masking of 0xFFFFFFFF
timestamp = 2 ** 32 + offset timestamp = 2 ** 32 + offset
os.utime(str(p), (timestamp, timestamp)) os.utime(str(p), (timestamp, timestamp))
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 0 assert result.ret == 0
def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch) -> None: def test_rewrite_infinite_recursion(
pytester: Pytester, pytestconfig, monkeypatch
) -> None:
"""Fix infinite recursion when writing pyc files: if an import happens to be triggered when writing the pyc """Fix infinite recursion when writing pyc files: if an import happens to be triggered when writing the pyc
file, this would cause another call to the hook, which would trigger another pyc writing, which could file, this would cause another call to the hook, which would trigger another pyc writing, which could
trigger another import, and so on. (#3506)""" trigger another import, and so on. (#3506)"""
from _pytest.assertion import rewrite as rewritemod from _pytest.assertion import rewrite as rewritemod
testdir.syspathinsert() pytester.syspathinsert()
testdir.makepyfile(test_foo="def test_foo(): pass") pytester.makepyfile(test_foo="def test_foo(): pass")
testdir.makepyfile(test_bar="def test_bar(): pass") pytester.makepyfile(test_bar="def test_bar(): pass")
original_write_pyc = rewritemod._write_pyc original_write_pyc = rewritemod._write_pyc
@ -1244,7 +1253,9 @@ def test_rewrite_infinite_recursion(testdir, pytestconfig, monkeypatch) -> None:
class TestEarlyRewriteBailout: class TestEarlyRewriteBailout:
@pytest.fixture @pytest.fixture
def hook(self, pytestconfig, monkeypatch, testdir) -> AssertionRewritingHook: def hook(
self, pytestconfig, monkeypatch, pytester: Pytester
) -> AssertionRewritingHook:
"""Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track """Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track
if PathFinder.find_spec has been called. if PathFinder.find_spec has been called.
""" """
@ -1268,25 +1279,25 @@ class TestEarlyRewriteBailout:
hook.fnpats[:] = ["test_*.py", "*_test.py"] hook.fnpats[:] = ["test_*.py", "*_test.py"]
monkeypatch.setattr(hook, "_find_spec", spy_find_spec) monkeypatch.setattr(hook, "_find_spec", spy_find_spec)
hook.set_session(StubSession()) # type: ignore[arg-type] hook.set_session(StubSession()) # type: ignore[arg-type]
testdir.syspathinsert() pytester.syspathinsert()
return hook return hook
def test_basic(self, testdir, hook: AssertionRewritingHook) -> None: def test_basic(self, pytester: Pytester, hook: AssertionRewritingHook) -> None:
""" """
Ensure we avoid calling PathFinder.find_spec when we know for sure a certain Ensure we avoid calling PathFinder.find_spec when we know for sure a certain
module will not be rewritten to optimize assertion rewriting (#3918). module will not be rewritten to optimize assertion rewriting (#3918).
""" """
testdir.makeconftest( pytester.makeconftest(
""" """
import pytest import pytest
@pytest.fixture @pytest.fixture
def fix(): return 1 def fix(): return 1
""" """
) )
testdir.makepyfile(test_foo="def test_foo(): pass") pytester.makepyfile(test_foo="def test_foo(): pass")
testdir.makepyfile(bar="def bar(): pass") pytester.makepyfile(bar="def bar(): pass")
foobar_path = testdir.makepyfile(foobar="def foobar(): pass") foobar_path = pytester.makepyfile(foobar="def foobar(): pass")
self.initial_paths.add(foobar_path) self.initial_paths.add(py.path.local(foobar_path))
# conftest files should always be rewritten # conftest files should always be rewritten
assert hook.find_spec("conftest") is not None assert hook.find_spec("conftest") is not None
@ -1305,12 +1316,12 @@ class TestEarlyRewriteBailout:
assert self.find_spec_calls == ["conftest", "test_foo", "foobar"] assert self.find_spec_calls == ["conftest", "test_foo", "foobar"]
def test_pattern_contains_subdirectories( def test_pattern_contains_subdirectories(
self, testdir, hook: AssertionRewritingHook self, pytester: Pytester, hook: AssertionRewritingHook
) -> None: ) -> None:
"""If one of the python_files patterns contain subdirectories ("tests/**.py") we can't bailout early """If one of the python_files patterns contain subdirectories ("tests/**.py") we can't bailout early
because we need to match with the full path, which can only be found by calling PathFinder.find_spec because we need to match with the full path, which can only be found by calling PathFinder.find_spec
""" """
p = testdir.makepyfile( pytester.makepyfile(
**{ **{
"tests/file.py": """\ "tests/file.py": """\
def test_simple_failure(): def test_simple_failure():
@ -1318,7 +1329,7 @@ class TestEarlyRewriteBailout:
""" """
} }
) )
testdir.syspathinsert(p.dirpath()) pytester.syspathinsert("tests")
hook.fnpats[:] = ["tests/**.py"] hook.fnpats[:] = ["tests/**.py"]
assert hook.find_spec("file") is not None assert hook.find_spec("file") is not None
assert self.find_spec_calls == ["file"] assert self.find_spec_calls == ["file"]
@ -1326,14 +1337,14 @@ class TestEarlyRewriteBailout:
@pytest.mark.skipif( @pytest.mark.skipif(
sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" sys.platform.startswith("win32"), reason="cannot remove cwd on Windows"
) )
def test_cwd_changed(self, testdir, monkeypatch): def test_cwd_changed(self, pytester: Pytester, monkeypatch) -> None:
# Setup conditions for py's fspath trying to import pathlib on py34 # Setup conditions for py's fspath trying to import pathlib on py34
# always (previously triggered via xdist only). # always (previously triggered via xdist only).
# Ref: https://github.com/pytest-dev/py/pull/207 # Ref: https://github.com/pytest-dev/py/pull/207
monkeypatch.syspath_prepend("") monkeypatch.syspath_prepend("")
monkeypatch.delitem(sys.modules, "pathlib", raising=False) monkeypatch.delitem(sys.modules, "pathlib", raising=False)
testdir.makepyfile( pytester.makepyfile(
**{ **{
"test_setup_nonexisting_cwd.py": """\ "test_setup_nonexisting_cwd.py": """\
import os import os
@ -1350,30 +1361,30 @@ class TestEarlyRewriteBailout:
""", """,
} }
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines(["* 1 passed in *"]) result.stdout.fnmatch_lines(["* 1 passed in *"])
class TestAssertionPass: class TestAssertionPass:
def test_option_default(self, testdir): def test_option_default(self, pytester: Pytester) -> None:
config = testdir.parseconfig() config = pytester.parseconfig()
assert config.getini("enable_assertion_pass_hook") is False assert config.getini("enable_assertion_pass_hook") is False
@pytest.fixture @pytest.fixture
def flag_on(self, testdir): def flag_on(self, pytester: Pytester):
testdir.makeini("[pytest]\nenable_assertion_pass_hook = True\n") pytester.makeini("[pytest]\nenable_assertion_pass_hook = True\n")
@pytest.fixture @pytest.fixture
def hook_on(self, testdir): def hook_on(self, pytester: Pytester):
testdir.makeconftest( pytester.makeconftest(
"""\ """\
def pytest_assertion_pass(item, lineno, orig, expl): def pytest_assertion_pass(item, lineno, orig, expl):
raise Exception("Assertion Passed: {} {} at line {}".format(orig, expl, lineno)) raise Exception("Assertion Passed: {} {} at line {}".format(orig, expl, lineno))
""" """
) )
def test_hook_call(self, testdir, flag_on, hook_on): def test_hook_call(self, pytester: Pytester, flag_on, hook_on) -> None:
testdir.makepyfile( pytester.makepyfile(
"""\ """\
def test_simple(): def test_simple():
a=1 a=1
@ -1388,23 +1399,25 @@ class TestAssertionPass:
assert False, "assert with message" assert False, "assert with message"
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
"*Assertion Passed: a+b == c+d (1 + 2) == (3 + 0) at line 7*" "*Assertion Passed: a+b == c+d (1 + 2) == (3 + 0) at line 7*"
) )
def test_hook_call_with_parens(self, testdir, flag_on, hook_on): def test_hook_call_with_parens(self, pytester: Pytester, flag_on, hook_on) -> None:
testdir.makepyfile( pytester.makepyfile(
"""\ """\
def f(): return 1 def f(): return 1
def test(): def test():
assert f() assert f()
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.stdout.fnmatch_lines("*Assertion Passed: f() 1") result.stdout.fnmatch_lines("*Assertion Passed: f() 1")
def test_hook_not_called_without_hookimpl(self, testdir, monkeypatch, flag_on): def test_hook_not_called_without_hookimpl(
self, pytester: Pytester, monkeypatch, flag_on
) -> None:
"""Assertion pass should not be called (and hence formatting should """Assertion pass should not be called (and hence formatting should
not occur) if there is no hook declared for pytest_assertion_pass""" not occur) if there is no hook declared for pytest_assertion_pass"""
@ -1415,7 +1428,7 @@ class TestAssertionPass:
_pytest.assertion.rewrite, "_call_assertion_pass", raise_on_assertionpass _pytest.assertion.rewrite, "_call_assertion_pass", raise_on_assertionpass
) )
testdir.makepyfile( pytester.makepyfile(
"""\ """\
def test_simple(): def test_simple():
a=1 a=1
@ -1426,10 +1439,12 @@ class TestAssertionPass:
assert a+b == c+d assert a+b == c+d
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.assert_outcomes(passed=1) result.assert_outcomes(passed=1)
def test_hook_not_called_without_cmd_option(self, testdir, monkeypatch): def test_hook_not_called_without_cmd_option(
self, pytester: Pytester, monkeypatch
) -> None:
"""Assertion pass should not be called (and hence formatting should """Assertion pass should not be called (and hence formatting should
not occur) if there is no hook declared for pytest_assertion_pass""" not occur) if there is no hook declared for pytest_assertion_pass"""
@ -1440,14 +1455,14 @@ class TestAssertionPass:
_pytest.assertion.rewrite, "_call_assertion_pass", raise_on_assertionpass _pytest.assertion.rewrite, "_call_assertion_pass", raise_on_assertionpass
) )
testdir.makeconftest( pytester.makeconftest(
"""\ """\
def pytest_assertion_pass(item, lineno, orig, expl): def pytest_assertion_pass(item, lineno, orig, expl):
raise Exception("Assertion Passed: {} {} at line {}".format(orig, expl, lineno)) raise Exception("Assertion Passed: {} {} at line {}".format(orig, expl, lineno))
""" """
) )
testdir.makepyfile( pytester.makepyfile(
"""\ """\
def test_simple(): def test_simple():
a=1 a=1
@ -1458,7 +1473,7 @@ class TestAssertionPass:
assert a+b == c+d assert a+b == c+d
""" """
) )
result = testdir.runpytest() result = pytester.runpytest()
result.assert_outcomes(passed=1) result.assert_outcomes(passed=1)
@ -1545,7 +1560,7 @@ class TestAssertionPass:
# fmt: on # fmt: on
), ),
) )
def test_get_assertion_exprs(src, expected): def test_get_assertion_exprs(src, expected) -> None:
assert _get_assertion_exprs(src) == expected assert _get_assertion_exprs(src) == expected
@ -1599,7 +1614,7 @@ class TestPyCacheDir:
(None, "/home/projects/src/foo.py", "/home/projects/src/__pycache__"), (None, "/home/projects/src/foo.py", "/home/projects/src/__pycache__"),
], ],
) )
def test_get_cache_dir(self, monkeypatch, prefix, source, expected): def test_get_cache_dir(self, monkeypatch, prefix, source, expected) -> None:
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False) monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
if prefix is not None and sys.version_info < (3, 8): if prefix is not None and sys.version_info < (3, 8):
@ -1611,13 +1626,15 @@ class TestPyCacheDir:
@pytest.mark.skipif( @pytest.mark.skipif(
sys.version_info < (3, 8), reason="pycache_prefix not available in py<38" sys.version_info < (3, 8), reason="pycache_prefix not available in py<38"
) )
def test_sys_pycache_prefix_integration(self, tmp_path, monkeypatch, testdir): def test_sys_pycache_prefix_integration(
self, tmp_path, monkeypatch, pytester: Pytester
) -> None:
"""Integration test for sys.pycache_prefix (#4730).""" """Integration test for sys.pycache_prefix (#4730)."""
pycache_prefix = tmp_path / "my/pycs" pycache_prefix = tmp_path / "my/pycs"
monkeypatch.setattr(sys, "pycache_prefix", str(pycache_prefix)) monkeypatch.setattr(sys, "pycache_prefix", str(pycache_prefix))
monkeypatch.setattr(sys, "dont_write_bytecode", False) monkeypatch.setattr(sys, "dont_write_bytecode", False)
testdir.makepyfile( pytester.makepyfile(
**{ **{
"src/test_foo.py": """ "src/test_foo.py": """
import bar import bar
@ -1627,11 +1644,11 @@ class TestPyCacheDir:
"src/bar/__init__.py": "", "src/bar/__init__.py": "",
} }
) )
result = testdir.runpytest() result = pytester.runpytest()
assert result.ret == 0 assert result.ret == 0
test_foo = Path(testdir.tmpdir) / "src/test_foo.py" test_foo = pytester.path.joinpath("src/test_foo.py")
bar_init = Path(testdir.tmpdir) / "src/bar/__init__.py" bar_init = pytester.path.joinpath("src/bar/__init__.py")
assert test_foo.is_file() assert test_foo.is_file()
assert bar_init.is_file() assert bar_init.is_file()