~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/python/test/test_components.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

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