5a4284e67d1b1202efcf457faa7ba79248afeb89
[platform/upstream/pygobject2.git] / tests / test_gobject.py
1 # -*- Mode: Python -*-
2
3 import unittest
4
5 from gi.repository import GObject
6 import sys
7 import testhelper
8
9
10 class TestGObjectAPI(unittest.TestCase):
11     def testGObjectModule(self):
12         obj = GObject.GObject()
13
14         self.assertEqual(obj.__module__,
15                           'gi._gobject._gobject')
16
17
18 class TestReferenceCounting(unittest.TestCase):
19     def testRegularObject(self):
20         obj = GObject.GObject()
21         self.assertEqual(obj.__grefcount__, 1)
22
23         obj = GObject.new(GObject.GObject)
24         self.assertEqual(obj.__grefcount__, 1)
25
26     def testFloating(self):
27         obj = testhelper.Floating()
28         self.assertEqual(obj.__grefcount__, 1)
29
30         obj = GObject.new(testhelper.Floating)
31         self.assertEqual(obj.__grefcount__, 1)
32
33     def testOwnedByLibrary(self):
34         # Upon creation, the refcount of the object should be 2:
35         # - someone already has a reference on the new object.
36         # - the python wrapper should hold its own reference.
37         obj = testhelper.OwnedByLibrary()
38         self.assertEqual(obj.__grefcount__, 2)
39
40         # We ask the library to release its reference, so the only
41         # remaining ref should be our wrapper's. Once the wrapper
42         # will run out of scope, the object will get finalized.
43         obj.release()
44         self.assertEqual(obj.__grefcount__, 1)
45
46     def testOwnedByLibraryOutOfScope(self):
47         obj = testhelper.OwnedByLibrary()
48         self.assertEqual(obj.__grefcount__, 2)
49
50         # We are manually taking the object out of scope. This means
51         # that our wrapper has been freed, and its reference dropped. We
52         # cannot check it but the refcount should now be 1 (the ref held
53         # by the library is still there, we didn't call release()
54         obj = None
55
56         # When we get the object back from the lib, the wrapper is
57         # re-created, so our refcount will be 2 once again.
58         obj = testhelper.owned_by_library_get_instance_list()[0]
59         self.assertEqual(obj.__grefcount__, 2)
60
61         obj.release()
62         self.assertEqual(obj.__grefcount__, 1)
63
64     def testOwnedByLibraryUsingGObjectNew(self):
65         # Upon creation, the refcount of the object should be 2:
66         # - someone already has a reference on the new object.
67         # - the python wrapper should hold its own reference.
68         obj = GObject.new(testhelper.OwnedByLibrary)
69         self.assertEqual(obj.__grefcount__, 2)
70
71         # We ask the library to release its reference, so the only
72         # remaining ref should be our wrapper's. Once the wrapper
73         # will run out of scope, the object will get finalized.
74         obj.release()
75         self.assertEqual(obj.__grefcount__, 1)
76
77     def testOwnedByLibraryOutOfScopeUsingGobjectNew(self):
78         obj = GObject.new(testhelper.OwnedByLibrary)
79         self.assertEqual(obj.__grefcount__, 2)
80
81         # We are manually taking the object out of scope. This means
82         # that our wrapper has been freed, and its reference dropped. We
83         # cannot check it but the refcount should now be 1 (the ref held
84         # by the library is still there, we didn't call release()
85         obj = None
86
87         # When we get the object back from the lib, the wrapper is
88         # re-created, so our refcount will be 2 once again.
89         obj = testhelper.owned_by_library_get_instance_list()[0]
90         self.assertEqual(obj.__grefcount__, 2)
91
92         obj.release()
93         self.assertEqual(obj.__grefcount__, 1)
94
95     def testFloatingAndSunk(self):
96         # Upon creation, the refcount of the object should be 2:
97         # - someone already has a reference on the new object.
98         # - the python wrapper should hold its own reference.
99         obj = testhelper.FloatingAndSunk()
100         self.assertEqual(obj.__grefcount__, 2)
101
102         # We ask the library to release its reference, so the only
103         # remaining ref should be our wrapper's. Once the wrapper
104         # will run out of scope, the object will get finalized.
105         obj.release()
106         self.assertEqual(obj.__grefcount__, 1)
107
108     def testFloatingAndSunkOutOfScope(self):
109         obj = testhelper.FloatingAndSunk()
110         self.assertEqual(obj.__grefcount__, 2)
111
112         # We are manually taking the object out of scope. This means
113         # that our wrapper has been freed, and its reference dropped. We
114         # cannot check it but the refcount should now be 1 (the ref held
115         # by the library is still there, we didn't call release()
116         obj = None
117
118         # When we get the object back from the lib, the wrapper is
119         # re-created, so our refcount will be 2 once again.
120         obj = testhelper.floating_and_sunk_get_instance_list()[0]
121         self.assertEqual(obj.__grefcount__, 2)
122
123         obj.release()
124         self.assertEqual(obj.__grefcount__, 1)
125
126     def testFloatingAndSunkUsingGObjectNew(self):
127         # Upon creation, the refcount of the object should be 2:
128         # - someone already has a reference on the new object.
129         # - the python wrapper should hold its own reference.
130         obj = GObject.new(testhelper.FloatingAndSunk)
131         self.assertEqual(obj.__grefcount__, 2)
132
133         # We ask the library to release its reference, so the only
134         # remaining ref should be our wrapper's. Once the wrapper
135         # will run out of scope, the object will get finalized.
136         obj.release()
137         self.assertEqual(obj.__grefcount__, 1)
138
139     def testFloatingAndSunkOutOfScopeUsingGObjectNew(self):
140         obj = GObject.new(testhelper.FloatingAndSunk)
141         self.assertEqual(obj.__grefcount__, 2)
142
143         # We are manually taking the object out of scope. This means
144         # that our wrapper has been freed, and its reference dropped. We
145         # cannot check it but the refcount should now be 1 (the ref held
146         # by the library is still there, we didn't call release()
147         obj = None
148
149         # When we get the object back from the lib, the wrapper is
150         # re-created, so our refcount will be 2 once again.
151         obj = testhelper.floating_and_sunk_get_instance_list()[0]
152         self.assertEqual(obj.__grefcount__, 2)
153
154         obj.release()
155         self.assertEqual(obj.__grefcount__, 1)
156
157     def testUninitializedObject(self):
158         class Obj(GObject.GObject):
159             def __init__(self):
160                 x = self.__grefcount__
161                 super(Obj, self).__init__()
162                 assert x >= 0  # quiesce pyflakes
163
164         # Accessing __grefcount__ before the object is initialized is wrong.
165         # Ensure we get a proper exception instead of a crash.
166         self.assertRaises(TypeError, Obj)
167
168
169 class A(GObject.GObject):
170     def __init__(self):
171         super(A, self).__init__()
172
173
174 class TestPythonReferenceCounting(unittest.TestCase):
175     # Newly created instances should alwayshave two references: one for
176     # the GC, and one for the bound variable in the local scope.
177
178     def testNewInstanceHasTwoRefs(self):
179         obj = GObject.GObject()
180         self.assertEqual(sys.getrefcount(obj), 2)
181
182     def testNewInstanceHasTwoRefsUsingGObjectNew(self):
183         obj = GObject.new(GObject.GObject)
184         self.assertEqual(sys.getrefcount(obj), 2)
185
186     def testNewSubclassInstanceHasTwoRefs(self):
187         obj = A()
188         self.assertEqual(sys.getrefcount(obj), 2)
189
190     def testNewSubclassInstanceHasTwoRefsUsingGObjectNew(self):
191         obj = GObject.new(A)
192         self.assertEqual(sys.getrefcount(obj), 2)
193
194
195 class TestContextManagers(unittest.TestCase):
196     class ContextTestObject(GObject.GObject):
197         prop = GObject.Property(default=0, type=int)
198
199     def on_prop_set(self, obj, prop):
200         # Handler which tracks property changed notifications.
201         self.tracking.append(obj.get_property(prop.name))
202
203     def setUp(self):
204         self.tracking = []
205         self.obj = self.ContextTestObject()
206         self.handler = self.obj.connect('notify::prop', self.on_prop_set)
207
208     def testFreezeNotifyContext(self):
209         # Verify prop tracking list
210         self.assertEqual(self.tracking, [])
211         self.obj.props.prop = 1
212         self.assertEqual(self.tracking, [1])
213         self.obj.props.prop = 2
214         self.assertEqual(self.tracking, [1, 2])
215         self.assertEqual(self.obj.__grefcount__, 1)
216
217         # Using the context manager the tracking list should not be affected
218         # and the GObject reference count should go up.
219         with self.obj.freeze_notify():
220             self.assertEqual(self.obj.__grefcount__, 2)
221             self.obj.props.prop = 3
222             self.assertEqual(self.obj.props.prop, 3)
223             self.assertEqual(self.tracking, [1, 2])
224
225         # After the context manager, the prop should have been modified,
226         # the tracking list will be modified, and the GObject ref
227         # count goes back down.
228         self.assertEqual(self.obj.props.prop, 3)
229         self.assertEqual(self.tracking, [1, 2, 3])
230         self.assertEqual(self.obj.__grefcount__, 1)
231
232     def testHandlerBlockContext(self):
233         # Verify prop tracking list
234         self.assertEqual(self.tracking, [])
235         self.obj.props.prop = 1
236         self.assertEqual(self.tracking, [1])
237         self.obj.props.prop = 2
238         self.assertEqual(self.tracking, [1, 2])
239         self.assertEqual(self.obj.__grefcount__, 1)
240
241         # Using the context manager the tracking list should not be affected
242         # and the GObject reference count should go up.
243         with self.obj.handler_block(self.handler):
244             self.assertEqual(self.obj.__grefcount__, 2)
245             self.obj.props.prop = 3
246             self.assertEqual(self.obj.props.prop, 3)
247             self.assertEqual(self.tracking, [1, 2])
248
249         # After the context manager, the prop should have been modified
250         # the tracking list should have stayed the same and the GObject ref
251         # count goes back down.
252         self.assertEqual(self.obj.props.prop, 3)
253         self.assertEqual(self.tracking, [1, 2])
254         self.assertEqual(self.obj.__grefcount__, 1)
255
256     def testFreezeNotifyContextNested(self):
257         self.assertEqual(self.tracking, [])
258         with self.obj.freeze_notify():
259             self.obj.props.prop = 1
260             self.assertEqual(self.tracking, [])
261
262             with self.obj.freeze_notify():
263                 self.obj.props.prop = 2
264                 self.assertEqual(self.tracking, [])
265
266                 with self.obj.freeze_notify():
267                     self.obj.props.prop = 3
268                     self.assertEqual(self.tracking, [])
269                 self.assertEqual(self.tracking, [])
270             self.assertEqual(self.tracking, [])
271
272         # Finally after last context, the notifications should have collapsed
273         # and the last one sent.
274         self.assertEqual(self.tracking, [3])
275
276     def testHandlerBlockContextNested(self):
277         self.assertEqual(self.tracking, [])
278         with self.obj.handler_block(self.handler):
279             self.obj.props.prop = 1
280             self.assertEqual(self.tracking, [])
281
282             with self.obj.handler_block(self.handler):
283                 self.obj.props.prop = 2
284                 self.assertEqual(self.tracking, [])
285
286                 with self.obj.handler_block(self.handler):
287                     self.obj.props.prop = 3
288                     self.assertEqual(self.tracking, [])
289                 self.assertEqual(self.tracking, [])
290             self.assertEqual(self.tracking, [])
291
292         # Finally after last context, the notifications should have collapsed
293         # and the last one sent.
294         self.assertEqual(self.obj.props.prop, 3)
295         self.assertEqual(self.tracking, [])
296
297     def testFreezeNotifyNormalUsageRefCounts(self):
298         # Ensure ref counts without using methods as context managers
299         # maintain the same count.
300         self.assertEqual(self.obj.__grefcount__, 1)
301         self.obj.freeze_notify()
302         self.assertEqual(self.obj.__grefcount__, 1)
303         self.obj.thaw_notify()
304         self.assertEqual(self.obj.__grefcount__, 1)
305
306     def testHandlerBlockNormalUsageRefCounts(self):
307         self.assertEqual(self.obj.__grefcount__, 1)
308         self.obj.handler_block(self.handler)
309         self.assertEqual(self.obj.__grefcount__, 1)
310         self.obj.handler_unblock(self.handler)
311         self.assertEqual(self.obj.__grefcount__, 1)
312
313     def testFreezeNotifyContextError(self):
314         # Test an exception occurring within a freeze context exits the context
315         try:
316             with self.obj.freeze_notify():
317                 self.obj.props.prop = 1
318                 self.assertEqual(self.tracking, [])
319                 raise ValueError('Simulation')
320         except ValueError:
321             pass
322
323         # Verify the property set within the context called notify.
324         self.assertEqual(self.obj.props.prop, 1)
325         self.assertEqual(self.tracking, [1])
326
327         # Verify we are still not in a frozen context.
328         self.obj.props.prop = 2
329         self.assertEqual(self.tracking, [1, 2])
330
331     def testHandlerBlockContextError(self):
332         # Test an exception occurring within a handler block exits the context
333         try:
334             with self.obj.handler_block(self.handler):
335                 self.obj.props.prop = 1
336                 self.assertEqual(self.tracking, [])
337                 raise ValueError('Simulation')
338         except ValueError:
339             pass
340
341         # Verify the property set within the context didn't call notify.
342         self.assertEqual(self.obj.props.prop, 1)
343         self.assertEqual(self.tracking, [])
344
345         # Verify we are still not in a handler block context.
346         self.obj.props.prop = 2
347         self.assertEqual(self.tracking, [2])
348
349 if __name__ == '__main__':
350     unittest.main()