test_interface.py 9.97 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
##############################################################################
#
# 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.1 (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.
#
##############################################################################

import unittest
from zope.testing.doctestunit import DocTestSuite
from zope.interface.tests.unitfixtures import *  # hehehe
from zope.interface.exceptions import BrokenImplementation, Invalid
from zope.interface import implementedBy, providedBy
from zope.interface import Interface, directlyProvides, Attribute

class InterfaceTests(unittest.TestCase):

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testClassImplements(self):
        self.assert_(IC.implementedBy(C))

        self.assert_(I1.implementedBy(A))
        self.assert_(I1.implementedBy(B))
        self.assert_(not I1.implementedBy(C))
        self.assert_(I1.implementedBy(D))
        self.assert_(I1.implementedBy(E))

        self.assert_(not I2.implementedBy(A))
        self.assert_(I2.implementedBy(B))
        self.assert_(not I2.implementedBy(C))

        # No longer after interfacegeddon
        # self.assert_(not I2.implementedBy(D))

        self.assert_(not I2.implementedBy(E))

    def testUtil(self):
        self.assert_(IC in implementedBy(C))
        self.assert_(I1 in implementedBy(A))
        self.assert_(not I1 in implementedBy(C))
        self.assert_(I2 in implementedBy(B))
        self.assert_(not I2 in implementedBy(C))

        self.assert_(IC in providedBy(C()))
        self.assert_(I1 in providedBy(A()))
        self.assert_(not I1 in providedBy(C()))
        self.assert_(I2 in providedBy(B()))
        self.assert_(not I2 in providedBy(C()))


    def testObjectImplements(self):
        self.assert_(IC.providedBy(C()))

        self.assert_(I1.providedBy(A()))
        self.assert_(I1.providedBy(B()))
        self.assert_(not I1.providedBy(C()))
        self.assert_(I1.providedBy(D()))
        self.assert_(I1.providedBy(E()))

        self.assert_(not I2.providedBy(A()))
        self.assert_(I2.providedBy(B()))
        self.assert_(not I2.providedBy(C()))

        # Not after interface geddon
        # self.assert_(not I2.providedBy(D()))

        self.assert_(not I2.providedBy(E()))

    def testDeferredClass(self):
        a = A()
        self.assertRaises(BrokenImplementation, a.ma)


    def testInterfaceExtendsInterface(self):
        self.assert_(BazInterface.extends(BobInterface))
        self.assert_(BazInterface.extends(BarInterface))
        self.assert_(BazInterface.extends(FunInterface))
        self.assert_(not BobInterface.extends(FunInterface))
        self.assert_(not BobInterface.extends(BarInterface))
        self.assert_(BarInterface.extends(FunInterface))
        self.assert_(not BarInterface.extends(BazInterface))

    def testVerifyImplementation(self):
        from zope.interface.verify import verifyClass
        self.assert_(verifyClass(FooInterface, Foo))
        self.assert_(Interface.providedBy(I1))

    def test_names(self):
        names = list(_I2.names()); names.sort()
        self.assertEqual(names, ['f21', 'f22', 'f23'])
        names = list(_I2.names(all=True)); names.sort()
        self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])

    def test_namesAndDescriptions(self):
        names = [nd[0] for nd in _I2.namesAndDescriptions()]; names.sort()
        self.assertEqual(names, ['f21', 'f22', 'f23'])
        names = [nd[0] for nd in _I2.namesAndDescriptions(1)]; names.sort()
        self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])

        for name, d in _I2.namesAndDescriptions(1):
            self.assertEqual(name, d.__name__)

    def test_getDescriptionFor(self):
        self.assertEqual(_I2.getDescriptionFor('f11').__name__, 'f11')
        self.assertEqual(_I2.getDescriptionFor('f22').__name__, 'f22')
        self.assertEqual(_I2.queryDescriptionFor('f33', self), self)
        self.assertRaises(KeyError, _I2.getDescriptionFor, 'f33')

    def test___getitem__(self):
        self.assertEqual(_I2['f11'].__name__, 'f11')
        self.assertEqual(_I2['f22'].__name__, 'f22')
        self.assertEqual(_I2.get('f33', self), self)
        self.assertRaises(KeyError, _I2.__getitem__, 'f33')

    def test___contains__(self):
        self.failUnless('f11' in _I2)
        self.failIf('f33' in _I2)

    def test___iter__(self):
        names = list(iter(_I2))
        names.sort()
        self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])

    def testAttr(self):
        description = _I2.getDescriptionFor('a1')
        self.assertEqual(description.__name__, 'a1')
        self.assertEqual(description.__doc__, 'This is an attribute')

    def testFunctionAttributes(self):
        # Make sure function attributes become tagged values.
        meth = _I1['f12']
        self.assertEqual(meth.getTaggedValue('optional'), 1)
    
    def testInvariant(self):
        # set up
        o = InvariantC()
        directlyProvides(o, IInvariant)
        # a helper
        def errorsEqual(self, o, error_len, error_msgs, interface=None):
            if interface is None:
                interface = IInvariant
            self.assertRaises(Invalid, interface.validateInvariants, o)
            e = []
            try:
                interface.validateInvariants(o, e)
            except Invalid, error:
                self.assertEquals(error.args[0], e)
            else:
                self._assert(0) # validateInvariants should always raise 
                # Invalid
            self.assertEquals(len(e), error_len)
            msgs = [error.args[0] for error in e]
            msgs.sort()
            for msg in msgs:
                self.assertEquals(msg, error_msgs.pop(0))
        # the tests
        self.assertEquals(IInvariant.getTaggedValue('invariants'), 
                          [ifFooThenBar])
        self.assertEquals(IInvariant.validateInvariants(o), None)
        o.bar = 27
        self.assertEquals(IInvariant.validateInvariants(o), None)
        o.foo = 42
        self.assertEquals(IInvariant.validateInvariants(o), None)
        del o.bar
        errorsEqual(self, o, 1, ['If Foo, then Bar!'])
        # nested interfaces with invariants:
        self.assertEquals(ISubInvariant.getTaggedValue('invariants'), 
                          [BarGreaterThanFoo])
        o = InvariantC()
        directlyProvides(o, ISubInvariant)
        o.foo = 42
        # even though the interface has changed, we should still only have one 
        # error.
        errorsEqual(self, o, 1, ['If Foo, then Bar!'], ISubInvariant)
        # however, if we set foo to 0 (Boolean False) and bar to a negative 
        # number then we'll get the new error
        o.foo = 2
        o.bar = 1
        errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'], 
                    ISubInvariant)
        # and if we set foo to a positive number and boo to 0, we'll
        # get both errors!
        o.foo = 1
        o.bar = 0
        errorsEqual(self, o, 2, ['If Foo, then Bar!',
                                 'Please, Boo MUST be greater than Foo!'],
                    ISubInvariant)
        # for a happy ending, we'll make the invariants happy
        o.foo = 1
        o.bar = 2
        self.assertEquals(IInvariant.validateInvariants(o), None) # woohoo
        # now we'll do two invariants on the same interface, 
        # just to make sure that a small
        # multi-invariant interface is at least minimally tested.
        o = InvariantC()
        directlyProvides(o, IInvariant)
        o.foo = 42
        old_invariants = IInvariant.getTaggedValue('invariants')
        invariants = old_invariants[:]
        invariants.append(BarGreaterThanFoo) # if you really need to mutate,
        # then this would be the way to do it.  Probably a bad idea, though. :-)
        IInvariant.setTaggedValue('invariants', invariants)
        #
        # even though the interface has changed, we should still only have one 
        # error.
        errorsEqual(self, o, 1, ['If Foo, then Bar!'])
        # however, if we set foo to 0 (Boolean False) and bar to a negative 
        # number then we'll get the new error
        o.foo = 2
        o.bar = 1
        errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'])
        # and if we set foo to a positive number and boo to 0, we'll
        # get both errors!
        o.foo = 1
        o.bar = 0
        errorsEqual(self, o, 2, ['If Foo, then Bar!',
                                 'Please, Boo MUST be greater than Foo!'])
        # for another happy ending, we'll make the invariants happy again
        o.foo = 1
        o.bar = 2
        self.assertEquals(IInvariant.validateInvariants(o), None) # bliss
        # clean up
        IInvariant.setTaggedValue('invariants', old_invariants)

    def test___doc___element(self):
        class I(Interface):
            "xxx"

        self.assertEqual(I.__doc__, "xxx")
        self.assertEqual(list(I), [])

        class I(Interface):
            "xxx"

            __doc__ = Attribute('the doc')

        self.assertEqual(I.__doc__, "")
        self.assertEqual(list(I), ['__doc__'])



class _I1(Interface):

    a1 = Attribute("This is an attribute")

    def f11(): pass
    def f12(): pass
    f12.optional = 1

class _I1_(_I1): pass
class _I1__(_I1_): pass

class _I2(_I1__):
    def f21(): pass
    def f22(): pass
    f23 = f22


def test_suite():
    from docfilesuite import DocFileSuite
    suite = unittest.makeSuite(InterfaceTests)
    suite.addTest(DocTestSuite("zope.interface.interface"))
    suite.addTest(DocFileSuite('../README.txt'))
    return suite

def main():
    unittest.TextTestRunner().run(test_suite())

if __name__=="__main__":
    main()