diff options
Diffstat (limited to 'third_party/python/pytest/testing/test_conftest.py')
-rw-r--r-- | third_party/python/pytest/testing/test_conftest.py | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/third_party/python/pytest/testing/test_conftest.py b/third_party/python/pytest/testing/test_conftest.py new file mode 100644 index 0000000000..61b640976f --- /dev/null +++ b/third_party/python/pytest/testing/test_conftest.py @@ -0,0 +1,543 @@ +from __future__ import absolute_import, division, print_function +from textwrap import dedent + +import _pytest._code +import py +import pytest +from _pytest.config import PytestPluginManager +from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR + + +@pytest.fixture(scope="module", params=["global", "inpackage"]) +def basedir(request, tmpdir_factory): + from _pytest.tmpdir import tmpdir + + tmpdir = tmpdir(request, tmpdir_factory) + tmpdir.ensure("adir/conftest.py").write("a=1 ; Directory = 3") + tmpdir.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5") + if request.param == "inpackage": + tmpdir.ensure("adir/__init__.py") + tmpdir.ensure("adir/b/__init__.py") + return tmpdir + + +def ConftestWithSetinitial(path): + conftest = PytestPluginManager() + conftest_setinitial(conftest, [path]) + return conftest + + +def conftest_setinitial(conftest, args, confcutdir=None): + + class Namespace(object): + + def __init__(self): + self.file_or_dir = args + self.confcutdir = str(confcutdir) + self.noconftest = False + + conftest._set_initial_conftests(Namespace()) + + +class TestConftestValueAccessGlobal(object): + + def test_basic_init(self, basedir): + conftest = PytestPluginManager() + p = basedir.join("adir") + assert conftest._rget_with_confmod("a", p)[1] == 1 + + def test_immediate_initialiation_and_incremental_are_the_same(self, basedir): + conftest = PytestPluginManager() + len(conftest._path2confmods) + conftest._getconftestmodules(basedir) + snap1 = len(conftest._path2confmods) + # assert len(conftest._path2confmods) == snap1 + 1 + conftest._getconftestmodules(basedir.join("adir")) + assert len(conftest._path2confmods) == snap1 + 1 + conftest._getconftestmodules(basedir.join("b")) + assert len(conftest._path2confmods) == snap1 + 2 + + def test_value_access_not_existing(self, basedir): + conftest = ConftestWithSetinitial(basedir) + with pytest.raises(KeyError): + conftest._rget_with_confmod("a", basedir) + + def test_value_access_by_path(self, basedir): + conftest = ConftestWithSetinitial(basedir) + adir = basedir.join("adir") + assert conftest._rget_with_confmod("a", adir)[1] == 1 + assert conftest._rget_with_confmod("a", adir.join("b"))[1] == 1.5 + + def test_value_access_with_confmod(self, basedir): + startdir = basedir.join("adir", "b") + startdir.ensure("xx", dir=True) + conftest = ConftestWithSetinitial(startdir) + mod, value = conftest._rget_with_confmod("a", startdir) + assert value == 1.5 + path = py.path.local(mod.__file__) + assert path.dirpath() == basedir.join("adir", "b") + assert path.purebasename.startswith("conftest") + + +def test_conftest_in_nonpkg_with_init(tmpdir): + tmpdir.ensure("adir-1.0/conftest.py").write("a=1 ; Directory = 3") + tmpdir.ensure("adir-1.0/b/conftest.py").write("b=2 ; a = 1.5") + tmpdir.ensure("adir-1.0/b/__init__.py") + tmpdir.ensure("adir-1.0/__init__.py") + ConftestWithSetinitial(tmpdir.join("adir-1.0", "b")) + + +def test_doubledash_considered(testdir): + conf = testdir.mkdir("--option") + conf.ensure("conftest.py") + conftest = PytestPluginManager() + conftest_setinitial(conftest, [conf.basename, conf.basename]) + values = conftest._getconftestmodules(conf) + assert len(values) == 1 + + +def test_issue151_load_all_conftests(testdir): + names = "code proj src".split() + for name in names: + p = testdir.mkdir(name) + p.ensure("conftest.py") + + conftest = PytestPluginManager() + conftest_setinitial(conftest, names) + d = list(conftest._conftestpath2mod.values()) + assert len(d) == len(names) + + +def test_conftest_global_import(testdir): + testdir.makeconftest("x=3") + p = testdir.makepyfile( + """ + import py, pytest + from _pytest.config import PytestPluginManager + conf = PytestPluginManager() + mod = conf._importconftest(py.path.local("conftest.py")) + assert mod.x == 3 + import conftest + assert conftest is mod, (conftest, mod) + subconf = py.path.local().ensure("sub", "conftest.py") + subconf.write("y=4") + mod2 = conf._importconftest(subconf) + assert mod != mod2 + assert mod2.y == 4 + import conftest + assert conftest is mod2, (conftest, mod) + """ + ) + res = testdir.runpython(p) + assert res.ret == 0 + + +def test_conftestcutdir(testdir): + conf = testdir.makeconftest("") + p = testdir.mkdir("x") + conftest = PytestPluginManager() + conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p) + values = conftest._getconftestmodules(p) + assert len(values) == 0 + values = conftest._getconftestmodules(conf.dirpath()) + assert len(values) == 0 + assert conf not in conftest._conftestpath2mod + # but we can still import a conftest directly + conftest._importconftest(conf) + values = conftest._getconftestmodules(conf.dirpath()) + assert values[0].__file__.startswith(str(conf)) + # and all sub paths get updated properly + values = conftest._getconftestmodules(p) + assert len(values) == 1 + assert values[0].__file__.startswith(str(conf)) + + +def test_conftestcutdir_inplace_considered(testdir): + conf = testdir.makeconftest("") + conftest = PytestPluginManager() + conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath()) + values = conftest._getconftestmodules(conf.dirpath()) + assert len(values) == 1 + assert values[0].__file__.startswith(str(conf)) + + +@pytest.mark.parametrize("name", "test tests whatever .dotdir".split()) +def test_setinitial_conftest_subdirs(testdir, name): + sub = testdir.mkdir(name) + subconftest = sub.ensure("conftest.py") + conftest = PytestPluginManager() + conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir) + if name not in ("whatever", ".dotdir"): + assert subconftest in conftest._conftestpath2mod + assert len(conftest._conftestpath2mod) == 1 + else: + assert subconftest not in conftest._conftestpath2mod + assert len(conftest._conftestpath2mod) == 0 + + +def test_conftest_confcutdir(testdir): + testdir.makeconftest("assert 0") + x = testdir.mkdir("x") + x.join("conftest.py").write( + _pytest._code.Source( + """ + def pytest_addoption(parser): + parser.addoption("--xyz", action="store_true") + """ + ) + ) + result = testdir.runpytest("-h", "--confcutdir=%s" % x, x) + result.stdout.fnmatch_lines(["*--xyz*"]) + assert "warning: could not load initial" not in result.stdout.str() + + +def test_no_conftest(testdir): + testdir.makeconftest("assert 0") + result = testdir.runpytest("--noconftest") + assert result.ret == EXIT_NOTESTSCOLLECTED + + result = testdir.runpytest() + assert result.ret == EXIT_USAGEERROR + + +def test_conftest_existing_resultlog(testdir): + x = testdir.mkdir("tests") + x.join("conftest.py").write( + _pytest._code.Source( + """ + def pytest_addoption(parser): + parser.addoption("--xyz", action="store_true") + """ + ) + ) + testdir.makefile(ext=".log", result="") # Writes result.log + result = testdir.runpytest("-h", "--resultlog", "result.log") + result.stdout.fnmatch_lines(["*--xyz*"]) + + +def test_conftest_existing_junitxml(testdir): + x = testdir.mkdir("tests") + x.join("conftest.py").write( + _pytest._code.Source( + """ + def pytest_addoption(parser): + parser.addoption("--xyz", action="store_true") + """ + ) + ) + testdir.makefile(ext=".xml", junit="") # Writes junit.xml + result = testdir.runpytest("-h", "--junitxml", "junit.xml") + result.stdout.fnmatch_lines(["*--xyz*"]) + + +def test_conftest_import_order(testdir, monkeypatch): + ct1 = testdir.makeconftest("") + sub = testdir.mkdir("sub") + ct2 = sub.join("conftest.py") + ct2.write("") + + def impct(p): + return p + + conftest = PytestPluginManager() + conftest._confcutdir = testdir.tmpdir + monkeypatch.setattr(conftest, "_importconftest", impct) + assert conftest._getconftestmodules(sub) == [ct1, ct2] + + +def test_fixture_dependency(testdir, monkeypatch): + ct1 = testdir.makeconftest("") + ct1 = testdir.makepyfile("__init__.py") + ct1.write("") + sub = testdir.mkdir("sub") + sub.join("__init__.py").write("") + sub.join("conftest.py").write( + dedent( + """ + import pytest + + @pytest.fixture + def not_needed(): + assert False, "Should not be called!" + + @pytest.fixture + def foo(): + assert False, "Should not be called!" + + @pytest.fixture + def bar(foo): + return 'bar' + """ + ) + ) + subsub = sub.mkdir("subsub") + subsub.join("__init__.py").write("") + subsub.join("test_bar.py").write( + dedent( + """ + import pytest + + @pytest.fixture + def bar(): + return 'sub bar' + + def test_event_fixture(bar): + assert bar == 'sub bar' + """ + ) + ) + result = testdir.runpytest("sub") + result.stdout.fnmatch_lines(["*1 passed*"]) + + +def test_conftest_found_with_double_dash(testdir): + sub = testdir.mkdir("sub") + sub.join("conftest.py").write( + dedent( + """ + def pytest_addoption(parser): + parser.addoption("--hello-world", action="store_true") + """ + ) + ) + p = sub.join("test_hello.py") + p.write("def test_hello(): pass") + result = testdir.runpytest(str(p) + "::test_hello", "-h") + result.stdout.fnmatch_lines( + """ + *--hello-world* + """ + ) + + +class TestConftestVisibility(object): + + def _setup_tree(self, testdir): # for issue616 + # example mostly taken from: + # https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html + runner = testdir.mkdir("empty") + package = testdir.mkdir("package") + + package.join("conftest.py").write( + dedent( + """\ + import pytest + @pytest.fixture + def fxtr(): + return "from-package" + """ + ) + ) + package.join("test_pkgroot.py").write( + dedent( + """\ + def test_pkgroot(fxtr): + assert fxtr == "from-package" + """ + ) + ) + + swc = package.mkdir("swc") + swc.join("__init__.py").ensure() + swc.join("conftest.py").write( + dedent( + """\ + import pytest + @pytest.fixture + def fxtr(): + return "from-swc" + """ + ) + ) + swc.join("test_with_conftest.py").write( + dedent( + """\ + def test_with_conftest(fxtr): + assert fxtr == "from-swc" + + """ + ) + ) + + snc = package.mkdir("snc") + snc.join("__init__.py").ensure() + snc.join("test_no_conftest.py").write( + dedent( + """\ + def test_no_conftest(fxtr): + assert fxtr == "from-package" # No local conftest.py, so should + # use value from parent dir's + + """ + ) + ) + print("created directory structure:") + for x in testdir.tmpdir.visit(): + print(" " + x.relto(testdir.tmpdir)) + + return {"runner": runner, "package": package, "swc": swc, "snc": snc} + + # N.B.: "swc" stands for "subdir with conftest.py" + # "snc" stands for "subdir no [i.e. without] conftest.py" + @pytest.mark.parametrize( + "chdir,testarg,expect_ntests_passed", + [ + # Effective target: package/.. + ("runner", "..", 3), + ("package", "..", 3), + ("swc", "../..", 3), + ("snc", "../..", 3), + # Effective target: package + ("runner", "../package", 3), + ("package", ".", 3), + ("swc", "..", 3), + ("snc", "..", 3), + # Effective target: package/swc + ("runner", "../package/swc", 1), + ("package", "./swc", 1), + ("swc", ".", 1), + ("snc", "../swc", 1), + # Effective target: package/snc + ("runner", "../package/snc", 1), + ("package", "./snc", 1), + ("swc", "../snc", 1), + ("snc", ".", 1), + ], + ) + @pytest.mark.issue616 + def test_parsefactories_relative_node_ids( + self, testdir, chdir, testarg, expect_ntests_passed + ): + dirs = self._setup_tree(testdir) + print("pytest run in cwd: %s" % (dirs[chdir].relto(testdir.tmpdir))) + print("pytestarg : %s" % (testarg)) + print("expected pass : %s" % (expect_ntests_passed)) + with dirs[chdir].as_cwd(): + reprec = testdir.inline_run(testarg, "-q", "--traceconfig") + reprec.assertoutcome(passed=expect_ntests_passed) + + +@pytest.mark.parametrize( + "confcutdir,passed,error", [(".", 2, 0), ("src", 1, 1), (None, 1, 1)] +) +def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error): + """Test that conftest files are detected only up to an ini file, unless + an explicit --confcutdir option is given. + """ + root = testdir.tmpdir + src = root.join("src").ensure(dir=1) + src.join("pytest.ini").write("[pytest]") + src.join("conftest.py").write( + _pytest._code.Source( + """ + import pytest + @pytest.fixture + def fix1(): pass + """ + ) + ) + src.join("test_foo.py").write( + _pytest._code.Source( + """ + def test_1(fix1): + pass + def test_2(out_of_reach): + pass + """ + ) + ) + root.join("conftest.py").write( + _pytest._code.Source( + """ + import pytest + @pytest.fixture + def out_of_reach(): pass + """ + ) + ) + + args = [str(src)] + if confcutdir: + args = ["--confcutdir=%s" % root.join(confcutdir)] + result = testdir.runpytest(*args) + match = "" + if passed: + match += "*%d passed*" % passed + if error: + match += "*%d error*" % error + result.stdout.fnmatch_lines(match) + + +def test_issue1073_conftest_special_objects(testdir): + testdir.makeconftest( + """ + class DontTouchMe(object): + def __getattr__(self, x): + raise Exception('cant touch me') + + x = DontTouchMe() + """ + ) + testdir.makepyfile( + """ + def test_some(): + pass + """ + ) + res = testdir.runpytest() + assert res.ret == 0 + + +def test_conftest_exception_handling(testdir): + testdir.makeconftest( + """ + raise ValueError() + """ + ) + testdir.makepyfile( + """ + def test_some(): + pass + """ + ) + res = testdir.runpytest() + assert res.ret == 4 + assert "raise ValueError()" in [line.strip() for line in res.errlines] + + +def test_hook_proxy(testdir): + """Session's gethookproxy() would cache conftests incorrectly (#2016). + It was decided to remove the cache altogether. + """ + testdir.makepyfile( + **{ + "root/demo-0/test_foo1.py": "def test1(): pass", + "root/demo-a/test_foo2.py": "def test1(): pass", + "root/demo-a/conftest.py": """ + def pytest_ignore_collect(path, config): + return True + """, + "root/demo-b/test_foo3.py": "def test1(): pass", + "root/demo-c/test_foo4.py": "def test1(): pass", + } + ) + result = testdir.runpytest() + result.stdout.fnmatch_lines( + ["*test_foo1.py*", "*test_foo3.py*", "*test_foo4.py*", "*3 passed*"] + ) + + +def test_required_option_help(testdir): + testdir.makeconftest("assert 0") + x = testdir.mkdir("x") + x.join("conftest.py").write( + _pytest._code.Source( + """ + def pytest_addoption(parser): + parser.addoption("--xyz", action="store_true", required=True) + """ + ) + ) + result = testdir.runpytest("-h", x) + assert "argument --xyz is required" not in result.stdout.str() + assert "general:" in result.stdout.str() |