54afd11913fb961336714e6690cbbda26747d044
[platform/upstream/pygobject2.git] / tests / test_properties.py
1 # coding=utf-8
2
3 import sys
4 import struct
5 import unittest
6
7 import gobject
8 from gobject import GObject, GType, GEnum, new, PARAM_READWRITE, \
9      PARAM_CONSTRUCT, PARAM_READABLE, PARAM_WRITABLE, PARAM_CONSTRUCT_ONLY
10 from gobject.constants import \
11      TYPE_INT, TYPE_UINT, TYPE_LONG, \
12      TYPE_ULONG, TYPE_INT64, TYPE_UINT64
13 from gobject.constants import \
14      G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, \
15      G_MAXULONG
16
17 if sys.version_info < (3, 0):
18     TEST_UTF8 = "\xe2\x99\xa5"
19     UNICODE_UTF8 = unicode(TEST_UTF8, 'UTF-8')
20 else:
21     TEST_UTF8 = "♥"
22     UNICODE_UTF8 = TEST_UTF8
23
24 from compathelper import _long
25
26 class PropertyObject(GObject):
27     normal = gobject.property(type=str)
28     construct = gobject.property(
29         type=str,
30         flags=PARAM_READWRITE|PARAM_CONSTRUCT, default='default')
31     construct_only = gobject.property(
32         type=str,
33         flags=PARAM_READWRITE|PARAM_CONSTRUCT_ONLY)
34     uint64 = gobject.property(
35         type=TYPE_UINT64, flags=PARAM_READWRITE|PARAM_CONSTRUCT)
36
37 class TestProperties(unittest.TestCase):
38     def testGetSet(self):
39         obj = PropertyObject()
40         obj.props.normal = "value"
41         self.assertEqual(obj.props.normal, "value")
42
43     def testListWithInstance(self):
44         obj = PropertyObject()
45         self.failUnless(hasattr(obj.props, "normal"))
46
47     def testListWithoutInstance(self):
48         self.failUnless(hasattr(PropertyObject.props, "normal"))
49
50     def testSetNoInstance(self):
51         def set(obj):
52             obj.props.normal = "foobar"
53
54         self.assertRaises(TypeError, set, PropertyObject)
55
56     def testIterator(self):
57         for obj in (PropertyObject.props, PropertyObject().props):
58             for pspec in obj:
59                 gtype = GType(pspec)
60                 self.assertEqual(gtype.parent.name, 'GParam')
61                 self.failUnless(pspec.name in ['normal',
62                                                'construct',
63                                                'construct-only',
64                                                'uint64'])
65             self.assertEqual(len(obj), 4)
66
67     def testNormal(self):
68         obj = new(PropertyObject, normal="123")
69         self.assertEqual(obj.props.normal, "123")
70         obj.set_property('normal', '456')
71         self.assertEqual(obj.props.normal, "456")
72         obj.props.normal = '789'
73         self.assertEqual(obj.props.normal, "789")
74
75     def testConstruct(self):
76         obj = new(PropertyObject, construct="123")
77         self.assertEqual(obj.props.construct, "123")
78         obj.set_property('construct', '456')
79         self.assertEqual(obj.props.construct, "456")
80         obj.props.construct = '789'
81         self.assertEqual(obj.props.construct, "789")
82    
83     def testUTF8(self):
84         obj = new(PropertyObject, construct_only=UNICODE_UTF8)
85         self.assertEqual(obj.props.construct_only, TEST_UTF8)
86         obj.set_property('construct', UNICODE_UTF8)
87         self.assertEqual(obj.props.construct, TEST_UTF8)
88         obj.props.normal = UNICODE_UTF8
89         self.assertEqual(obj.props.normal, TEST_UTF8)
90
91     def testIntToStr(self):
92         obj = new(PropertyObject, construct_only=1)
93         self.assertEqual(obj.props.construct_only, '1')
94         obj.set_property('construct', '2')
95         self.assertEqual(obj.props.construct, '2')
96         obj.props.normal = 3
97         self.assertEqual(obj.props.normal, '3')
98
99     def testConstructOnly(self):
100         obj = new(PropertyObject, construct_only="123")
101         self.assertEqual(obj.props.construct_only, "123")
102         self.assertRaises(TypeError,
103                           setattr, obj.props, 'construct_only', '456')
104         self.assertRaises(TypeError,
105                           obj.set_property, 'construct-only', '456')
106
107     def testUint64(self):
108         obj = new(PropertyObject)
109         self.assertEqual(obj.props.uint64, 0)
110         obj.props.uint64 = _long(1)
111         self.assertEqual(obj.props.uint64, _long(1))
112         obj.props.uint64 = 1
113         self.assertEqual(obj.props.uint64, _long(1))
114
115         self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", _long(-1))
116         self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1)
117
118     def testUInt64DefaultValue(self):
119         try:
120             class TimeControl(GObject):
121                 __gproperties__ = {
122                     'time': (TYPE_UINT64, 'Time', 'Time',
123                              _long(0), (1<<64) - 1, _long(0),
124                              PARAM_READABLE)
125                     }
126         except OverflowError:
127             (etype, ex) = sys.exc_info()[2:]
128             self.fail(str(ex))
129
130     def testRange(self):
131         # kiwi code
132         def max(c):
133             return 2 ** ((8 * struct.calcsize(c)) - 1) - 1
134         def umax(c):
135             return 2 ** (8 * struct.calcsize(c)) - 1
136
137         maxint = max('i')
138         minint = -maxint - 1
139         maxuint = umax('I')
140         maxlong = max('l')
141         minlong = -maxlong - 1
142         maxulong = umax('L')
143         maxint64 = max('q')
144         minint64 = -maxint64 - 1
145         maxuint64 = umax('Q')
146
147         types = dict(int=(TYPE_INT, minint, maxint),
148                      uint=(TYPE_UINT, 0, maxuint),
149                      long=(TYPE_LONG, minlong, maxlong),
150                      ulong=(TYPE_ULONG, 0, maxulong),
151                      int64=(TYPE_INT64, minint64, maxint64),
152                      uint64=(TYPE_UINT64, 0, maxuint64))
153
154         def build_gproperties(types):
155             d = {}
156             for key, (gtype, min, max) in types.items():
157                 d[key] = (gtype, 'blurb', 'desc', min, max, 0,
158                           PARAM_READABLE | PARAM_WRITABLE)
159             return d
160
161         class RangeCheck(GObject):
162             __gproperties__ = build_gproperties(types)
163
164             def __init__(self):
165                 self.values = {}
166                 GObject.__init__(self)
167
168             def do_set_property(self, pspec, value):
169                 self.values[pspec.name] = value
170
171             def do_get_property(self, pspec):
172                 return self.values.get(pspec.name, pspec.default_value)
173
174         self.assertEqual(RangeCheck.props.int.minimum, minint)
175         self.assertEqual(RangeCheck.props.int.maximum, maxint)
176         self.assertEqual(RangeCheck.props.uint.minimum, 0)
177         self.assertEqual(RangeCheck.props.uint.maximum, maxuint)
178         self.assertEqual(RangeCheck.props.long.minimum, minlong)
179         self.assertEqual(RangeCheck.props.long.maximum, maxlong)
180         self.assertEqual(RangeCheck.props.ulong.minimum, 0)
181         self.assertEqual(RangeCheck.props.ulong.maximum, maxulong)
182         self.assertEqual(RangeCheck.props.int64.minimum, minint64)
183         self.assertEqual(RangeCheck.props.int64.maximum, maxint64)
184         self.assertEqual(RangeCheck.props.uint64.minimum, 0)
185         self.assertEqual(RangeCheck.props.uint64.maximum, maxuint64)
186
187         obj = RangeCheck()
188         for key, (gtype, min, max) in types.items():
189             self.assertEqual(obj.get_property(key),
190                              getattr(RangeCheck.props, key).default_value)
191
192             obj.set_property(key, min)
193             self.assertEqual(obj.get_property(key), min)
194
195             obj.set_property(key, max)
196             self.assertEqual(obj.get_property(key), max)
197
198
199     def testMulti(self):
200         obj = PropertyObject()
201         obj.set_properties(normal="foo",
202                            uint64=7)
203         normal, uint64 = obj.get_properties("normal", "uint64")
204         self.assertEqual(normal, "foo")
205         self.assertEqual(uint64, 7)
206
207 class TestProperty(unittest.TestCase):
208     def testSimple(self):
209         class C(gobject.GObject):
210             str = gobject.property(type=str)
211             int = gobject.property(type=int)
212             float = gobject.property(type=float)
213             long = gobject.property(type=_long)
214
215         self.failUnless(hasattr(C.props, 'str'))
216         self.failUnless(hasattr(C.props, 'int'))
217         self.failUnless(hasattr(C.props, 'float'))
218         self.failUnless(hasattr(C.props, 'long'))
219
220         o = C()
221         self.assertEqual(o.str, '')
222         o.str = 'str'
223         self.assertEqual(o.str, 'str')
224
225         self.assertEqual(o.int, 0)
226         o.int = 1138
227         self.assertEqual(o.int, 1138)
228
229         self.assertEqual(o.float, 0.0)
230         o.float = 3.14
231         self.assertEqual(o.float, 3.14)
232
233         self.assertEqual(o.long, _long(0))
234         o.long = _long(100)
235         self.assertEqual(o.long, _long(100))
236
237     def testCustomGetter(self):
238         class C(gobject.GObject):
239             def get_prop(self):
240                 return 'value'
241             prop = gobject.property(getter=get_prop)
242
243         o = C()
244         self.assertEqual(o.prop, 'value')
245         self.assertRaises(TypeError, setattr, o, 'prop', 'xxx')
246
247     def testCustomSetter(self):
248         class C(gobject.GObject):
249             def set_prop(self, value):
250                 self._value = value
251             prop = gobject.property(setter=set_prop)
252
253             def __init__(self):
254                 self._value = None
255                 gobject.GObject.__init__(self)
256
257         o = C()
258         self.assertEquals(o._value, None)
259         o.prop = 'bar'
260         self.assertEquals(o._value, 'bar')
261         self.assertRaises(TypeError, getattr, o, 'prop')
262
263     def testErrors(self):
264         self.assertRaises(TypeError, gobject.property, type='str')
265         self.assertRaises(TypeError, gobject.property, nick=False)
266         self.assertRaises(TypeError, gobject.property, blurb=False)
267         # this never fail while bool is a subclass of int
268         # >>> bool.__bases__
269         # (<type 'int'>,)
270         # self.assertRaises(TypeError, gobject.property, type=bool, default=0)
271         self.assertRaises(TypeError, gobject.property, type=bool, default='ciao mamma')
272         self.assertRaises(TypeError, gobject.property, type=bool)
273         self.assertRaises(TypeError, gobject.property, type=GEnum)
274         self.assertRaises(TypeError, gobject.property, type=GEnum, default=0)
275         self.assertRaises(TypeError, gobject.property, type=object, default=0)
276         self.assertRaises(TypeError, gobject.property, type=complex)
277         self.assertRaises(TypeError, gobject.property, flags=-10)
278
279     def testDefaults(self):
280         p1 = gobject.property(type=bool, default=True)
281         p2 = gobject.property(type=bool, default=False)
282
283     def testNameWithUnderscore(self):
284         class C(gobject.GObject):
285             prop_name = gobject.property(type=int)
286         o = C()
287         o.prop_name = 10
288         self.assertEqual(o.prop_name, 10)
289
290     def testRange(self):
291         maxint64 = 2 ** 62 - 1
292         minint64 = -2 ** 62 - 1
293         maxuint64 = 2 ** 63 - 1
294
295         types = [
296             (TYPE_INT, G_MININT, G_MAXINT),
297             (TYPE_UINT, 0, G_MAXUINT),
298             (TYPE_LONG, G_MINLONG, G_MAXLONG),
299             (TYPE_ULONG, 0, G_MAXULONG),
300             (TYPE_INT64, minint64, maxint64),
301             (TYPE_UINT64, 0, maxuint64),
302             ]
303
304         for gtype, min, max in types:
305             # Normal, everything is alright
306             prop = gobject.property(type=gtype, minimum=min, maximum=max)
307             subtype = type('', (gobject.GObject,),
308                          dict(prop=prop))
309             self.assertEqual(subtype.props.prop.minimum, min)
310             self.assertEqual(subtype.props.prop.maximum, max)
311
312             # Lower than minimum
313             self.assertRaises(TypeError,
314                               gobject.property, type=gtype, minimum=min-1,
315                               maximum=max)
316
317             # Higher than maximum
318             self.assertRaises(TypeError,
319                               gobject.property, type=gtype, minimum=min,
320                               maximum=max+1)
321
322     def testMultipleInstances(self):
323         class C(gobject.GObject):
324             prop = gobject.property(type=str, default='default')
325
326         o1 = C()
327         o2 = C()
328         self.assertEqual(o1.prop, 'default')
329         self.assertEqual(o2.prop, 'default')
330         o1.prop = 'value'
331         self.assertEqual(o1.prop, 'value')
332         self.assertEqual(o2.prop, 'default')
333
334     def testObjectProperty(self):
335         class PropertyObject(GObject):
336             obj = gobject.property(type=GObject)
337
338         pobj1 = PropertyObject()
339         obj1_hash = hash(pobj1)
340         pobj2 = PropertyObject()
341
342         pobj2.obj = pobj1
343         del pobj1
344         pobj1 = pobj2.obj
345         self.assertEqual(hash(pobj1), obj1_hash)
346
347     def testObjectSubclassProperty(self):
348         class ObjectSubclass(GObject):
349             __gtype_name__ = 'ObjectSubclass'
350
351         class PropertyObjectSubclass(GObject):
352             obj = gobject.property(type=ObjectSubclass)
353
354         obj1 = PropertyObjectSubclass(obj=ObjectSubclass())
355
356     def testPropertySubclass(self):
357         # test for #470718
358         class A(GObject):
359             prop1 = gobject.property(type=int)
360
361         class B(A):
362             prop2 = gobject.property(type=int)
363
364         b = B()
365         b.prop2 = 10
366         self.assertEquals(b.prop2, 10)
367         b.prop1 = 20
368         self.assertEquals(b.prop1, 20)
369
370     def testPropertySubclassCustomSetter(self):
371         # test for #523352
372         class A(GObject):
373             def get_first(self):
374                 return 'first'
375             first = gobject.property(type=str, getter=get_first)
376
377         class B(A):
378             def get_second(self):
379                 return 'second'
380             second = gobject.property(type=str, getter=get_second)
381
382         a = A()
383         self.assertEquals(a.first, 'first')
384         self.assertRaises(TypeError, setattr, a, 'first', 'foo')
385
386         b = B()
387         self.assertEquals(b.first, 'first')
388         self.assertRaises(TypeError, setattr, b, 'first', 'foo')
389         self.assertEquals(b.second, 'second')
390         self.assertRaises(TypeError, setattr, b, 'second', 'foo')
391
392     def testPropertySubclassCustomSetterError(self):
393         try:
394             class A(GObject):
395                 def get_first(self):
396                     return 'first'
397                 first = gobject.property(type=str, getter=get_first)
398
399                 def do_get_property(self, pspec):
400                     pass
401         except TypeError:
402             pass
403         else:
404             raise AssertionError
405
406     # Bug 587637.
407     def test_float_min(self):
408         gobject.property(type=float, minimum=-1)
409         gobject.property(type=gobject.TYPE_FLOAT, minimum=-1)
410         gobject.property(type=gobject.TYPE_DOUBLE, minimum=-1)
411
412     # Bug 644039
413     def testReferenceCount(self):
414         # We can check directly if an object gets finalized, so we will
415         # observe it indirectly through the refcount of a member object.
416
417         # We create our dummy object and store its current refcount
418         o = object()
419         rc = sys.getrefcount(o)
420
421         # We add our object as a member to our newly created object we
422         # want to observe. Its refcount is increased by one.
423         t = PropertyObject(normal="test")
424         t.o = o
425         self.assertEquals(sys.getrefcount(o), rc + 1)
426
427         # Now we want to ensure we do not leak any references to our
428         # object with properties. If no ref is leaked, then when deleting
429         # the local reference to this object, its reference count shoud
430         # drop to zero, and our dummy object should loose one reference.
431         del t
432         self.assertEquals(sys.getrefcount(o), rc)
433
434
435 if __name__ == '__main__':
436     unittest.main()