Initial import to Tizen
[profile/ivi/python-zope.interface.git] / src / zope / interface / tests / test_adapter.py
1 ##############################################################################
2 #
3 # Copyright (c) 2003 Zope Foundation and Contributors.
4 # All Rights Reserved.
5 #
6 # This software is subject to the provisions of the Zope Public License,
7 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11 # FOR A PARTICULAR PURPOSE.
12 #
13 ##############################################################################
14 """Adapter registry tests
15 """
16 import doctest
17 import unittest
18 import zope.interface
19 from zope.interface.adapter import AdapterRegistry
20
21
22 class IF0(zope.interface.Interface):
23     pass
24 class IF1(IF0):
25     pass
26
27 class IB0(zope.interface.Interface):
28     pass
29 class IB1(IB0):
30     pass
31
32 class IR0(zope.interface.Interface):
33     pass
34 class IR1(IR0):
35     pass
36
37 def test_multi_adapter_get_best_match():
38     """
39     >>> registry = AdapterRegistry()
40
41     >>> class IB2(IB0):
42     ...     pass
43     >>> class IB3(IB2, IB1):
44     ...     pass
45     >>> class IB4(IB1, IB2):
46     ...     pass
47
48     >>> registry.register([None, IB1], IR0, '', 'A1')
49     >>> registry.register([None, IB0], IR0, '', 'A0')
50     >>> registry.register([None, IB2], IR0, '', 'A2')
51
52     >>> registry.lookup((IF1, IB1), IR0, '')
53     'A1'
54     >>> registry.lookup((IF1, IB2), IR0, '')
55     'A2'
56     >>> registry.lookup((IF1, IB0), IR0, '')
57     'A0'
58     >>> registry.lookup((IF1, IB3), IR0, '')
59     'A2'
60     >>> registry.lookup((IF1, IB4), IR0, '')
61     'A1'
62     """
63
64 def test_multi_adapter_lookupAll_get_best_matches():
65     """
66     >>> registry = AdapterRegistry()
67
68     >>> class IB2(IB0):
69     ...     pass
70     >>> class IB3(IB2, IB1):
71     ...     pass
72     >>> class IB4(IB1, IB2):
73     ...     pass
74
75     >>> registry.register([None, IB1], IR0, '', 'A1')
76     >>> registry.register([None, IB0], IR0, '', 'A0')
77     >>> registry.register([None, IB2], IR0, '', 'A2')
78
79     >>> tuple(registry.lookupAll((IF1, IB1), IR0))[0][1]
80     'A1'
81     >>> tuple(registry.lookupAll((IF1, IB2), IR0))[0][1]
82     'A2'
83     >>> tuple(registry.lookupAll((IF1, IB0), IR0))[0][1]
84     'A0'
85     >>> tuple(registry.lookupAll((IF1, IB3), IR0))[0][1]
86     'A2'
87     >>> tuple(registry.lookupAll((IF1, IB4), IR0))[0][1]
88     'A1'
89     """
90
91
92 def test_multi_adapter_w_default():
93     """
94     >>> registry = AdapterRegistry()
95     
96     >>> registry.register([None, None], IB1, 'bob', 'A0')
97
98     >>> registry.lookup((IF1, IR1), IB0, 'bob')
99     'A0'
100     
101     >>> registry.register([None, IR0], IB1, 'bob', 'A1')
102
103     >>> registry.lookup((IF1, IR1), IB0, 'bob')
104     'A1'
105     
106     >>> registry.lookup((IF1, IR1), IB0, 'bruce')
107
108     >>> registry.register([None, IR1], IB1, 'bob', 'A2')
109     >>> registry.lookup((IF1, IR1), IB0, 'bob')
110     'A2'
111     """
112
113 def test_multi_adapter_w_inherited_and_multiple_registrations():
114     """
115     >>> registry = AdapterRegistry()
116
117     >>> class IX(zope.interface.Interface):
118     ...    pass
119
120     >>> registry.register([IF0, IR0], IB1, 'bob', 'A1')
121     >>> registry.register([IF1, IX], IB1, 'bob', 'AX')
122
123     >>> registry.lookup((IF1, IR1), IB0, 'bob')
124     'A1'
125     """
126
127 def test_named_adapter_with_default():
128     """Query a named simple adapter
129
130     >>> registry = AdapterRegistry()
131
132     If we ask for a named adapter, we won't get a result unless there
133     is a named adapter, even if the object implements the interface:
134
135     >>> registry.lookup([IF1], IF0, 'bob')
136
137     >>> registry.register([None], IB1, 'bob', 'A1')
138     >>> registry.lookup([IF1], IB0, 'bob')
139     'A1'
140
141     >>> registry.lookup([IF1], IB0, 'bruce')
142
143     >>> registry.register([None], IB0, 'bob', 'A2')
144     >>> registry.lookup([IF1], IB0, 'bob')
145     'A2'
146     """
147
148 def test_multi_adapter_gets_closest_provided():
149     """
150     >>> registry = AdapterRegistry()
151     >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
152     >>> registry.register((IF1, IR0), IB1, 'bob', 'A2')
153     >>> registry.lookup((IF1, IR1), IB0, 'bob')
154     'A1'
155
156     >>> registry = AdapterRegistry()
157     >>> registry.register([IF1, IR0], IB1, 'bob', 'A2')
158     >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
159     >>> registry.lookup([IF1, IR0], IB0, 'bob')
160     'A1'
161
162     >>> registry = AdapterRegistry()
163     >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
164     >>> registry.register([IF1, IR1], IB1, 'bob', 'A2')
165     >>> registry.lookup([IF1, IR1], IB0, 'bob')
166     'A2'
167
168     >>> registry = AdapterRegistry()
169     >>> registry.register([IF1, IR1], IB1, 'bob', 2)
170     >>> registry.register([IF1, IR0], IB0, 'bob', 1)
171     >>> registry.lookup([IF1, IR1], IB0, 'bob')
172     2
173     """
174
175 def test_multi_adapter_check_non_default_dont_hide_default():
176     """
177     >>> registry = AdapterRegistry()
178
179     >>> class IX(zope.interface.Interface):
180     ...     pass
181
182
183     >>> registry.register([None, IR0], IB0, 'bob', 1)
184     >>> registry.register([IF1,   IX], IB0, 'bob', 2)
185     >>> registry.lookup([IF1, IR1], IB0, 'bob')
186     1
187     """
188
189 def test_adapter_hook_with_factory_producing_None():
190     """
191     >>> registry = AdapterRegistry()
192     >>> default = object()
193     
194     >>> class Object1(object):
195     ...     zope.interface.implements(IF0)
196     >>> class Object2(object):
197     ...     zope.interface.implements(IF0)
198
199     >>> def factory(context):
200     ...     if isinstance(context, Object1):
201     ...         return 'adapter'
202     ...     return None
203
204     >>> registry.register([IF0], IB0, '', factory)
205
206     >>> registry.adapter_hook(IB0, Object1())
207     'adapter'
208     >>> registry.adapter_hook(IB0, Object2()) is None
209     True
210     >>> registry.adapter_hook(IB0, Object2(), default=default) is default
211     True
212     """
213
214 def test_adapter_registry_update_upon_interface_bases_change():
215     """
216     Let's first create a adapter registry and a simple adaptation hook:
217
218     >>> globalRegistry = AdapterRegistry()
219
220     >>> def _hook(iface, ob, lookup=globalRegistry.lookup1):
221     ...     factory = lookup(zope.interface.providedBy(ob), iface)
222     ...     if factory is None:
223     ...         return None
224     ...     else:
225     ...         return factory(ob)
226
227     >>> zope.interface.interface.adapter_hooks.append(_hook)
228
229     Now we create some interfaces and an implementation:
230
231     >>> class IX(zope.interface.Interface):
232     ...   pass
233
234     >>> class IY(zope.interface.Interface):
235     ...   pass
236
237     >>> class X(object):
238     ...  pass
239
240     >>> class Y(object):
241     ...  zope.interface.implements(IY)
242     ...  def __init__(self, original):
243     ...   self.original=original
244
245     and register an adapter:
246
247     >>> globalRegistry.register((IX,), IY, '', Y)
248
249     at first, we still expect the adapter lookup from `X` to `IY` to fail:
250
251     >>> IY(X()) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
252     Traceback (most recent call last):
253     ...
254     TypeError: ('Could not adapt',
255                 <zope.interface.tests.test_adapter.X object at ...>,
256                 <InterfaceClass zope.interface.tests.test_adapter.IY>)
257
258     But after we declare an interface on the class `X`, it should pass:
259
260     >>> zope.interface.classImplementsOnly(X, IX)
261
262     >>> IY(X()) #doctest: +ELLIPSIS
263     <zope.interface.tests.test_adapter.Y object at ...>
264
265     >>> hook = zope.interface.interface.adapter_hooks.pop()
266     """
267
268
269 def test_changing_declarations():
270     """
271
272     If we change declarations for a class, those adapter lookup should
273     eflect the changes:
274
275     >>> class I1(zope.interface.Interface):
276     ...     pass
277     >>> class I2(zope.interface.Interface):
278     ...     pass
279
280     >>> registry = AdapterRegistry()
281     >>> registry.register([I1], I2, '', 42)
282
283     >>> class C:
284     ...     pass
285
286     >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
287
288     >>> zope.interface.classImplements(C, I1)
289
290     >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
291     42
292     """
293
294 def test_correct_multi_adapter_lookup():
295     """
296     >>> registry = AdapterRegistry()
297     >>> registry.register([IF0, IB1], IR0, '', 'A01')
298     >>> registry.register([IF1, IB0], IR0, '', 'A10')
299     >>> registry.lookup((IF1, IB1), IR0, '')
300     'A10'
301     """
302
303 def test_duplicate_bases():
304     """
305 There was a bug that caused problems if a spec had multiple bases:
306
307     >>> class I(zope.interface.Interface):
308     ...     pass
309     >>> class I2(I, I):
310     ...     pass
311     >>> registry = AdapterRegistry()
312     >>> registry.register([I2], IR0, 'x', 'X')
313     >>> registry.lookup((I2, ), IR0, 'x')
314     'X'
315     >>> registry.register([I2], IR0, 'y', 'Y')
316     >>> registry.lookup((I2, ), IR0, 'x')
317     'X'
318     >>> registry.lookup((I2, ), IR0, 'y')
319     'Y'
320 """
321
322 def test_register_objects_with_cmp():
323     """
324     The registry should never use == as that will tend to fail when
325     objects are picky about what they are compared with:
326
327     >>> class Picky:
328     ...     def __cmp__(self, other):
329     ...         raise TypeError("I\'m too picky for comparison!")
330     >>> class I(zope.interface.Interface):
331     ...     pass
332     >>> class I2(I, I):
333     ...     pass
334
335     >>> registry = AdapterRegistry()
336     >>> picky = Picky()
337     >>> registry.register([I2], IR0, '', picky)
338     >>> registry.unregister([I2], IR0, '', picky)
339
340     >>> registry.subscribe([I2], IR0, picky)
341     >>> registry.unsubscribe([I2], IR0, picky)
342
343     """
344
345 def test_unregister_cleans_up_empties():
346     """
347     >>> class I(zope.interface.Interface):
348     ...     pass
349     >>> class IP(zope.interface.Interface):
350     ...     pass
351     >>> class C(object):
352     ...     pass
353
354     >>> registry = AdapterRegistry()
355
356     >>> registry.register([], IP, '', C)
357     >>> registry.register([I], IP, '', C)
358     >>> registry.register([I], IP, 'name', C)
359     >>> registry.register([I, I], IP, '', C)
360     >>> len(registry._adapters)
361     3
362     >>> map(len, registry._adapters)
363     [1, 1, 1]
364
365     >>> registry.unregister([], IP, '', C)
366     >>> registry.unregister([I], IP, '', C)
367     >>> registry.unregister([I], IP, 'name', C)
368     >>> registry.unregister([I, I], IP, '', C)
369     >>> registry._adapters
370     []
371
372     """
373
374 def test_unsubscribe_cleans_up_empties():
375     """
376     >>> class I1(zope.interface.Interface):
377     ...     pass
378     >>> class I2(zope.interface.Interface):
379     ...     pass
380     >>> class IP(zope.interface.Interface):
381     ...     pass
382
383     >>> registry = AdapterRegistry()
384     >>> def handler(event):
385     ...     pass
386
387     >>> registry.subscribe([I1], I1, handler)
388     >>> registry.subscribe([I2], I1, handler)
389     >>> len(registry._subscribers)
390     2
391     >>> map(len, registry._subscribers)
392     [0, 2]
393
394     >>> registry.unsubscribe([I1], I1, handler)
395     >>> registry.unsubscribe([I2], I1, handler)
396     >>> registry._subscribers
397     []
398
399     """
400
401
402 def test_suite():
403     return unittest.TestSuite((
404         doctest.DocFileSuite('../adapter.txt', '../adapter.ru.txt',
405                                  '../human.txt', '../human.ru.txt',
406                                  'foodforthought.txt',
407                                  globs={'__name__': '__main__'}),
408         doctest.DocTestSuite(),
409         ))
410
411 if __name__ == '__main__':
412     unittest.main(defaultTest='test_suite')