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

Jim Fulton jim@zope.com
Sun, 28 Apr 2002 13:16:50 -0400


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

Added Files:
      Tag: Zope-3x-branch
	__init__.py testChecker.py testRestrictedInterpreter.py 
	testSecurityManagement.py testSecurityManager.py test_Proxy.py 
Log Message:
HOTYB: Merged SecurityProxy-branch into main branch.  

All tests pass and folders can be listed and added through the web.
It is likely that most other things don't work and will need to be
fixed. The reason is that many accesses that should have been checked
before are now being checked and additional checks and thinking about
permissions and security settings are needed.

I'm in the process of drafting a paper for the wiki that describes the
changes in more detail.


=== Added File Zope3/lib/python/Zope/Security/tests/__init__.py ===
# these aren't the droids you're looking for


=== Added File Zope3/lib/python/Zope/Security/tests/testChecker.py ===
##############################################################################
#
# 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: testChecker.py,v 1.1.4.1 2002/04/28 17:16:49 jim Exp $
"""

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')










=== Added File Zope3/lib/python/Zope/Security/tests/testRestrictedInterpreter.py ===
import unittest

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 TestChecker:
    def check_getattr(self, object, name):
        pass
    def check(self, object, opname):
        pass
    def proxy(self, value):
        return ProxyFactory(value)

class RITests(unittest.TestCase):

    def setUp(self):
        self.checker = TestChecker()
        self.rinterp = RestrictedInterpreter(self.checker)

    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')


=== Added File Zope3/lib/python/Zope/Security/tests/testSecurityManagement.py ===
##############################################################################
#
# 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: testSecurityManagement.py,v 1.1.4.1 2002/04/28 17:16:49 jim Exp $
"""

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())


=== Added File Zope3/lib/python/Zope/Security/tests/testSecurityManager.py ===
##############################################################################
#
# 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())


=== Added File Zope3/lib/python/Zope/Security/tests/test_Proxy.py ===
import unittest
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"):
            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))

    def testRepr(self):
        self.assertEqual(repr(self.p), repr(self.x))

    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')