1from textwrap import dedent 2 3import _pytest._code 4import py 5import pytest 6from _pytest.config import PytestPluginManager 7from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR 8 9 10@pytest.fixture(scope="module", params=["global", "inpackage"]) 11def basedir(request, tmpdir_factory): 12 from _pytest.tmpdir import tmpdir 13 tmpdir = tmpdir(request, tmpdir_factory) 14 tmpdir.ensure("adir/conftest.py").write("a=1 ; Directory = 3") 15 tmpdir.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5") 16 if request.param == "inpackage": 17 tmpdir.ensure("adir/__init__.py") 18 tmpdir.ensure("adir/b/__init__.py") 19 return tmpdir 20 21def ConftestWithSetinitial(path): 22 conftest = PytestPluginManager() 23 conftest_setinitial(conftest, [path]) 24 return conftest 25 26def conftest_setinitial(conftest, args, confcutdir=None): 27 class Namespace: 28 def __init__(self): 29 self.file_or_dir = args 30 self.confcutdir = str(confcutdir) 31 self.noconftest = False 32 conftest._set_initial_conftests(Namespace()) 33 34class TestConftestValueAccessGlobal: 35 def test_basic_init(self, basedir): 36 conftest = PytestPluginManager() 37 p = basedir.join("adir") 38 assert conftest._rget_with_confmod("a", p)[1] == 1 39 40 def test_immediate_initialiation_and_incremental_are_the_same(self, basedir): 41 conftest = PytestPluginManager() 42 len(conftest._path2confmods) 43 conftest._getconftestmodules(basedir) 44 snap1 = len(conftest._path2confmods) 45 #assert len(conftest._path2confmods) == snap1 + 1 46 conftest._getconftestmodules(basedir.join('adir')) 47 assert len(conftest._path2confmods) == snap1 + 1 48 conftest._getconftestmodules(basedir.join('b')) 49 assert len(conftest._path2confmods) == snap1 + 2 50 51 def test_value_access_not_existing(self, basedir): 52 conftest = ConftestWithSetinitial(basedir) 53 with pytest.raises(KeyError): 54 conftest._rget_with_confmod('a', basedir) 55 56 def test_value_access_by_path(self, basedir): 57 conftest = ConftestWithSetinitial(basedir) 58 adir = basedir.join("adir") 59 assert conftest._rget_with_confmod("a", adir)[1] == 1 60 assert conftest._rget_with_confmod("a", adir.join("b"))[1] == 1.5 61 62 def test_value_access_with_confmod(self, basedir): 63 startdir = basedir.join("adir", "b") 64 startdir.ensure("xx", dir=True) 65 conftest = ConftestWithSetinitial(startdir) 66 mod, value = conftest._rget_with_confmod("a", startdir) 67 assert value == 1.5 68 path = py.path.local(mod.__file__) 69 assert path.dirpath() == basedir.join("adir", "b") 70 assert path.purebasename.startswith("conftest") 71 72def test_conftest_in_nonpkg_with_init(tmpdir): 73 tmpdir.ensure("adir-1.0/conftest.py").write("a=1 ; Directory = 3") 74 tmpdir.ensure("adir-1.0/b/conftest.py").write("b=2 ; a = 1.5") 75 tmpdir.ensure("adir-1.0/b/__init__.py") 76 tmpdir.ensure("adir-1.0/__init__.py") 77 ConftestWithSetinitial(tmpdir.join("adir-1.0", "b")) 78 79def test_doubledash_considered(testdir): 80 conf = testdir.mkdir("--option") 81 conf.join("conftest.py").ensure() 82 conftest = PytestPluginManager() 83 conftest_setinitial(conftest, [conf.basename, conf.basename]) 84 l = conftest._getconftestmodules(conf) 85 assert len(l) == 1 86 87def test_issue151_load_all_conftests(testdir): 88 names = "code proj src".split() 89 for name in names: 90 p = testdir.mkdir(name) 91 p.ensure("conftest.py") 92 93 conftest = PytestPluginManager() 94 conftest_setinitial(conftest, names) 95 d = list(conftest._conftestpath2mod.values()) 96 assert len(d) == len(names) 97 98def test_conftest_global_import(testdir): 99 testdir.makeconftest("x=3") 100 p = testdir.makepyfile(""" 101 import py, pytest 102 from _pytest.config import PytestPluginManager 103 conf = PytestPluginManager() 104 mod = conf._importconftest(py.path.local("conftest.py")) 105 assert mod.x == 3 106 import conftest 107 assert conftest is mod, (conftest, mod) 108 subconf = py.path.local().ensure("sub", "conftest.py") 109 subconf.write("y=4") 110 mod2 = conf._importconftest(subconf) 111 assert mod != mod2 112 assert mod2.y == 4 113 import conftest 114 assert conftest is mod2, (conftest, mod) 115 """) 116 res = testdir.runpython(p) 117 assert res.ret == 0 118 119def test_conftestcutdir(testdir): 120 conf = testdir.makeconftest("") 121 p = testdir.mkdir("x") 122 conftest = PytestPluginManager() 123 conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p) 124 l = conftest._getconftestmodules(p) 125 assert len(l) == 0 126 l = conftest._getconftestmodules(conf.dirpath()) 127 assert len(l) == 0 128 assert conf not in conftest._conftestpath2mod 129 # but we can still import a conftest directly 130 conftest._importconftest(conf) 131 l = conftest._getconftestmodules(conf.dirpath()) 132 assert l[0].__file__.startswith(str(conf)) 133 # and all sub paths get updated properly 134 l = conftest._getconftestmodules(p) 135 assert len(l) == 1 136 assert l[0].__file__.startswith(str(conf)) 137 138def test_conftestcutdir_inplace_considered(testdir): 139 conf = testdir.makeconftest("") 140 conftest = PytestPluginManager() 141 conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath()) 142 l = conftest._getconftestmodules(conf.dirpath()) 143 assert len(l) == 1 144 assert l[0].__file__.startswith(str(conf)) 145 146@pytest.mark.parametrize("name", 'test tests whatever .dotdir'.split()) 147def test_setinitial_conftest_subdirs(testdir, name): 148 sub = testdir.mkdir(name) 149 subconftest = sub.ensure("conftest.py") 150 conftest = PytestPluginManager() 151 conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir) 152 if name not in ('whatever', '.dotdir'): 153 assert subconftest in conftest._conftestpath2mod 154 assert len(conftest._conftestpath2mod) == 1 155 else: 156 assert subconftest not in conftest._conftestpath2mod 157 assert len(conftest._conftestpath2mod) == 0 158 159def test_conftest_confcutdir(testdir): 160 testdir.makeconftest("assert 0") 161 x = testdir.mkdir("x") 162 x.join("conftest.py").write(_pytest._code.Source(""" 163 def pytest_addoption(parser): 164 parser.addoption("--xyz", action="store_true") 165 """)) 166 result = testdir.runpytest("-h", "--confcutdir=%s" % x, x) 167 result.stdout.fnmatch_lines(["*--xyz*"]) 168 assert 'warning: could not load initial' not in result.stdout.str() 169 170def test_no_conftest(testdir): 171 testdir.makeconftest("assert 0") 172 result = testdir.runpytest("--noconftest") 173 assert result.ret == EXIT_NOTESTSCOLLECTED 174 175 result = testdir.runpytest() 176 assert result.ret == EXIT_USAGEERROR 177 178def test_conftest_existing_resultlog(testdir): 179 x = testdir.mkdir("tests") 180 x.join("conftest.py").write(_pytest._code.Source(""" 181 def pytest_addoption(parser): 182 parser.addoption("--xyz", action="store_true") 183 """)) 184 testdir.makefile(ext=".log", result="") # Writes result.log 185 result = testdir.runpytest("-h", "--resultlog", "result.log") 186 result.stdout.fnmatch_lines(["*--xyz*"]) 187 188def test_conftest_existing_junitxml(testdir): 189 x = testdir.mkdir("tests") 190 x.join("conftest.py").write(_pytest._code.Source(""" 191 def pytest_addoption(parser): 192 parser.addoption("--xyz", action="store_true") 193 """)) 194 testdir.makefile(ext=".xml", junit="") # Writes junit.xml 195 result = testdir.runpytest("-h", "--junitxml", "junit.xml") 196 result.stdout.fnmatch_lines(["*--xyz*"]) 197 198def test_conftest_import_order(testdir, monkeypatch): 199 ct1 = testdir.makeconftest("") 200 sub = testdir.mkdir("sub") 201 ct2 = sub.join("conftest.py") 202 ct2.write("") 203 def impct(p): 204 return p 205 conftest = PytestPluginManager() 206 monkeypatch.setattr(conftest, '_importconftest', impct) 207 assert conftest._getconftestmodules(sub) == [ct1, ct2] 208 209 210def test_fixture_dependency(testdir, monkeypatch): 211 ct1 = testdir.makeconftest("") 212 ct1 = testdir.makepyfile("__init__.py") 213 ct1.write("") 214 sub = testdir.mkdir("sub") 215 sub.join("__init__.py").write("") 216 sub.join("conftest.py").write(py.std.textwrap.dedent(""" 217 import pytest 218 219 @pytest.fixture 220 def not_needed(): 221 assert False, "Should not be called!" 222 223 @pytest.fixture 224 def foo(): 225 assert False, "Should not be called!" 226 227 @pytest.fixture 228 def bar(foo): 229 return 'bar' 230 """)) 231 subsub = sub.mkdir("subsub") 232 subsub.join("__init__.py").write("") 233 subsub.join("test_bar.py").write(py.std.textwrap.dedent(""" 234 import pytest 235 236 @pytest.fixture 237 def bar(): 238 return 'sub bar' 239 240 def test_event_fixture(bar): 241 assert bar == 'sub bar' 242 """)) 243 result = testdir.runpytest("sub") 244 result.stdout.fnmatch_lines(["*1 passed*"]) 245 246 247def test_conftest_found_with_double_dash(testdir): 248 sub = testdir.mkdir("sub") 249 sub.join("conftest.py").write(py.std.textwrap.dedent(""" 250 def pytest_addoption(parser): 251 parser.addoption("--hello-world", action="store_true") 252 """)) 253 p = sub.join("test_hello.py") 254 p.write(py.std.textwrap.dedent(""" 255 import pytest 256 def test_hello(found): 257 assert found == 1 258 """)) 259 result = testdir.runpytest(str(p) + "::test_hello", "-h") 260 result.stdout.fnmatch_lines(""" 261 *--hello-world* 262 """) 263 264 265class TestConftestVisibility: 266 def _setup_tree(self, testdir): # for issue616 267 # example mostly taken from: 268 # https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html 269 runner = testdir.mkdir("empty") 270 package = testdir.mkdir("package") 271 272 package.join("conftest.py").write(dedent("""\ 273 import pytest 274 @pytest.fixture 275 def fxtr(): 276 return "from-package" 277 """)) 278 package.join("test_pkgroot.py").write(dedent("""\ 279 def test_pkgroot(fxtr): 280 assert fxtr == "from-package" 281 """)) 282 283 swc = package.mkdir("swc") 284 swc.join("__init__.py").ensure() 285 swc.join("conftest.py").write(dedent("""\ 286 import pytest 287 @pytest.fixture 288 def fxtr(): 289 return "from-swc" 290 """)) 291 swc.join("test_with_conftest.py").write(dedent("""\ 292 def test_with_conftest(fxtr): 293 assert fxtr == "from-swc" 294 295 """)) 296 297 snc = package.mkdir("snc") 298 snc.join("__init__.py").ensure() 299 snc.join("test_no_conftest.py").write(dedent("""\ 300 def test_no_conftest(fxtr): 301 assert fxtr == "from-package" # No local conftest.py, so should 302 # use value from parent dir's 303 304 """)) 305 print ("created directory structure:") 306 for x in testdir.tmpdir.visit(): 307 print (" " + x.relto(testdir.tmpdir)) 308 309 return { 310 "runner": runner, 311 "package": package, 312 "swc": swc, 313 "snc": snc} 314 315 # N.B.: "swc" stands for "subdir with conftest.py" 316 # "snc" stands for "subdir no [i.e. without] conftest.py" 317 @pytest.mark.parametrize("chdir,testarg,expect_ntests_passed", [ 318 # Effective target: package/.. 319 ("runner", "..", 3), 320 ("package", "..", 3), 321 ("swc", "../..", 3), 322 ("snc", "../..", 3), 323 324 # Effective target: package 325 ("runner", "../package", 3), 326 ("package", ".", 3), 327 ("swc", "..", 3), 328 ("snc", "..", 3), 329 330 # Effective target: package/swc 331 ("runner", "../package/swc", 1), 332 ("package", "./swc", 1), 333 ("swc", ".", 1), 334 ("snc", "../swc", 1), 335 336 # Effective target: package/snc 337 ("runner", "../package/snc", 1), 338 ("package", "./snc", 1), 339 ("swc", "../snc", 1), 340 ("snc", ".", 1), 341 ]) 342 @pytest.mark.issue616 343 def test_parsefactories_relative_node_ids( 344 self, testdir, chdir,testarg, expect_ntests_passed): 345 dirs = self._setup_tree(testdir) 346 print("pytest run in cwd: %s" %( 347 dirs[chdir].relto(testdir.tmpdir))) 348 print("pytestarg : %s" %(testarg)) 349 print("expected pass : %s" %(expect_ntests_passed)) 350 with dirs[chdir].as_cwd(): 351 reprec = testdir.inline_run(testarg, "-q", "--traceconfig") 352 reprec.assertoutcome(passed=expect_ntests_passed) 353 354 355@pytest.mark.parametrize('confcutdir,passed,error', [ 356 ('.', 2, 0), 357 ('src', 1, 1), 358 (None, 1, 1), 359]) 360def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error): 361 """Test that conftest files are detected only up to a ini file, unless 362 an explicit --confcutdir option is given. 363 """ 364 root = testdir.tmpdir 365 src = root.join('src').ensure(dir=1) 366 src.join('pytest.ini').write('[pytest]') 367 src.join('conftest.py').write(_pytest._code.Source(""" 368 import pytest 369 @pytest.fixture 370 def fix1(): pass 371 """)) 372 src.join('test_foo.py').write(_pytest._code.Source(""" 373 def test_1(fix1): 374 pass 375 def test_2(out_of_reach): 376 pass 377 """)) 378 root.join('conftest.py').write(_pytest._code.Source(""" 379 import pytest 380 @pytest.fixture 381 def out_of_reach(): pass 382 """)) 383 384 args = [str(src)] 385 if confcutdir: 386 args = ['--confcutdir=%s' % root.join(confcutdir)] 387 result = testdir.runpytest(*args) 388 match = '' 389 if passed: 390 match += '*%d passed*' % passed 391 if error: 392 match += '*%d error*' % error 393 result.stdout.fnmatch_lines(match) 394 395 396def test_issue1073_conftest_special_objects(testdir): 397 testdir.makeconftest(""" 398 class DontTouchMe: 399 def __getattr__(self, x): 400 raise Exception('cant touch me') 401 402 x = DontTouchMe() 403 """) 404 testdir.makepyfile(""" 405 def test_some(): 406 pass 407 """) 408 res = testdir.runpytest() 409 assert res.ret == 0 410