Imported Upstream version 3.21.91
[platform/upstream/python-gobject.git] / tests / test_properties.py
1 # coding=utf-8
2
3 import gc
4 import sys
5 import struct
6 import types
7 import unittest
8
9 import gi
10 from gi.repository import GObject
11 from gi.repository.GObject import ParamFlags, GType, new
12 from gi.repository.GObject import \
13     TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_INT64, \
14     TYPE_UINT64, TYPE_GTYPE, TYPE_INVALID, TYPE_NONE, TYPE_STRV, \
15     TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, TYPE_BOOLEAN, TYPE_FLOAT, \
16     TYPE_DOUBLE, TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \
17     TYPE_STRING, TYPE_PYOBJECT, TYPE_VARIANT
18
19 from gi.repository.GLib import \
20     MININT, MAXINT, MAXUINT, MINLONG, MAXLONG, MAXULONG, \
21     MAXUINT64, MAXINT64, MININT64
22
23 from gi.repository import Gio
24 from gi.repository import GLib
25 gi.require_version('GIMarshallingTests', '1.0')
26 from gi.repository import GIMarshallingTests
27 from gi import _propertyhelper as propertyhelper
28
29 try:
30     gi.require_version('Regress', '1.0')
31     from gi.repository import Regress
32     has_regress = True
33 except (ValueError, ImportError):
34     has_regress = False
35
36 if sys.version_info < (3, 0):
37     TEST_UTF8 = "\xe2\x99\xa5"
38     UNICODE_UTF8 = unicode(TEST_UTF8, 'UTF-8')
39 else:
40     TEST_UTF8 = "♥"
41     UNICODE_UTF8 = TEST_UTF8
42
43 from compathelper import _long, _unicode
44 from helper import capture_glib_warnings, capture_output
45
46
47 class PropertyObject(GObject.GObject):
48     normal = GObject.Property(type=str)
49     construct = GObject.Property(
50         type=str,
51         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT,
52         default='default')
53
54     construct_only = GObject.Property(
55         type=str,
56         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT_ONLY)
57
58     uint64 = GObject.Property(
59         type=TYPE_UINT64,
60         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
61
62     enum = GObject.Property(
63         type=Gio.SocketType, default=Gio.SocketType.STREAM)
64
65     boxed = GObject.Property(
66         type=GLib.Regex,
67         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
68
69     flags = GObject.Property(
70         type=GIMarshallingTests.Flags,
71         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT,
72         default=GIMarshallingTests.Flags.VALUE1)
73
74     gtype = GObject.Property(
75         type=TYPE_GTYPE,
76         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
77
78     strings = GObject.Property(
79         type=TYPE_STRV,
80         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
81
82     variant = GObject.Property(
83         type=TYPE_VARIANT,
84         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
85
86     variant_def = GObject.Property(
87         type=TYPE_VARIANT,
88         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT,
89         default=GLib.Variant('i', 42))
90
91     interface = GObject.Property(
92         type=Gio.File,
93         flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
94
95
96 if has_regress:
97     class PropertyInheritanceObject(Regress.TestObj):
98         # override property from the base class, with a different type
99         string = GObject.Property(type=int)
100
101         # a property entirely defined at the Python level
102         python_prop = GObject.Property(type=str)
103
104     class PropertySubClassObject(PropertyInheritanceObject):
105         # override property from the base class, with a different type
106         python_prop = GObject.Property(type=int)
107
108
109 @unittest.skipUnless(has_regress, 'Missing Regress typelib')
110 class TestPropertyInheritanceObject(unittest.TestCase):
111     def test_override_gi_property(self):
112         self.assertNotEqual(Regress.TestObj.props.string.value_type,
113                             PropertyInheritanceObject.props.string.value_type)
114         obj = PropertyInheritanceObject()
115         self.assertEqual(type(obj.props.string), int)
116         obj.props.string = 4
117         self.assertEqual(obj.props.string, 4)
118
119     def test_override_python_property(self):
120         obj = PropertySubClassObject()
121         self.assertEqual(type(obj.props.python_prop), int)
122         obj.props.python_prop = 5
123         self.assertEqual(obj.props.python_prop, 5)
124
125
126 class TestPropertyObject(unittest.TestCase):
127     def test_get_set(self):
128         obj = PropertyObject()
129         obj.props.normal = "value"
130         self.assertEqual(obj.props.normal, "value")
131
132     def test_hasattr_on_object(self):
133         obj = PropertyObject()
134         self.assertTrue(hasattr(obj.props, "normal"))
135
136     def test_hasattr_on_class(self):
137         self.assertTrue(hasattr(PropertyObject.props, "normal"))
138
139     def test_set_on_class(self):
140         def set(obj):
141             obj.props.normal = "foobar"
142
143         self.assertRaises(TypeError, set, PropertyObject)
144
145     def test_iteration(self):
146         for obj in (PropertyObject.props, PropertyObject().props):
147             names = []
148             for pspec in obj:
149                 gtype = GType(pspec)
150                 self.assertEqual(gtype.parent.name, 'GParam')
151                 names.append(pspec.name)
152
153             names.sort()
154             self.assertEqual(names, ['boxed',
155                                      'construct',
156                                      'construct-only',
157                                      'enum',
158                                      'flags',
159                                      'gtype',
160                                      'interface',
161                                      'normal',
162                                      'strings',
163                                      'uint64',
164                                      'variant',
165                                      'variant-def'])
166
167     def test_normal(self):
168         obj = new(PropertyObject, normal="123")
169         self.assertEqual(obj.props.normal, "123")
170         obj.set_property('normal', '456')
171         self.assertEqual(obj.props.normal, "456")
172         obj.props.normal = '789'
173         self.assertEqual(obj.props.normal, "789")
174
175     def test_construct(self):
176         obj = new(PropertyObject, construct="123")
177         self.assertEqual(obj.props.construct, "123")
178         obj.set_property('construct', '456')
179         self.assertEqual(obj.props.construct, "456")
180         obj.props.construct = '789'
181         self.assertEqual(obj.props.construct, "789")
182
183     def test_utf8(self):
184         obj = new(PropertyObject, construct_only=UNICODE_UTF8)
185         self.assertEqual(obj.props.construct_only, TEST_UTF8)
186         obj.set_property('construct', UNICODE_UTF8)
187         self.assertEqual(obj.props.construct, TEST_UTF8)
188         obj.props.normal = UNICODE_UTF8
189         self.assertEqual(obj.props.normal, TEST_UTF8)
190
191     def test_int_to_str(self):
192         obj = new(PropertyObject, construct_only=1)
193         self.assertEqual(obj.props.construct_only, '1')
194         obj.set_property('construct', '2')
195         self.assertEqual(obj.props.construct, '2')
196         obj.props.normal = 3
197         self.assertEqual(obj.props.normal, '3')
198
199     def test_construct_only(self):
200         obj = new(PropertyObject, construct_only="123")
201         self.assertEqual(obj.props.construct_only, "123")
202         self.assertRaises(TypeError,
203                           setattr, obj.props, 'construct_only', '456')
204         self.assertRaises(TypeError,
205                           obj.set_property, 'construct-only', '456')
206
207     def test_uint64(self):
208         obj = new(PropertyObject)
209         self.assertEqual(obj.props.uint64, 0)
210         obj.props.uint64 = _long(1)
211         self.assertEqual(obj.props.uint64, _long(1))
212         obj.props.uint64 = 1
213         self.assertEqual(obj.props.uint64, _long(1))
214
215         self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", _long(-1))
216         self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1)
217
218     def test_uint64_default_value(self):
219         try:
220             class TimeControl(GObject.GObject):
221                 __gproperties__ = {
222                     'time': (TYPE_UINT64, 'Time', 'Time',
223                              _long(0), (1 << 64) - 1, _long(0),
224                              ParamFlags.READABLE)
225                     }
226         except OverflowError:
227             (etype, ex) = sys.exc_info()[2:]
228             self.fail(str(ex))
229
230     def test_enum(self):
231         obj = new(PropertyObject)
232         self.assertEqual(obj.props.enum, Gio.SocketType.STREAM)
233         self.assertEqual(obj.enum, Gio.SocketType.STREAM)
234         obj.enum = Gio.SocketType.DATAGRAM
235         self.assertEqual(obj.props.enum, Gio.SocketType.DATAGRAM)
236         self.assertEqual(obj.enum, Gio.SocketType.DATAGRAM)
237         obj.props.enum = Gio.SocketType.STREAM
238         self.assertEqual(obj.props.enum, Gio.SocketType.STREAM)
239         self.assertEqual(obj.enum, Gio.SocketType.STREAM)
240         obj.props.enum = 2
241         self.assertEqual(obj.props.enum, Gio.SocketType.DATAGRAM)
242         self.assertEqual(obj.enum, Gio.SocketType.DATAGRAM)
243         obj.enum = 1
244         self.assertEqual(obj.props.enum, Gio.SocketType.STREAM)
245         self.assertEqual(obj.enum, Gio.SocketType.STREAM)
246
247         self.assertRaises(TypeError, setattr, obj, 'enum', 'foo')
248         self.assertRaises(TypeError, setattr, obj, 'enum', object())
249
250         self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType)
251         self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType,
252                           default=Gio.SocketProtocol.TCP)
253         self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType,
254                           default=object())
255         self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType,
256                           default=1)
257
258     def test_flags(self):
259         obj = new(PropertyObject)
260         self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE1)
261         self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE1)
262
263         obj.flags = GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3
264         self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3)
265         self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3)
266
267         self.assertRaises(TypeError, setattr, obj, 'flags', 'foo')
268         self.assertRaises(TypeError, setattr, obj, 'flags', object())
269         self.assertRaises(TypeError, setattr, obj, 'flags', None)
270
271         self.assertRaises(TypeError, GObject.Property,
272                           type=GIMarshallingTests.Flags, default='foo')
273         self.assertRaises(TypeError, GObject.Property,
274                           type=GIMarshallingTests.Flags, default=object())
275         self.assertRaises(TypeError, GObject.Property,
276                           type=GIMarshallingTests.Flags, default=None)
277
278     def test_gtype(self):
279         obj = new(PropertyObject)
280
281         self.assertEqual(obj.props.gtype, TYPE_NONE)
282         self.assertEqual(obj.gtype, TYPE_NONE)
283
284         obj.gtype = TYPE_UINT64
285         self.assertEqual(obj.props.gtype, TYPE_UINT64)
286         self.assertEqual(obj.gtype, TYPE_UINT64)
287
288         obj.gtype = TYPE_INVALID
289         self.assertEqual(obj.props.gtype, TYPE_INVALID)
290         self.assertEqual(obj.gtype, TYPE_INVALID)
291
292         # GType parameters do not support defaults in GLib
293         self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE,
294                           default=TYPE_INT)
295
296         # incompatible type
297         self.assertRaises(TypeError, setattr, obj, 'gtype', 'foo')
298         self.assertRaises(TypeError, setattr, obj, 'gtype', object())
299
300         self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE,
301                           default='foo')
302         self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE,
303                           default=object())
304
305         # set in constructor
306         obj = new(PropertyObject, gtype=TYPE_UINT)
307         self.assertEqual(obj.props.gtype, TYPE_UINT)
308         self.assertEqual(obj.gtype, TYPE_UINT)
309
310     def test_boxed(self):
311         obj = new(PropertyObject)
312
313         regex = GLib.Regex.new('[a-z]*', 0, 0)
314         obj.props.boxed = regex
315         self.assertEqual(obj.props.boxed.get_pattern(), '[a-z]*')
316         self.assertEqual(obj.boxed.get_pattern(), '[a-z]*')
317
318         self.assertRaises(TypeError, setattr, obj, 'boxed', 'foo')
319         self.assertRaises(TypeError, setattr, obj, 'boxed', object())
320
321     def test_strings(self):
322         obj = new(PropertyObject)
323
324         # Should work with actual GStrv objects as well as
325         # Python string lists
326         class GStrv(list):
327             __gtype__ = GObject.TYPE_STRV
328
329         self.assertEqual(obj.props.strings, GStrv([]))
330         self.assertEqual(obj.strings, GStrv([]))
331         self.assertEqual(obj.props.strings, [])
332         self.assertEqual(obj.strings, [])
333
334         obj.strings = ['hello', 'world']
335         self.assertEqual(obj.props.strings, ['hello', 'world'])
336         self.assertEqual(obj.strings, ['hello', 'world'])
337
338         obj.strings = GStrv(['hello', 'world'])
339         self.assertEqual(obj.props.strings, GStrv(['hello', 'world']))
340         self.assertEqual(obj.strings, GStrv(['hello', 'world']))
341
342         obj.strings = []
343         self.assertEqual(obj.strings, [])
344         obj.strings = GStrv([])
345         self.assertEqual(obj.strings, GStrv([]))
346
347         p = GObject.Property(type=TYPE_STRV, default=['hello', '1'])
348         self.assertEqual(p.default, ['hello', '1'])
349         self.assertEqual(p.type, TYPE_STRV)
350         p = GObject.Property(type=TYPE_STRV, default=GStrv(['hello', '1']))
351         self.assertEqual(p.default, ['hello', '1'])
352         self.assertEqual(p.type, TYPE_STRV)
353
354         # set in constructor
355         obj = new(PropertyObject, strings=['hello', 'world'])
356         self.assertEqual(obj.props.strings, ['hello', 'world'])
357         self.assertEqual(obj.strings, ['hello', 'world'])
358
359         # wrong types
360         self.assertRaises(TypeError, setattr, obj, 'strings', 1)
361         self.assertRaises(TypeError, setattr, obj, 'strings', 'foo')
362         self.assertRaises(TypeError, setattr, obj, 'strings', ['foo', 1])
363
364         self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV,
365                           default=1)
366         self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV,
367                           default='foo')
368         self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV,
369                           default=['hello', 1])
370
371     def test_variant(self):
372         obj = new(PropertyObject)
373
374         self.assertEqual(obj.props.variant, None)
375         self.assertEqual(obj.variant, None)
376
377         obj.variant = GLib.Variant('s', 'hello')
378         self.assertEqual(obj.variant.print_(True), "'hello'")
379
380         obj.variant = GLib.Variant('b', True)
381         self.assertEqual(obj.variant.print_(True), "true")
382
383         obj.props.variant = GLib.Variant('y', 2)
384         self.assertEqual(obj.variant.print_(True), "byte 0x02")
385
386         obj.variant = None
387         self.assertEqual(obj.variant, None)
388
389         # set in constructor
390         obj = new(PropertyObject, variant=GLib.Variant('u', 5))
391         self.assertEqual(obj.props.variant.print_(True), 'uint32 5')
392
393         GObject.Property(type=TYPE_VARIANT, default=GLib.Variant('i', 1))
394
395         # incompatible types
396         self.assertRaises(TypeError, setattr, obj, 'variant', 'foo')
397         self.assertRaises(TypeError, setattr, obj, 'variant', 42)
398
399         self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT,
400                           default='foo')
401         self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT,
402                           default=object())
403
404     def test_variant_default(self):
405         obj = new(PropertyObject)
406
407         self.assertEqual(obj.props.variant_def.print_(True), '42')
408         self.assertEqual(obj.variant_def.print_(True), '42')
409
410         obj.props.variant_def = GLib.Variant('y', 2)
411         self.assertEqual(obj.variant_def.print_(True), "byte 0x02")
412
413         # set in constructor
414         obj = new(PropertyObject, variant_def=GLib.Variant('u', 5))
415         self.assertEqual(obj.props.variant_def.print_(True), 'uint32 5')
416
417     def test_interface(self):
418         obj = new(PropertyObject)
419
420         file = Gio.File.new_for_path('/some/path')
421         obj.props.interface = file
422         self.assertEqual(obj.props.interface.get_path(), '/some/path')
423         self.assertEqual(obj.interface.get_path(), '/some/path')
424
425         self.assertRaises(TypeError, setattr, obj, 'interface', 'foo')
426         self.assertRaises(TypeError, setattr, obj, 'interface', object())
427
428     def test_range(self):
429         # kiwi code
430         def max(c):
431             return 2 ** ((8 * struct.calcsize(c)) - 1) - 1
432
433         def umax(c):
434             return 2 ** (8 * struct.calcsize(c)) - 1
435
436         maxint = max('i')
437         minint = -maxint - 1
438         maxuint = umax('I')
439         maxlong = max('l')
440         minlong = -maxlong - 1
441         maxulong = umax('L')
442         maxint64 = max('q')
443         minint64 = -maxint64 - 1
444         maxuint64 = umax('Q')
445
446         types_ = dict(int=(TYPE_INT, minint, maxint),
447                       uint=(TYPE_UINT, 0, maxuint),
448                       long=(TYPE_LONG, minlong, maxlong),
449                       ulong=(TYPE_ULONG, 0, maxulong),
450                       int64=(TYPE_INT64, minint64, maxint64),
451                       uint64=(TYPE_UINT64, 0, maxuint64))
452
453         def build_gproperties(types_):
454             d = {}
455             for key, (gtype, min, max) in types_.items():
456                 d[key] = (gtype, 'blurb', 'desc', min, max, 0,
457                           ParamFlags.READABLE | ParamFlags.WRITABLE)
458             return d
459
460         class RangeCheck(GObject.GObject):
461             __gproperties__ = build_gproperties(types_)
462
463             def __init__(self):
464                 self.values = {}
465                 GObject.GObject.__init__(self)
466
467             def do_set_property(self, pspec, value):
468                 self.values[pspec.name] = value
469
470             def do_get_property(self, pspec):
471                 return self.values.get(pspec.name, pspec.default_value)
472
473         self.assertEqual(RangeCheck.props.int.minimum, minint)
474         self.assertEqual(RangeCheck.props.int.maximum, maxint)
475         self.assertEqual(RangeCheck.props.uint.minimum, 0)
476         self.assertEqual(RangeCheck.props.uint.maximum, maxuint)
477         self.assertEqual(RangeCheck.props.long.minimum, minlong)
478         self.assertEqual(RangeCheck.props.long.maximum, maxlong)
479         self.assertEqual(RangeCheck.props.ulong.minimum, 0)
480         self.assertEqual(RangeCheck.props.ulong.maximum, maxulong)
481         self.assertEqual(RangeCheck.props.int64.minimum, minint64)
482         self.assertEqual(RangeCheck.props.int64.maximum, maxint64)
483         self.assertEqual(RangeCheck.props.uint64.minimum, 0)
484         self.assertEqual(RangeCheck.props.uint64.maximum, maxuint64)
485
486         obj = RangeCheck()
487         for key, (gtype, min, max) in types_.items():
488             self.assertEqual(obj.get_property(key),
489                              getattr(RangeCheck.props, key).default_value)
490
491             obj.set_property(key, min)
492             self.assertEqual(obj.get_property(key), min)
493
494             obj.set_property(key, max)
495             self.assertEqual(obj.get_property(key), max)
496
497     def test_multi(self):
498         obj = PropertyObject()
499         obj.set_properties(normal="foo",
500                            uint64=7)
501         normal, uint64 = obj.get_properties("normal", "uint64")
502         self.assertEqual(normal, "foo")
503         self.assertEqual(uint64, 7)
504
505
506 class TestProperty(unittest.TestCase):
507     def test_simple(self):
508         class C(GObject.GObject):
509             str = GObject.Property(type=str)
510             int = GObject.Property(type=int)
511             float = GObject.Property(type=float)
512             long = GObject.Property(type=_long)
513
514         self.assertTrue(hasattr(C.props, 'str'))
515         self.assertTrue(hasattr(C.props, 'int'))
516         self.assertTrue(hasattr(C.props, 'float'))
517         self.assertTrue(hasattr(C.props, 'long'))
518
519         o = C()
520         self.assertEqual(o.str, '')
521         o.str = 'str'
522         self.assertEqual(o.str, 'str')
523
524         self.assertEqual(o.int, 0)
525         o.int = 1138
526         self.assertEqual(o.int, 1138)
527
528         self.assertEqual(o.float, 0.0)
529         o.float = 3.14
530         self.assertEqual(o.float, 3.14)
531
532         self.assertEqual(o.long, _long(0))
533         o.long = _long(100)
534         self.assertEqual(o.long, _long(100))
535
536     def test_custom_getter(self):
537         class C(GObject.GObject):
538             def get_prop(self):
539                 return 'value'
540             prop = GObject.Property(getter=get_prop)
541
542         o = C()
543         self.assertEqual(o.prop, 'value')
544         self.assertRaises(TypeError, setattr, o, 'prop', 'xxx')
545
546     @unittest.expectedFailure  # https://bugzilla.gnome.org/show_bug.cgi?id=575652
547     def test_getter_exception(self):
548         class C(GObject.Object):
549             @GObject.Property(type=int)
550             def prop(self):
551                 raise ValueError('something bad happend')
552
553         o = C()
554
555         # silence exception printed to stderr
556         with capture_output():
557             with self.assertRaisesRegex(ValueError, 'something bad happend'):
558                 o.prop
559
560             with self.assertRaisesRegex(ValueError, 'something bad happend'):
561                 o.get_property('prop')
562
563             with self.assertRaisesRegex(ValueError, 'something bad happend'):
564                 o.props.prop
565
566     def test_custom_setter(self):
567         class C(GObject.GObject):
568             def set_prop(self, value):
569                 self._value = value
570             prop = GObject.Property(setter=set_prop)
571
572             def __init__(self):
573                 self._value = None
574                 GObject.GObject.__init__(self)
575
576         o = C()
577         self.assertEqual(o._value, None)
578         o.prop = 'bar'
579         self.assertEqual(o._value, 'bar')
580         self.assertRaises(TypeError, getattr, o, 'prop')
581
582     def test_decorator_default(self):
583         class C(GObject.GObject):
584             _value = 'value'
585
586             @GObject.Property
587             def value(self):
588                 return self._value
589
590             @value.setter
591             def value_setter(self, value):
592                 self._value = value
593
594         o = C()
595         self.assertEqual(o.value, 'value')
596         o.value = 'blah'
597         self.assertEqual(o.value, 'blah')
598         self.assertEqual(o.props.value, 'blah')
599
600     def test_decorator_private_setter(self):
601         class C(GObject.GObject):
602             _value = 'value'
603
604             @GObject.Property
605             def value(self):
606                 return self._value
607
608             @value.setter
609             def _set_value(self, value):
610                 self._value = value
611
612         o = C()
613         self.assertEqual(o.value, 'value')
614         o.value = 'blah'
615         self.assertEqual(o.value, 'blah')
616         self.assertEqual(o.props.value, 'blah')
617
618     def test_decorator_with_call(self):
619         class C(GObject.GObject):
620             _value = 1
621
622             @GObject.Property(type=int, default=1, minimum=1, maximum=10)
623             def typedValue(self):
624                 return self._value
625
626             @typedValue.setter
627             def typedValue_setter(self, value):
628                 self._value = value
629
630         o = C()
631         self.assertEqual(o.typedValue, 1)
632         o.typedValue = 5
633         self.assertEqual(o.typedValue, 5)
634         self.assertEqual(o.props.typedValue, 5)
635
636     def test_errors(self):
637         self.assertRaises(TypeError, GObject.Property, type='str')
638         self.assertRaises(TypeError, GObject.Property, nick=False)
639         self.assertRaises(TypeError, GObject.Property, blurb=False)
640         # this never fail while bool is a subclass of int
641         # >>> bool.__bases__
642         # (<type 'int'>,)
643         # self.assertRaises(TypeError, GObject.Property, type=bool, default=0)
644         self.assertRaises(TypeError, GObject.Property, type=bool, default='ciao mamma')
645         self.assertRaises(TypeError, GObject.Property, type=bool)
646         self.assertRaises(TypeError, GObject.Property, type=object, default=0)
647         self.assertRaises(TypeError, GObject.Property, type=complex)
648
649     def test_defaults(self):
650         GObject.Property(type=bool, default=True)
651         GObject.Property(type=bool, default=False)
652
653     def test_name_with_underscore(self):
654         class C(GObject.GObject):
655             prop_name = GObject.Property(type=int)
656         o = C()
657         o.prop_name = 10
658         self.assertEqual(o.prop_name, 10)
659
660     def test_range(self):
661         types_ = [
662             (TYPE_INT, MININT, MAXINT),
663             (TYPE_UINT, 0, MAXUINT),
664             (TYPE_LONG, MINLONG, MAXLONG),
665             (TYPE_ULONG, 0, MAXULONG),
666             (TYPE_INT64, MININT64, MAXINT64),
667             (TYPE_UINT64, 0, MAXUINT64),
668             ]
669
670         for gtype, min, max in types_:
671             # Normal, everything is alright
672             prop = GObject.Property(type=gtype, minimum=min, maximum=max)
673             subtype = type('', (GObject.GObject,), dict(prop=prop))
674             self.assertEqual(subtype.props.prop.minimum, min)
675             self.assertEqual(subtype.props.prop.maximum, max)
676
677             # Lower than minimum
678             self.assertRaises(TypeError,
679                               GObject.Property, type=gtype, minimum=min - 1,
680                               maximum=max)
681
682             # Higher than maximum
683             self.assertRaises(TypeError,
684                               GObject.Property, type=gtype, minimum=min,
685                               maximum=max + 1)
686
687     def test_min_max(self):
688         class C(GObject.GObject):
689             prop_int = GObject.Property(type=int, minimum=1, maximum=100, default=1)
690             prop_float = GObject.Property(type=float, minimum=0.1, maximum=10.5, default=1.1)
691
692             def __init__(self):
693                 GObject.GObject.__init__(self)
694
695         # we test known-bad values here which cause Gtk-WARNING logs.
696         # Explicitly allow these for this test.
697         with capture_glib_warnings(allow_warnings=True):
698             o = C()
699             self.assertEqual(o.prop_int, 1)
700
701             o.prop_int = 5
702             self.assertEqual(o.prop_int, 5)
703
704             o.prop_int = 0
705             self.assertEqual(o.prop_int, 5)
706
707             o.prop_int = 101
708             self.assertEqual(o.prop_int, 5)
709
710             self.assertEqual(o.prop_float, 1.1)
711
712             o.prop_float = 7.75
713             self.assertEqual(o.prop_float, 7.75)
714
715             o.prop_float = 0.09
716             self.assertEqual(o.prop_float, 7.75)
717
718             o.prop_float = 10.51
719             self.assertEqual(o.prop_float, 7.75)
720
721     def test_multiple_instances(self):
722         class C(GObject.GObject):
723             prop = GObject.Property(type=str, default='default')
724
725         o1 = C()
726         o2 = C()
727         self.assertEqual(o1.prop, 'default')
728         self.assertEqual(o2.prop, 'default')
729         o1.prop = 'value'
730         self.assertEqual(o1.prop, 'value')
731         self.assertEqual(o2.prop, 'default')
732
733     def test_object_property(self):
734         class PropertyObject(GObject.GObject):
735             obj = GObject.Property(type=GObject.GObject)
736
737         pobj1 = PropertyObject()
738         obj1_hash = hash(pobj1)
739         pobj2 = PropertyObject()
740
741         pobj2.obj = pobj1
742         del pobj1
743         pobj1 = pobj2.obj
744         self.assertEqual(hash(pobj1), obj1_hash)
745
746     def test_object_subclass_property(self):
747         class ObjectSubclass(GObject.GObject):
748             __gtype_name__ = 'ObjectSubclass'
749
750         class PropertyObjectSubclass(GObject.GObject):
751             obj = GObject.Property(type=ObjectSubclass)
752
753         PropertyObjectSubclass(obj=ObjectSubclass())
754
755     def test_property_subclass(self):
756         # test for #470718
757         class A(GObject.GObject):
758             prop1 = GObject.Property(type=int)
759
760         class B(A):
761             prop2 = GObject.Property(type=int)
762
763         b = B()
764         b.prop2 = 10
765         self.assertEqual(b.prop2, 10)
766         b.prop1 = 20
767         self.assertEqual(b.prop1, 20)
768
769     @unittest.skipUnless(has_regress, 'Missing regress typelib')
770     def test_property_subclass_c(self):
771         class A(Regress.TestSubObj):
772             prop1 = GObject.Property(type=int)
773
774         a = A()
775         a.prop1 = 10
776         self.assertEqual(a.prop1, 10)
777
778         # also has parent properties
779         a.props.int = 20
780         self.assertEqual(a.props.int, 20)
781
782         # Some of which are unusable without introspection
783         a.props.list = ("str1", "str2")
784         self.assertEqual(a.props.list, ["str1", "str2"])
785
786         a.set_property("list", ("str3", "str4"))
787         self.assertEqual(a.props.list, ["str3", "str4"])
788
789     def test_property_subclass_custom_setter(self):
790         # test for #523352
791         class A(GObject.GObject):
792             def get_first(self):
793                 return 'first'
794             first = GObject.Property(type=str, getter=get_first)
795
796         class B(A):
797             def get_second(self):
798                 return 'second'
799             second = GObject.Property(type=str, getter=get_second)
800
801         a = A()
802         self.assertEqual(a.first, 'first')
803         self.assertRaises(TypeError, setattr, a, 'first', 'foo')
804
805         b = B()
806         self.assertEqual(b.first, 'first')
807         self.assertRaises(TypeError, setattr, b, 'first', 'foo')
808         self.assertEqual(b.second, 'second')
809         self.assertRaises(TypeError, setattr, b, 'second', 'foo')
810
811     def test_property_subclass_custom_setter_error(self):
812         try:
813             class A(GObject.GObject):
814                 def get_first(self):
815                     return 'first'
816                 first = GObject.Property(type=str, getter=get_first)
817
818                 def do_get_property(self, pspec):
819                     pass
820         except TypeError:
821             pass
822         else:
823             raise AssertionError
824
825     # Bug 587637.
826
827     def test_float_min(self):
828         GObject.Property(type=float, minimum=-1)
829         GObject.Property(type=GObject.TYPE_FLOAT, minimum=-1)
830         GObject.Property(type=GObject.TYPE_DOUBLE, minimum=-1)
831
832     # Bug 644039
833
834     def test_reference_count(self):
835         # We can check directly if an object gets finalized, so we will
836         # observe it indirectly through the refcount of a member object.
837
838         # We create our dummy object and store its current refcount
839         o = object()
840         rc = sys.getrefcount(o)
841
842         # We add our object as a member to our newly created object we
843         # want to observe. Its refcount is increased by one.
844         t = PropertyObject(normal="test")
845         t.o = o
846         self.assertEqual(sys.getrefcount(o), rc + 1)
847
848         # Now we want to ensure we do not leak any references to our
849         # object with properties. If no ref is leaked, then when deleting
850         # the local reference to this object, its reference count shoud
851         # drop to zero, and our dummy object should loose one reference.
852         del t
853         self.assertEqual(sys.getrefcount(o), rc)
854
855     def test_doc_strings(self):
856         class C(GObject.GObject):
857             foo_blurbed = GObject.Property(type=int, blurb='foo_blurbed doc string')
858
859             @GObject.Property
860             def foo_getter(self):
861                 """foo_getter doc string"""
862                 return 0
863
864         self.assertEqual(C.foo_blurbed.blurb, 'foo_blurbed doc string')
865         self.assertEqual(C.foo_blurbed.__doc__, 'foo_blurbed doc string')
866
867         self.assertEqual(C.foo_getter.blurb, 'foo_getter doc string')
868         self.assertEqual(C.foo_getter.__doc__, 'foo_getter doc string')
869
870     def test_python_to_glib_type_mapping(self):
871         tester = GObject.Property()
872         self.assertEqual(tester._type_from_python(int), GObject.TYPE_INT)
873         if sys.version_info < (3, 0):
874             self.assertEqual(tester._type_from_python(long), GObject.TYPE_LONG)
875         self.assertEqual(tester._type_from_python(bool), GObject.TYPE_BOOLEAN)
876         self.assertEqual(tester._type_from_python(float), GObject.TYPE_DOUBLE)
877         self.assertEqual(tester._type_from_python(str), GObject.TYPE_STRING)
878         self.assertEqual(tester._type_from_python(object), GObject.TYPE_PYOBJECT)
879
880         self.assertEqual(tester._type_from_python(GObject.GObject), GObject.GObject.__gtype__)
881         self.assertEqual(tester._type_from_python(GObject.GEnum), GObject.GEnum.__gtype__)
882         self.assertEqual(tester._type_from_python(GObject.GFlags), GObject.GFlags.__gtype__)
883         self.assertEqual(tester._type_from_python(GObject.GBoxed), GObject.GBoxed.__gtype__)
884         self.assertEqual(tester._type_from_python(GObject.GInterface), GObject.GInterface.__gtype__)
885
886         for type_ in [TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR,
887                       TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG,
888                       TYPE_ULONG, TYPE_INT64, TYPE_UINT64,
889                       TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER,
890                       TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING,
891                       TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV]:
892             self.assertEqual(tester._type_from_python(type_), type_)
893
894         self.assertRaises(TypeError, tester._type_from_python, types.CodeType)
895
896
897 class TestInstallProperties(unittest.TestCase):
898     # These tests only test how signalhelper.install_signals works
899     # with the __gsignals__ dict and therefore does not need to use
900     # GObject as a base class because that would automatically call
901     # install_signals within the meta-class.
902     class Base(object):
903         __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)}
904
905     class Sub1(Base):
906         pass
907
908     class Sub2(Base):
909         @GObject.Property(type=int)
910         def sub2test(self):
911             return 123
912
913     class ClassWithPropertyAndGetterVFunc(object):
914         @GObject.Property(type=int)
915         def sub2test(self):
916             return 123
917
918         def do_get_property(self, name):
919             return 321
920
921     class ClassWithPropertyRedefined(object):
922         __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)}
923         test = GObject.Property(type=int)
924
925     def setUp(self):
926         self.assertEqual(len(self.Base.__gproperties__), 1)
927         propertyhelper.install_properties(self.Base)
928         self.assertEqual(len(self.Base.__gproperties__), 1)
929
930     def test_subclass_without_properties_is_not_modified(self):
931         self.assertFalse('__gproperties__' in self.Sub1.__dict__)
932         propertyhelper.install_properties(self.Sub1)
933         self.assertFalse('__gproperties__' in self.Sub1.__dict__)
934
935     def test_subclass_with_decorator_gets_gproperties_dict(self):
936         # Sub2 has Property instances but will not have a __gproperties__
937         # until install_properties is called
938         self.assertFalse('__gproperties__' in self.Sub2.__dict__)
939         self.assertFalse('do_get_property' in self.Sub2.__dict__)
940         self.assertFalse('do_set_property' in self.Sub2.__dict__)
941
942         propertyhelper.install_properties(self.Sub2)
943         self.assertTrue('__gproperties__' in self.Sub2.__dict__)
944         self.assertEqual(len(self.Base.__gproperties__), 1)
945         self.assertEqual(len(self.Sub2.__gproperties__), 1)
946         self.assertTrue('sub2test' in self.Sub2.__gproperties__)
947
948         # get/set vfuncs should have been added
949         self.assertTrue('do_get_property' in self.Sub2.__dict__)
950         self.assertTrue('do_set_property' in self.Sub2.__dict__)
951
952     def test_object_with_property_and_do_get_property_vfunc_raises(self):
953         self.assertRaises(TypeError, propertyhelper.install_properties,
954                           self.ClassWithPropertyAndGetterVFunc)
955
956     def test_same_name_property_definitions_raises(self):
957         self.assertRaises(ValueError, propertyhelper.install_properties,
958                           self.ClassWithPropertyRedefined)
959
960
961 class CPropertiesTestBase(object):
962     # Tests for properties implemented in C not Python.
963
964     def setUp(self):
965         self.obj = GIMarshallingTests.PropertiesObject()
966
967     def get_prop(self, obj, name):
968         raise NotImplementedError
969
970     def set_prop(self, obj, name, value):
971         raise NotImplementedError
972
973     def test_boolean(self):
974         self.assertEqual(self.get_prop(self.obj, 'some-boolean'), False)
975         self.set_prop(self.obj, 'some-boolean', True)
976         self.assertEqual(self.get_prop(self.obj, 'some-boolean'), True)
977
978         obj = GIMarshallingTests.PropertiesObject(some_boolean=True)
979         self.assertEqual(self.get_prop(obj, 'some-boolean'), True)
980
981     def test_char(self):
982         self.assertEqual(self.get_prop(self.obj, 'some-char'), 0)
983         self.set_prop(self.obj, 'some-char', GLib.MAXINT8)
984         self.assertEqual(self.get_prop(self.obj, 'some-char'), GLib.MAXINT8)
985
986         obj = GIMarshallingTests.PropertiesObject(some_char=-42)
987         self.assertEqual(self.get_prop(obj, 'some-char'), -42)
988
989     def test_uchar(self):
990         self.assertEqual(self.get_prop(self.obj, 'some-uchar'), 0)
991         self.set_prop(self.obj, 'some-uchar', GLib.MAXUINT8)
992         self.assertEqual(self.get_prop(self.obj, 'some-uchar'), GLib.MAXUINT8)
993
994         obj = GIMarshallingTests.PropertiesObject(some_uchar=42)
995         self.assertEqual(self.get_prop(obj, 'some-uchar'), 42)
996
997     def test_int(self):
998         self.assertEqual(self.get_prop(self.obj, 'some_int'), 0)
999         self.set_prop(self.obj, 'some-int', GLib.MAXINT)
1000         self.assertEqual(self.get_prop(self.obj, 'some_int'), GLib.MAXINT)
1001
1002         obj = GIMarshallingTests.PropertiesObject(some_int=-42)
1003         self.assertEqual(self.get_prop(obj, 'some-int'), -42)
1004
1005         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', 'foo')
1006         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', None)
1007
1008         self.assertEqual(self.get_prop(obj, 'some-int'), -42)
1009
1010     def test_uint(self):
1011         self.assertEqual(self.get_prop(self.obj, 'some_uint'), 0)
1012         self.set_prop(self.obj, 'some-uint', GLib.MAXUINT)
1013         self.assertEqual(self.get_prop(self.obj, 'some_uint'), GLib.MAXUINT)
1014
1015         obj = GIMarshallingTests.PropertiesObject(some_uint=42)
1016         self.assertEqual(self.get_prop(obj, 'some-uint'), 42)
1017
1018         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', 'foo')
1019         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', None)
1020
1021         self.assertEqual(self.get_prop(obj, 'some-uint'), 42)
1022
1023     def test_long(self):
1024         self.assertEqual(self.get_prop(self.obj, 'some_long'), 0)
1025         self.set_prop(self.obj, 'some-long', GLib.MAXLONG)
1026         self.assertEqual(self.get_prop(self.obj, 'some_long'), GLib.MAXLONG)
1027
1028         obj = GIMarshallingTests.PropertiesObject(some_long=-42)
1029         self.assertEqual(self.get_prop(obj, 'some-long'), -42)
1030
1031         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', 'foo')
1032         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', None)
1033
1034         self.assertEqual(self.get_prop(obj, 'some-long'), -42)
1035
1036     def test_ulong(self):
1037         self.assertEqual(self.get_prop(self.obj, 'some_ulong'), 0)
1038         self.set_prop(self.obj, 'some-ulong', GLib.MAXULONG)
1039         self.assertEqual(self.get_prop(self.obj, 'some_ulong'), GLib.MAXULONG)
1040
1041         obj = GIMarshallingTests.PropertiesObject(some_ulong=42)
1042         self.assertEqual(self.get_prop(obj, 'some-ulong'), 42)
1043
1044         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', 'foo')
1045         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', None)
1046
1047         self.assertEqual(self.get_prop(obj, 'some-ulong'), 42)
1048
1049     def test_int64(self):
1050         self.assertEqual(self.get_prop(self.obj, 'some-int64'), 0)
1051         self.set_prop(self.obj, 'some-int64', GLib.MAXINT64)
1052         self.assertEqual(self.get_prop(self.obj, 'some-int64'), GLib.MAXINT64)
1053
1054         obj = GIMarshallingTests.PropertiesObject(some_int64=-4200000000000000)
1055         self.assertEqual(self.get_prop(obj, 'some-int64'), -4200000000000000)
1056
1057     def test_uint64(self):
1058         self.assertEqual(self.get_prop(self.obj, 'some-uint64'), 0)
1059         self.set_prop(self.obj, 'some-uint64', GLib.MAXUINT64)
1060         self.assertEqual(self.get_prop(self.obj, 'some-uint64'), GLib.MAXUINT64)
1061
1062         obj = GIMarshallingTests.PropertiesObject(some_uint64=4200000000000000)
1063         self.assertEqual(self.get_prop(obj, 'some-uint64'), 4200000000000000)
1064
1065     def test_float(self):
1066         self.assertEqual(self.get_prop(self.obj, 'some-float'), 0)
1067         self.set_prop(self.obj, 'some-float', GLib.MAXFLOAT)
1068         self.assertEqual(self.get_prop(self.obj, 'some-float'), GLib.MAXFLOAT)
1069
1070         obj = GIMarshallingTests.PropertiesObject(some_float=42.42)
1071         self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.42, places=4)
1072
1073         obj = GIMarshallingTests.PropertiesObject(some_float=42)
1074         self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4)
1075
1076         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', 'foo')
1077         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', None)
1078
1079         self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4)
1080
1081     def test_double(self):
1082         self.assertEqual(self.get_prop(self.obj, 'some-double'), 0)
1083         self.set_prop(self.obj, 'some-double', GLib.MAXDOUBLE)
1084         self.assertEqual(self.get_prop(self.obj, 'some-double'), GLib.MAXDOUBLE)
1085
1086         obj = GIMarshallingTests.PropertiesObject(some_double=42.42)
1087         self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.42)
1088
1089         obj = GIMarshallingTests.PropertiesObject(some_double=42)
1090         self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0)
1091
1092         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', 'foo')
1093         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', None)
1094
1095         self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0)
1096
1097     def test_strv(self):
1098         self.assertEqual(self.get_prop(self.obj, 'some-strv'), [])
1099         self.set_prop(self.obj, 'some-strv', ['hello', 'world'])
1100         self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world'])
1101
1102         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 1)
1103         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 'foo')
1104         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', [1, 2])
1105         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', ['foo', 1])
1106
1107         self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world'])
1108
1109         obj = GIMarshallingTests.PropertiesObject(some_strv=['hello', 'world'])
1110         self.assertEqual(self.get_prop(obj, 'some-strv'), ['hello', 'world'])
1111
1112         # unicode on py2
1113         obj = GIMarshallingTests.PropertiesObject(some_strv=[_unicode('foo')])
1114         self.assertEqual(self.get_prop(obj, 'some-strv'), [_unicode('foo')])
1115         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv',
1116                           [_unicode('foo'), 1])
1117
1118     def test_boxed_struct(self):
1119         self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct'), None)
1120
1121         class GStrv(list):
1122             __gtype__ = GObject.TYPE_STRV
1123
1124         struct1 = GIMarshallingTests.BoxedStruct()
1125         struct1.long_ = 1
1126
1127         self.set_prop(self.obj, 'some-boxed-struct', struct1)
1128         self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct').long_, 1)
1129         self.assertEqual(self.obj.some_boxed_struct.long_, 1)
1130
1131         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 1)
1132         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 'foo')
1133
1134         obj = GIMarshallingTests.PropertiesObject(some_boxed_struct=struct1)
1135         self.assertEqual(self.get_prop(obj, 'some-boxed-struct').long_, 1)
1136
1137     def test_boxed_glist(self):
1138         self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), [])
1139
1140         l = [GLib.MININT, 42, GLib.MAXINT]
1141         self.set_prop(self.obj, 'some-boxed-glist', l)
1142         self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), l)
1143         self.set_prop(self.obj, 'some-boxed-glist', [])
1144         self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), [])
1145
1146         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 1)
1147         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 'foo')
1148         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', ['a'])
1149
1150     @unittest.skipUnless(has_regress, 'built without cairo support')
1151     def test_annotated_glist(self):
1152         obj = Regress.TestObj()
1153         self.assertEqual(self.get_prop(obj, 'list'), [])
1154
1155         self.set_prop(obj, 'list', ['1', '2', '3'])
1156         self.assertTrue(isinstance(self.get_prop(obj, 'list'), list))
1157         self.assertEqual(self.get_prop(obj, 'list'), ['1', '2', '3'])
1158
1159     @unittest.expectedFailure
1160     def test_boxed_glist_ctor(self):
1161         l = [GLib.MININT, 42, GLib.MAXINT]
1162         obj = GIMarshallingTests.PropertiesObject(some_boxed_glist=l)
1163         self.assertEqual(self.get_prop(obj, 'some-boxed-glist'), l)
1164
1165     def test_variant(self):
1166         self.assertEqual(self.get_prop(self.obj, 'some-variant'), None)
1167
1168         self.set_prop(self.obj, 'some-variant', GLib.Variant('o', '/myobj'))
1169         self.assertEqual(self.get_prop(self.obj, 'some-variant').get_type_string(), 'o')
1170         self.assertEqual(self.get_prop(self.obj, 'some-variant').print_(False), "'/myobj'")
1171
1172         self.set_prop(self.obj, 'some-variant', None)
1173         self.assertEqual(self.get_prop(self.obj, 'some-variant'), None)
1174
1175         obj = GIMarshallingTests.PropertiesObject(some_variant=GLib.Variant('b', True))
1176         self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b')
1177         self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True)
1178
1179         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 'foo')
1180         self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 23)
1181
1182         self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b')
1183         self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True)
1184
1185     def test_setting_several_properties(self):
1186         obj = GIMarshallingTests.PropertiesObject()
1187         obj.set_properties(some_uchar=54, some_int=42)
1188         self.assertEqual(42, self.get_prop(obj, 'some-int'))
1189         self.assertEqual(54, self.get_prop(obj, 'some-uchar'))
1190
1191     @unittest.skipUnless(has_regress, 'built without cairo support')
1192     def test_gtype(self):
1193         obj = Regress.TestObj()
1194         self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INVALID)
1195         self.set_prop(obj, 'gtype', int)
1196         self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT)
1197
1198         obj = Regress.TestObj(gtype=int)
1199         self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT)
1200         self.set_prop(obj, 'gtype', str)
1201         self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_STRING)
1202
1203     @unittest.skipUnless(has_regress, 'built without cairo support')
1204     def test_hash_table(self):
1205         obj = Regress.TestObj()
1206         self.assertEqual(self.get_prop(obj, 'hash-table'), None)
1207
1208         self.set_prop(obj, 'hash-table', {'mec': 56})
1209         self.assertTrue(isinstance(self.get_prop(obj, 'hash-table'), dict))
1210         self.assertEqual(list(self.get_prop(obj, 'hash-table').items())[0],
1211                          ('mec', 56))
1212
1213     @unittest.skipUnless(has_regress, 'built without cairo support')
1214     def test_parent_class(self):
1215         class A(Regress.TestObj):
1216             prop1 = GObject.Property(type=int)
1217
1218         a = A()
1219         self.set_prop(a, 'int', 20)
1220         self.assertEqual(self.get_prop(a, 'int'), 20)
1221
1222         # test parent property which needs introspection
1223         self.set_prop(a, 'list', ("str1", "str2"))
1224         self.assertEqual(self.get_prop(a, 'list'), ["str1", "str2"])
1225
1226     def test_held_object_ref_count_getter(self):
1227         holder = GIMarshallingTests.PropertiesObject()
1228         held = GObject.Object()
1229
1230         self.assertEqual(holder.__grefcount__, 1)
1231         self.assertEqual(held.__grefcount__, 1)
1232
1233         self.set_prop(holder, 'some-object', held)
1234         self.assertEqual(holder.__grefcount__, 1)
1235
1236         initial_ref_count = held.__grefcount__
1237         self.get_prop(holder, 'some-object')
1238         gc.collect()
1239         self.assertEqual(held.__grefcount__, initial_ref_count)
1240
1241     def test_held_object_ref_count_setter(self):
1242         holder = GIMarshallingTests.PropertiesObject()
1243         held = GObject.Object()
1244
1245         self.assertEqual(holder.__grefcount__, 1)
1246         self.assertEqual(held.__grefcount__, 1)
1247
1248         # Setting property should only increase ref count by 1
1249         self.set_prop(holder, 'some-object', held)
1250         self.assertEqual(holder.__grefcount__, 1)
1251         self.assertEqual(held.__grefcount__, 2)
1252
1253         # Clearing should pull it back down
1254         self.set_prop(holder, 'some-object', None)
1255         self.assertEqual(held.__grefcount__, 1)
1256
1257     def test_set_object_property_to_invalid_type(self):
1258         obj = GIMarshallingTests.PropertiesObject()
1259         self.assertRaises(TypeError, self.set_prop, obj, 'some-object', 'not_an_object')
1260
1261
1262 class TestCPropsAccessor(CPropertiesTestBase, unittest.TestCase):
1263     # C property tests using the "props" accessor.
1264     def get_prop(self, obj, name):
1265         return getattr(obj.props, name.replace('-', '_'))
1266
1267     def set_prop(self, obj, name, value):
1268         setattr(obj.props, name.replace('-', '_'), value)
1269
1270     def test_props_accessor_dir(self):
1271         # Test class
1272         props = dir(GIMarshallingTests.PropertiesObject.props)
1273         self.assertTrue('some_float' in props)
1274         self.assertTrue('some_double' in props)
1275         self.assertTrue('some_variant' in props)
1276
1277         # Test instance
1278         obj = GIMarshallingTests.PropertiesObject()
1279         props = dir(obj.props)
1280         self.assertTrue('some_float' in props)
1281         self.assertTrue('some_double' in props)
1282         self.assertTrue('some_variant' in props)
1283
1284     def test_param_spec_dir(self):
1285         attrs = dir(GIMarshallingTests.PropertiesObject.props.some_float)
1286         self.assertTrue('name' in attrs)
1287         self.assertTrue('nick' in attrs)
1288         self.assertTrue('blurb' in attrs)
1289         self.assertTrue('flags' in attrs)
1290         self.assertTrue('default_value' in attrs)
1291         self.assertTrue('minimum' in attrs)
1292         self.assertTrue('maximum' in attrs)
1293
1294
1295 class TestCGetPropertyMethod(CPropertiesTestBase, unittest.TestCase):
1296     # C property tests using the "props" accessor.
1297     def get_prop(self, obj, name):
1298         return obj.get_property(name)
1299
1300     def set_prop(self, obj, name, value):
1301         obj.set_property(name, value)
1302
1303
1304 if __name__ == '__main__':
1305     unittest.main()