From 526e71e1040294df835eb61b805b2b7ec2a6384a Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Mon, 16 Jun 2008 11:52:37 +0000 Subject: [PATCH] Added test for firewall, fixed implementation so it actually works. --- scripts/supybot-test | 2 +- src/log.py | 35 +++++++++++------ test/test_firewall.py | 87 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 test/test_firewall.py diff --git a/scripts/supybot-test b/scripts/supybot-test index a8420c4f2..934dd0429 100644 --- a/scripts/supybot-test +++ b/scripts/supybot-test @@ -185,7 +185,7 @@ if __name__ == '__main__': pluginModule = plugin.loadPluginModule(pluginName) except (ImportError, callbacks.Error), e: sys.stderr.write('Failed to load plugin %s: %s\n' % (pluginName,e)) - sys.stderr.write('(pluginDirs: %s)' % + sys.stderr.write('(pluginDirs: %s)\n' % conf.supybot.directories.plugins()) continue if hasattr(pluginModule, 'test'): diff --git a/src/log.py b/src/log.py index 476f49421..82d5c9866 100644 --- a/src/log.py +++ b/src/log.py @@ -355,24 +355,35 @@ def firewall(f, errorHandler=None): logException(self) if errorHandler is not None: try: - errorHandler(self, *args, **kwargs) + return errorHandler(self, *args, **kwargs) except Exception, e: logException(self, 'Uncaught exception in errorHandler') - m = utils.python.changeFunctionName(m, f.func_name, f.__doc__) return m class MetaFirewall(type): - def __new__(cls, name, bases, dict): - if '__firewalled__' in dict: - for attr in dict['__firewalled__']: - try: - errorHandler = firewalled[attr] - except: # This is raw here so people can still use tuples. - errorHandler = None - dict[attr] = firewall(dict[attr], errorHandler) - return super(MetaFirewall, cls).__new__(cls, name, bases, dict) - #return type.__new__(cls, name, bases, dict) + def __new__(cls, name, bases, classdict): + firewalled = {} + for base in bases: + if hasattr(base, '__firewalled__'): + cls.updateFirewalled(firewalled, base.__firewalled__) + cls.updateFirewalled(firewalled, classdict.get('__firewalled__', [])) + for (attr, errorHandler) in firewalled.iteritems(): + if attr in classdict: + classdict[attr] = firewall(classdict[attr], errorHandler) + return super(MetaFirewall, cls).__new__(cls, name, bases, classdict) + + def getErrorHandler(cls, dictOrTuple, name): + if isinstance(dictOrTuple, dict): + return dictOrTuple[name] + else: + return None + getErrorHandler = classmethod(getErrorHandler) + + def updateFirewalled(cls, firewalled, __firewalled__): + for attr in __firewalled__: + firewalled[attr] = cls.getErrorHandler(__firewalled__, attr) + updateFirewalled = classmethod(updateFirewalled) class PluginLogFilter(logging.Filter): diff --git a/test/test_firewall.py b/test/test_firewall.py new file mode 100644 index 000000000..9429478f8 --- /dev/null +++ b/test/test_firewall.py @@ -0,0 +1,87 @@ +### +# Copyright (c) 2008, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from supybot.test import * +from supybot import log + +class FirewallTestCase(SupyTestCase): + def setUp(self): + log.testing = False + + def tearDown(self): + log.testing = True + + class C(object): + __metaclass__ = log.MetaFirewall + __firewalled__ = {'foo': None} + class MyException(Exception): + pass + def foo(self): + raise self.MyException() + + def testCFooDoesNotRaise(self): + c = self.C() + self.assertEqual(c.foo(), None) + + class D(C): + def foo(self): + raise self.MyException() + + def testDFooDoesNotRaise(self): + d = self.D() + self.assertEqual(d.foo(), None) + + class E(C): + __firewalled__ = {'bar': None} + def foo(self): + raise self.MyException() + def bar(self): + raise self.MyException() + + def testEFooDoesNotRaise(self): + e = self.E() + self.assertEqual(e.foo(), None) + + def testEBarDoesNotRaise(self): + e = self.E() + self.assertEqual(e.bar(), None) + + class F(C): + __firewalled__ = {'bar': lambda self: 2} + def bar(self): + raise self.MyException() + + def testFBarReturns2(self): + f = self.F() + self.assertEqual(f.bar(), 2) + + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: +