1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
6 Test cases for Twisted component architecture.
9 from zope.interface import Interface, implements, Attribute
10 from zope.interface.adapter import AdapterRegistry
12 from twisted.trial import unittest
13 from twisted.python import components
14 from twisted.python.components import _addHook, _removeHook, proxyForInterface
17 class InterfacesTestCase(unittest.TestCase):
18 """Test interfaces."""
20 class Compo(components.Componentized):
23 self.num = self.num + 1
26 class IAdept(Interface):
28 raise NotImplementedError()
30 class IElapsed(Interface):
36 class Adept(components.Adapter):
38 def __init__(self, orig):
41 def adaptorFunc(self):
42 self.num = self.num + 1
43 return self.num, self.original.inc()
45 class Elapsed(components.Adapter):
47 def elapsedFunc(self):
50 class AComp(components.Componentized):
57 class ITest(Interface):
59 class ITest2(Interface):
61 class ITest3(Interface):
63 class ITest4(Interface):
65 class Test(components.Adapter):
66 implements(ITest, ITest3, ITest4)
67 def __init__(self, orig):
72 def __init__(self, orig):
77 class RegistryUsingMixin(object):
79 Mixin for test cases which modify the global registry somehow.
83 Configure L{twisted.python.components.registerAdapter} to mutate an
84 alternate registry to improve test isolation.
86 # Create a brand new, empty registry and put it onto the components
87 # module where registerAdapter will use it. Also ensure that it goes
88 # away at the end of the test.
89 scratchRegistry = AdapterRegistry()
90 self.patch(components, 'globalRegistry', scratchRegistry)
91 # Hook the new registry up to the adapter lookup system and ensure that
92 # association is also discarded after the test.
93 hook = _addHook(scratchRegistry)
94 self.addCleanup(_removeHook, hook)
98 class ComponentizedTestCase(unittest.TestCase, RegistryUsingMixin):
100 Simple test case for caching in Componentized.
103 RegistryUsingMixin.setUp(self)
105 components.registerAdapter(Test, AComp, ITest)
106 components.registerAdapter(Test, AComp, ITest3)
107 components.registerAdapter(Test2, AComp, ITest2)
110 def testComponentized(self):
111 components.registerAdapter(Adept, Compo, IAdept)
112 components.registerAdapter(Elapsed, Compo, IElapsed)
115 assert c.getComponent(IAdept).adaptorFunc() == (1, 1)
116 assert c.getComponent(IAdept).adaptorFunc() == (2, 2)
117 assert IElapsed(IAdept(c)).elapsedFunc() == 1
119 def testInheritanceAdaptation(self):
121 co1 = c.getComponent(ITest)
122 co2 = c.getComponent(ITest)
123 co3 = c.getComponent(ITest2)
124 co4 = c.getComponent(ITest2)
126 assert co3 is not co4
127 c.removeComponent(co1)
128 co5 = c.getComponent(ITest)
129 co6 = c.getComponent(ITest)
131 assert co1 is not co5
133 def testMultiAdapter(self):
135 co1 = c.getComponent(ITest)
136 co2 = c.getComponent(ITest2)
137 co3 = c.getComponent(ITest3)
138 co4 = c.getComponent(ITest4)
139 self.assertIdentical(None, co4)
140 self.assertIdentical(co1, co3)
143 def test_getComponentDefaults(self):
145 Test that a default value specified to Componentized.getComponent if
146 there is no component for the requested interface.
148 componentized = components.Componentized()
150 self.assertIdentical(
151 componentized.getComponent(ITest, default),
153 self.assertIdentical(
154 componentized.getComponent(ITest, default=default),
156 self.assertIdentical(
157 componentized.getComponent(ITest),
162 class AdapterTestCase(unittest.TestCase):
165 def testAdapterGetComponent(self):
168 self.assertRaises(components.CannotAdapt, ITest, a)
169 self.assertEqual(ITest(a, None), None)
173 class IMeta(Interface):
176 class MetaAdder(components.Adapter):
179 return self.original.num + num
181 class BackwardsAdder(components.Adapter):
184 return self.original.num - num
187 def __init__(self, num):
197 class ComponentNumber(components.Componentized):
200 components.Componentized.__init__(self)
202 class ComponentMeta(components.Adapter):
204 def __init__(self, original):
205 components.Adapter.__init__(self, original)
206 self.num = self.original.num
208 class ComponentAdder(ComponentMeta):
213 class ComponentDoubler(ComponentMeta):
215 self.num += (num * 2)
216 return self.original.num
218 class IAttrX(Interface):
222 class IAttrXX(Interface):
231 class DoubleXAdapter:
233 def __init__(self, original):
234 self.original = original
236 return (self.original.x(), self.original.x())
237 def __cmp__(self, other):
238 return cmp(self.num, other.num)
241 class TestMetaInterface(RegistryUsingMixin, unittest.TestCase):
243 components.registerAdapter(MetaAdder, MetaNumber, IMeta)
245 self.assertEqual(IMeta(n).add(1), 2)
247 def testComponentizedInteraction(self):
248 components.registerAdapter(ComponentAdder, ComponentNumber, IMeta)
249 c = ComponentNumber()
252 self.assertEqual(IMeta(c).add(1), 3)
254 def testAdapterWithCmp(self):
255 # Make sure that a __cmp__ on an adapter doesn't break anything
256 components.registerAdapter(DoubleXAdapter, IAttrX, IAttrXX)
257 xx = IAttrXX(Xcellent())
258 self.assertEqual(('x!', 'x!'), xx.xx())
261 class RegistrationTestCase(RegistryUsingMixin, unittest.TestCase):
263 Tests for adapter registration.
265 def _registerAdapterForClassOrInterface(self, original):
267 Register an adapter with L{components.registerAdapter} for the given
268 class or interface and verify that the adapter can be looked up with
269 L{components.getAdapterFactory}.
271 adapter = lambda o: None
272 components.registerAdapter(adapter, original, ITest)
273 self.assertIdentical(
274 components.getAdapterFactory(original, ITest, None),
278 def test_registerAdapterForClass(self):
280 Test that an adapter from a class can be registered and then looked
283 class TheOriginal(object):
285 return self._registerAdapterForClassOrInterface(TheOriginal)
288 def test_registerAdapterForInterface(self):
290 Test that an adapter from an interface can be registered and then
293 return self._registerAdapterForClassOrInterface(ITest2)
296 def _duplicateAdapterForClassOrInterface(self, original):
298 Verify that L{components.registerAdapter} raises L{ValueError} if the
299 from-type/interface and to-interface pair is not unique.
301 firstAdapter = lambda o: False
302 secondAdapter = lambda o: True
303 components.registerAdapter(firstAdapter, original, ITest)
306 components.registerAdapter,
307 secondAdapter, original, ITest)
308 # Make sure that the original adapter is still around as well
309 self.assertIdentical(
310 components.getAdapterFactory(original, ITest, None),
314 def test_duplicateAdapterForClass(self):
316 Test that attempting to register a second adapter from a class
317 raises the appropriate exception.
319 class TheOriginal(object):
321 return self._duplicateAdapterForClassOrInterface(TheOriginal)
324 def test_duplicateAdapterForInterface(self):
326 Test that attempting to register a second adapter from an interface
327 raises the appropriate exception.
329 return self._duplicateAdapterForClassOrInterface(ITest2)
332 def _duplicateAdapterForClassOrInterfaceAllowed(self, original):
334 Verify that when C{components.ALLOW_DUPLICATES} is set to C{True}, new
335 adapter registrations for a particular from-type/interface and
336 to-interface pair replace older registrations.
338 firstAdapter = lambda o: False
339 secondAdapter = lambda o: True
340 class TheInterface(Interface):
342 components.registerAdapter(firstAdapter, original, TheInterface)
343 components.ALLOW_DUPLICATES = True
345 components.registerAdapter(secondAdapter, original, TheInterface)
346 self.assertIdentical(
347 components.getAdapterFactory(original, TheInterface, None),
350 components.ALLOW_DUPLICATES = False
352 # It should be rejected again at this point
355 components.registerAdapter,
356 firstAdapter, original, TheInterface)
358 self.assertIdentical(
359 components.getAdapterFactory(original, TheInterface, None),
363 def test_duplicateAdapterForClassAllowed(self):
365 Test that when L{components.ALLOW_DUPLICATES} is set to a true
366 value, duplicate registrations from classes are allowed to override
367 the original registration.
369 class TheOriginal(object):
371 return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal)
374 def test_duplicateAdapterForInterfaceAllowed(self):
376 Test that when L{components.ALLOW_DUPLICATES} is set to a true
377 value, duplicate registrations from interfaces are allowed to
378 override the original registration.
380 class TheOriginal(Interface):
382 return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal)
385 def _multipleInterfacesForClassOrInterface(self, original):
387 Verify that an adapter can be registered for multiple to-interfaces at a
390 adapter = lambda o: None
391 components.registerAdapter(adapter, original, ITest, ITest2)
392 self.assertIdentical(
393 components.getAdapterFactory(original, ITest, None), adapter)
394 self.assertIdentical(
395 components.getAdapterFactory(original, ITest2, None), adapter)
398 def test_multipleInterfacesForClass(self):
400 Test the registration of an adapter from a class to several
403 class TheOriginal(object):
405 return self._multipleInterfacesForClassOrInterface(TheOriginal)
408 def test_multipleInterfacesForInterface(self):
410 Test the registration of an adapter from an interface to several
413 return self._multipleInterfacesForClassOrInterface(ITest3)
416 def _subclassAdapterRegistrationForClassOrInterface(self, original):
418 Verify that a new adapter can be registered for a particular
419 to-interface from a subclass of a type or interface which already has an
420 adapter registered to that interface and that the subclass adapter takes
421 precedence over the base class adapter.
423 firstAdapter = lambda o: True
424 secondAdapter = lambda o: False
425 class TheSubclass(original):
427 components.registerAdapter(firstAdapter, original, ITest)
428 components.registerAdapter(secondAdapter, TheSubclass, ITest)
429 self.assertIdentical(
430 components.getAdapterFactory(original, ITest, None),
432 self.assertIdentical(
433 components.getAdapterFactory(TheSubclass, ITest, None),
437 def test_subclassAdapterRegistrationForClass(self):
439 Test that an adapter to a particular interface can be registered
440 from both a class and its subclass.
442 class TheOriginal(object):
444 return self._subclassAdapterRegistrationForClassOrInterface(TheOriginal)
447 def test_subclassAdapterRegistrationForInterface(self):
449 Test that an adapter to a particular interface can be registered
450 from both an interface and its subclass.
452 return self._subclassAdapterRegistrationForClassOrInterface(ITest2)
456 class IProxiedInterface(Interface):
458 An interface class for use by L{proxyForInterface}.
461 ifaceAttribute = Attribute("""
462 An example declared attribute, which should be proxied.""")
466 A sample method which should be proxied.
469 class IProxiedSubInterface(IProxiedInterface):
471 An interface that derives from another for use with L{proxyForInterface}.
476 A different sample method which should be proxied.
481 class Yayable(object):
483 A provider of L{IProxiedInterface} which increments a counter for
484 every call to C{yay}.
486 @ivar yays: The number of times C{yay} has been called.
488 implements(IProxiedInterface)
494 def yay(self, *a, **kw):
496 Increment C{self.yays}.
499 self.yayArgs.append((a, kw))
503 class Booable(object):
505 An implementation of IProxiedSubInterface
507 implements(IProxiedSubInterface)
512 Mark the fact that 'yay' has been called.
519 Mark the fact that 'boo' has been called.1
525 class IMultipleMethods(Interface):
527 An interface with multiple methods.
532 The first method. Should return 1.
537 The second method. Should return 2.
542 class MultipleMethodImplementor(object):
544 A precise implementation of L{IMultipleMethods}.
562 class ProxyForInterfaceTests(unittest.TestCase):
564 Tests for L{proxyForInterface}.
567 def test_original(self):
569 Proxy objects should have an C{original} attribute which refers to the
570 original object passed to the constructor.
573 proxy = proxyForInterface(IProxiedInterface)(original)
574 self.assertIdentical(proxy.original, original)
577 def test_proxyMethod(self):
579 The class created from L{proxyForInterface} passes methods on an
580 interface to the object which is passed to its constructor.
582 klass = proxyForInterface(IProxiedInterface)
584 proxy = klass(yayable)
586 self.assertEqual(proxy.yay(), 2)
587 self.assertEqual(yayable.yays, 2)
590 def test_proxyAttribute(self):
592 Proxy objects should proxy declared attributes, but not other
596 yayable.ifaceAttribute = object()
597 proxy = proxyForInterface(IProxiedInterface)(yayable)
598 self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute)
599 self.assertRaises(AttributeError, lambda: proxy.yays)
602 def test_proxySetAttribute(self):
604 The attributes that proxy objects proxy should be assignable and affect
608 proxy = proxyForInterface(IProxiedInterface)(yayable)
610 proxy.ifaceAttribute = thingy
611 self.assertIdentical(yayable.ifaceAttribute, thingy)
614 def test_proxyDeleteAttribute(self):
616 The attributes that proxy objects proxy should be deletable and affect
620 yayable.ifaceAttribute = None
621 proxy = proxyForInterface(IProxiedInterface)(yayable)
622 del proxy.ifaceAttribute
623 self.assertFalse(hasattr(yayable, 'ifaceAttribute'))
626 def test_multipleMethods(self):
628 [Regression test] The proxy should send its method calls to the correct
629 method, not the incorrect one.
631 multi = MultipleMethodImplementor()
632 proxy = proxyForInterface(IMultipleMethods)(multi)
633 self.assertEqual(proxy.methodOne(), 1)
634 self.assertEqual(proxy.methodTwo(), 2)
637 def test_subclassing(self):
639 It is possible to subclass the result of L{proxyForInterface}.
642 class SpecializedProxy(proxyForInterface(IProxiedInterface)):
644 A specialized proxy which can decrement the number of yays.
648 Decrement the number of yays.
650 self.original.yays -= 1
653 special = SpecializedProxy(yayable)
654 self.assertEqual(yayable.yays, 0)
656 self.assertEqual(yayable.yays, -1)
659 def test_proxyName(self):
661 The name of a proxy class indicates which interface it proxies.
663 proxy = proxyForInterface(IProxiedInterface)
667 "twisted.python.test.test_components.IProxiedInterface)")
670 def test_implements(self):
672 The resulting proxy implements the interface that it proxies.
674 proxy = proxyForInterface(IProxiedInterface)
675 self.assertTrue(IProxiedInterface.implementedBy(proxy))
678 def test_proxyDescriptorGet(self):
680 _ProxyDescriptor's __get__ method should return the appropriate
681 attribute of its argument's 'original' attribute if it is invoked with
682 an object. If it is invoked with None, it should return a false
683 class-method emulator instead.
685 For some reason, Python's documentation recommends to define
686 descriptors' __get__ methods with the 'type' parameter as optional,
687 despite the fact that Python itself never actually calls the descriptor
688 that way. This is probably do to support 'foo.__get__(bar)' as an
689 idiom. Let's make sure that the behavior is correct. Since we don't
690 actually use the 'type' argument at all, this test calls it the
691 idiomatic way to ensure that signature works; test_proxyInheritance
692 verifies the how-Python-actually-calls-it signature.
699 testObject = Sample()
700 fakeProxy.original = testObject
701 pd = components._ProxyDescriptor("hello", "original")
702 self.assertEqual(pd.__get__(fakeProxy), testObject.hello)
703 fakeClassMethod = pd.__get__(None)
704 fakeClassMethod(fakeProxy)
705 self.failUnless(testObject.called)
708 def test_proxyInheritance(self):
710 Subclasses of the class returned from L{proxyForInterface} should be
711 able to upcall methods by reference to their superclass, as any normal
714 class YayableWrapper(proxyForInterface(IProxiedInterface)):
716 This class does not override any functionality.
719 class EnhancedWrapper(YayableWrapper):
721 This class overrides the 'yay' method.
724 def yay(self, *a, **k):
725 self.wrappedYays += 1
726 return YayableWrapper.yay(self, *a, **k) + 7
729 wrapper = EnhancedWrapper(yayable)
730 self.assertEqual(wrapper.yay(3, 4, x=5, y=6), 8)
731 self.assertEqual(yayable.yayArgs,
732 [((3, 4), dict(x=5, y=6))])
735 def test_interfaceInheritance(self):
737 Proxies of subinterfaces generated with proxyForInterface should allow
738 access to attributes of both the child and the base interfaces.
740 proxyClass = proxyForInterface(IProxiedSubInterface)
742 proxy = proxyClass(booable)
745 self.failUnless(booable.yayed)
746 self.failUnless(booable.booed)
749 def test_attributeCustomization(self):
751 The original attribute name can be customized via the
752 C{originalAttribute} argument of L{proxyForInterface}: the attribute
753 should change, but the methods of the original object should still be
754 callable, and the attributes still accessible.
757 yayable.ifaceAttribute = object()
758 proxy = proxyForInterface(
759 IProxiedInterface, originalAttribute='foo')(yayable)
760 self.assertIdentical(proxy.foo, yayable)
763 self.assertEqual(proxy.yay(), 1)
764 self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute)
766 proxy.ifaceAttribute = thingy
767 self.assertIdentical(yayable.ifaceAttribute, thingy)
768 del proxy.ifaceAttribute
769 self.assertFalse(hasattr(yayable, 'ifaceAttribute'))