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