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