940 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			940 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
| from __future__ import absolute_import
 | |
| from __future__ import division
 | |
| from __future__ import print_function
 | |
| 
 | |
| import os
 | |
| import shutil
 | |
| import sys
 | |
| import textwrap
 | |
| 
 | |
| import py
 | |
| 
 | |
| import pytest
 | |
| 
 | |
| pytest_plugins = ("pytester",)
 | |
| 
 | |
| 
 | |
| class TestNewAPI(object):
 | |
|     def test_config_cache_makedir(self, testdir):
 | |
|         testdir.makeini("[pytest]")
 | |
|         config = testdir.parseconfigure()
 | |
|         with pytest.raises(ValueError):
 | |
|             config.cache.makedir("key/name")
 | |
| 
 | |
|         p = config.cache.makedir("name")
 | |
|         assert p.check()
 | |
| 
 | |
|     def test_config_cache_dataerror(self, testdir):
 | |
|         testdir.makeini("[pytest]")
 | |
|         config = testdir.parseconfigure()
 | |
|         cache = config.cache
 | |
|         pytest.raises(TypeError, lambda: cache.set("key/name", cache))
 | |
|         config.cache.set("key/name", 0)
 | |
|         config.cache._getvaluepath("key/name").write_bytes(b"123invalid")
 | |
|         val = config.cache.get("key/name", -2)
 | |
|         assert val == -2
 | |
| 
 | |
|     @pytest.mark.filterwarnings("default")
 | |
|     def test_cache_writefail_cachfile_silent(self, testdir):
 | |
|         testdir.makeini("[pytest]")
 | |
|         testdir.tmpdir.join(".pytest_cache").write("gone wrong")
 | |
|         config = testdir.parseconfigure()
 | |
|         cache = config.cache
 | |
|         cache.set("test/broken", [])
 | |
| 
 | |
|     @pytest.mark.skipif(sys.platform.startswith("win"), reason="no chmod on windows")
 | |
|     @pytest.mark.filterwarnings(
 | |
|         "ignore:could not create cache path:pytest.PytestWarning"
 | |
|     )
 | |
|     def test_cache_writefail_permissions(self, testdir):
 | |
|         testdir.makeini("[pytest]")
 | |
|         testdir.tmpdir.ensure_dir(".pytest_cache").chmod(0)
 | |
|         config = testdir.parseconfigure()
 | |
|         cache = config.cache
 | |
|         cache.set("test/broken", [])
 | |
| 
 | |
|     @pytest.mark.skipif(sys.platform.startswith("win"), reason="no chmod on windows")
 | |
|     @pytest.mark.filterwarnings("default")
 | |
|     def test_cache_failure_warns(self, testdir):
 | |
|         testdir.tmpdir.ensure_dir(".pytest_cache").chmod(0)
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             def test_error():
 | |
|                 raise Exception
 | |
| 
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest("-rw")
 | |
|         assert result.ret == 1
 | |
|         # warnings from nodeids, lastfailed, and stepwise
 | |
|         result.stdout.fnmatch_lines(["*could not create cache path*", "*3 warnings*"])
 | |
| 
 | |
|     def test_config_cache(self, testdir):
 | |
|         testdir.makeconftest(
 | |
|             """
 | |
|             def pytest_configure(config):
 | |
|                 # see that we get cache information early on
 | |
|                 assert hasattr(config, "cache")
 | |
|         """
 | |
|         )
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             def test_session(pytestconfig):
 | |
|                 assert hasattr(pytestconfig, "cache")
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         assert result.ret == 0
 | |
|         result.stdout.fnmatch_lines(["*1 passed*"])
 | |
| 
 | |
|     def test_cachefuncarg(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             import pytest
 | |
|             def test_cachefuncarg(cache):
 | |
|                 val = cache.get("some/thing", None)
 | |
|                 assert val is None
 | |
|                 cache.set("some/thing", [1])
 | |
|                 pytest.raises(TypeError, lambda: cache.get("some/thing"))
 | |
|                 val = cache.get("some/thing", [])
 | |
|                 assert val == [1]
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         assert result.ret == 0
 | |
|         result.stdout.fnmatch_lines(["*1 passed*"])
 | |
| 
 | |
|     def test_custom_rel_cache_dir(self, testdir):
 | |
|         rel_cache_dir = os.path.join("custom_cache_dir", "subdir")
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             cache_dir = {cache_dir}
 | |
|         """.format(
 | |
|                 cache_dir=rel_cache_dir
 | |
|             )
 | |
|         )
 | |
|         testdir.makepyfile(test_errored="def test_error():\n    assert False")
 | |
|         testdir.runpytest()
 | |
|         assert testdir.tmpdir.join(rel_cache_dir).isdir()
 | |
| 
 | |
|     def test_custom_abs_cache_dir(self, testdir, tmpdir_factory):
 | |
|         tmp = str(tmpdir_factory.mktemp("tmp"))
 | |
|         abs_cache_dir = os.path.join(tmp, "custom_cache_dir")
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             cache_dir = {cache_dir}
 | |
|         """.format(
 | |
|                 cache_dir=abs_cache_dir
 | |
|             )
 | |
|         )
 | |
|         testdir.makepyfile(test_errored="def test_error():\n    assert False")
 | |
|         testdir.runpytest()
 | |
|         assert py.path.local(abs_cache_dir).isdir()
 | |
| 
 | |
|     def test_custom_cache_dir_with_env_var(self, testdir, monkeypatch):
 | |
|         monkeypatch.setenv("env_var", "custom_cache_dir")
 | |
|         testdir.makeini(
 | |
|             """
 | |
|             [pytest]
 | |
|             cache_dir = {cache_dir}
 | |
|         """.format(
 | |
|                 cache_dir="$env_var"
 | |
|             )
 | |
|         )
 | |
|         testdir.makepyfile(test_errored="def test_error():\n    assert False")
 | |
|         testdir.runpytest()
 | |
|         assert testdir.tmpdir.join("custom_cache_dir").isdir()
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize("env", ((), ("TOX_ENV_DIR", "/tox_env_dir")))
 | |
| def test_cache_reportheader(env, testdir, monkeypatch):
 | |
|     testdir.makepyfile("""def test_foo(): pass""")
 | |
|     if env:
 | |
|         monkeypatch.setenv(*env)
 | |
|         expected = os.path.join(env[1], ".pytest_cache")
 | |
|     else:
 | |
|         monkeypatch.delenv("TOX_ENV_DIR", raising=False)
 | |
|         expected = ".pytest_cache"
 | |
|     result = testdir.runpytest("-v")
 | |
|     result.stdout.fnmatch_lines(["cachedir: %s" % expected])
 | |
| 
 | |
| 
 | |
| def test_cache_reportheader_external_abspath(testdir, tmpdir_factory):
 | |
|     external_cache = tmpdir_factory.mktemp(
 | |
|         "test_cache_reportheader_external_abspath_abs"
 | |
|     )
 | |
| 
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         def test_hello():
 | |
|             pass
 | |
|     """
 | |
|     )
 | |
|     testdir.makeini(
 | |
|         """
 | |
|     [pytest]
 | |
|     cache_dir = {abscache}
 | |
|     """.format(
 | |
|             abscache=external_cache
 | |
|         )
 | |
|     )
 | |
| 
 | |
|     result = testdir.runpytest("-v")
 | |
|     result.stdout.fnmatch_lines(
 | |
|         ["cachedir: {abscache}".format(abscache=external_cache)]
 | |
|     )
 | |
| 
 | |
| 
 | |
| def test_cache_show(testdir):
 | |
|     result = testdir.runpytest("--cache-show")
 | |
|     assert result.ret == 0
 | |
|     result.stdout.fnmatch_lines(["*cache is empty*"])
 | |
|     testdir.makeconftest(
 | |
|         """
 | |
|         def pytest_configure(config):
 | |
|             config.cache.set("my/name", [1,2,3])
 | |
|             config.cache.set("other/some", {1:2})
 | |
|             dp = config.cache.makedir("mydb")
 | |
|             dp.ensure("hello")
 | |
|             dp.ensure("world")
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     assert result.ret == 5  # no tests executed
 | |
|     result = testdir.runpytest("--cache-show")
 | |
|     result.stdout.fnmatch_lines_random(
 | |
|         [
 | |
|             "*cachedir:*",
 | |
|             "-*cache values*-",
 | |
|             "*my/name contains:",
 | |
|             "  [1, 2, 3]",
 | |
|             "*other/some contains*",
 | |
|             "  {*1*: 2}",
 | |
|             "-*cache directories*-",
 | |
|             "*mydb/hello*length 0*",
 | |
|             "*mydb/world*length 0*",
 | |
|         ]
 | |
|     )
 | |
| 
 | |
| 
 | |
| class TestLastFailed(object):
 | |
|     def test_lastfailed_usecase(self, testdir, monkeypatch):
 | |
|         monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
 | |
|         p = testdir.makepyfile(
 | |
|             """
 | |
|             def test_1():
 | |
|                 assert 0
 | |
|             def test_2():
 | |
|                 assert 0
 | |
|             def test_3():
 | |
|                 assert 1
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines(["*2 failed*"])
 | |
|         p.write(
 | |
|             textwrap.dedent(
 | |
|                 """\
 | |
|                 def test_1():
 | |
|                     assert 1
 | |
| 
 | |
|                 def test_2():
 | |
|                     assert 1
 | |
| 
 | |
|                 def test_3():
 | |
|                     assert 0
 | |
|                 """
 | |
|             )
 | |
|         )
 | |
|         result = testdir.runpytest("--lf")
 | |
|         result.stdout.fnmatch_lines(["*2 passed*1 desel*"])
 | |
|         result = testdir.runpytest("--lf")
 | |
|         result.stdout.fnmatch_lines(["*1 failed*2 passed*"])
 | |
|         result = testdir.runpytest("--lf", "--cache-clear")
 | |
|         result.stdout.fnmatch_lines(["*1 failed*2 passed*"])
 | |
| 
 | |
|         # Run this again to make sure clear-cache is robust
 | |
|         if os.path.isdir(".pytest_cache"):
 | |
|             shutil.rmtree(".pytest_cache")
 | |
|         result = testdir.runpytest("--lf", "--cache-clear")
 | |
|         result.stdout.fnmatch_lines(["*1 failed*2 passed*"])
 | |
| 
 | |
|     def test_failedfirst_order(self, testdir):
 | |
|         testdir.tmpdir.join("test_a.py").write(
 | |
|             textwrap.dedent(
 | |
|                 """\
 | |
|                 def test_always_passes():
 | |
|                     assert 1
 | |
|                 """
 | |
|             )
 | |
|         )
 | |
|         testdir.tmpdir.join("test_b.py").write(
 | |
|             textwrap.dedent(
 | |
|                 """\
 | |
|                 def test_always_fails():
 | |
|                     assert 0
 | |
|                 """
 | |
|             )
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         # Test order will be collection order; alphabetical
 | |
|         result.stdout.fnmatch_lines(["test_a.py*", "test_b.py*"])
 | |
|         result = testdir.runpytest("--ff")
 | |
|         # Test order will be failing tests firs
 | |
|         result.stdout.fnmatch_lines(["test_b.py*", "test_a.py*"])
 | |
| 
 | |
|     def test_lastfailed_failedfirst_order(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             **{
 | |
|                 "test_a.py": """\
 | |
|                 def test_always_passes():
 | |
|                     assert 1
 | |
|                 """,
 | |
|                 "test_b.py": """\
 | |
|                 def test_always_fails():
 | |
|                     assert 0
 | |
|                 """,
 | |
|             }
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         # Test order will be collection order; alphabetical
 | |
|         result.stdout.fnmatch_lines(["test_a.py*", "test_b.py*"])
 | |
|         result = testdir.runpytest("--lf", "--ff")
 | |
|         # Test order will be failing tests firs
 | |
|         result.stdout.fnmatch_lines(["test_b.py*"])
 | |
|         assert "test_a.py" not in result.stdout.str()
 | |
| 
 | |
|     def test_lastfailed_difference_invocations(self, testdir, monkeypatch):
 | |
|         monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
 | |
|         testdir.makepyfile(
 | |
|             test_a="""\
 | |
|             def test_a1():
 | |
|                 assert 0
 | |
|             def test_a2():
 | |
|                 assert 1
 | |
|             """,
 | |
|             test_b="""\
 | |
|             def test_b1():
 | |
|                 assert 0
 | |
|             """,
 | |
|         )
 | |
|         p = testdir.tmpdir.join("test_a.py")
 | |
|         p2 = testdir.tmpdir.join("test_b.py")
 | |
| 
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines(["*2 failed*"])
 | |
|         result = testdir.runpytest("--lf", p2)
 | |
|         result.stdout.fnmatch_lines(["*1 failed*"])
 | |
|         p2.write(
 | |
|             textwrap.dedent(
 | |
|                 """\
 | |
|                 def test_b1():
 | |
|                     assert 1
 | |
|                 """
 | |
|             )
 | |
|         )
 | |
|         result = testdir.runpytest("--lf", p2)
 | |
|         result.stdout.fnmatch_lines(["*1 passed*"])
 | |
|         result = testdir.runpytest("--lf", p)
 | |
|         result.stdout.fnmatch_lines(["*1 failed*1 desel*"])
 | |
| 
 | |
|     def test_lastfailed_usecase_splice(self, testdir, monkeypatch):
 | |
|         monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1")
 | |
|         testdir.makepyfile(
 | |
|             """\
 | |
|             def test_1():
 | |
|                 assert 0
 | |
|             """
 | |
|         )
 | |
|         p2 = testdir.tmpdir.join("test_something.py")
 | |
|         p2.write(
 | |
|             textwrap.dedent(
 | |
|                 """\
 | |
|                 def test_2():
 | |
|                     assert 0
 | |
|                 """
 | |
|             )
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines(["*2 failed*"])
 | |
|         result = testdir.runpytest("--lf", p2)
 | |
|         result.stdout.fnmatch_lines(["*1 failed*"])
 | |
|         result = testdir.runpytest("--lf")
 | |
|         result.stdout.fnmatch_lines(["*2 failed*"])
 | |
| 
 | |
|     def test_lastfailed_xpass(self, testdir):
 | |
|         testdir.inline_runsource(
 | |
|             """
 | |
|             import pytest
 | |
|             @pytest.mark.xfail
 | |
|             def test_hello():
 | |
|                 assert 1
 | |
|         """
 | |
|         )
 | |
|         config = testdir.parseconfigure()
 | |
|         lastfailed = config.cache.get("cache/lastfailed", -1)
 | |
|         assert lastfailed == -1
 | |
| 
 | |
|     def test_non_serializable_parametrize(self, testdir):
 | |
|         """Test that failed parametrized tests with unmarshable parameters
 | |
|         don't break pytest-cache.
 | |
|         """
 | |
|         testdir.makepyfile(
 | |
|             r"""
 | |
|             import pytest
 | |
| 
 | |
|             @pytest.mark.parametrize('val', [
 | |
|                 b'\xac\x10\x02G',
 | |
|             ])
 | |
|             def test_fail(val):
 | |
|                 assert False
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines("*1 failed in*")
 | |
| 
 | |
|     def test_terminal_report_lastfailed(self, testdir):
 | |
|         test_a = testdir.makepyfile(
 | |
|             test_a="""
 | |
|             def test_a1():
 | |
|                 pass
 | |
|             def test_a2():
 | |
|                 pass
 | |
|         """
 | |
|         )
 | |
|         test_b = testdir.makepyfile(
 | |
|             test_b="""
 | |
|             def test_b1():
 | |
|                 assert 0
 | |
|             def test_b2():
 | |
|                 assert 0
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines(["collected 4 items", "*2 failed, 2 passed in*"])
 | |
| 
 | |
|         result = testdir.runpytest("--lf")
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "collected 4 items / 2 deselected / 2 selected",
 | |
|                 "run-last-failure: rerun previous 2 failures",
 | |
|                 "*2 failed, 2 deselected in*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|         result = testdir.runpytest(test_a, "--lf")
 | |
|         result.stdout.fnmatch_lines(["collected 2 items", "*2 passed in*"])
 | |
| 
 | |
|         result = testdir.runpytest(test_b, "--lf")
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "collected 2 items",
 | |
|                 "run-last-failure: rerun previous 2 failures",
 | |
|                 "*2 failed in*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|         result = testdir.runpytest("test_b.py::test_b1", "--lf")
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "collected 1 item",
 | |
|                 "run-last-failure: rerun previous 1 failure",
 | |
|                 "*1 failed in*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def test_terminal_report_failedfirst(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             test_a="""
 | |
|             def test_a1():
 | |
|                 assert 0
 | |
|             def test_a2():
 | |
|                 pass
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines(["collected 2 items", "*1 failed, 1 passed in*"])
 | |
| 
 | |
|         result = testdir.runpytest("--ff")
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "collected 2 items",
 | |
|                 "run-last-failure: rerun previous 1 failure first",
 | |
|                 "*1 failed, 1 passed in*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def test_lastfailed_collectfailure(self, testdir, monkeypatch):
 | |
| 
 | |
|         testdir.makepyfile(
 | |
|             test_maybe="""
 | |
|             import os
 | |
|             env = os.environ
 | |
|             if '1' == env['FAILIMPORT']:
 | |
|                 raise ImportError('fail')
 | |
|             def test_hello():
 | |
|                 assert '0' == env['FAILTEST']
 | |
|         """
 | |
|         )
 | |
| 
 | |
|         def rlf(fail_import, fail_run):
 | |
|             monkeypatch.setenv("FAILIMPORT", str(fail_import))
 | |
|             monkeypatch.setenv("FAILTEST", str(fail_run))
 | |
| 
 | |
|             testdir.runpytest("-q")
 | |
|             config = testdir.parseconfigure()
 | |
|             lastfailed = config.cache.get("cache/lastfailed", -1)
 | |
|             return lastfailed
 | |
| 
 | |
|         lastfailed = rlf(fail_import=0, fail_run=0)
 | |
|         assert lastfailed == -1
 | |
| 
 | |
|         lastfailed = rlf(fail_import=1, fail_run=0)
 | |
|         assert list(lastfailed) == ["test_maybe.py"]
 | |
| 
 | |
|         lastfailed = rlf(fail_import=0, fail_run=1)
 | |
|         assert list(lastfailed) == ["test_maybe.py::test_hello"]
 | |
| 
 | |
|     def test_lastfailed_failure_subset(self, testdir, monkeypatch):
 | |
| 
 | |
|         testdir.makepyfile(
 | |
|             test_maybe="""
 | |
|             import os
 | |
|             env = os.environ
 | |
|             if '1' == env['FAILIMPORT']:
 | |
|                 raise ImportError('fail')
 | |
|             def test_hello():
 | |
|                 assert '0' == env['FAILTEST']
 | |
|         """
 | |
|         )
 | |
| 
 | |
|         testdir.makepyfile(
 | |
|             test_maybe2="""
 | |
|             import os
 | |
|             env = os.environ
 | |
|             if '1' == env['FAILIMPORT']:
 | |
|                 raise ImportError('fail')
 | |
|             def test_hello():
 | |
|                 assert '0' == env['FAILTEST']
 | |
| 
 | |
|             def test_pass():
 | |
|                 pass
 | |
|         """
 | |
|         )
 | |
| 
 | |
|         def rlf(fail_import, fail_run, args=()):
 | |
|             monkeypatch.setenv("FAILIMPORT", str(fail_import))
 | |
|             monkeypatch.setenv("FAILTEST", str(fail_run))
 | |
| 
 | |
|             result = testdir.runpytest("-q", "--lf", *args)
 | |
|             config = testdir.parseconfigure()
 | |
|             lastfailed = config.cache.get("cache/lastfailed", -1)
 | |
|             return result, lastfailed
 | |
| 
 | |
|         result, lastfailed = rlf(fail_import=0, fail_run=0)
 | |
|         assert lastfailed == -1
 | |
|         result.stdout.fnmatch_lines(["*3 passed*"])
 | |
| 
 | |
|         result, lastfailed = rlf(fail_import=1, fail_run=0)
 | |
|         assert sorted(list(lastfailed)) == ["test_maybe.py", "test_maybe2.py"]
 | |
| 
 | |
|         result, lastfailed = rlf(fail_import=0, fail_run=0, args=("test_maybe2.py",))
 | |
|         assert list(lastfailed) == ["test_maybe.py"]
 | |
| 
 | |
|         # edge case of test selection - even if we remember failures
 | |
|         # from other tests we still need to run all tests if no test
 | |
|         # matches the failures
 | |
|         result, lastfailed = rlf(fail_import=0, fail_run=0, args=("test_maybe2.py",))
 | |
|         assert list(lastfailed) == ["test_maybe.py"]
 | |
|         result.stdout.fnmatch_lines(["*2 passed*"])
 | |
| 
 | |
|     def test_lastfailed_creates_cache_when_needed(self, testdir):
 | |
|         # Issue #1342
 | |
|         testdir.makepyfile(test_empty="")
 | |
|         testdir.runpytest("-q", "--lf")
 | |
|         assert not os.path.exists(".pytest_cache/v/cache/lastfailed")
 | |
| 
 | |
|         testdir.makepyfile(test_successful="def test_success():\n    assert True")
 | |
|         testdir.runpytest("-q", "--lf")
 | |
|         assert not os.path.exists(".pytest_cache/v/cache/lastfailed")
 | |
| 
 | |
|         testdir.makepyfile(test_errored="def test_error():\n    assert False")
 | |
|         testdir.runpytest("-q", "--lf")
 | |
|         assert os.path.exists(".pytest_cache/v/cache/lastfailed")
 | |
| 
 | |
|     def test_xfail_not_considered_failure(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             import pytest
 | |
|             @pytest.mark.xfail
 | |
|             def test():
 | |
|                 assert 0
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines("*1 xfailed*")
 | |
|         assert self.get_cached_last_failed(testdir) == []
 | |
| 
 | |
|     def test_xfail_strict_considered_failure(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             import pytest
 | |
|             @pytest.mark.xfail(strict=True)
 | |
|             def test():
 | |
|                 pass
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines("*1 failed*")
 | |
|         assert self.get_cached_last_failed(testdir) == [
 | |
|             "test_xfail_strict_considered_failure.py::test"
 | |
|         ]
 | |
| 
 | |
|     @pytest.mark.parametrize("mark", ["mark.xfail", "mark.skip"])
 | |
|     def test_failed_changed_to_xfail_or_skip(self, testdir, mark):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             import pytest
 | |
|             def test():
 | |
|                 assert 0
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         assert self.get_cached_last_failed(testdir) == [
 | |
|             "test_failed_changed_to_xfail_or_skip.py::test"
 | |
|         ]
 | |
|         assert result.ret == 1
 | |
| 
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             import pytest
 | |
|             @pytest.{mark}
 | |
|             def test():
 | |
|                 assert 0
 | |
|         """.format(
 | |
|                 mark=mark
 | |
|             )
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         assert result.ret == 0
 | |
|         assert self.get_cached_last_failed(testdir) == []
 | |
|         assert result.ret == 0
 | |
| 
 | |
|     @pytest.mark.parametrize("quiet", [True, False])
 | |
|     @pytest.mark.parametrize("opt", ["--ff", "--lf"])
 | |
|     def test_lf_and_ff_prints_no_needless_message(self, quiet, opt, testdir):
 | |
|         # Issue 3853
 | |
|         testdir.makepyfile("def test(): assert 0")
 | |
|         args = [opt]
 | |
|         if quiet:
 | |
|             args.append("-q")
 | |
|         result = testdir.runpytest(*args)
 | |
|         assert "run all" not in result.stdout.str()
 | |
| 
 | |
|         result = testdir.runpytest(*args)
 | |
|         if quiet:
 | |
|             assert "run all" not in result.stdout.str()
 | |
|         else:
 | |
|             assert "rerun previous" in result.stdout.str()
 | |
| 
 | |
|     def get_cached_last_failed(self, testdir):
 | |
|         config = testdir.parseconfigure()
 | |
|         return sorted(config.cache.get("cache/lastfailed", {}))
 | |
| 
 | |
|     def test_cache_cumulative(self, testdir):
 | |
|         """
 | |
|         Test workflow where user fixes errors gradually file by file using --lf.
 | |
|         """
 | |
|         # 1. initial run
 | |
|         test_bar = testdir.makepyfile(
 | |
|             test_bar="""
 | |
|             def test_bar_1():
 | |
|                 pass
 | |
|             def test_bar_2():
 | |
|                 assert 0
 | |
|         """
 | |
|         )
 | |
|         test_foo = testdir.makepyfile(
 | |
|             test_foo="""
 | |
|             def test_foo_3():
 | |
|                 pass
 | |
|             def test_foo_4():
 | |
|                 assert 0
 | |
|         """
 | |
|         )
 | |
|         testdir.runpytest()
 | |
|         assert self.get_cached_last_failed(testdir) == [
 | |
|             "test_bar.py::test_bar_2",
 | |
|             "test_foo.py::test_foo_4",
 | |
|         ]
 | |
| 
 | |
|         # 2. fix test_bar_2, run only test_bar.py
 | |
|         testdir.makepyfile(
 | |
|             test_bar="""
 | |
|             def test_bar_1():
 | |
|                 pass
 | |
|             def test_bar_2():
 | |
|                 pass
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest(test_bar)
 | |
|         result.stdout.fnmatch_lines("*2 passed*")
 | |
|         # ensure cache does not forget that test_foo_4 failed once before
 | |
|         assert self.get_cached_last_failed(testdir) == ["test_foo.py::test_foo_4"]
 | |
| 
 | |
|         result = testdir.runpytest("--last-failed")
 | |
|         result.stdout.fnmatch_lines("*1 failed, 3 deselected*")
 | |
|         assert self.get_cached_last_failed(testdir) == ["test_foo.py::test_foo_4"]
 | |
| 
 | |
|         # 3. fix test_foo_4, run only test_foo.py
 | |
|         test_foo = testdir.makepyfile(
 | |
|             test_foo="""
 | |
|             def test_foo_3():
 | |
|                 pass
 | |
|             def test_foo_4():
 | |
|                 pass
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest(test_foo, "--last-failed")
 | |
|         result.stdout.fnmatch_lines("*1 passed, 1 deselected*")
 | |
|         assert self.get_cached_last_failed(testdir) == []
 | |
| 
 | |
|         result = testdir.runpytest("--last-failed")
 | |
|         result.stdout.fnmatch_lines("*4 passed*")
 | |
|         assert self.get_cached_last_failed(testdir) == []
 | |
| 
 | |
|     def test_lastfailed_no_failures_behavior_all_passed(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             def test_1():
 | |
|                 assert True
 | |
|             def test_2():
 | |
|                 assert True
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest()
 | |
|         result.stdout.fnmatch_lines(["*2 passed*"])
 | |
|         result = testdir.runpytest("--lf")
 | |
|         result.stdout.fnmatch_lines(["*2 passed*"])
 | |
|         result = testdir.runpytest("--lf", "--lfnf", "all")
 | |
|         result.stdout.fnmatch_lines(["*2 passed*"])
 | |
|         result = testdir.runpytest("--lf", "--lfnf", "none")
 | |
|         result.stdout.fnmatch_lines(["*2 desel*"])
 | |
| 
 | |
|     def test_lastfailed_no_failures_behavior_empty_cache(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             def test_1():
 | |
|                 assert True
 | |
|             def test_2():
 | |
|                 assert False
 | |
|         """
 | |
|         )
 | |
|         result = testdir.runpytest("--lf", "--cache-clear")
 | |
|         result.stdout.fnmatch_lines(["*1 failed*1 passed*"])
 | |
|         result = testdir.runpytest("--lf", "--cache-clear", "--lfnf", "all")
 | |
|         result.stdout.fnmatch_lines(["*1 failed*1 passed*"])
 | |
|         result = testdir.runpytest("--lf", "--cache-clear", "--lfnf", "none")
 | |
|         result.stdout.fnmatch_lines(["*2 desel*"])
 | |
| 
 | |
| 
 | |
| class TestNewFirst(object):
 | |
|     def test_newfirst_usecase(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             **{
 | |
|                 "test_1/test_1.py": """
 | |
|                 def test_1(): assert 1
 | |
|                 def test_2(): assert 1
 | |
|                 def test_3(): assert 1
 | |
|             """,
 | |
|                 "test_2/test_2.py": """
 | |
|                 def test_1(): assert 1
 | |
|                 def test_2(): assert 1
 | |
|                 def test_3(): assert 1
 | |
|             """,
 | |
|             }
 | |
|         )
 | |
| 
 | |
|         testdir.tmpdir.join("test_1/test_1.py").setmtime(1)
 | |
| 
 | |
|         result = testdir.runpytest("-v")
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*test_1/test_1.py::test_1 PASSED*",
 | |
|                 "*test_1/test_1.py::test_2 PASSED*",
 | |
|                 "*test_1/test_1.py::test_3 PASSED*",
 | |
|                 "*test_2/test_2.py::test_1 PASSED*",
 | |
|                 "*test_2/test_2.py::test_2 PASSED*",
 | |
|                 "*test_2/test_2.py::test_3 PASSED*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|         result = testdir.runpytest("-v", "--nf")
 | |
| 
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*test_2/test_2.py::test_1 PASSED*",
 | |
|                 "*test_2/test_2.py::test_2 PASSED*",
 | |
|                 "*test_2/test_2.py::test_3 PASSED*",
 | |
|                 "*test_1/test_1.py::test_1 PASSED*",
 | |
|                 "*test_1/test_1.py::test_2 PASSED*",
 | |
|                 "*test_1/test_1.py::test_3 PASSED*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|         testdir.tmpdir.join("test_1/test_1.py").write(
 | |
|             "def test_1(): assert 1\n"
 | |
|             "def test_2(): assert 1\n"
 | |
|             "def test_3(): assert 1\n"
 | |
|             "def test_4(): assert 1\n"
 | |
|         )
 | |
|         testdir.tmpdir.join("test_1/test_1.py").setmtime(1)
 | |
| 
 | |
|         result = testdir.runpytest("-v", "--nf")
 | |
| 
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*test_1/test_1.py::test_4 PASSED*",
 | |
|                 "*test_2/test_2.py::test_1 PASSED*",
 | |
|                 "*test_2/test_2.py::test_2 PASSED*",
 | |
|                 "*test_2/test_2.py::test_3 PASSED*",
 | |
|                 "*test_1/test_1.py::test_1 PASSED*",
 | |
|                 "*test_1/test_1.py::test_2 PASSED*",
 | |
|                 "*test_1/test_1.py::test_3 PASSED*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|     def test_newfirst_parametrize(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             **{
 | |
|                 "test_1/test_1.py": """
 | |
|                 import pytest
 | |
|                 @pytest.mark.parametrize('num', [1, 2])
 | |
|                 def test_1(num): assert num
 | |
|             """,
 | |
|                 "test_2/test_2.py": """
 | |
|                 import pytest
 | |
|                 @pytest.mark.parametrize('num', [1, 2])
 | |
|                 def test_1(num): assert num
 | |
|             """,
 | |
|             }
 | |
|         )
 | |
| 
 | |
|         testdir.tmpdir.join("test_1/test_1.py").setmtime(1)
 | |
| 
 | |
|         result = testdir.runpytest("-v")
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*test_1/test_1.py::test_1[1*",
 | |
|                 "*test_1/test_1.py::test_1[2*",
 | |
|                 "*test_2/test_2.py::test_1[1*",
 | |
|                 "*test_2/test_2.py::test_1[2*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|         result = testdir.runpytest("-v", "--nf")
 | |
| 
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*test_2/test_2.py::test_1[1*",
 | |
|                 "*test_2/test_2.py::test_1[2*",
 | |
|                 "*test_1/test_1.py::test_1[1*",
 | |
|                 "*test_1/test_1.py::test_1[2*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
|         testdir.tmpdir.join("test_1/test_1.py").write(
 | |
|             "import pytest\n"
 | |
|             "@pytest.mark.parametrize('num', [1, 2, 3])\n"
 | |
|             "def test_1(num): assert num\n"
 | |
|         )
 | |
|         testdir.tmpdir.join("test_1/test_1.py").setmtime(1)
 | |
| 
 | |
|         result = testdir.runpytest("-v", "--nf")
 | |
| 
 | |
|         result.stdout.fnmatch_lines(
 | |
|             [
 | |
|                 "*test_1/test_1.py::test_1[3*",
 | |
|                 "*test_2/test_2.py::test_1[1*",
 | |
|                 "*test_2/test_2.py::test_1[2*",
 | |
|                 "*test_1/test_1.py::test_1[1*",
 | |
|                 "*test_1/test_1.py::test_1[2*",
 | |
|             ]
 | |
|         )
 | |
| 
 | |
| 
 | |
| class TestReadme(object):
 | |
|     def check_readme(self, testdir):
 | |
|         config = testdir.parseconfigure()
 | |
|         readme = config.cache._cachedir.joinpath("README.md")
 | |
|         return readme.is_file()
 | |
| 
 | |
|     def test_readme_passed(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             def test_always_passes():
 | |
|                 assert 1
 | |
|         """
 | |
|         )
 | |
|         testdir.runpytest()
 | |
|         assert self.check_readme(testdir) is True
 | |
| 
 | |
|     def test_readme_failed(self, testdir):
 | |
|         testdir.makepyfile(
 | |
|             """
 | |
|             def test_always_passes():
 | |
|                 assert 0
 | |
|         """
 | |
|         )
 | |
|         testdir.runpytest()
 | |
|         assert self.check_readme(testdir) is True
 | |
| 
 | |
| 
 | |
| def test_gitignore(testdir):
 | |
|     """Ensure we automatically create .gitignore file in the pytest_cache directory (#3286)."""
 | |
|     from _pytest.cacheprovider import Cache
 | |
| 
 | |
|     config = testdir.parseconfig()
 | |
|     cache = Cache.for_config(config)
 | |
|     cache.set("foo", "bar")
 | |
|     msg = "# Created by pytest automatically.\n*"
 | |
|     gitignore_path = cache._cachedir.joinpath(".gitignore")
 | |
|     assert gitignore_path.read_text(encoding="UTF-8") == msg
 | |
| 
 | |
|     # Does not overwrite existing/custom one.
 | |
|     gitignore_path.write_text(u"custom")
 | |
|     cache.set("something", "else")
 | |
|     assert gitignore_path.read_text(encoding="UTF-8") == "custom"
 | |
| 
 | |
| 
 | |
| def test_does_not_create_boilerplate_in_existing_dirs(testdir):
 | |
|     from _pytest.cacheprovider import Cache
 | |
| 
 | |
|     testdir.makeini(
 | |
|         """
 | |
|         [pytest]
 | |
|         cache_dir = .
 | |
|         """
 | |
|     )
 | |
|     config = testdir.parseconfig()
 | |
|     cache = Cache.for_config(config)
 | |
|     cache.set("foo", "bar")
 | |
| 
 | |
|     assert os.path.isdir("v")  # cache contents
 | |
|     assert not os.path.exists(".gitignore")
 | |
|     assert not os.path.exists("README.md")
 | |
| 
 | |
| 
 | |
| def test_cachedir_tag(testdir):
 | |
|     """Ensure we automatically create CACHEDIR.TAG file in the pytest_cache directory (#4278)."""
 | |
|     from _pytest.cacheprovider import Cache
 | |
|     from _pytest.cacheprovider import CACHEDIR_TAG_CONTENT
 | |
| 
 | |
|     config = testdir.parseconfig()
 | |
|     cache = Cache.for_config(config)
 | |
|     cache.set("foo", "bar")
 | |
|     cachedir_tag_path = cache._cachedir.joinpath("CACHEDIR.TAG")
 | |
|     assert cachedir_tag_path.read_bytes() == CACHEDIR_TAG_CONTENT
 |