[svn r62211] merge 60797:HEAD of pytestplugin branch:

this merge contains:

* a new plugin architecture
* a pluginized pytest core
* many pytest related refactorings
* refactorings/streamlining of pytest's own tests

--HG--
branch : trunk
This commit is contained in:
hpk
2009-02-27 11:18:27 +01:00
parent 1c85d7fe9a
commit c17a09adaf
117 changed files with 6079 additions and 4370 deletions

View File

@@ -71,3 +71,11 @@ def strip_html_header(string, encoding='utf8'):
break
uni = match.group(1)
return uni
class Project: # used for confrest.py files
def __init__(self, sourcepath):
self.sourcepath = sourcepath
def process(self, path):
return process(path)
def get_htmloutputpath(self, path):
return path.new(ext='html')

View File

@@ -52,7 +52,7 @@ class TestBuildcostAccess(BasicCacheAPITest):
class TestAging(BasicCacheAPITest):
maxsecs = 0.02
maxsecs = 0.10
cache = AgingCache(maxentries=128, maxseconds=maxsecs)
def test_cache_eviction(self):

233
py/misc/testing/test_com.py Normal file
View File

@@ -0,0 +1,233 @@
import py
import os
from py._com import PyPlugins, MultiCall
pytest_plugins = "xfail"
class TestMultiCall:
def test_call_passing(self):
class P1:
def m(self, __call__, x):
assert __call__.currentmethod == self.m
assert len(__call__.results) == 1
assert not __call__.methods
return 17
class P2:
def m(self, __call__, x):
assert __call__.currentmethod == self.m
assert __call__.args
assert __call__.results == []
assert __call__.methods
return 23
p1 = P1()
p2 = P2()
multicall = MultiCall([p1.m, p2.m], 23)
reslist = multicall.execute()
assert len(reslist) == 2
# ensure reversed order
assert reslist == [23, 17]
def test_optionalcallarg(self):
class P1:
def m(self, x):
return x
call = MultiCall([P1().m], 23)
assert call.execute() == [23]
assert call.execute(firstresult=True) == 23
def test_call_subexecute(self):
def m(__call__):
subresult = __call__.execute(firstresult=True)
return subresult + 1
def n():
return 1
call = MultiCall([n, m])
res = call.execute(firstresult=True)
assert res == 2
class TestPyPlugins:
def test_MultiCall(self):
plugins = PyPlugins()
assert hasattr(plugins, "MultiCall")
def test_register(self):
plugins = PyPlugins()
class MyPlugin:
pass
my = MyPlugin()
plugins.register(my)
assert plugins.getplugins() == [my]
my2 = MyPlugin()
plugins.register(my2)
assert plugins.getplugins() == [my, my2]
assert plugins.isregistered(my)
assert plugins.isregistered(my2)
plugins.unregister(my)
assert not plugins.isregistered(my)
assert plugins.getplugins() == [my2]
#@py.test.keywords(xfail=True)
def test_onregister(self):
py.test.skip("implement exitfirst plugin and "
"modify xfail plugin to override exitfirst behaviour?")
plugins = PyPlugins()
l = []
class MyApi:
def pyevent_plugin_registered(self, plugin):
l.append(plugin)
def pyevent_plugin_unregistered(self, plugin):
l.remove(plugin)
myapi = MyApi()
plugins.register(myapi)
assert len(l) == 1
assert l[0] is myapi
plugins.unregister(myapi)
assert not l
def test_call_methods(self):
plugins = PyPlugins()
class api1:
def m(self, __call__, x):
return x
class api2:
def m(self, __call__, x, y=33):
return y
plugins.register(api1())
plugins.register(api2())
res = plugins.call_firstresult("m", x=5)
assert plugins.call_firstresult("notexist") is None
assert res == 33
reslist = plugins.call_each("m", x=5)
assert len(reslist) == 2
assert 5 in reslist
assert 33 in reslist
assert plugins.call_each("notexist") == []
assert plugins.call_plugin(api1(), 'm', x=12) == 12
assert plugins.call_plugin(api2(), 't') is None
def test_call_none_is_no_result(self):
plugins = PyPlugins()
class api1:
def m(self):
return None
class api2:
def m(self, __call__):
return 41
plugins.register(api1())
plugins.register(api1())
plugins.register(api2())
assert plugins.call_firstresult('m') == 41
assert plugins.call_each('m') == [41]
def test_call_noneasresult(self):
plugins = PyPlugins()
class api1:
def m(self, __call__):
return __call__.NONEASRESULT
plugins.register(api1())
plugins.register(api1())
assert plugins.call_firstresult('m') is None
assert plugins.call_each('m') == [None, None]
def test_listattr(self):
plugins = PyPlugins()
class api1:
x = 42
class api2:
x = 41
plugins.register(api1())
plugins.register(api2())
l = list(plugins.listattr('x'))
l.sort()
assert l == [41, 42]
def test_notify_anonymous_ordered(self):
plugins = PyPlugins()
l = []
class api1:
def pyevent_hello(self):
l.append("hellospecific")
class api2:
def pyevent(self, name, *args):
if name == "hello":
l.append(name + "anonymous")
plugins.register(api1())
plugins.register(api2())
plugins.notify('hello')
assert l == ["hellospecific", "helloanonymous"]
def test_consider_env(self, monkeypatch):
# XXX write a helper for preserving os.environ
plugins = PyPlugins()
monkeypatch.setitem(os.environ, 'PYLIB', "unknownconsider_env")
py.test.raises(ImportError, "plugins.consider_env()")
def test_consider_module(self):
plugins = PyPlugins()
mod = py.std.new.module("temp")
mod.pylib = ["xxx nomod"]
excinfo = py.test.raises(ImportError, "plugins.consider_module(mod)")
mod.pylib = "os"
class Events(list):
def pyevent_importingmodule(self, mod):
self.append(mod)
l = Events()
plugins.register(l)
plugins.consider_module(mod)
assert len(l) == 1
assert l[0] == (mod.pylib)
def test_api_and_defaults():
assert isinstance(py._com.pyplugins, PyPlugins)
def test_subprocess_env():
# XXX write a helper for preserving os.environ
plugins = PyPlugins()
KEY = "PYLIB"
old = os.environ.get(KEY, None)
olddir = py.path.local(py.__file__).dirpath().dirpath().chdir()
try:
os.environ[KEY] = "unknownconsider_env"
excinfo = py.test.raises(py.process.cmdexec.Error, """
py.process.cmdexec("python -c 'import py'")
""")
assert str(excinfo.value).find("ImportError") != -1
assert str(excinfo.value).find("unknownconsider") != -1
finally:
olddir.chdir()
if old is None:
del os.environ[KEY]
else:
os.environ[KEY] = old
class TestPyPluginsEvents:
def test_pyevent_named_dispatch(self):
plugins = PyPlugins()
l = []
class A:
def pyevent_name(self, x):
l.append(x)
plugins.register(A())
plugins.notify("name", 13)
assert l == [13]
def test_pyevent_anonymous_dispatch(self):
plugins = PyPlugins()
l = []
class A:
def pyevent(self, name, *args, **kwargs):
if name == "name":
l.extend([args, kwargs])
plugins.register(A())
plugins.notify("name", 13, x=15)
assert l == [(13, ), {'x':15}]

View File

@@ -12,20 +12,20 @@ def checksubpackage(name):
assert getattr(obj, '__map__') == {}
def test_dir():
from py.__.initpkg import Module
from py.__.initpkg import ApiModule
for name in dir(py):
if name == 'magic': # greenlets don't work everywhere, we don't care here
continue
if not name.startswith('_'):
yield checksubpackage, name
from py.initpkg import Module
from py.initpkg import ApiModule
glob = []
class MyModule(Module):
class MyModule(ApiModule):
def __init__(self, *args):
glob.append(self.__dict__)
assert isinstance(glob[-1], (dict, type(None)))
Module.__init__(self, *args)
ApiModule.__init__(self, *args)
def test_early__dict__access():
mymod = MyModule("whatever", "myname")
@@ -68,7 +68,10 @@ def test_importall():
base.join('execnet', 'script'),
base.join('compat', 'testing'),
)
for p in base.visit('*.py', lambda x: x.check(dotfile=0)):
def recurse(p):
return p.check(dotfile=0) and p.basename != "attic"
for p in base.visit('*.py', recurse):
if p.basename == '__init__.py':
continue
relpath = p.new(ext='').relto(base)
@@ -255,3 +258,8 @@ class TestRealModule:
# help(std.path)
# #assert False
def test_autoimport():
from py.initpkg import autoimport
py.std.os.environ['AUTOTEST_AUTOIMPORT'] = "nonexistmodule"
py.test.raises(ImportError, "autoimport('autotest')")

View File

@@ -1,20 +1,20 @@
import py
from py.__.misc.warn import WarningBus
from py.__.misc.warn import WarningPlugin
mypath = py.magic.autopath()
class TestWarningBus:
class TestWarningPlugin:
def setup_method(self, method):
self.wb = WarningBus()
self.bus = py._com.PyPlugins()
self.wb = WarningPlugin(self.bus)
self.bus.register(self)
self.warnings = []
self.wb.subscribe(self.warnings.append)
def test_basic(self):
def pyevent_WARNING(self, warning):
self.warnings.append(warning)
def test_event_generation(self):
self.wb.warn("hello")
assert len(self.warnings) == 1
self.wb.unsubscribe(self.warnings.append)
self.wb.warn("this")
assert len(self.warnings) == 1
w = self.warnings[0]
def test_location(self):
self.wb.warn("again")
@@ -27,19 +27,16 @@ class TestWarningBus:
assert str(warning) == warning.msg
def test_stacklevel(self):
l = []
self.wb.subscribe(l.append)
def f():
self.wb.warn("x", stacklevel=2)
# 5
# 6
# 3
# 4
f()
lno = self.test_stacklevel.im_func.func_code.co_firstlineno + 7
warning = l[0]
lno = self.test_stacklevel.im_func.func_code.co_firstlineno + 5
warning = self.warnings[0]
assert warning.lineno == lno
def test_forwarding_to_warnings_module(self):
self.wb._setforwarding()
py.test.deprecated_call(self.wb.warn, "x")
def test_apiwarn(self):
@@ -47,7 +44,6 @@ class TestWarningBus:
warning = self.warnings[0]
assert warning.msg == "xxx (since version 3.0)"
def test_APIWARN():
def test_default():
from py.__.misc.warn import APIWARN
wb = APIWARN.im_self
assert wb._forward in wb._eventbus._subscribers
assert py._com.pyplugins.isregistered(APIWARN.im_self)

View File

@@ -1,5 +1,4 @@
import py, sys
from py.__.test.event import EventBus
class Warning(py.std.exceptions.DeprecationWarning):
def __init__(self, msg, path, lineno):
@@ -11,19 +10,16 @@ class Warning(py.std.exceptions.DeprecationWarning):
def __str__(self):
return self.msg
class WarningBus(object):
def __init__(self):
self._eventbus = EventBus()
# XXX probably only apiwarn() + py._com.pyplugins forwarding
# warn_explicit is actually needed
def subscribe(self, callable):
self._eventbus.subscribe(callable)
def unsubscribe(self, callable):
self._eventbus.unsubscribe(callable)
def _setforwarding(self):
self._eventbus.subscribe(self._forward)
def _forward(self, warning):
class WarningPlugin(object):
def __init__(self, bus):
self.bus = bus
bus.register(self)
def pyevent_WARNING(self, warning):
# forward to python warning system
py.std.warnings.warn_explicit(warning, category=Warning,
filename=str(warning.path),
lineno=warning.lineno,
@@ -66,9 +62,8 @@ class WarningBus(object):
filename = module
path = py.path.local(filename)
warning = Warning(msg, path, lineno)
self._eventbus.notify(warning)
self.bus.notify("WARNING", warning)
# singleton api warner for py lib
apiwarner = WarningBus()
apiwarner._setforwarding()
apiwarner = WarningPlugin(py._com.pyplugins)
APIWARN = apiwarner.apiwarn