~divmod-dev/divmod.org/trunk

« back to all changes in this revision

Viewing changes to Epsilon/epsilon/test/test_expose.py

  • Committer: Jean-Paul Calderone
  • Date: 2014-06-29 20:33:04 UTC
  • mfrom: (2749.1.1 remove-epsilon-1325289)
  • Revision ID: exarkun@twistedmatrix.com-20140629203304-gdkmbwl1suei4m97
mergeĀ lp:~exarkun/divmod.org/remove-epsilon-1325289

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copright 2008 Divmod, Inc.  See LICENSE file for details.
2
 
 
3
 
"""
4
 
L{epsilon.expose} is a module which allows a system that needs to expose code
5
 
to a network endpoint do so in a manner which only exposes methods which have
6
 
been explicitly designated.  It provides utilities for convenient annotation
7
 
and lookup of exposed methods.
8
 
"""
9
 
 
10
 
from epsilon.structlike import record
11
 
 
12
 
from epsilon.expose import Exposer, MethodNotExposed, NameRequired
13
 
 
14
 
from twisted.trial.unittest import TestCase
15
 
 
16
 
 
17
 
class ExposeTests:
18
 
    """
19
 
    This mixin provides tests for expose, based on a parameterized base type
20
 
    for the class which methods are being exposed on.  Subclass this before
21
 
    L{TestCase} and set L{superClass} to use this.
22
 
 
23
 
    @ivar superClass: the class to be subclassed by all classes which expose
24
 
    methods.
25
 
    """
26
 
 
27
 
    superClass = None
28
 
    def setUp(self):
29
 
        """
30
 
        Create two exposers to expose methods in tests.
31
 
        """
32
 
        self.exposer = Exposer("test exposer")
33
 
        self.otherExposer = Exposer("other exposer")
34
 
 
35
 
 
36
 
    def test_exposeDocAttribute(self):
37
 
        """
38
 
        Creating an exposer should require a docstring explaining what it's
39
 
        for.
40
 
        """
41
 
        docstring = "This is my docstring."
42
 
        exposer = Exposer(docstring)
43
 
        self.assertEqual(exposer.__doc__, docstring)
44
 
 
45
 
 
46
 
    def test_simpleExpose(self):
47
 
        """
48
 
        Creating an exposer, defining a class and exposing a method of a class
49
 
        with that exposer, then retrieving a method of that class should result
50
 
        in the method of that class.
51
 
        """
52
 
        class Foo(self.superClass):
53
 
            def __init__(self, num):
54
 
                self.num = num
55
 
 
56
 
            @self.exposer.expose()
57
 
            def bar(self):
58
 
                return self.num + 1
59
 
        f = Foo(3)
60
 
        method = self.exposer.get(f, 'bar')
61
 
        self.assertEqual(method(), 4)
62
 
 
63
 
 
64
 
    def test_notExposed(self):
65
 
        """
66
 
        Creating an exposer and then attempting to retrieve a method not
67
 
        exposed with it should result in a L{MethodNotExposed} exception.
68
 
        """
69
 
        class Foo(self.superClass):
70
 
            def bar(self):
71
 
                return 1
72
 
        f = Foo()
73
 
        self.assertRaises(MethodNotExposed, self.exposer.get, f, 'bar')
74
 
 
75
 
 
76
 
    def test_differentMethodsDifferentExposers(self):
77
 
        """
78
 
        Methods should only be able to be retrieved with the exposer that
79
 
        exposed them, not with any other exposer.
80
 
        """
81
 
        class Foo(self.superClass):
82
 
            @self.exposer.expose()
83
 
            def bar(self):
84
 
                return 1
85
 
            @self.otherExposer.expose()
86
 
            def baz(self):
87
 
                return 2
88
 
        f = Foo()
89
 
        self.assertEqual(self.exposer.get(f, 'bar')(), 1)
90
 
        self.assertEqual(self.otherExposer.get(f, 'baz')(), 2)
91
 
        self.assertRaises(MethodNotExposed, self.otherExposer.get, f, 'bar')
92
 
        self.assertRaises(MethodNotExposed, self.exposer.get, f, 'baz')
93
 
 
94
 
 
95
 
    def test_sameMethodExposedByDifferentExposers(self):
96
 
        """
97
 
        If the same method is exposed by two different exposers, it should be
98
 
        accessible by both of them.
99
 
        """
100
 
        class Foo(self.superClass):
101
 
            @self.exposer.expose()
102
 
            @self.otherExposer.expose()
103
 
            def bar(self):
104
 
                return 4
105
 
        f = Foo()
106
 
        self.assertEqual(self.exposer.get(f, 'bar')(), 4)
107
 
        self.assertEqual(self.otherExposer.get(f, 'bar')(), 4)
108
 
 
109
 
 
110
 
    def test_exposeWithDifferentKey(self):
111
 
        """
112
 
        The 'key' argument to {Exposer.expose} should change the argument to
113
 
        'get'.
114
 
        """
115
 
        class Foo(self.superClass):
116
 
            @self.exposer.expose(key='hello')
117
 
            def bar(self):
118
 
                return 7
119
 
        f = Foo()
120
 
        self.assertEqual(self.exposer.get(f, 'hello')(), 7)
121
 
 
122
 
 
123
 
    def test_exposeOnDifferentClass(self):
124
 
        """
125
 
        An exposer should only be able to retrieve a method from instances of
126
 
        types which it has explicitly exposed methods on.  Instances of
127
 
        different types with the same method name should raise
128
 
        L{MethodNotExposed}.
129
 
        """
130
 
        class Foo(self.superClass):
131
 
            @self.exposer.expose()
132
 
            def bar(self):
133
 
                return 7
134
 
        class Baz(self.superClass):
135
 
            def bar(self):
136
 
                return 8
137
 
        f = Foo()
138
 
        b = Baz()
139
 
        self.assertEqual(self.exposer.get(f, 'bar')(), 7)
140
 
        self.assertRaises(MethodNotExposed, self.otherExposer.get, b, 'bar')
141
 
 
142
 
 
143
 
    def test_exposeUnnamedNoKey(self):
144
 
        """
145
 
        L{Exposer.expose} raises L{NameRequired} when called without a value
146
 
        for the C{key} parameter if it is used to decorate a non-function
147
 
        object.
148
 
        """
149
 
        def f():
150
 
            class Foo(self.superClass):
151
 
                @self.exposer.expose()
152
 
                @classmethod
153
 
                def foo(self):
154
 
                    pass
155
 
        self.assertRaises(NameRequired, f)
156
 
 
157
 
 
158
 
    def test_exposeNonMethod(self):
159
 
        """
160
 
        L{Exposer.expose} should work on methods which have been decorated by
161
 
        another decorator and will therefore not result in function objects
162
 
        when retrieved with __get__.
163
 
        """
164
 
        class Getter(record('function')):
165
 
            def __get__(self, oself, type):
166
 
                return self.function
167
 
 
168
 
        class Foo(self.superClass):
169
 
            @self.exposer.expose(key='bar')
170
 
            @Getter
171
 
            def bar():
172
 
                return 7
173
 
 
174
 
        f = Foo()
175
 
        # Sanity check
176
 
        self.assertEqual(f.bar(), 7)
177
 
        self.assertEqual(self.exposer.get(f, 'bar')(), 7)
178
 
 
179
 
 
180
 
    def test_descriptorGetsType(self):
181
 
        """
182
 
        L{Exposer.get} should not interfere with the appropriate type object
183
 
        being passed to the wrapped descriptor's C{__get__}.
184
 
        """
185
 
        types = []
186
 
        class Getter(record('function')):
187
 
            def __get__(self, oself, type):
188
 
                types.append(type)
189
 
                return self.function
190
 
        class Foo(self.superClass):
191
 
            @self.exposer.expose(key='bar')
192
 
            @Getter
193
 
            def bar():
194
 
                return 7
195
 
        f = Foo()
196
 
        self.exposer.get(f, 'bar')
197
 
        self.assertEqual(types, [Foo])
198
 
 
199
 
 
200
 
    def test_descriptorGetsSubtype(self):
201
 
        """
202
 
        When a descriptor is exposed through a superclass, getting it from a
203
 
        subclass results in the subclass being passed to the C{__get__} method.
204
 
        """
205
 
        types = []
206
 
        class Getter(record('function')):
207
 
            def __get__(self, oself, type):
208
 
                types.append(type)
209
 
                return self.function
210
 
        class Foo(self.superClass):
211
 
            @self.exposer.expose(key='bar')
212
 
            @Getter
213
 
            def bar():
214
 
                return 7
215
 
        class Baz(Foo):
216
 
            pass
217
 
        b = Baz()
218
 
        self.exposer.get(b, 'bar')
219
 
        self.assertEqual(types, [Baz])
220
 
 
221
 
 
222
 
    def test_implicitSubclassExpose(self):
223
 
        """
224
 
        L{Exposer.expose} should expose the given object on all subclasses.
225
 
        """
226
 
        class Foo(self.superClass):
227
 
            @self.exposer.expose()
228
 
            def bar(self):
229
 
                return 7
230
 
        class Baz(Foo):
231
 
            pass
232
 
        b = Baz()
233
 
        self.assertEqual(self.exposer.get(b, 'bar')(), 7)
234
 
 
235
 
 
236
 
    def test_overrideDontExpose(self):
237
 
        """
238
 
        L{Exposer.expose} should not expose overridden methods on subclasses.
239
 
        """
240
 
        class Foo(self.superClass):
241
 
            @self.exposer.expose()
242
 
            def bar(self):
243
 
                return 7
244
 
        class Baz(Foo):
245
 
            def bar(self):
246
 
                return 8
247
 
        b = Baz()
248
 
        self.assertRaises(MethodNotExposed, self.otherExposer.get, b, 'bar')
249
 
 
250
 
 
251
 
    def test_sameKeyOnDifferentTypes(self):
252
 
        """
253
 
        L{Exposer.expose} should work with the same key on different types.
254
 
        """
255
 
        class Foo(self.superClass):
256
 
            @self.exposer.expose()
257
 
            def bar(self):
258
 
                return 17
259
 
        class Qux(self.superClass):
260
 
            @self.exposer.expose()
261
 
            def bar(self):
262
 
                return 71
263
 
        q = Qux()
264
 
        f = Foo()
265
 
        self.assertEqual(self.exposer.get(q, 'bar')(), 71)
266
 
        self.assertEqual(self.exposer.get(f, 'bar')(), 17)
267
 
 
268
 
 
269
 
    def test_overrideReExpose(self):
270
 
        """
271
 
        L{Exposer.expose} should expose a method on a subclass if that method
272
 
        is overridden.
273
 
        """
274
 
        class Foo(self.superClass):
275
 
            @self.exposer.expose()
276
 
            def bar(self):
277
 
                return 7
278
 
        class Baz(Foo):
279
 
            @self.exposer.expose()
280
 
            def bar(self):
281
 
                return 8
282
 
        f = Foo()
283
 
        b = Baz()
284
 
        self.assertEqual(self.exposer.get(f, 'bar')(), 7)
285
 
        self.assertEqual(self.exposer.get(b, 'bar')(), 8)
286
 
 
287
 
 
288
 
    def test_deleteExposedAttribute(self):
289
 
        """
290
 
        When an exposed attribute is deleted from a class, it should no longer
291
 
        be exposed; calling L{Exposer.get} should result in
292
 
        L{MethodNotExposed}.
293
 
        """
294
 
        class Foo(self.superClass):
295
 
            @self.exposer.expose()
296
 
            def bar(self):
297
 
                return 7
298
 
        f = Foo()
299
 
        del Foo.bar
300
 
        self.assertRaises(MethodNotExposed, self.otherExposer.get, f, 'bar')
301
 
 
302
 
 
303
 
 
304
 
class ExposeNewStyle(ExposeTests, TestCase):
305
 
    """
306
 
    All of the above functionality should work on new-style classes.
307
 
    """
308
 
    superClass = object
309
 
 
310
 
 
311
 
class Classic:
312
 
    """
313
 
    A dummy classic class.
314
 
    """
315
 
 
316
 
 
317
 
class ExposeOldStyle(ExposeTests, TestCase):
318
 
    """
319
 
    All of the above functionality should work on old-style classes.
320
 
    """
321
 
    superClass = Classic