Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / python / test / test_components.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4
5 """
6 Test cases for Twisted component architecture.
7 """
8
9 from zope.interface import Interface, implements, Attribute
10 from zope.interface.adapter import AdapterRegistry
11
12 from twisted.trial import unittest
13 from twisted.python import components
14 from twisted.python.components import _addHook, _removeHook, proxyForInterface
15
16
17 class InterfacesTestCase(unittest.TestCase):
18     """Test interfaces."""
19
20 class Compo(components.Componentized):
21     num = 0
22     def inc(self):
23         self.num = self.num + 1
24         return self.num
25
26 class IAdept(Interface):
27     def adaptorFunc():
28         raise NotImplementedError()
29
30 class IElapsed(Interface):
31     def elapsedFunc():
32         """
33         1!
34         """
35
36 class Adept(components.Adapter):
37     implements(IAdept)
38     def __init__(self, orig):
39         self.original = orig
40         self.num = 0
41     def adaptorFunc(self):
42         self.num = self.num + 1
43         return self.num, self.original.inc()
44
45 class Elapsed(components.Adapter):
46     implements(IElapsed)
47     def elapsedFunc(self):
48         return 1
49
50 class AComp(components.Componentized):
51     pass
52 class BComp(AComp):
53     pass
54 class CComp(BComp):
55     pass
56
57 class ITest(Interface):
58     pass
59 class ITest2(Interface):
60     pass
61 class ITest3(Interface):
62     pass
63 class ITest4(Interface):
64     pass
65 class Test(components.Adapter):
66     implements(ITest, ITest3, ITest4)
67     def __init__(self, orig):
68         pass
69 class Test2:
70     implements(ITest2)
71     temporaryAdapter = 1
72     def __init__(self, orig):
73         pass
74
75
76
77 class RegistryUsingMixin(object):
78     """
79     Mixin for test cases which modify the global registry somehow.
80     """
81     def setUp(self):
82         """
83         Configure L{twisted.python.components.registerAdapter} to mutate an
84         alternate registry to improve test isolation.
85         """
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)
95
96
97
98 class ComponentizedTestCase(unittest.TestCase, RegistryUsingMixin):
99     """
100     Simple test case for caching in Componentized.
101     """
102     def setUp(self):
103         RegistryUsingMixin.setUp(self)
104
105         components.registerAdapter(Test, AComp, ITest)
106         components.registerAdapter(Test, AComp, ITest3)
107         components.registerAdapter(Test2, AComp, ITest2)
108
109
110     def testComponentized(self):
111         components.registerAdapter(Adept, Compo, IAdept)
112         components.registerAdapter(Elapsed, Compo, IElapsed)
113
114         c = Compo()
115         assert c.getComponent(IAdept).adaptorFunc() == (1, 1)
116         assert c.getComponent(IAdept).adaptorFunc() == (2, 2)
117         assert IElapsed(IAdept(c)).elapsedFunc() == 1
118
119     def testInheritanceAdaptation(self):
120         c = CComp()
121         co1 = c.getComponent(ITest)
122         co2 = c.getComponent(ITest)
123         co3 = c.getComponent(ITest2)
124         co4 = c.getComponent(ITest2)
125         assert co1 is co2
126         assert co3 is not co4
127         c.removeComponent(co1)
128         co5 = c.getComponent(ITest)
129         co6 = c.getComponent(ITest)
130         assert co5 is co6
131         assert co1 is not co5
132
133     def testMultiAdapter(self):
134         c = CComp()
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)
141
142
143     def test_getComponentDefaults(self):
144         """
145         Test that a default value specified to Componentized.getComponent if
146         there is no component for the requested interface.
147         """
148         componentized = components.Componentized()
149         default = object()
150         self.assertIdentical(
151             componentized.getComponent(ITest, default),
152             default)
153         self.assertIdentical(
154             componentized.getComponent(ITest, default=default),
155             default)
156         self.assertIdentical(
157             componentized.getComponent(ITest),
158             None)
159
160
161
162 class AdapterTestCase(unittest.TestCase):
163     """Test adapters."""
164
165     def testAdapterGetComponent(self):
166         o = object()
167         a = Adept(o)
168         self.assertRaises(components.CannotAdapt, ITest, a)
169         self.assertEqual(ITest(a, None), None)
170
171
172
173 class IMeta(Interface):
174     pass
175
176 class MetaAdder(components.Adapter):
177     implements(IMeta)
178     def add(self, num):
179         return self.original.num + num
180
181 class BackwardsAdder(components.Adapter):
182     implements(IMeta)
183     def add(self, num):
184         return self.original.num - num
185
186 class MetaNumber:
187     def __init__(self, num):
188         self.num = num
189
190 class FakeAdder:
191     def add(self, num):
192         return num + 5
193
194 class FakeNumber:
195     num = 3
196
197 class ComponentNumber(components.Componentized):
198     def __init__(self):
199         self.num = 0
200         components.Componentized.__init__(self)
201
202 class ComponentMeta(components.Adapter):
203     implements(IMeta)
204     def __init__(self, original):
205         components.Adapter.__init__(self, original)
206         self.num = self.original.num
207
208 class ComponentAdder(ComponentMeta):
209     def add(self, num):
210         self.num += num
211         return self.num
212
213 class ComponentDoubler(ComponentMeta):
214     def add(self, num):
215         self.num += (num * 2)
216         return self.original.num
217
218 class IAttrX(Interface):
219     def x():
220         pass
221
222 class IAttrXX(Interface):
223     def xx():
224         pass
225
226 class Xcellent:
227     implements(IAttrX)
228     def x(self):
229         return 'x!'
230
231 class DoubleXAdapter:
232     num = 42
233     def __init__(self, original):
234         self.original = original
235     def xx(self):
236         return (self.original.x(), self.original.x())
237     def __cmp__(self, other):
238         return cmp(self.num, other.num)
239
240
241 class TestMetaInterface(RegistryUsingMixin, unittest.TestCase):
242     def testBasic(self):
243         components.registerAdapter(MetaAdder, MetaNumber, IMeta)
244         n = MetaNumber(1)
245         self.assertEqual(IMeta(n).add(1), 2)
246
247     def testComponentizedInteraction(self):
248         components.registerAdapter(ComponentAdder, ComponentNumber, IMeta)
249         c = ComponentNumber()
250         IMeta(c).add(1)
251         IMeta(c).add(1)
252         self.assertEqual(IMeta(c).add(1), 3)
253
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())
259
260
261 class RegistrationTestCase(RegistryUsingMixin, unittest.TestCase):
262     """
263     Tests for adapter registration.
264     """
265     def _registerAdapterForClassOrInterface(self, original):
266         """
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}.
270         """
271         adapter = lambda o: None
272         components.registerAdapter(adapter, original, ITest)
273         self.assertIdentical(
274             components.getAdapterFactory(original, ITest, None),
275             adapter)
276
277
278     def test_registerAdapterForClass(self):
279         """
280         Test that an adapter from a class can be registered and then looked
281         up.
282         """
283         class TheOriginal(object):
284             pass
285         return self._registerAdapterForClassOrInterface(TheOriginal)
286
287
288     def test_registerAdapterForInterface(self):
289         """
290         Test that an adapter from an interface can be registered and then
291         looked up.
292         """
293         return self._registerAdapterForClassOrInterface(ITest2)
294
295
296     def _duplicateAdapterForClassOrInterface(self, original):
297         """
298         Verify that L{components.registerAdapter} raises L{ValueError} if the
299         from-type/interface and to-interface pair is not unique.
300         """
301         firstAdapter = lambda o: False
302         secondAdapter = lambda o: True
303         components.registerAdapter(firstAdapter, original, ITest)
304         self.assertRaises(
305             ValueError,
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),
311             firstAdapter)
312
313
314     def test_duplicateAdapterForClass(self):
315         """
316         Test that attempting to register a second adapter from a class
317         raises the appropriate exception.
318         """
319         class TheOriginal(object):
320             pass
321         return self._duplicateAdapterForClassOrInterface(TheOriginal)
322
323
324     def test_duplicateAdapterForInterface(self):
325         """
326         Test that attempting to register a second adapter from an interface
327         raises the appropriate exception.
328         """
329         return self._duplicateAdapterForClassOrInterface(ITest2)
330
331
332     def _duplicateAdapterForClassOrInterfaceAllowed(self, original):
333         """
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.
337         """
338         firstAdapter = lambda o: False
339         secondAdapter = lambda o: True
340         class TheInterface(Interface):
341             pass
342         components.registerAdapter(firstAdapter, original, TheInterface)
343         components.ALLOW_DUPLICATES = True
344         try:
345             components.registerAdapter(secondAdapter, original, TheInterface)
346             self.assertIdentical(
347                 components.getAdapterFactory(original, TheInterface, None),
348                 secondAdapter)
349         finally:
350             components.ALLOW_DUPLICATES = False
351
352         # It should be rejected again at this point
353         self.assertRaises(
354             ValueError,
355             components.registerAdapter,
356             firstAdapter, original, TheInterface)
357
358         self.assertIdentical(
359             components.getAdapterFactory(original, TheInterface, None),
360             secondAdapter)
361
362
363     def test_duplicateAdapterForClassAllowed(self):
364         """
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.
368         """
369         class TheOriginal(object):
370             pass
371         return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal)
372
373
374     def test_duplicateAdapterForInterfaceAllowed(self):
375         """
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.
379         """
380         class TheOriginal(Interface):
381             pass
382         return self._duplicateAdapterForClassOrInterfaceAllowed(TheOriginal)
383
384
385     def _multipleInterfacesForClassOrInterface(self, original):
386         """
387         Verify that an adapter can be registered for multiple to-interfaces at a
388         time.
389         """
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)
396
397
398     def test_multipleInterfacesForClass(self):
399         """
400         Test the registration of an adapter from a class to several
401         interfaces at once.
402         """
403         class TheOriginal(object):
404             pass
405         return self._multipleInterfacesForClassOrInterface(TheOriginal)
406
407
408     def test_multipleInterfacesForInterface(self):
409         """
410         Test the registration of an adapter from an interface to several
411         interfaces at once.
412         """
413         return self._multipleInterfacesForClassOrInterface(ITest3)
414
415
416     def _subclassAdapterRegistrationForClassOrInterface(self, original):
417         """
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.
422         """
423         firstAdapter = lambda o: True
424         secondAdapter = lambda o: False
425         class TheSubclass(original):
426             pass
427         components.registerAdapter(firstAdapter, original, ITest)
428         components.registerAdapter(secondAdapter, TheSubclass, ITest)
429         self.assertIdentical(
430             components.getAdapterFactory(original, ITest, None),
431             firstAdapter)
432         self.assertIdentical(
433             components.getAdapterFactory(TheSubclass, ITest, None),
434             secondAdapter)
435
436
437     def test_subclassAdapterRegistrationForClass(self):
438         """
439         Test that an adapter to a particular interface can be registered
440         from both a class and its subclass.
441         """
442         class TheOriginal(object):
443             pass
444         return self._subclassAdapterRegistrationForClassOrInterface(TheOriginal)
445
446
447     def test_subclassAdapterRegistrationForInterface(self):
448         """
449         Test that an adapter to a particular interface can be registered
450         from both an interface and its subclass.
451         """
452         return self._subclassAdapterRegistrationForClassOrInterface(ITest2)
453
454
455
456 class IProxiedInterface(Interface):
457     """
458     An interface class for use by L{proxyForInterface}.
459     """
460
461     ifaceAttribute = Attribute("""
462         An example declared attribute, which should be proxied.""")
463
464     def yay(*a, **kw):
465         """
466         A sample method which should be proxied.
467         """
468
469 class IProxiedSubInterface(IProxiedInterface):
470     """
471     An interface that derives from another for use with L{proxyForInterface}.
472     """
473
474     def boo(self):
475         """
476         A different sample method which should be proxied.
477         """
478
479
480
481 class Yayable(object):
482     """
483     A provider of L{IProxiedInterface} which increments a counter for
484     every call to C{yay}.
485
486     @ivar yays: The number of times C{yay} has been called.
487     """
488     implements(IProxiedInterface)
489
490     def __init__(self):
491         self.yays = 0
492         self.yayArgs = []
493
494     def yay(self, *a, **kw):
495         """
496         Increment C{self.yays}.
497         """
498         self.yays += 1
499         self.yayArgs.append((a, kw))
500         return self.yays
501
502
503 class Booable(object):
504     """
505     An implementation of IProxiedSubInterface
506     """
507     implements(IProxiedSubInterface)
508     yayed = False
509     booed = False
510     def yay(self):
511         """
512         Mark the fact that 'yay' has been called.
513         """
514         self.yayed = True
515
516
517     def boo(self):
518         """
519         Mark the fact that 'boo' has been called.1
520         """
521         self.booed = True
522
523
524
525 class IMultipleMethods(Interface):
526     """
527     An interface with multiple methods.
528     """
529
530     def methodOne():
531         """
532         The first method. Should return 1.
533         """
534
535     def methodTwo():
536         """
537         The second method. Should return 2.
538         """
539
540
541
542 class MultipleMethodImplementor(object):
543     """
544     A precise implementation of L{IMultipleMethods}.
545     """
546
547     def methodOne(self):
548         """
549         @return: 1
550         """
551         return 1
552
553
554     def methodTwo(self):
555         """
556         @return: 2
557         """
558         return 2
559
560
561
562 class ProxyForInterfaceTests(unittest.TestCase):
563     """
564     Tests for L{proxyForInterface}.
565     """
566
567     def test_original(self):
568         """
569         Proxy objects should have an C{original} attribute which refers to the
570         original object passed to the constructor.
571         """
572         original = object()
573         proxy = proxyForInterface(IProxiedInterface)(original)
574         self.assertIdentical(proxy.original, original)
575
576
577     def test_proxyMethod(self):
578         """
579         The class created from L{proxyForInterface} passes methods on an
580         interface to the object which is passed to its constructor.
581         """
582         klass = proxyForInterface(IProxiedInterface)
583         yayable = Yayable()
584         proxy = klass(yayable)
585         proxy.yay()
586         self.assertEqual(proxy.yay(), 2)
587         self.assertEqual(yayable.yays, 2)
588
589
590     def test_proxyAttribute(self):
591         """
592         Proxy objects should proxy declared attributes, but not other
593         attributes.
594         """
595         yayable = Yayable()
596         yayable.ifaceAttribute = object()
597         proxy = proxyForInterface(IProxiedInterface)(yayable)
598         self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute)
599         self.assertRaises(AttributeError, lambda: proxy.yays)
600
601
602     def test_proxySetAttribute(self):
603         """
604         The attributes that proxy objects proxy should be assignable and affect
605         the original object.
606         """
607         yayable = Yayable()
608         proxy = proxyForInterface(IProxiedInterface)(yayable)
609         thingy = object()
610         proxy.ifaceAttribute = thingy
611         self.assertIdentical(yayable.ifaceAttribute, thingy)
612
613
614     def test_proxyDeleteAttribute(self):
615         """
616         The attributes that proxy objects proxy should be deletable and affect
617         the original object.
618         """
619         yayable = Yayable()
620         yayable.ifaceAttribute = None
621         proxy = proxyForInterface(IProxiedInterface)(yayable)
622         del proxy.ifaceAttribute
623         self.assertFalse(hasattr(yayable, 'ifaceAttribute'))
624
625
626     def test_multipleMethods(self):
627         """
628         [Regression test] The proxy should send its method calls to the correct
629         method, not the incorrect one.
630         """
631         multi = MultipleMethodImplementor()
632         proxy = proxyForInterface(IMultipleMethods)(multi)
633         self.assertEqual(proxy.methodOne(), 1)
634         self.assertEqual(proxy.methodTwo(), 2)
635
636
637     def test_subclassing(self):
638         """
639         It is possible to subclass the result of L{proxyForInterface}.
640         """
641
642         class SpecializedProxy(proxyForInterface(IProxiedInterface)):
643             """
644             A specialized proxy which can decrement the number of yays.
645             """
646             def boo(self):
647                 """
648                 Decrement the number of yays.
649                 """
650                 self.original.yays -= 1
651
652         yayable = Yayable()
653         special = SpecializedProxy(yayable)
654         self.assertEqual(yayable.yays, 0)
655         special.boo()
656         self.assertEqual(yayable.yays, -1)
657
658
659     def test_proxyName(self):
660         """
661         The name of a proxy class indicates which interface it proxies.
662         """
663         proxy = proxyForInterface(IProxiedInterface)
664         self.assertEqual(
665             proxy.__name__,
666             "(Proxy for "
667             "twisted.python.test.test_components.IProxiedInterface)")
668
669
670     def test_implements(self):
671         """
672         The resulting proxy implements the interface that it proxies.
673         """
674         proxy = proxyForInterface(IProxiedInterface)
675         self.assertTrue(IProxiedInterface.implementedBy(proxy))
676
677
678     def test_proxyDescriptorGet(self):
679         """
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.
684
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.
693         """
694         class Sample:
695             called = False
696             def hello(self):
697                 self.called = True
698         fakeProxy = Sample()
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)
706
707
708     def test_proxyInheritance(self):
709         """
710         Subclasses of the class returned from L{proxyForInterface} should be
711         able to upcall methods by reference to their superclass, as any normal
712         Python class can.
713         """
714         class YayableWrapper(proxyForInterface(IProxiedInterface)):
715             """
716             This class does not override any functionality.
717             """
718
719         class EnhancedWrapper(YayableWrapper):
720             """
721             This class overrides the 'yay' method.
722             """
723             wrappedYays = 1
724             def yay(self, *a, **k):
725                 self.wrappedYays += 1
726                 return YayableWrapper.yay(self, *a, **k) + 7
727
728         yayable = Yayable()
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))])
733
734
735     def test_interfaceInheritance(self):
736         """
737         Proxies of subinterfaces generated with proxyForInterface should allow
738         access to attributes of both the child and the base interfaces.
739         """
740         proxyClass = proxyForInterface(IProxiedSubInterface)
741         booable = Booable()
742         proxy = proxyClass(booable)
743         proxy.yay()
744         proxy.boo()
745         self.failUnless(booable.yayed)
746         self.failUnless(booable.booed)
747
748
749     def test_attributeCustomization(self):
750         """
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.
755         """
756         yayable = Yayable()
757         yayable.ifaceAttribute = object()
758         proxy = proxyForInterface(
759             IProxiedInterface, originalAttribute='foo')(yayable)
760         self.assertIdentical(proxy.foo, yayable)
761
762         # Check the behavior
763         self.assertEqual(proxy.yay(), 1)
764         self.assertIdentical(proxy.ifaceAttribute, yayable.ifaceAttribute)
765         thingy = object()
766         proxy.ifaceAttribute = thingy
767         self.assertIdentical(yayable.ifaceAttribute, thingy)
768         del proxy.ifaceAttribute
769         self.assertFalse(hasattr(yayable, 'ifaceAttribute'))
770