[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security/tests - __init__.py:1.2 testChecker.py:1.2 testRestrictedBuiltins.py:1.2 testRestrictedInterpreter.py:1.2 testSecurityManagement.py:1.2 testSecurityManager.py:1.2 test_Proxy.py:1.2

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:30:06 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Security/tests
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/Security/tests

Added Files:
	__init__.py testChecker.py testRestrictedBuiltins.py 
	testRestrictedInterpreter.py testSecurityManagement.py 
	testSecurityManager.py test_Proxy.py 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.

=== Zope3/lib/python/Zope/Security/tests/__init__.py 1.1 => 1.2 ===


=== Zope3/lib/python/Zope/Security/tests/testChecker.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from unittest import TestCase, TestSuite, main, makeSuite
+from Zope.Security.Checker import NamesChecker, CheckerPublic
+from Zope.Testing.CleanUp import cleanUp
+from Zope.Security.ISecurityPolicy import ISecurityPolicy
+from Zope.Exceptions import Forbidden, Unauthorized
+from Zope.Security.SecurityManagement import setSecurityPolicy
+from Zope.Security.Proxy import getChecker, getObject
+from Zope.Security.Checker import defineChecker
+
+class SecurityPolicy:
+
+    __implements__ =  ISecurityPolicy
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Security.ISecurityPolicy.
+
+    def checkPermission(self, permission, object, context):
+        'See Zope.Security.ISecurityPolicy.ISecurityPolicy'
+
+        return permission == 'test_allowed'
+
+    #
+    ############################################################
+
+
+class OldInst:
+    a=1
+    
+    def b(self):
+        pass
+    
+    c=2
+
+    def gete(self): return 3
+    e = property(gete)
+
+    def __getitem__(self, x): return 5, x
+
+    def __setitem__(self, x, v): pass
+
+class NewInst(object, OldInst):
+
+    def gete(self): return 3
+    def sete(self, v): pass
+    e = property(gete, sete)
+
+class Test(TestCase):
+
+    def setUp(self):
+        self.__oldpolicy = setSecurityPolicy(SecurityPolicy())
+
+    def tearDown(self):
+        setSecurityPolicy(self.__oldpolicy)
+        cleanUp()
+
+
+    # check_getattr cases:
+    #
+    # - no attribute there
+    # - method
+    # - allow and disallow by permission
+    def test_check_getattr(self):        
+
+        oldinst = OldInst()
+        oldinst.d = OldInst()
+
+        newinst = NewInst()
+        newinst.d = NewInst()
+
+        for inst in oldinst, newinst:
+            checker = NamesChecker(['a', 'b', 'c', '__getitem__'],
+                                   'perm')
+
+            self.assertRaises(Unauthorized, checker.check_getattr, inst, 'a')
+            self.assertRaises(Unauthorized, checker.check_getattr, inst, 'b')
+            self.assertRaises(Unauthorized, checker.check_getattr, inst, 'c')
+            self.assertRaises(Unauthorized, checker.check, inst, '__getitem__')
+            self.assertRaises(Forbidden, checker.check, inst, '__setitem__')
+            self.assertRaises(Forbidden, checker.check_getattr, inst, 'd')
+            self.assertRaises(Forbidden, checker.check_getattr, inst, 'e')
+            self.assertRaises(Forbidden, checker.check_getattr, inst, 'f')
+
+            checker = NamesChecker(['a', 'b', 'c', '__getitem__'],
+                                   'test_allowed')
+
+            checker.check_getattr(inst, 'a')
+            checker.check_getattr(inst, 'b')
+            checker.check_getattr(inst, 'c')
+            checker.check(inst, '__getitem__')
+            self.assertRaises(Forbidden, checker.check, inst, '__setitem__')
+            self.assertRaises(Forbidden, checker.check_getattr, inst, 'd')
+            self.assertRaises(Forbidden, checker.check_getattr, inst, 'e')
+            self.assertRaises(Forbidden, checker.check_getattr, inst, 'f')
+
+    def test_proxy(self):
+        checker = NamesChecker(())
+
+
+        for rock in (1, 1.0, 1l, 1j,
+                     '1', u'1', None,
+                     AttributeError, AttributeError(),
+                     ):
+            proxy = checker.proxy(rock)
+            
+            self.failUnless(proxy is rock, (rock, type(proxy)))
+
+        for class_ in OldInst, NewInst:
+            inst = class_()
+
+            for ob in inst, class_:
+                proxy = checker.proxy(ob)
+                self.failUnless(getObject(proxy) is ob)
+                checker = getChecker(proxy)
+                if ob is inst:
+                    self.assertEqual(checker.permission_id('__str__'),
+                                     None)
+                else:
+                    self.assertEqual(checker.permission_id('__str__'),
+                                     CheckerPublic)
+        
+            special = NamesChecker(['a', 'b'], 'test_allowed')
+            defineChecker(class_, special)
+
+            proxy = checker.proxy(inst)
+            self.failUnless(getObject(proxy) is inst)
+
+                
+            checker = getChecker(proxy)
+            self.failUnless(checker is special, checker.__dict__)
+
+            proxy2 = checker.proxy(proxy)
+            self.failUnless(proxy2 is proxy, [proxy, proxy2])
+
+    def testMultiChecker(self):
+        from Interface import Interface
+
+        class I1(Interface):
+            def f1(): ''
+            def f2(): ''
+
+        class I2(I1):
+            def f3(): ''
+            def f4(): ''
+
+        class I3(Interface):
+            def g(): ''
+
+        from Zope.Exceptions import DuplicationError
+
+        from Zope.Security.Checker import MultiChecker
+
+        self.assertRaises(DuplicationError,
+                          MultiChecker,
+                          [(I1, 'p1'), (I2, 'p2')])
+
+        self.assertRaises(DuplicationError,
+                          MultiChecker,
+                          [(I1, 'p1'), {'f2': 'p2'}])
+
+        MultiChecker([(I1, 'p1'), (I2, 'p1')])
+
+        checker = MultiChecker([
+            (I2, 'p1'),
+            {'a': 'p3'},
+            (I3, 'p2'),
+            (('x','y','z'), 'p4'),
+            ])
+
+        self.assertEqual(checker.permission_id('f1'), 'p1')
+        self.assertEqual(checker.permission_id('f2'), 'p1')
+        self.assertEqual(checker.permission_id('f3'), 'p1')
+        self.assertEqual(checker.permission_id('f4'), 'p1')
+        self.assertEqual(checker.permission_id('g'), 'p2')
+        self.assertEqual(checker.permission_id('a'), 'p3')
+        self.assertEqual(checker.permission_id('x'), 'p4')
+        self.assertEqual(checker.permission_id('y'), 'p4')
+        self.assertEqual(checker.permission_id('z'), 'p4')
+        self.assertEqual(checker.permission_id('zzz'), None)
+            
+    def testNonPrivateChecker(self):
+        from Zope.Security.Checker import NonPrivateChecker
+        checker = NonPrivateChecker('p')
+        self.assertEqual(checker.permission_id('z'), 'p')
+        self.assertEqual(checker.permission_id('_z'), None)
+            
+    def testAlwaysAvailable(self):
+        from Zope.Security.Checker import NamesChecker
+        checker = NamesChecker(())
+        class C: pass
+        self.assertEqual(checker.check(C, '__hash__'), None)
+        self.assertEqual(checker.check(C, '__nonzero__'), None)
+        self.assertEqual(checker.check(C, '__class__'), None)
+        self.assertEqual(checker.check(C, '__implements__'), None)
+        self.assertEqual(checker.check(C, '__lt__'), None)
+        self.assertEqual(checker.check(C, '__le__'), None)
+        self.assertEqual(checker.check(C, '__gt__'), None)
+        self.assertEqual(checker.check(C, '__ge__'), None)
+        self.assertEqual(checker.check(C, '__eq__'), None)
+        self.assertEqual(checker.check(C, '__ne__'), None)
+
+    def test_setattr(self):
+        checker = NamesChecker(['a', 'b', 'c', '__getitem__'],
+                               'test_allowed')
+
+        for inst in NewInst(), OldInst():
+            self.assertRaises(Forbidden, checker.check_setattr, inst, 'a')
+            self.assertRaises(Forbidden, checker.check_setattr, inst, 'z')
+
+
+
+def test_suite():
+    return TestSuite((
+        makeSuite(Test),
+        ))
+
+if __name__=='__main__':
+    main(defaultTest='test_suite')
+
+
+
+
+
+
+
+


=== Zope3/lib/python/Zope/Security/tests/testRestrictedBuiltins.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from unittest import TestCase, TestSuite, main, makeSuite
+from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup
+
+class Test(CleanUp, TestCase):
+
+    def test(self):
+        from Zope.Security.RestrictedBuiltins import RestrictedBuiltins
+        from Zope.Security.Proxy import Proxy
+        from Zope.Exceptions import Forbidden
+
+        def e(expr):
+            return eval(expr, {'__builtins__': RestrictedBuiltins})
+
+        self.assertEqual(e('__import__("sys").__name__'), "sys")
+        self.assertEqual(e('__import__("Zope.Security").__name__'), "Zope")
+        self.assertEqual(e(
+            '__import__("Zope.Security",{},None,("__doc__",)).__name__'),
+                         "Zope.Security")
+        self.assertRaises(Forbidden, e, '__import__("sys").exit')
+        
+    
+
+def test_suite():
+    return TestSuite((
+        makeSuite(Test),
+        ))
+
+if __name__=='__main__':
+    main(defaultTest='test_suite')


=== Zope3/lib/python/Zope/Security/tests/testRestrictedInterpreter.py 1.1 => 1.2 ===
+
+from Zope.Security.RestrictedInterpreter import RestrictedInterpreter
+from Zope.Security.Proxy import ProxyFactory
+from Zope.Security.Checker import defineChecker
+
+from Zope.Testing.CleanUp import cleanUp
+
+class RITests(unittest.TestCase):
+
+    def setUp(self):
+        self.rinterp = RestrictedInterpreter()
+
+    def tearDown(self):
+        cleanUp()
+
+    def testExec(self):
+        self.rinterp.ri_exec("str(type(1))\n")
+
+    def testImport(self):
+        self.rinterp.ri_exec("import Zope.Security.Proxy")
+
+    def testWrapping(self):
+        # make sure we've really got proxies
+        import types
+        from Zope.Security.Checker import NamesChecker
+
+        checker = NamesChecker(['Proxy'])
+
+        import Zope.Security.Proxy
+        defineChecker(Zope.Security.Proxy, checker)
+
+        checker = NamesChecker(['BuiltinFunctionType'])
+        defineChecker(types, checker)
+
+        code = ("from Zope.Security.Proxy import Proxy\n"
+                "import types\n"
+                "assert type(id) is not types.BuiltinFunctionType\n"
+                )
+        self.rinterp.ri_exec(code)
+
+def test_suite():
+    return unittest.makeSuite(RITests)
+
+
+if __name__=='__main__':
+    from unittest import main
+    main(defaultTest='test_suite')


=== Zope3/lib/python/Zope/Security/tests/testSecurityManagement.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+""" Unit tests for SecurityManagement
+
+$Id$
+"""
+
+import unittest
+
+from Interface.Verify import verifyObject
+from Zope.Testing.CleanUp import CleanUp
+
+import Zope.Security.SecurityManagement
+from Zope.Security.SecurityManagement import \
+     noSecurityManager, setSecurityPolicy, newSecurityManager
+
+
+class Test(CleanUp, unittest.TestCase):
+
+    def test_import( self ):
+        from Zope.Security import SecurityManagement
+        from Zope.Security.ISecurityManagement import ISecurityManagement
+        from Zope.Security.ISecurityManagement \
+            import ISecurityManagementSetup
+
+        verifyObject( ISecurityManagementSetup, SecurityManagement )
+        verifyObject( ISecurityManagement, SecurityManagement )
+
+    def test_ISecurityManagementSetup( self ):
+
+        from Zope.Security.SecurityManagement import noSecurityManager
+        from Zope.Security.SecurityManagement import newSecurityManager
+        from Zope.Security.SecurityManagement import replaceSecurityManager
+
+        some_user = []
+        other_user = []
+        old = newSecurityManager( some_user )
+        self.assertEqual( old, None )
+
+        old = newSecurityManager( other_user )
+        self.failUnless( old is not None )
+        self.failUnless( old.getPrincipal() is some_user )
+
+        old2 = replaceSecurityManager( old )
+        self.failUnless( old2 is not None )
+        self.failUnless( old2.getPrincipal() is other_user )
+
+        noSecurityManager()
+
+    def test_getSecurityManager( self ):
+        # This is a test for the case when there is no principal
+
+        from Zope.Security.SecurityManagement import noSecurityManager
+        from Zope.Security.SecurityManagement import replaceSecurityManager
+        from Zope.Security.SecurityManagement import getSecurityManager
+
+        noSecurityManager()
+        self.failUnless( replaceSecurityManager( None ) is None )
+
+        mgr = getSecurityManager()
+        self.assertEqual( mgr.getPrincipal(), None)
+        # XXX maybe add test for default principal case
+        self.failIf( mgr.calledByExecutable() )
+        self.assertEqual( replaceSecurityManager( None ), mgr )
+
+        noSecurityManager()
+
+    def _setPermissive( self ):
+        from Zope.Security.SecurityManagement import setSecurityPolicy
+        from Zope.Security.SimpleSecurityPolicies \
+                                import PermissiveSecurityPolicy
+        setSecurityPolicy( PermissiveSecurityPolicy() )
+
+    def _setParanoid( self ):
+        from Zope.Security.SecurityManagement import setSecurityPolicy
+        from Zope.Security.SimpleSecurityPolicies \
+                                import ParanoidSecurityPolicy
+        setSecurityPolicy( ParanoidSecurityPolicy() )
+
+    def test_setSecurityPolicy( self ):
+
+        from Zope.Security.SecurityManagement import noSecurityManager
+        from Zope.Security.SecurityManagement import getSecurityManager
+        from Zope.Exceptions import Unauthorized
+
+        # test against default policy (paranoid)
+        self._setParanoid()
+        newSecurityManager('some user')
+        mgr = getSecurityManager()
+        self.failIf( mgr.checkPermission( None, None ) )
+
+        # test against explicit permissive policy
+        self._setPermissive()
+        newSecurityManager('some user')
+        mgr = getSecurityManager()
+        self.failUnless( mgr.checkPermission( None, None ) )
+
+        # test against explicit paranoid policy
+        self._setParanoid()
+        newSecurityManager('some user')
+        mgr = getSecurityManager()
+        self.failIf( mgr.checkPermission( None, None ) )
+        
+
+def test_suite():
+    loader=unittest.TestLoader()
+    return loader.loadTestsFromTestCase(Test)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/lib/python/Zope/Security/tests/testSecurityManager.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+""" Unit tests for SecurityManager """
+
+import unittest
+
+from Interface.Verify import verifyClass
+
+from Zope.Security import SecurityManager
+from Zope.Security.SimpleSecurityPolicies import \
+     ParanoidSecurityPolicy, PermissiveSecurityPolicy
+from Zope.Security.SecurityContext import SecurityContext
+from Zope.Exceptions import Unauthorized
+
+class DummyExecutable:
+
+    """__implements__ = (pseudo) IExecutableObject"""
+
+class DummyExecutableWithCustomPolicy:
+
+    """__implements__ = (pseudo) IExecutableObjectWithCustomSecurityPolicy"""
+
+    def _customSecurityPolicy( self ):
+        return PermissiveSecurityPolicy()
+
+class Test( unittest.TestCase ):
+
+    def setUp( self ):
+
+        self._oldPolicy = SecurityManager._defaultPolicy
+        SecurityManager.setSecurityPolicy( ParanoidSecurityPolicy() )
+        self._context = SecurityContext( 'xyzzy' )
+
+    def tearDown( self ):
+
+        from Zope.Security.SecurityManager import setSecurityPolicy
+        setSecurityPolicy( self._oldPolicy )
+
+    def _makeMgr( self ):
+        
+        from Zope.Security.SecurityManager import SecurityManager
+
+        return SecurityManager( self._context )
+
+    def _setPermissive( self ):
+
+        from Zope.Security.SecurityManager import setSecurityPolicy
+        setSecurityPolicy( PermissiveSecurityPolicy() )
+            
+    def test_import( self ):
+
+        from Zope.Security.SecurityManager import SecurityManager
+        from Zope.Security.ISecurityManager import ISecurityManager
+
+        verifyClass( ISecurityManager, SecurityManager )
+
+    def test_empty( self ):
+ 
+        mgr = self._makeMgr()
+
+        self.assertEqual( mgr.getPrincipal(), self._context.user )
+        self.failIf( mgr.calledByExecutable() )
+
+    def test_w_default_policy( self ):
+ 
+        mgr = self._makeMgr()
+
+        self.failIf( mgr.checkPermission( None, None ) )
+
+    def test_w_permissive_policy( self ):
+ 
+        mgr = self._makeMgr()
+        self._setPermissive()
+
+        self.failUnless( mgr.checkPermission( None, None ) )
+
+    def test_exec_stack_overflow( self ):
+ 
+        from Zope.Security.SecurityManager import MAX_STACK_SIZE
+        mgr = self._makeMgr()
+
+        for i in range( MAX_STACK_SIZE ):
+            mgr.pushExecutable( None )
+
+        self.assertRaises( SystemError, mgr.pushExecutable, None )
+
+    def test_pushExecutable_simple( self ):
+
+        mgr = self._makeMgr()
+        self.failIf( mgr.calledByExecutable() )
+
+        mgr.pushExecutable( DummyExecutable() )
+        self.failUnless( mgr.calledByExecutable() )
+
+    def test_popExecutable_simple( self ):
+
+        mgr = self._makeMgr()
+        exe = DummyExecutable()
+        exe2 = DummyExecutable()
+
+        mgr.pushExecutable( exe )
+        mgr.pushExecutable( exe2 )
+        mgr.popExecutable( exe2 )
+        self.failUnless( mgr.calledByExecutable() )
+
+        mgr.popExecutable( exe )
+        self.failIf( mgr.calledByExecutable() )
+
+    def test_popExecutable_nomatch( self ):
+
+        mgr = self._makeMgr()
+        exe = DummyExecutable()
+        exe2 = DummyExecutable()
+        other = DummyExecutable()
+
+        mgr.pushExecutable( exe )
+        mgr.pushExecutable( exe2 )
+        mgr.popExecutable( other ) # not on stack => no change
+        self.failUnless( mgr.calledByExecutable() )
+
+        mgr.popExecutable( exe ) # bottom of stack => empty it
+        self.failIf( mgr.calledByExecutable() )
+
+    def test_pushExecutable_customPolicy( self ):
+
+        mgr = self._makeMgr()
+        exe = DummyExecutableWithCustomPolicy()
+        self.failIf( mgr.checkPermission( None, None ) )
+        mgr.pushExecutable( exe )
+        self.failUnless( mgr.checkPermission( None, None ) )
+        mgr.popExecutable( exe )
+        self.failIf( mgr.checkPermission( None, None ) )
+
+    def test_pushPop_complexPolicies( self ):
+
+        mgr = self._makeMgr()
+
+        exe1 = DummyExecutableWithCustomPolicy()
+        exe2 = DummyExecutable()
+        exe3 = DummyExecutableWithCustomPolicy()
+
+        mgr.pushExecutable( exe1 ) # now has custom permissive policy
+        self.failUnless( mgr.checkPermission( None, None ) )
+
+        mgr.pushExecutable( exe2 ) # now has default policy
+        self.failIf( mgr.checkPermission( None, None ) )
+
+        mgr.pushExecutable( exe3 ) # now has custom permissive policy
+        self.failUnless( mgr.checkPermission( None, None ) )
+
+        mgr.popExecutable( exe3 ) # back to default policy
+        self.failIf( mgr.checkPermission( None, None ) )
+
+        mgr.popExecutable( exe2 ) # back to has custom permissive policy
+        self.failUnless( mgr.checkPermission( None, None ) )
+
+        mgr.popExecutable( exe1 ) # back to default policy
+        self.failIf( mgr.checkPermission( None, None ) )
+
+
+def test_suite():
+    loader=unittest.TestLoader()
+    return loader.loadTestsFromTestCase(Test)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/lib/python/Zope/Security/tests/test_Proxy.py 1.1 => 1.2 ===
+from Zope.Exceptions import Forbidden
+from Zope.Security.Proxy import getObject, getChecker, ProxyFactory
+
+class Checker:
+
+    ok = 1
+
+    def check_getattr(self, object, name):
+        if name not in ("foo", "next", "__class__", "__name__", "__module__"):
+            raise RuntimeError
+
+    def check_setattr(self, object, name):
+        if name != "foo":
+            raise RuntimeError
+
+    def check(self, object, opname):
+        if not self.ok:
+            raise RuntimeError
+
+    def proxy(self, value):
+        if type(value) is str:
+            return value
+        return ProxyFactory(value, self)
+
+
+class Something:
+    def __init__(self):
+        self.foo = [1,2,3]
+    def __getitem__(self, key):
+        return self.foo[key]
+    def __setitem__(self, key, value):
+        self.foo[key] = value
+    def __call__(self, arg):
+        return 42
+    def __eq__(self, other):
+        return self is other
+    def __hash__(self):
+        return 42
+    def __iter__(self):
+        return self
+    def next(self):
+        return 42 # Infinite sequence
+    def __len__(self):
+        return 42
+    def __nonzero__(self):
+        return 1
+    def __getslice__(self, i, j):
+        return [42]
+    def __setslice__(self, i, j, value):
+        if value != [42]:
+            raise ValueError
+    def __contains__(self, x):
+        return x == 42
+
+
+class ProxyTests(unittest.TestCase):
+
+    def setUp(self):
+        self.x = Something()
+        self.c = Checker()
+        self.p = ProxyFactory(self.x, self.c)
+
+    def shouldFail(self, *args):
+        self.c.ok = 0
+        self.assertRaises(RuntimeError, *args)
+        self.c.ok = 1
+
+    def testStr(self):
+        self.assertEqual(str(self.p), str(self.x))
+
+        x = Something()
+        c = Checker()
+        c.ok = 0
+        p = ProxyFactory(x, c)
+        s = str(p)
+        self.failUnless(s.startswith(
+            "<security proxied %s.%s instance at"
+            % (x.__class__.__module__, x.__class__.__name__)),
+                        s)
+        
+
+    def testRepr(self):
+        self.assertEqual(repr(self.p), repr(self.x))
+
+        x = Something()
+        c = Checker()
+        c.ok = 0
+        p = ProxyFactory(x, c)
+        s = repr(p)
+        self.failUnless(s.startswith(
+            "<security proxied %s.%s instance at"
+            % (x.__class__.__module__, x.__class__.__name__)),
+                        s)
+
+    def testGetAttrOK(self):
+        self.assertEqual(getObject(self.p.foo), [1,2,3])
+
+    def testGetAttrFail(self):
+        self.assertRaises(RuntimeError, lambda: self.p.bar)
+
+    def testSetAttrOK(self):
+        self.p.foo = 42
+        self.assertEqual(self.p.foo, 42)
+
+    def testSetAttrFail(self):
+        def doit(): self.p.bar = 42
+        self.assertRaises(RuntimeError, doit)
+
+    def testGetItemOK(self):
+        self.assertEqual(self.p[0], 1)
+
+    def testGetItemFail(self):
+        self.shouldFail(lambda: self.p[10])
+
+    def testSetItemOK(self):
+        self.p[0] = 42
+        self.assertEqual(self.p[0], 42)
+
+    def testSetItemFail(self):
+        def doit(): self.p[10] = 42
+        self.shouldFail(doit)
+
+    def testCallOK(self):
+        self.assertEqual(self.p(None), 42)
+
+    def testCallFail(self):
+        self.shouldFail(self.p, None)
+
+    def testRichCompareOK(self):
+        self.failUnless(self.p == self.x)
+
+    def testRichCompareFail(self):
+        self.shouldFail(lambda: self.p == self.x)
+
+    def testIterOK(self):
+        self.assertEqual(getObject(iter(self.p)), self.x)
+
+    def testIterFail(self):
+        self.shouldFail(iter, self.p)
+
+    def testNextOK(self):
+        self.assertEqual(self.p.next(), 42)
+
+    def testNextFail(self):
+        self.shouldFail(self.p.next)
+
+    def testCompareOK(self):
+        self.assertEqual(cmp(self.p, self.x), 0)
+
+    def testCompareFail(self):
+        self.shouldFail(cmp, self.p, self.x)
+
+    def testHashOK(self):
+        self.assertEqual(hash(self.p), hash(self.x))
+
+    def testHashFail(self):
+        self.shouldFail(hash, self.p)
+
+    def testNonzeroOK(self):
+        self.assertEqual(not self.p, 0)
+
+    def testNonzeroFail(self):
+        self.shouldFail(lambda: not self.p)
+
+    def testLenOK(self):
+        self.assertEqual(len(self.p), 42)
+
+    def testLenFail(self):
+        self.shouldFail(len, self.p)
+
+    def testSliceOK(self):
+        self.assertEqual(getObject(self.p[:]), [42])
+
+    def testSliceFail(self):
+        self.shouldFail(lambda: self.p[:])
+
+    def testSetSliceOK(self):
+        self.p[:] = [42]
+
+    def testSetSliceFail(self):
+        def doit(): self.p[:] = [42]
+        self.shouldFail(doit)
+
+    def testContainsOK(self):
+        self.failUnless(42 in self.p)
+
+    def testContainsFail(self):
+        self.shouldFail(lambda: 42 in self.p)
+
+    def testGetObject(self):
+        self.assertEqual(self.x, getObject(self.p))
+
+    def testGetChecker(self):
+        self.assertEqual(self.c, getChecker(self.p))
+
+    def testProxiedClassicClassAsDictKey(self):
+        class C:
+            pass
+        d = {C: C()}
+        pC = ProxyFactory(C, self.c)
+        self.assertEqual(d[pC], d[C])
+
+    def testProxiedNewClassAsDictKey(self):
+        class C(object):
+            pass
+        d = {C: C()}
+        pC = ProxyFactory(C, self.c)
+        self.assertEqual(d[pC], d[C])
+
+    unops = [
+        "-x", "+x", "abs(x)", "~x",
+        "int(x)", "long(x)", "float(x)",
+        ]
+
+    def test_unops(self):
+        P = self.c.proxy
+        for expr in self.unops:
+            x = 1
+            y = eval(expr)
+            x = P(1)
+            z = eval(expr)
+            self.assertEqual(getObject(z), y, "x=%r; expr=%r" % (x, expr))
+            self.shouldFail(lambda x: eval(expr), x)
+
+    def test_odd_unops(self):
+        # unops that don't return a proxy
+        P = self.c.proxy
+        for func in hex, oct, lambda x: not x:
+            self.assertEqual(func(P(100)), func(100))
+            self.shouldFail(func, P(100))
+
+    binops = [
+        "x+y", "x-y", "x*y", "x/y", "divmod(x, y)", "x**y", "x//y",
+        "x<<y", "x>>y", "x&y", "x|y", "x^y",
+        ]
+
+    def test_binops(self):
+        P = self.c.proxy
+        for expr in self.binops:
+            first = 1
+            for x in [1, P(1)]:
+                for y in [2, P(2)]:
+                    if first:
+                        z = eval(expr)
+                        first = 0
+                    else:
+                        self.assertEqual(getObject(eval(expr)), z,
+                                         "x=%r; y=%r; expr=%r" % (x, y, expr))
+                        self.shouldFail(lambda x, y: eval(expr), x, y)
+
+    def test_inplace(self):
+        # XXX should test all inplace operators...
+        P = self.c.proxy
+
+        pa = P(1)
+        pa += 2
+        self.assertEqual(getObject(pa), 3)
+
+        a = [1, 2, 3]
+        pa = qa = P(a)
+        pa += [4, 5, 6]
+        self.failUnless(pa is qa)
+        self.assertEqual(a, [1, 2, 3, 4, 5, 6])
+
+        def doit():
+            pa = P(1)
+            pa += 2
+        self.shouldFail(doit)
+
+        pa = P(2)
+        pa **= 2
+        self.assertEqual(getObject(pa), 4)
+
+        def doit():
+            pa = P(2)
+            pa **= 2
+        self.shouldFail(doit)
+
+    def test_coerce(self):
+        P = self.c.proxy
+
+        # Before 2.3, coerce() of two proxies returns them unchanged
+        import sys
+        fixed_coerce = sys.version_info >= (2, 3, 0)
+
+        x = P(1)
+        y = P(2)
+        a, b = coerce(x, y)
+        self.failUnless(a is x and b is y)
+
+        x = P(1)
+        y = P(2.1)
+        a, b = coerce(x, y)
+        self.failUnless(getObject(a) == 1.0 and b is y)
+        if fixed_coerce:
+            self.failUnless(type(getObject(a)) is float and b is y)
+
+        x = P(1.1)
+        y = P(2)
+        a, b = coerce(x, y)
+        self.failUnless(a is x and getObject(b) == 2.0)
+        if fixed_coerce:
+            self.failUnless(a is x and type(getObject(b)) is float)
+
+        x = P(1)
+        y = 2
+        a, b = coerce(x, y)
+        self.failUnless(a is x and b is y)
+
+        x = P(1)
+        y = 2.1
+        a, b = coerce(x, y)
+        self.failUnless(type(getObject(a)) is float and b is y)
+
+        x = P(1.1)
+        y = 2
+        a, b = coerce(x, y)
+        self.failUnless(a is x and type(getObject(b)) is float)
+
+        x = 1
+        y = P(2)
+        a, b = coerce(x, y)
+        self.failUnless(a is x and b is y)
+
+        x = 1.1
+        y = P(2)
+        a, b = coerce(x, y)
+        self.failUnless(a is x and type(getObject(b)) is float)
+
+        x = 1
+        y = P(2.1)
+        a, b = coerce(x, y)
+        self.failUnless(type(getObject(a)) is float and b is y)
+
+def test_suite():
+    return unittest.makeSuite(ProxyTests)
+
+if __name__=='__main__':
+    from unittest import main
+    main(defaultTest='test_suite')