diff --git a/py/_com.py b/py/_com.py index 9bf31a273..6c8f83d0b 100644 --- a/py/_com.py +++ b/py/_com.py @@ -63,6 +63,7 @@ class Registry: """ Manage Plugins: Load plugins and manage calls to plugins. """ + logfile = None MultiCall = MultiCall def __init__(self, plugins=None): @@ -130,6 +131,11 @@ class HookCall: "for api call to %r" % self.name) attr = self.registry.listattr(self.name, extra=self.extralookup) mc = MultiCall(attr, **kwargs) + # XXX this should be doable from a hook impl: + if self.registry.logfile: + self.registry.logfile.write("%s(**%s) # firstresult=%s\n" % + (self.name, kwargs, self.firstresult)) + self.registry.logfile.flush() return mc.execute(firstresult=self.firstresult) comregistry = Registry() diff --git a/py/test/plugin/conftest.py b/py/test/plugin/conftest.py index 12f639454..5d5b81f4c 100644 --- a/py/test/plugin/conftest.py +++ b/py/test/plugin/conftest.py @@ -18,6 +18,7 @@ def pytest_funcarg__testdir(request): basename = request.module.__name__.split(".")[-1] if basename.startswith("pytest_"): testdir.plugins.append(vars(request.module)) + testdir.plugins.append(basename) else: pass # raise ValueError("need better support code") return testdir diff --git a/py/test/plugin/pytest_doctest.py b/py/test/plugin/pytest_doctest.py index c97e89749..cec84ddb8 100644 --- a/py/test/plugin/pytest_doctest.py +++ b/py/test/plugin/pytest_doctest.py @@ -1,4 +1,9 @@ +""" +automatically collect and execute doctests. +""" + import py +from py.__.code.excinfo import Repr, ReprFileLocation def pytest_addoption(parser): group = parser.addgroup("doctest options") @@ -13,8 +18,6 @@ def pytest_collect_file(path, parent): if path.check(fnmatch="test_*.txt"): return DoctestTextfile(path, parent) -from py.__.code.excinfo import Repr, ReprFileLocation - class ReprFailDoctest(Repr): def __init__(self, reprlocation, lines): self.reprlocation = reprlocation diff --git a/py/test/plugin/pytest_eventlog.py b/py/test/plugin/pytest_eventlog.py deleted file mode 100644 index 07268ed0e..000000000 --- a/py/test/plugin/pytest_eventlog.py +++ /dev/null @@ -1,45 +0,0 @@ -import py - -""" expected to fail. -""" - -class EventlogPlugin: - """ log pytest events to a file. """ - def pytest_addoption(self, parser): - parser.addoption("--eventlog", dest="eventlog", - help="write all pytest events to the given file.") - - def pytest_configure(self, config): - eventlog = config.getvalue("eventlog") - if eventlog: - self.eventlogfile = open(eventlog, 'w') - - def pytest_unconfigure(self, config): - if hasattr(self, 'eventlogfile'): - self.eventlogfile.close() - del self.eventlogfile - - def pyevent(self, eventname, args, kwargs): - if hasattr(self, 'eventlogfile'): - f = self.eventlogfile - print >>f, eventname, args, kwargs - f.flush() - -# =============================================================================== -# plugin tests -# =============================================================================== - -@py.test.mark.xfail -def test_generic(plugintester): - plugintester.hookcheck() - - testdir = plugintester.testdir() - testdir.makepyfile(""" - def test_pass(): - pass - """) - testdir.runpytest("--eventlog=event.log") - s = testdir.tmpdir.join("event.log").read() - assert s.find("testrunstart") != -1 - assert s.find("ItemTestReport") != -1 - assert s.find("testrunfinish") != -1 diff --git a/py/test/plugin/pytest_execnetcleanup.py b/py/test/plugin/pytest_execnetcleanup.py index a31036892..689653e5e 100644 --- a/py/test/plugin/pytest_execnetcleanup.py +++ b/py/test/plugin/pytest_execnetcleanup.py @@ -1,3 +1,6 @@ +""" +cleanup gateways that were instantiated during a test function run. +""" import py def pytest_configure(config): diff --git a/py/test/plugin/pytest_figleaf.py b/py/test/plugin/pytest_figleaf.py index d23345eb1..220f86aa7 100644 --- a/py/test/plugin/pytest_figleaf.py +++ b/py/test/plugin/pytest_figleaf.py @@ -1,3 +1,6 @@ +""" +write and report coverage data using the 'figleaf' module. +""" import py figleaf = py.test.importorskip("figleaf") diff --git a/py/test/plugin/pytest_hooklog.py b/py/test/plugin/pytest_hooklog.py new file mode 100644 index 000000000..b9333f371 --- /dev/null +++ b/py/test/plugin/pytest_hooklog.py @@ -0,0 +1,36 @@ +""" log calling of plugin hooks to a file. """ +import py + +def pytest_addoption(parser): + parser.addoption("--hooklog", dest="hooklog", default=None, + help="write hook calls to the given file.") + +def pytest_configure(config): + hooklog = config.getvalue("hooklog") + if hooklog: + assert not config.pluginmanager.comregistry.logfile + config.pluginmanager.comregistry.logfile = open(hooklog, 'w') + +def pytest_unconfigure(config): + f = config.pluginmanager.comregistry.logfile + if f: + f.close() + config.pluginmanager.comregistry.logfile = None + +# =============================================================================== +# plugin tests +# =============================================================================== + +def test_generic(plugintester): + plugintester.hookcheck() + +def test_functional(testdir): + testdir.makepyfile(""" + def test_pass(): + pass + """) + testdir.runpytest("--hooklog=hook.log") + s = testdir.tmpdir.join("hook.log").read() + assert s.find("pytest_testrunstart") != -1 + assert s.find("ItemTestReport") != -1 + assert s.find("testrunfinish") != -1 diff --git a/py/test/plugin/pytest_iocapture.py b/py/test/plugin/pytest_iocapture.py index 32221ed0d..0c0eb228f 100644 --- a/py/test/plugin/pytest_iocapture.py +++ b/py/test/plugin/pytest_iocapture.py @@ -1,12 +1,22 @@ +""" +'capsys' and 'capfd' funcargs for capturing stdout/stderror either +by intercepting sys.stdout/stderr or File Descriptors 1/2. + +Calling the reset() method of the capture funcargs gives +a out/err tuple of strings representing the captured streams. +You can call reset() multiple times each time getting +the chunk of output that was captured between the invocations. + +""" import py -def pytest_funcarg__stdcapture(request): +def pytest_funcarg__capsys(request): """ capture writes to sys.stdout/sys.stderr. """ capture = Capture(py.io.StdCapture) request.addfinalizer(capture.finalize) return capture -def pytest_funcarg__stdcapturefd(request): +def pytest_funcarg__capfd(request): """ capture writes to filedescriptors 1 and 2""" capture = Capture(py.io.StdCaptureFD) request.addfinalizer(capture.finalize) @@ -31,19 +41,19 @@ def test_generic(plugintester): class TestCapture: def test_std_functional(self, testdir): reprec = testdir.inline_runsource(""" - def test_hello(stdcapture): + def test_hello(capsys): print 42 - out, err = stdcapture.reset() + out, err = capsys.reset() assert out.startswith("42") """) reprec.assertoutcome(passed=1) def test_stdfd_functional(self, testdir): reprec = testdir.inline_runsource(""" - def test_hello(stdcapturefd): + def test_hello(capfd): import os os.write(1, "42") - out, err = stdcapturefd.reset() + out, err = capfd.reset() assert out.startswith("42") """) reprec.assertoutcome(passed=1) diff --git a/py/test/plugin/pytest_monkeypatch.py b/py/test/plugin/pytest_monkeypatch.py index 943c6443a..0f0c47ff4 100644 --- a/py/test/plugin/pytest_monkeypatch.py +++ b/py/test/plugin/pytest_monkeypatch.py @@ -1,17 +1,15 @@ -import os """ - provides the "monkeypatch" funcarg for safely patching objects, + "monkeypatch" funcarg for safely patching objects, dictionaries and environment variables during the execution of - a test. There are three helper functions: + a test. "monkeypatch" has three helper functions: monkeypatch.setattr(obj, name, value) monkeypatch.setitem(obj, name, value) monkeypatch.setenv(name, value) - After the test run all such modifications will be undone, - which may even mean deleting the attribute or dictionary entry - if it didn't exist before. + After the test has run modifications will be undone. """ +import os def pytest_funcarg__monkeypatch(request): monkeypatch = MonkeyPatch() diff --git a/py/test/plugin/pytest_pdb.py b/py/test/plugin/pytest_pdb.py index 6320903d3..1f1c026c5 100644 --- a/py/test/plugin/pytest_pdb.py +++ b/py/test/plugin/pytest_pdb.py @@ -1,3 +1,4 @@ +""" XXX should be used sometime. """ from py.__.test.custompdb import post_mortem def pytest_item_runtest_finished(item, excinfo, outerr): diff --git a/py/test/plugin/pytest_pylint.py b/py/test/plugin/pytest_pylint.py index d7dc7529a..2bd46ad2d 100644 --- a/py/test/plugin/pytest_pylint.py +++ b/py/test/plugin/pytest_pylint.py @@ -1,6 +1,5 @@ """pylint plugin - XXX: Currently in progress, NOT IN WORKING STATE. """ import py diff --git a/py/test/plugin/pytest_pytester.py b/py/test/plugin/pytest_pytester.py index 7794fe579..4a243cd6d 100644 --- a/py/test/plugin/pytest_pytester.py +++ b/py/test/plugin/pytest_pytester.py @@ -1,5 +1,5 @@ """ -pytes plugin for easing testing of pytest runs themselves. +funcargs and support code for testing py.test functionality. """ import py diff --git a/py/test/plugin/pytest_recwarn.py b/py/test/plugin/pytest_recwarn.py index e56ac5eb2..8d8fe66b4 100644 --- a/py/test/plugin/pytest_recwarn.py +++ b/py/test/plugin/pytest_recwarn.py @@ -1,8 +1,5 @@ """ - -provides "recwarn" funcarg for asserting warnings to be shown -to a user. See the test at the bottom for an example. - +"recwarn" funcarg for asserting that warnings are shown to a user. """ import py import os diff --git a/py/test/plugin/pytest_restdoc.py b/py/test/plugin/pytest_restdoc.py index 6492fbe22..4a4d36968 100644 --- a/py/test/plugin/pytest_restdoc.py +++ b/py/test/plugin/pytest_restdoc.py @@ -1,3 +1,7 @@ +""" +perform ReST specific tests on .txt files, including +linkchecks and remote URL checks. +""" import py def pytest_addoption(parser): diff --git a/py/test/plugin/pytest_resultdb.py b/py/test/plugin/pytest_resultdb.py index 59b1660f8..3cbfccceb 100644 --- a/py/test/plugin/pytest_resultdb.py +++ b/py/test/plugin/pytest_resultdb.py @@ -1,54 +1,51 @@ +"""XXX in progress: resultdb plugin for database logging of test results. + +Saves test results to a datastore. + +XXX this needs to be merged with resultlog plugin + +Also mixes in some early ideas about an archive abstraction for test +results. +""" import py + +py.test.skip("XXX needs to be merged with resultlog") + from pytest_resultlog import ResultLog -class ResultdbPlugin: - """XXX in progress: resultdb plugin for database logging of test results. +def pytest_addoption(parser): + group = parser.addgroup("resultdb", "resultdb plugin options") + group.addoption('--resultdb', action="store", dest="resultdb", + metavar="path", + help="path to the file to store test results.") + group.addoption('--resultdb_format', action="store", + dest="resultdbformat", default='json', + help="data format (json, sqlite)") - Saves test results to a datastore. - - XXX this needs to be merged with resultlog plugin - - Also mixes in some early ideas about an archive abstraction for test - results. - """ - def pytest_addoption(self, parser): - group = parser.addgroup("resultdb", "resultdb plugin options") - group.addoption('--resultdb', action="store", dest="resultdb", - metavar="path", - help="path to the file to store test results.") - group.addoption('--resultdb_format', action="store", - dest="resultdbformat", default='json', - help="data format (json, sqlite)") - - def pytest_configure(self, config): - if config.getvalue('resultdb'): - if config.option.resultdb: - # local import so missing module won't crash py.test - try: - import sqlite3 - except ImportError: - raise config.Error('Could not import sqlite3 module') - try: - import simplejson - except ImportError: - raise config.Error('Could not import simplejson module') - if config.option.resultdbformat.lower() == 'json': - self.resultdb = ResultDB(JSONResultArchive, - config.option.resultdb) - elif config.option.resultdbformat.lower() == 'sqlite': - self.resultdb = ResultDB(SQLiteResultArchive, - config.option.resultdb) - else: - raise config.Error('Unknown --resultdb_format: %s' % - config.option.resultdbformat) - - config.pluginmanager.register(self.resultdb) - - def pytest_unconfigure(self, config): - if hasattr(self, 'resultdb'): - del self.resultdb - #config.pluginmanager.unregister(self.resultdb) +def pytest_configure(config): + # XXX using config.XYZ is not good + if config.getvalue('resultdb'): + if config.option.resultdb: + # local import so missing module won't crash py.test + try: + import sqlite3 + except ImportError: + raise config.Error('Could not import sqlite3 module') + try: + import simplejson + except ImportError: + raise config.Error('Could not import simplejson module') + if config.option.resultdbformat.lower() == 'json': + resultdb = ResultDB(JSONResultArchive, + config.option.resultdb) + elif config.option.resultdbformat.lower() == 'sqlite': + resultdb = ResultDB(SQLiteResultArchive, + config.option.resultdb) + else: + raise config.Error('Unknown --resultdb_format: %s' % + config.option.resultdbformat) + config.pluginmanager.register(resultdb) class JSONResultArchive(object): def __init__(self, archive_path): @@ -328,8 +325,7 @@ class TestWithFunctionIntegration: assert x.startswith(" ") assert "XXX" in "".join(lines[1:]) - def test_log_test_outcomes(self, plugintester): - testdir = plugintester.testdir() + def test_log_test_outcomes(self, testdir): mod = testdir.makepyfile(test_mod=""" import py def test_pass(): pass diff --git a/py/test/plugin/pytest_unittest.py b/py/test/plugin/pytest_unittest.py index ff2c54d3e..03e38628f 100644 --- a/py/test/plugin/pytest_unittest.py +++ b/py/test/plugin/pytest_unittest.py @@ -10,8 +10,6 @@ this code is somewhat derived from Guido Wesdorps http://johnnydebris.net/svn/projects/py_unittest -$HeadURL: https://codespeak.net/svn/py/branch/pytestplugin/contrib/py_unittest/conftest.py $ -$Id: conftest.py 60979 2009-01-14 22:29:32Z hpk $ """ import py diff --git a/py/test/plugin/pytest_xfail.py b/py/test/plugin/pytest_xfail.py index 84cbb58ac..6024eb673 100644 --- a/py/test/plugin/pytest_xfail.py +++ b/py/test/plugin/pytest_xfail.py @@ -1,7 +1,8 @@ """ -mark and report specially about "expected to fail" tests. +mark tests as expected-to-fail and report them separately. + +example: -for marking and reporting "expected to fail" tests. @py.test.mark.xfail("needs refactoring") def test_hello(): ... @@ -29,7 +30,7 @@ def pytest_report_teststatus(rep): elif rep.failed: return "xpassed", "P", "xpass" -# a hook implemented called by the terminalreporter instance/plugin +# called by the terminalreporter instance/plugin def pytest_terminal_summary(terminalreporter): tr = terminalreporter xfailed = tr.stats.get("xfailed")