import pytest, py from _pytest.main import Session class TestCollector: def test_collect_versus_item(self): from pytest import Collector, Item assert not issubclass(Collector, Item) assert not issubclass(Item, Collector) def test_compat_attributes(self, testdir, recwarn): modcol = testdir.getmodulecol(""" def test_pass(): pass def test_fail(): assert 0 """) recwarn.clear() assert modcol.Module == pytest.Module assert modcol.Class == pytest.Class assert modcol.Item == pytest.Item assert modcol.File == pytest.File assert modcol.Function == pytest.Function def test_check_equality(self, testdir): modcol = testdir.getmodulecol(""" def test_pass(): pass def test_fail(): assert 0 """) fn1 = testdir.collect_by_name(modcol, "test_pass") assert isinstance(fn1, pytest.Function) fn2 = testdir.collect_by_name(modcol, "test_pass") assert isinstance(fn2, pytest.Function) assert fn1 == fn2 assert fn1 != modcol if py.std.sys.version_info < (3, 0): assert cmp(fn1, fn2) == 0 assert hash(fn1) == hash(fn2) fn3 = testdir.collect_by_name(modcol, "test_fail") assert isinstance(fn3, pytest.Function) assert not (fn1 == fn3) assert fn1 != fn3 for fn in fn1,fn2,fn3: assert fn != 3 assert fn != modcol assert fn != [1,2,3] assert [1,2,3] != fn assert modcol != fn def test_getparent(self, testdir): modcol = testdir.getmodulecol(""" class TestClass: def test_foo(): pass """) cls = testdir.collect_by_name(modcol, "TestClass") fn = testdir.collect_by_name( testdir.collect_by_name(cls, "()"), "test_foo") parent = fn.getparent(pytest.Module) assert parent is modcol parent = fn.getparent(pytest.Function) assert parent is fn parent = fn.getparent(pytest.Class) assert parent is cls def test_getcustomfile_roundtrip(self, testdir): hello = testdir.makefile(".xxx", hello="world") testdir.makepyfile(conftest=""" import pytest class CustomFile(pytest.File): pass def pytest_collect_file(path, parent): if path.ext == ".xxx": return CustomFile(path, parent=parent) """) node = testdir.getpathnode(hello) assert isinstance(node, pytest.File) assert node.name == "hello.xxx" nodes = node.session.perform_collect([node.nodeid], genitems=False) assert len(nodes) == 1 assert isinstance(nodes[0], pytest.File) class TestCollectFS: def test_ignored_certain_directories(self, testdir): tmpdir = testdir.tmpdir tmpdir.ensure("_darcs", 'test_notfound.py') tmpdir.ensure("CVS", 'test_notfound.py') tmpdir.ensure("{arch}", 'test_notfound.py') tmpdir.ensure(".whatever", 'test_notfound.py') tmpdir.ensure(".bzr", 'test_notfound.py') tmpdir.ensure("normal", 'test_found.py') for x in tmpdir.visit("test_*.py"): x.write("def test_hello(): pass") result = testdir.runpytest("--collect-only") s = result.stdout.str() assert "test_notfound" not in s assert "test_found" in s def test_custom_norecursedirs(self, testdir): testdir.makeini(""" [pytest] norecursedirs = mydir xyz* """) tmpdir = testdir.tmpdir tmpdir.ensure("mydir", "test_hello.py").write("def test_1(): pass") tmpdir.ensure("xyz123", "test_2.py").write("def test_2(): 0/0") tmpdir.ensure("xy", "test_ok.py").write("def test_3(): pass") rec = testdir.inline_run() rec.assertoutcome(passed=1) rec = testdir.inline_run("xyz123/test_2.py") rec.assertoutcome(failed=1) class TestCollectPluginHookRelay: def test_pytest_collect_file(self, testdir): wascalled = [] class Plugin: def pytest_collect_file(self, path, parent): wascalled.append(path) testdir.makefile(".abc", "xyz") pytest.main([testdir.tmpdir], plugins=[Plugin()]) assert len(wascalled) == 1 assert wascalled[0].ext == '.abc' def test_pytest_collect_directory(self, testdir): wascalled = [] class Plugin: def pytest_collect_directory(self, path, parent): wascalled.append(path.basename) testdir.mkdir("hello") testdir.mkdir("world") pytest.main(testdir.tmpdir, plugins=[Plugin()]) assert "hello" in wascalled assert "world" in wascalled class TestPrunetraceback: def test_collection_error(self, testdir): p = testdir.makepyfile(""" import not_exists """) result = testdir.runpytest(p) assert "__import__" not in result.stdout.str(), "too long traceback" result.stdout.fnmatch_lines([ "*ERROR collecting*", "*mport*not_exists*" ]) def test_custom_repr_failure(self, testdir): p = testdir.makepyfile(""" import not_exists """) testdir.makeconftest(""" import pytest def pytest_collect_file(path, parent): return MyFile(path, parent) class MyError(Exception): pass class MyFile(pytest.File): def collect(self): raise MyError() def repr_failure(self, excinfo): if excinfo.errisinstance(MyError): return "hello world" return pytest.File.repr_failure(self, excinfo) """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*ERROR collecting*", "*hello world*", ]) @pytest.mark.xfail(reason="other mechanism for adding to reporting needed") def test_collect_report_postprocessing(self, testdir): p = testdir.makepyfile(""" import not_exists """) testdir.makeconftest(""" import pytest def pytest_make_collect_report(__multicall__): rep = __multicall__.execute() rep.headerlines += ["header1"] return rep """) result = testdir.runpytest(p) result.stdout.fnmatch_lines([ "*ERROR collecting*", "*header1*", ]) class TestCustomConftests: def test_ignore_collect_path(self, testdir): testdir.makeconftest(""" def pytest_ignore_collect(path, config): return path.basename.startswith("x") or \ path.basename == "test_one.py" """) sub = testdir.mkdir("xy123") sub.ensure("test_hello.py").write("syntax error") sub.join("conftest.py").write("syntax error") testdir.makepyfile("def test_hello(): pass") testdir.makepyfile(test_one="syntax error") result = testdir.runpytest("--fulltrace") assert result.ret == 0 result.stdout.fnmatch_lines(["*1 passed*"]) def test_ignore_collect_not_called_on_argument(self, testdir): testdir.makeconftest(""" def pytest_ignore_collect(path, config): return True """) p = testdir.makepyfile("def test_hello(): pass") result = testdir.runpytest(p) assert result.ret == 0 assert "1 passed" in result.stdout.str() result = testdir.runpytest() assert result.ret == 0 assert "1 passed" not in result.stdout.str() def test_collectignore_exclude_on_option(self, testdir): testdir.makeconftest(""" collect_ignore = ['hello', 'test_world.py'] def pytest_addoption(parser): parser.addoption("--XX", action="store_true", default=False) def pytest_configure(config): if config.getvalue("XX"): collect_ignore[:] = [] """) testdir.mkdir("hello") testdir.makepyfile(test_world="def test_hello(): pass") result = testdir.runpytest() assert result.ret == 0 assert "passed" not in result.stdout.str() result = testdir.runpytest("--XX") assert result.ret == 0 assert "passed" in result.stdout.str() def test_pytest_fs_collect_hooks_are_seen(self, testdir): conf = testdir.makeconftest(""" import pytest class MyModule(pytest.Module): pass def pytest_collect_file(path, parent): if path.ext == ".py": return MyModule(path, parent) """) sub = testdir.mkdir("sub") p = testdir.makepyfile("def test_x(): pass") result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*MyModule*", "*test_x*" ]) def test_pytest_collect_file_from_sister_dir(self, testdir): sub1 = testdir.mkpydir("sub1") sub2 = testdir.mkpydir("sub2") conf1 = testdir.makeconftest(""" import pytest class MyModule1(pytest.Module): pass def pytest_collect_file(path, parent): if path.ext == ".py": return MyModule1(path, parent) """) conf1.move(sub1.join(conf1.basename)) conf2 = testdir.makeconftest(""" import pytest class MyModule2(pytest.Module): pass def pytest_collect_file(path, parent): if path.ext == ".py": return MyModule2(path, parent) """) conf2.move(sub2.join(conf2.basename)) p = testdir.makepyfile("def test_x(): pass") p.copy(sub1.join(p.basename)) p.copy(sub2.join(p.basename)) result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*MyModule1*", "*MyModule2*", "*test_x*" ]) class TestSession: def test_parsearg(self, testdir): p = testdir.makepyfile("def test_func(): pass") subdir = testdir.mkdir("sub") subdir.ensure("__init__.py") target = subdir.join(p.basename) p.move(target) testdir.chdir() subdir.chdir() config = testdir.parseconfig(p.basename) rcol = Session(config=config) assert rcol.fspath == subdir parts = rcol._parsearg(p.basename) assert parts[0] == target assert len(parts) == 1 parts = rcol._parsearg(p.basename + "::test_func") assert parts[0] == target assert parts[1] == "test_func" assert len(parts) == 2 def test_collect_topdir(self, testdir): p = testdir.makepyfile("def test_func(): pass") id = "::".join([p.basename, "test_func"]) # XXX migrate to inline_genitems? (see below) config = testdir.parseconfig(id) topdir = testdir.tmpdir rcol = Session(config) assert topdir == rcol.fspath rootid = rcol.nodeid #root2 = rcol.perform_collect([rcol.nodeid], genitems=False)[0] #assert root2 == rcol, rootid colitems = rcol.perform_collect([rcol.nodeid], genitems=False) assert len(colitems) == 1 assert colitems[0].fspath == p def test_collect_protocol_single_function(self, testdir): p = testdir.makepyfile("def test_func(): pass") id = "::".join([p.basename, "test_func"]) topdir = testdir.tmpdir items, hookrec = testdir.inline_genitems(id) item, = items assert item.name == "test_func" newid = item.nodeid assert newid == id py.std.pprint.pprint(hookrec.hookrecorder.calls) hookrec.hookrecorder.contains([ ("pytest_collectstart", "collector.fspath == topdir"), ("pytest_make_collect_report", "collector.fspath == topdir"), ("pytest_collectstart", "collector.fspath == p"), ("pytest_make_collect_report", "collector.fspath == p"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", "report.nodeid.startswith(p.basename)"), ("pytest_collectreport", "report.nodeid == '.'") ]) def test_collect_protocol_method(self, testdir): p = testdir.makepyfile(""" class TestClass: def test_method(self): pass """) normid = p.basename + "::TestClass::()::test_method" for id in [p.basename, p.basename + "::TestClass", p.basename + "::TestClass::()", normid, ]: items, hookrec = testdir.inline_genitems(id) assert len(items) == 1 assert items[0].name == "test_method" newid = items[0].nodeid assert newid == normid def test_collect_custom_nodes_multi_id(self, testdir): p = testdir.makepyfile("def test_func(): pass") testdir.makeconftest(""" import pytest class SpecialItem(pytest.Item): def runtest(self): return # ok class SpecialFile(pytest.File): def collect(self): return [SpecialItem(name="check", parent=self)] def pytest_collect_file(path, parent): if path.basename == %r: return SpecialFile(fspath=path, parent=parent) """ % p.basename) id = p.basename items, hookrec = testdir.inline_genitems(id) py.std.pprint.pprint(hookrec.hookrecorder.calls) assert len(items) == 2 hookrec.hookrecorder.contains([ ("pytest_collectstart", "collector.fspath == collector.session.fspath"), ("pytest_collectstart", "collector.__class__.__name__ == 'SpecialFile'"), ("pytest_collectstart", "collector.__class__.__name__ == 'Module'"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", "report.nodeid.startswith(p.basename)"), #("pytest_collectreport", # "report.fspath == %r" % str(rcol.fspath)), ]) def test_collect_subdir_event_ordering(self, testdir): p = testdir.makepyfile("def test_func(): pass") aaa = testdir.mkpydir("aaa") test_aaa = aaa.join("test_aaa.py") p.move(test_aaa) items, hookrec = testdir.inline_genitems() assert len(items) == 1 py.std.pprint.pprint(hookrec.hookrecorder.calls) hookrec.hookrecorder.contains([ ("pytest_collectstart", "collector.fspath == test_aaa"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", "report.nodeid.startswith('aaa/test_aaa.py')"), ]) def test_collect_two_commandline_args(self, testdir): p = testdir.makepyfile("def test_func(): pass") aaa = testdir.mkpydir("aaa") bbb = testdir.mkpydir("bbb") test_aaa = aaa.join("test_aaa.py") p.copy(test_aaa) test_bbb = bbb.join("test_bbb.py") p.move(test_bbb) id = "." items, hookrec = testdir.inline_genitems(id) assert len(items) == 2 py.std.pprint.pprint(hookrec.hookrecorder.calls) hookrec.hookrecorder.contains([ ("pytest_collectstart", "collector.fspath == test_aaa"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", "report.nodeid == 'aaa/test_aaa.py'"), ("pytest_collectstart", "collector.fspath == test_bbb"), ("pytest_pycollect_makeitem", "name == 'test_func'"), ("pytest_collectreport", "report.nodeid == 'bbb/test_bbb.py'"), ]) def test_serialization_byid(self, testdir): p = testdir.makepyfile("def test_func(): pass") items, hookrec = testdir.inline_genitems() assert len(items) == 1 item, = items items2, hookrec = testdir.inline_genitems(item.nodeid) item2, = items2 assert item2.name == item.name assert item2.fspath == item.fspath def test_find_byid_without_instance_parents(self, testdir): p = testdir.makepyfile(""" class TestClass: def test_method(self): pass """) arg = p.basename + ("::TestClass::test_method") items, hookrec = testdir.inline_genitems(arg) assert len(items) == 1 item, = items assert item.nodeid.endswith("TestClass::()::test_method") class Test_getinitialnodes: def test_global_file(self, testdir, tmpdir): x = tmpdir.ensure("x.py") config = testdir.parseconfigure(x) col = testdir.getnode(config, x) assert isinstance(col, pytest.Module) assert col.name == 'x.py' assert col.parent.name == testdir.tmpdir.basename assert col.parent.parent is None for col in col.listchain(): assert col.config is config def test_pkgfile(self, testdir): testdir.chdir() tmpdir = testdir.tmpdir subdir = tmpdir.join("subdir") x = subdir.ensure("x.py") subdir.ensure("__init__.py") config = testdir.parseconfigure(x) col = testdir.getnode(config, x) assert isinstance(col, pytest.Module) assert col.name == 'subdir/x.py' assert col.parent.parent is None for col in col.listchain(): assert col.config is config class Test_genitems: def test_check_collect_hashes(self, testdir): p = testdir.makepyfile(""" def test_1(): pass def test_2(): pass """) p.copy(p.dirpath(p.purebasename + "2" + ".py")) items, reprec = testdir.inline_genitems(p.dirpath()) assert len(items) == 4 for numi, i in enumerate(items): for numj, j in enumerate(items): if numj != numi: assert hash(i) != hash(j) assert i != j def test_example_items1(self, testdir): p = testdir.makepyfile(''' def testone(): pass class TestX: def testmethod_one(self): pass class TestY(TestX): pass ''') items, reprec = testdir.inline_genitems(p) assert len(items) == 3 assert items[0].name == 'testone' assert items[1].name == 'testmethod_one' assert items[2].name == 'testmethod_one' # let's also test getmodpath here assert items[0].getmodpath() == "testone" assert items[1].getmodpath() == "TestX.testmethod_one" assert items[2].getmodpath() == "TestY.testmethod_one" s = items[0].getmodpath(stopatmodule=False) assert s.endswith("test_example_items1.testone") print(s) def test_matchnodes_two_collections_same_file(testdir): testdir.makeconftest(""" import pytest def pytest_configure(config): config.pluginmanager.register(Plugin2()) class Plugin2: def pytest_collect_file(self, path, parent): if path.ext == ".abc": return MyFile2(path, parent) def pytest_collect_file(path, parent): if path.ext == ".abc": return MyFile1(path, parent) class MyFile1(pytest.Item, pytest.File): def runtest(self): pass class MyFile2(pytest.File): def collect(self): return [Item2("hello", parent=self)] class Item2(pytest.Item): def runtest(self): pass """) p = testdir.makefile(".abc", "") result = testdir.runpytest() assert result.ret == 0 result.stdout.fnmatch_lines([ "*2 passed*", ]) res = testdir.runpytest("%s::hello" % p.basename) res.stdout.fnmatch_lines([ "*1 passed*", ])