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