5 from gi.repository import GObject
10 class TestGObjectAPI(unittest.TestCase):
11 def testGObjectModule(self):
12 obj = GObject.GObject()
14 self.assertEqual(obj.__module__,
15 'gi._gobject._gobject')
18 class TestReferenceCounting(unittest.TestCase):
19 def testRegularObject(self):
20 obj = GObject.GObject()
21 self.assertEqual(obj.__grefcount__, 1)
23 obj = GObject.new(GObject.GObject)
24 self.assertEqual(obj.__grefcount__, 1)
26 def testFloating(self):
27 obj = testhelper.Floating()
28 self.assertEqual(obj.__grefcount__, 1)
30 obj = GObject.new(testhelper.Floating)
31 self.assertEqual(obj.__grefcount__, 1)
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)
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.
44 self.assertEqual(obj.__grefcount__, 1)
46 def testOwnedByLibraryOutOfScope(self):
47 obj = testhelper.OwnedByLibrary()
48 self.assertEqual(obj.__grefcount__, 2)
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()
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)
62 self.assertEqual(obj.__grefcount__, 1)
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)
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.
75 self.assertEqual(obj.__grefcount__, 1)
77 def testOwnedByLibraryOutOfScopeUsingGobjectNew(self):
78 obj = GObject.new(testhelper.OwnedByLibrary)
79 self.assertEqual(obj.__grefcount__, 2)
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()
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)
93 self.assertEqual(obj.__grefcount__, 1)
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)
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.
106 self.assertEqual(obj.__grefcount__, 1)
108 def testFloatingAndSunkOutOfScope(self):
109 obj = testhelper.FloatingAndSunk()
110 self.assertEqual(obj.__grefcount__, 2)
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()
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)
124 self.assertEqual(obj.__grefcount__, 1)
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)
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.
137 self.assertEqual(obj.__grefcount__, 1)
139 def testFloatingAndSunkOutOfScopeUsingGObjectNew(self):
140 obj = GObject.new(testhelper.FloatingAndSunk)
141 self.assertEqual(obj.__grefcount__, 2)
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()
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)
155 self.assertEqual(obj.__grefcount__, 1)
157 def testUninitializedObject(self):
158 class Obj(GObject.GObject):
160 x = self.__grefcount__
161 super(Obj, self).__init__()
162 assert x >= 0 # quiesce pyflakes
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)
169 class A(GObject.GObject):
171 super(A, self).__init__()
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.
178 def testNewInstanceHasTwoRefs(self):
179 obj = GObject.GObject()
180 self.assertEqual(sys.getrefcount(obj), 2)
182 def testNewInstanceHasTwoRefsUsingGObjectNew(self):
183 obj = GObject.new(GObject.GObject)
184 self.assertEqual(sys.getrefcount(obj), 2)
186 def testNewSubclassInstanceHasTwoRefs(self):
188 self.assertEqual(sys.getrefcount(obj), 2)
190 def testNewSubclassInstanceHasTwoRefsUsingGObjectNew(self):
192 self.assertEqual(sys.getrefcount(obj), 2)
195 class TestContextManagers(unittest.TestCase):
196 class ContextTestObject(GObject.GObject):
197 prop = GObject.Property(default=0, type=int)
199 def on_prop_set(self, obj, prop):
200 # Handler which tracks property changed notifications.
201 self.tracking.append(obj.get_property(prop.name))
205 self.obj = self.ContextTestObject()
206 self.handler = self.obj.connect('notify::prop', self.on_prop_set)
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)
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])
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)
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)
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])
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)
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, [])
262 with self.obj.freeze_notify():
263 self.obj.props.prop = 2
264 self.assertEqual(self.tracking, [])
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, [])
272 # Finally after last context, the notifications should have collapsed
273 # and the last one sent.
274 self.assertEqual(self.tracking, [3])
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, [])
282 with self.obj.handler_block(self.handler):
283 self.obj.props.prop = 2
284 self.assertEqual(self.tracking, [])
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, [])
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, [])
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)
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)
313 def testFreezeNotifyContextError(self):
314 # Test an exception occurring within a freeze context exits the context
316 with self.obj.freeze_notify():
317 self.obj.props.prop = 1
318 self.assertEqual(self.tracking, [])
319 raise ValueError('Simulation')
323 # Verify the property set within the context called notify.
324 self.assertEqual(self.obj.props.prop, 1)
325 self.assertEqual(self.tracking, [1])
327 # Verify we are still not in a frozen context.
328 self.obj.props.prop = 2
329 self.assertEqual(self.tracking, [1, 2])
331 def testHandlerBlockContextError(self):
332 # Test an exception occurring within a handler block exits the context
334 with self.obj.handler_block(self.handler):
335 self.obj.props.prop = 1
336 self.assertEqual(self.tracking, [])
337 raise ValueError('Simulation')
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, [])
345 # Verify we are still not in a handler block context.
346 self.obj.props.prop = 2
347 self.assertEqual(self.tracking, [2])
349 if __name__ == '__main__':