test_everything.py 49.9 KB
Newer Older
Tomeu Vizoso's avatar
Tomeu Vizoso committed
1
# -*- Mode: Python; py-indent-offset: 4 -*-
2
# coding=utf-8
Tomeu Vizoso's avatar
Tomeu Vizoso committed
3 4 5
# vim: tabstop=4 shiftwidth=4 expandtab

import unittest
6
import traceback
7
import ctypes
8
import warnings
Tomeu Vizoso's avatar
Tomeu Vizoso committed
9 10
import sys

11 12 13
try:
    import cairo
    has_cairo = True
14
    from gi.repository import Regress as Everything
15 16
except ImportError:
    has_cairo = False
Tomeu Vizoso's avatar
Tomeu Vizoso committed
17

18
#import gi
19
from gi.repository import GObject
20
from gi.repository import GLib
21
from gi.repository import Gio
Tomeu Vizoso's avatar
Tomeu Vizoso committed
22

23 24 25 26 27 28
try:
    from gi.repository import Gtk
    Gtk  # pyflakes
except:
    Gtk = None

29 30 31 32 33 34 35
if sys.version_info < (3, 0):
    UNICHAR = "\xe2\x99\xa5"
    PY2_UNICODE_UNICHAR = unicode(UNICHAR, 'UTF-8')
else:
    UNICHAR = "鈾"


36 37 38 39 40 41 42 43 44 45 46
class RawGList(ctypes.Structure):
    _fields_ = [('data', ctypes.c_void_p),
                ('next', ctypes.c_void_p),
                ('prev', ctypes.c_void_p)]

    @classmethod
    def from_wrapped(cls, obj):
        offset = sys.getsizeof(object())  # size of PyObject_HEAD
        return ctypes.POINTER(cls).from_address(id(obj) + offset)


47
@unittest.skipUnless(has_cairo, 'built without cairo support')
Tomeu Vizoso's avatar
Tomeu Vizoso committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61
class TestEverything(unittest.TestCase):

    def test_cairo_context(self):
        context = Everything.test_cairo_context_full_return()
        self.assertTrue(isinstance(context, cairo.Context))

        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
        context = cairo.Context(surface)
        Everything.test_cairo_context_none_in(context)

    def test_cairo_surface(self):
        surface = Everything.test_cairo_surface_none_return()
        self.assertTrue(isinstance(surface, cairo.ImageSurface))
        self.assertTrue(isinstance(surface, cairo.Surface))
62 63 64
        self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
        self.assertEqual(surface.get_width(), 10)
        self.assertEqual(surface.get_height(), 10)
Tomeu Vizoso's avatar
Tomeu Vizoso committed
65 66 67 68

        surface = Everything.test_cairo_surface_full_return()
        self.assertTrue(isinstance(surface, cairo.ImageSurface))
        self.assertTrue(isinstance(surface, cairo.Surface))
69 70 71
        self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
        self.assertEqual(surface.get_width(), 10)
        self.assertEqual(surface.get_height(), 10)
Tomeu Vizoso's avatar
Tomeu Vizoso committed
72 73 74 75 76 77 78

        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
        Everything.test_cairo_surface_none_in(surface)

        surface = Everything.test_cairo_surface_full_out()
        self.assertTrue(isinstance(surface, cairo.ImageSurface))
        self.assertTrue(isinstance(surface, cairo.Surface))
79 80 81
        self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
        self.assertEqual(surface.get_width(), 10)
        self.assertEqual(surface.get_height(), 10)
Tomeu Vizoso's avatar
Tomeu Vizoso committed
82

83 84 85 86 87 88 89 90 91 92 93 94 95 96
    def test_bool(self):
        self.assertEqual(Everything.test_boolean(False), False)
        self.assertEqual(Everything.test_boolean(True), True)
        self.assertEqual(Everything.test_boolean('hello'), True)
        self.assertEqual(Everything.test_boolean(''), False)

        self.assertEqual(Everything.test_boolean_true(True), True)
        self.assertEqual(Everything.test_boolean_false(False), False)

    def test_int8(self):
        self.assertEqual(Everything.test_int8(GObject.G_MAXINT8),
                         GObject.G_MAXINT8)
        self.assertEqual(Everything.test_int8(GObject.G_MININT8),
                         GObject.G_MININT8)
97
        self.assertRaises(OverflowError, Everything.test_int8, GObject.G_MAXINT8 + 1)
98 99 100 101

        self.assertEqual(Everything.test_uint8(GObject.G_MAXUINT8),
                         GObject.G_MAXUINT8)
        self.assertEqual(Everything.test_uint8(0), 0)
102 103
        self.assertRaises(OverflowError, Everything.test_uint8, -1)
        self.assertRaises(OverflowError, Everything.test_uint8, GObject.G_MAXUINT8 + 1)
104 105 106 107 108 109

    def test_int16(self):
        self.assertEqual(Everything.test_int16(GObject.G_MAXINT16),
                         GObject.G_MAXINT16)
        self.assertEqual(Everything.test_int16(GObject.G_MININT16),
                         GObject.G_MININT16)
110
        self.assertRaises(OverflowError, Everything.test_int16, GObject.G_MAXINT16 + 1)
111 112 113 114

        self.assertEqual(Everything.test_uint16(GObject.G_MAXUINT16),
                         GObject.G_MAXUINT16)
        self.assertEqual(Everything.test_uint16(0), 0)
115 116
        self.assertRaises(OverflowError, Everything.test_uint16, -1)
        self.assertRaises(OverflowError, Everything.test_uint16, GObject.G_MAXUINT16 + 1)
117 118 119 120 121 122

    def test_int32(self):
        self.assertEqual(Everything.test_int32(GObject.G_MAXINT32),
                         GObject.G_MAXINT32)
        self.assertEqual(Everything.test_int32(GObject.G_MININT32),
                         GObject.G_MININT32)
123
        self.assertRaises(OverflowError, Everything.test_int32, GObject.G_MAXINT32 + 1)
124 125 126 127

        self.assertEqual(Everything.test_uint32(GObject.G_MAXUINT32),
                         GObject.G_MAXUINT32)
        self.assertEqual(Everything.test_uint32(0), 0)
128 129
        self.assertRaises(OverflowError, Everything.test_uint32, -1)
        self.assertRaises(OverflowError, Everything.test_uint32, GObject.G_MAXUINT32 + 1)
130 131 132 133 134 135

    def test_int64(self):
        self.assertEqual(Everything.test_int64(GObject.G_MAXINT64),
                         GObject.G_MAXINT64)
        self.assertEqual(Everything.test_int64(GObject.G_MININT64),
                         GObject.G_MININT64)
136
        self.assertRaises(OverflowError, Everything.test_int64, GObject.G_MAXINT64 + 1)
137 138 139 140

        self.assertEqual(Everything.test_uint64(GObject.G_MAXUINT64),
                         GObject.G_MAXUINT64)
        self.assertEqual(Everything.test_uint64(0), 0)
141 142
        self.assertRaises(OverflowError, Everything.test_uint64, -1)
        self.assertRaises(OverflowError, Everything.test_uint64, GObject.G_MAXUINT64 + 1)
143 144 145 146 147 148

    def test_int(self):
        self.assertEqual(Everything.test_int(GObject.G_MAXINT),
                         GObject.G_MAXINT)
        self.assertEqual(Everything.test_int(GObject.G_MININT),
                         GObject.G_MININT)
149
        self.assertRaises(OverflowError, Everything.test_int, GObject.G_MAXINT + 1)
150 151 152 153

        self.assertEqual(Everything.test_uint(GObject.G_MAXUINT),
                         GObject.G_MAXUINT)
        self.assertEqual(Everything.test_uint(0), 0)
154 155
        self.assertRaises(OverflowError, Everything.test_uint, -1)
        self.assertRaises(OverflowError, Everything.test_uint, GObject.G_MAXUINT + 1)
156 157 158 159 160 161

    def test_short(self):
        self.assertEqual(Everything.test_short(GObject.G_MAXSHORT),
                         GObject.G_MAXSHORT)
        self.assertEqual(Everything.test_short(GObject.G_MINSHORT),
                         GObject.G_MINSHORT)
162
        self.assertRaises(OverflowError, Everything.test_short, GObject.G_MAXSHORT + 1)
163 164 165 166

        self.assertEqual(Everything.test_ushort(GObject.G_MAXUSHORT),
                         GObject.G_MAXUSHORT)
        self.assertEqual(Everything.test_ushort(0), 0)
167 168
        self.assertRaises(OverflowError, Everything.test_ushort, -1)
        self.assertRaises(OverflowError, Everything.test_ushort, GObject.G_MAXUSHORT + 1)
169 170 171 172 173 174

    def test_long(self):
        self.assertEqual(Everything.test_long(GObject.G_MAXLONG),
                         GObject.G_MAXLONG)
        self.assertEqual(Everything.test_long(GObject.G_MINLONG),
                         GObject.G_MINLONG)
175
        self.assertRaises(OverflowError, Everything.test_long, GObject.G_MAXLONG + 1)
176 177 178 179

        self.assertEqual(Everything.test_ulong(GObject.G_MAXULONG),
                         GObject.G_MAXULONG)
        self.assertEqual(Everything.test_ulong(0), 0)
180 181
        self.assertRaises(OverflowError, Everything.test_ulong, -1)
        self.assertRaises(OverflowError, Everything.test_ulong, GObject.G_MAXULONG + 1)
182 183 184 185 186 187

    def test_size(self):
        self.assertEqual(Everything.test_ssize(GObject.G_MAXSSIZE),
                         GObject.G_MAXSSIZE)
        self.assertEqual(Everything.test_ssize(GObject.G_MINSSIZE),
                         GObject.G_MINSSIZE)
188
        self.assertRaises(OverflowError, Everything.test_ssize, GObject.G_MAXSSIZE + 1)
189 190 191 192

        self.assertEqual(Everything.test_size(GObject.G_MAXSIZE),
                         GObject.G_MAXSIZE)
        self.assertEqual(Everything.test_size(0), 0)
193 194
        self.assertRaises(OverflowError, Everything.test_size, -1)
        self.assertRaises(OverflowError, Everything.test_size, GObject.G_MAXSIZE + 1)
195 196 197

    def test_timet(self):
        self.assertEqual(Everything.test_timet(42), 42)
198
        self.assertRaises(OverflowError, Everything.test_timet, GObject.G_MAXUINT64 + 1)
199

Paolo Borelli's avatar
Paolo Borelli committed
200
    def test_unichar(self):
201
        self.assertEqual("c", Everything.test_unichar("c"))
202 203

        if sys.version_info < (3, 0):
204 205
            self.assertEqual(UNICHAR, Everything.test_unichar(PY2_UNICODE_UNICHAR))
        self.assertEqual(UNICHAR, Everything.test_unichar(UNICHAR))
206 207
        self.assertRaises(TypeError, Everything.test_unichar, "")
        self.assertRaises(TypeError, Everything.test_unichar, "morethanonechar")
208

209 210 211 212 213
    def test_float(self):
        self.assertEqual(Everything.test_float(GObject.G_MAXFLOAT),
                         GObject.G_MAXFLOAT)
        self.assertEqual(Everything.test_float(GObject.G_MINFLOAT),
                         GObject.G_MINFLOAT)
214
        self.assertRaises(OverflowError, Everything.test_float, GObject.G_MAXFLOAT * 2)
215 216 217 218 219 220 221

    def test_double(self):
        self.assertEqual(Everything.test_double(GObject.G_MAXDOUBLE),
                         GObject.G_MAXDOUBLE)
        self.assertEqual(Everything.test_double(GObject.G_MINDOUBLE),
                         GObject.G_MINDOUBLE)

222 223 224 225
        (two, three) = Everything.test_multi_double_args(2.5)
        self.assertAlmostEqual(two, 5.0)
        self.assertAlmostEqual(three, 7.5)

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
    def test_value(self):
        self.assertEqual(Everything.test_int_value_arg(GObject.G_MAXINT), GObject.G_MAXINT)
        self.assertEqual(Everything.test_value_return(GObject.G_MAXINT), GObject.G_MAXINT)

    def test_variant(self):
        v = Everything.test_gvariant_i()
        self.assertEqual(v.get_type_string(), 'i')
        self.assertEqual(v.get_int32(), 1)

        v = Everything.test_gvariant_s()
        self.assertEqual(v.get_type_string(), 's')
        self.assertEqual(v.get_string(), 'one')

        v = Everything.test_gvariant_v()
        self.assertEqual(v.get_type_string(), 'v')
        vi = v.get_variant()
        self.assertEqual(vi.get_type_string(), 's')
        self.assertEqual(vi.get_string(), 'contents')

        v = Everything.test_gvariant_as()
        self.assertEqual(v.get_type_string(), 'as')
        self.assertEqual(v.get_strv(), ['one', 'two', 'three'])

        v = Everything.test_gvariant_asv()
        self.assertEqual(v.get_type_string(), 'a{sv}')
        self.assertEqual(v.lookup_value('nosuchkey', None), None)
        name = v.lookup_value('name', None)
        self.assertEqual(name.get_string(), 'foo')
        timeout = v.lookup_value('timeout', None)
        self.assertEqual(timeout.get_int32(), 10)

    def test_string(self):
Martin Pitt's avatar
Martin Pitt committed
258 259 260
        const_str = b'const \xe2\x99\xa5 utf8'
        if sys.version_info >= (3, 0):
            const_str = const_str.decode('UTF-8')
261 262 263 264 265 266 267 268 269
        noconst_str = 'non' + const_str

        self.assertEqual(Everything.test_utf8_const_return(), const_str)
        self.assertEqual(Everything.test_utf8_nonconst_return(), noconst_str)
        self.assertEqual(Everything.test_utf8_out(), noconst_str)

        Everything.test_utf8_const_in(const_str)
        self.assertEqual(Everything.test_utf8_inout(const_str), noconst_str)

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
        self.assertEqual(Everything.test_filename_return(), ['氓盲枚', '/etc/fstab'])

        # returns g_utf8_strlen() in out argument
        self.assertEqual(Everything.test_int_out_utf8(''), 0)
        self.assertEqual(Everything.test_int_out_utf8('hello world'), 11)
        self.assertEqual(Everything.test_int_out_utf8('氓盲枚'), 3)

        self.assertEqual(Everything.test_utf8_out_out(), ('first', 'second'))
        self.assertEqual(Everything.test_utf8_out_nonconst_return(), ('first', 'second'))

    def test_enum(self):
        self.assertEqual(Everything.test_enum_param(Everything.TestEnum.VALUE1), 'value1')
        self.assertEqual(Everything.test_enum_param(Everything.TestEnum.VALUE3), 'value3')
        self.assertRaises(TypeError, Everything.test_enum_param, 'hello')

    # FIXME: ValueError: invalid enum value: 2147483648
    @unittest.expectedFailure
    def test_enum_unsigned(self):
        self.assertEqual(Everything.test_unsigned_enum_param(Everything.TestEnumUnsigned.VALUE1), 'value1')
        self.assertEqual(Everything.test_unsigned_enum_param(Everything.TestEnumUnsigned.VALUE3), 'value3')
        self.assertRaises(TypeError, Everything.test_unsigned_enum_param, 'hello')

    def test_flags(self):
        result = Everything.global_get_flags_out()
        # assert that it's not an int
        self.assertEqual(type(result), Everything.TestFlags)
        self.assertEqual(result, Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3)

298
    def test_floating(self):
299
        e = Everything.TestFloating()
300
        self.assertEqual(e.__grefcount__, 1)
301 302

        e = GObject.new(Everything.TestFloating)
303
        self.assertEqual(e.__grefcount__, 1)
304 305

        e = Everything.TestFloating.new()
306
        self.assertEqual(e.__grefcount__, 1)
307

308 309 310 311 312 313 314 315 316
    def test_caller_allocates(self):
        struct_a = Everything.TestStructA()
        struct_a.some_int = 10
        struct_a.some_int8 = 21
        struct_a.some_double = 3.14
        struct_a.some_enum = Everything.TestEnum.VALUE3

        struct_a_clone = struct_a.clone()
        self.assertTrue(struct_a != struct_a_clone)
317 318 319 320
        self.assertEqual(struct_a.some_int, struct_a_clone.some_int)
        self.assertEqual(struct_a.some_int8, struct_a_clone.some_int8)
        self.assertEqual(struct_a.some_double, struct_a_clone.some_double)
        self.assertEqual(struct_a.some_enum, struct_a_clone.some_enum)
321 322 323 324 325 326 327 328 329 330

        struct_b = Everything.TestStructB()
        struct_b.some_int8 = 8
        struct_b.nested_a.some_int = 20
        struct_b.nested_a.some_int8 = 12
        struct_b.nested_a.some_double = 333.3333
        struct_b.nested_a.some_enum = Everything.TestEnum.VALUE2

        struct_b_clone = struct_b.clone()
        self.assertTrue(struct_b != struct_b_clone)
331 332 333 334 335
        self.assertEqual(struct_b.some_int8, struct_b_clone.some_int8)
        self.assertEqual(struct_b.nested_a.some_int, struct_b_clone.nested_a.some_int)
        self.assertEqual(struct_b.nested_a.some_int8, struct_b_clone.nested_a.some_int8)
        self.assertEqual(struct_b.nested_a.some_double, struct_b_clone.nested_a.some_double)
        self.assertEqual(struct_b.nested_a.some_enum, struct_b_clone.nested_a.some_enum)
336

337 338 339
        struct_a = Everything.test_struct_a_parse('ignored')
        self.assertEqual(struct_a.some_int, 23)

340 341 342
    def test_wrong_type_of_arguments(self):
        try:
            Everything.test_int8()
343 344
        except TypeError:
            (e_type, e) = sys.exc_info()[:2]
345
            self.assertEqual(e.args, ("test_int8() takes exactly 1 argument (0 given)",))
346

347 348 349
    def test_gtypes(self):
        gchararray_gtype = GObject.type_from_name('gchararray')
        gtype = Everything.test_gtype(str)
350
        self.assertEqual(gchararray_gtype, gtype)
351
        gtype = Everything.test_gtype('gchararray')
352
        self.assertEqual(gchararray_gtype, gtype)
353 354
        gobject_gtype = GObject.GObject.__gtype__
        gtype = Everything.test_gtype(GObject.GObject)
355
        self.assertEqual(gobject_gtype, gtype)
356
        gtype = Everything.test_gtype('GObject')
357
        self.assertEqual(gobject_gtype, gtype)
358 359 360 361 362 363 364 365 366 367 368
        self.assertRaises(TypeError, Everything.test_gtype, 'invalidgtype')

        class NotARegisteredClass(object):
            pass

        self.assertRaises(TypeError, Everything.test_gtype, NotARegisteredClass)

        class ARegisteredClass(GObject.GObject):
            __gtype_name__ = 'EverythingTestsARegisteredClass'

        gtype = Everything.test_gtype('EverythingTestsARegisteredClass')
369
        self.assertEqual(ARegisteredClass.__gtype__, gtype)
370
        gtype = Everything.test_gtype(ARegisteredClass)
371
        self.assertEqual(ARegisteredClass.__gtype__, gtype)
372
        self.assertRaises(TypeError, Everything.test_gtype, 'ARegisteredClass')
373

374 375
    def test_dir(self):
        attr_list = dir(Everything)
376

377 378
        # test that typelib attributes are listed
        self.assertTrue('TestStructA' in attr_list)
379

380 381 382 383
        # test that class attributes and methods are listed
        self.assertTrue('__class__' in attr_list)
        self.assertTrue('__dir__' in attr_list)
        self.assertTrue('__repr__' in attr_list)
384

385 386
        # test that instance members are listed
        self.assertTrue('_namespace' in attr_list)
387
        self.assertTrue('_version' in attr_list)
388

389 390
        # test that there are no duplicates returned
        self.assertEqual(len(attr_list), len(set(attr_list)))
391

392 393 394 395 396 397 398 399
    def test_array(self):
        self.assertEqual(Everything.test_array_int_in([]), 0)
        self.assertEqual(Everything.test_array_int_in([1, 5, -2]), 4)
        self.assertEqual(Everything.test_array_int_out(), [0, 1, 2, 3, 4])
        self.assertEqual(Everything.test_array_int_full_out(), [0, 1, 2, 3, 4])
        self.assertEqual(Everything.test_array_int_none_out(), [1, 2, 3, 4, 5])
        self.assertEqual(Everything.test_array_int_inout([1, 5, 42, -8]), [6, 43, -7])

Martin Pitt's avatar
Martin Pitt committed
400 401
        if sys.version_info >= (3, 0):
            self.assertEqual(Everything.test_array_gint8_in(b'\x01\x03\x05'), 9)
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
        self.assertEqual(Everything.test_array_gint8_in([1, 3, 5, -50]), -41)
        self.assertEqual(Everything.test_array_gint16_in([256, 257, -1000, 10000]), 9513)
        self.assertEqual(Everything.test_array_gint32_in([30000, 1, -2]), 29999)
        self.assertEqual(Everything.test_array_gint64_in([2 ** 33, 2 ** 34]), 2 ** 33 + 2 ** 34)

        self.assertEqual(Everything.test_array_gtype_in(
            [GObject.TYPE_STRING, GObject.TYPE_UINT64, GObject.TYPE_VARIANT]),
            '[gchararray,guint64,GVariant,]')

    def test_array_fixed_size(self):
        # fixed length of 5
        self.assertEqual(Everything.test_array_fixed_size_int_in([1, 2, -10, 5, 3]), 1)
        self.assertRaises(ValueError, Everything.test_array_fixed_size_int_in, [1, 2, 3, 4])
        self.assertRaises(ValueError, Everything.test_array_fixed_size_int_in, [1, 2, 3, 4, 5, 6])

        self.assertEqual(Everything.test_array_fixed_size_int_out(), [0, 1, 2, 3, 4])
        self.assertEqual(Everything.test_array_fixed_size_int_return(), [0, 1, 2, 3, 4])

Xavier Claessens's avatar
Xavier Claessens committed
420
    def test_ptrarray(self):
421 422
        # transfer container
        result = Everything.test_garray_container_return()
423
        self.assertEqual(result, ['regress'])
424 425 426 427
        result = None

        # transfer full
        result = Everything.test_garray_full_return()
428
        self.assertEqual(result, ['regress'])
429
        result = None
Xavier Claessens's avatar
Xavier Claessens committed
430

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    def test_strv(self):
        self.assertEqual(Everything.test_strv_out(), ['thanks', 'for', 'all', 'the', 'fish'])
        self.assertEqual(Everything.test_strv_out_c(), ['thanks', 'for', 'all', 'the', 'fish'])
        self.assertEqual(Everything.test_strv_out_container(), ['1', '2', '3'])
        self.assertEqual(Everything.test_strv_outarg(), ['1', '2', '3'])

        self.assertEqual(Everything.test_strv_in_gvalue(), ['one', 'two', 'three'])

        Everything.test_strv_in(['1', '2', '3'])

    def test_glist(self):
        self.assertEqual(Everything.test_glist_nothing_return(), ['1', '2', '3'])
        self.assertEqual(Everything.test_glist_nothing_return2(), ['1', '2', '3'])
        self.assertEqual(Everything.test_glist_container_return(), ['1', '2', '3'])
        self.assertEqual(Everything.test_glist_everything_return(), ['1', '2', '3'])

        Everything.test_glist_nothing_in(['1', '2', '3'])
        Everything.test_glist_nothing_in2(['1', '2', '3'])

    def test_gslist(self):
        self.assertEqual(Everything.test_gslist_nothing_return(), ['1', '2', '3'])
        self.assertEqual(Everything.test_gslist_nothing_return2(), ['1', '2', '3'])
        self.assertEqual(Everything.test_gslist_container_return(), ['1', '2', '3'])
        self.assertEqual(Everything.test_gslist_everything_return(), ['1', '2', '3'])

        Everything.test_gslist_nothing_in(['1', '2', '3'])
        Everything.test_gslist_nothing_in2(['1', '2', '3'])

459
    def test_hash_return(self):
460 461 462 463 464 465 466 467
        expected = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'}

        self.assertEqual(Everything.test_ghash_null_return(), None)
        self.assertEqual(Everything.test_ghash_nothing_return(), expected)
        self.assertEqual(Everything.test_ghash_nothing_return(), expected)
        self.assertEqual(Everything.test_ghash_container_return(), expected)
        self.assertEqual(Everything.test_ghash_everything_return(), expected)

468
        result = Everything.test_ghash_gvalue_return()
469 470 471
        self.assertEqual(result['integer'], 12)
        self.assertEqual(result['boolean'], True)
        self.assertEqual(result['string'], 'some text')
472
        self.assertEqual(result['strings'], ['first', 'second', 'third'])
473 474
        self.assertEqual(result['flags'], Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3)
        self.assertEqual(result['enum'], Everything.TestEnum.VALUE2)
475 476
        result = None

477 478 479 480 481
    # FIXME: CRITICAL **: Unsupported type ghash
    def disabled_test_hash_return_nested(self):
        self.assertEqual(Everything.test_ghash_nested_everything_return(), {})
        self.assertEqual(Everything.test_ghash_nested_everything_return2(), {})

482
    def test_hash_in(self):
483 484 485 486 487
        expected = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'}

        Everything.test_ghash_nothing_in(expected)
        Everything.test_ghash_nothing_in2(expected)

488 489 490 491
    def test_hash_in_with_typed_strv(self):
        class GStrv(list):
            __gtype__ = GObject.TYPE_STRV

492 493 494 495 496 497 498
        data = {'integer': 12,
                'boolean': True,
                'string': 'some text',
                'strings': GStrv(['first', 'second', 'third']),
                'flags': Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3,
                'enum': Everything.TestEnum.VALUE2,
               }
499 500
        Everything.test_ghash_gvalue_in(data)
        data = None
501

502 503 504 505 506 507 508 509 510 511 512
    def test_hash_in_with_gvalue_strv(self):
        data = {'integer': 12,
                'boolean': True,
                'string': 'some text',
                'strings': GObject.Value(GObject.TYPE_STRV, ['first', 'second', 'third']),
                'flags': Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3,
                'enum': Everything.TestEnum.VALUE2,
               }
        Everything.test_ghash_gvalue_in(data)
        data = None

513
    def test_struct_gpointer(self):
514 515 516
        glist = GLib.List()
        raw = RawGList.from_wrapped(glist)

517 518
        # Note that pointer fields use 0 for NULL in PyGObject and None in ctypes
        self.assertEqual(glist.data, 0)
519 520 521 522 523 524 525
        self.assertEqual(raw.contents.data, None)

        glist.data = 123
        self.assertEqual(glist.data, 123)
        self.assertEqual(raw.contents.data, 123)

        glist.data = None
526
        self.assertEqual(glist.data, 0)
527 528 529 530 531 532
        self.assertEqual(raw.contents.data, None)

        # Setting to anything other than an int should raise
        self.assertRaises(TypeError, setattr, glist.data, 'nan')
        self.assertRaises(TypeError, setattr, glist.data, object())
        self.assertRaises(TypeError, setattr, glist.data, 123.321)
533

534 535 536 537 538
    def test_struct_opaque(self):
        # we should get a sensible error message
        try:
            Everything.TestBoxedPrivate()
            self.fail('allocating disguised struct without default constructor unexpectedly succeeded')
539 540 541 542 543 544 545
        except TypeError:
            (e_type, e_value, e_tb) = sys.exc_info()
            self.assertEqual(e_type, TypeError)
            self.assertTrue('TestBoxedPrivate' in str(e_value), str(e_value))
            self.assertTrue('override' in str(e_value), str(e_value))
            self.assertTrue('constructor' in str(e_value), str(e_value))
            tb = ''.join(traceback.format_exception(e_type, e_value, e_tb))
546 547
            self.assertTrue('tests/test_everything.py", line' in tb, tb)

548

549
@unittest.skipUnless(has_cairo, 'built without cairo support')
550 551 552 553 554 555 556
class TestNullableArgs(unittest.TestCase):
    def test_in_nullable_hash(self):
        Everything.test_ghash_null_in(None)

    def test_in_nullable_list(self):
        Everything.test_gslist_null_in(None)
        Everything.test_glist_null_in(None)
557 558
        Everything.test_gslist_null_in([])
        Everything.test_glist_null_in([])
559 560

    def test_in_nullable_array(self):
561
        Everything.test_array_int_null_in(None)
562
        Everything.test_array_int_null_in([])
563 564 565 566

    def test_in_nullable_string(self):
        Everything.test_utf8_null_in(None)

567
    def test_in_nullable_object(self):
568
        Everything.func_obj_null_in(None)
569

570 571 572 573
    def test_out_nullable_hash(self):
        self.assertEqual(None, Everything.test_ghash_null_out())

    def test_out_nullable_list(self):
574 575
        self.assertEqual([], Everything.test_gslist_null_out())
        self.assertEqual([], Everything.test_glist_null_out())
576 577

    def test_out_nullable_array(self):
578
        self.assertEqual([], Everything.test_array_int_null_out())
579 580 581 582

    def test_out_nullable_string(self):
        self.assertEqual(None, Everything.test_utf8_null_out())

583
    def test_out_nullable_object(self):
584
        self.assertEqual(None, Everything.TestObj.null_out())
585

586

587
@unittest.skipUnless(has_cairo, 'built without cairo support')
588 589
class TestCallbacks(unittest.TestCase):
    called = False
590
    main_loop = GLib.MainLoop()
Tomeu Vizoso's avatar
Tomeu Vizoso committed
591

592
    def test_callback(self):
593
        TestCallbacks.called = False
594

595 596
        def callback():
            TestCallbacks.called = True
597

598 599 600
        Everything.test_simple_callback(callback)
        self.assertTrue(TestCallbacks.called)

601
    def test_callback_exception(self):
602 603 604 605 606 607
        """
        This test ensures that we get errors from callbacks correctly
        and in particular that we do not segv when callbacks fail
        """
        def callback():
            x = 1 / 0
608
            self.fail('unexpected surviving zero divsion:' + str(x))
609

610 611 612 613
        # note that we do NOT expect the ZeroDivisionError to be propagated
        # through from the callback, as it crosses the Python<->C boundary
        # twice. (See GNOME #616279)
        Everything.test_simple_callback(callback)
614

615
    def test_double_callback_exception(self):
616 617 618 619 620 621
        """
        This test ensures that we get errors from callbacks correctly
        and in particular that we do not segv when callbacks fail
        """
        def badcallback():
            x = 1 / 0
622
            self.fail('unexpected surviving zero divsion:' + str(x))
623 624 625 626 627 628

        def callback():
            Everything.test_boolean(True)
            Everything.test_boolean(False)
            Everything.test_simple_callback(badcallback())

629 630 631 632
        # note that we do NOT expect the ZeroDivisionError to be propagated
        # through from the callback, as it crosses the Python<->C boundary
        # twice. (See GNOME #616279)
        Everything.test_simple_callback(callback)
633

634
    def test_return_value_callback(self):
635
        TestCallbacks.called = False
636

637 638 639 640
        def callback():
            TestCallbacks.called = True
            return 44

641
        self.assertEqual(Everything.test_callback(callback), 44)
642
        self.assertTrue(TestCallbacks.called)
643

644
    def test_callback_scope_async(self):
645
        TestCallbacks.called = False
646
        ud = 'Test Value 44'
647

648 649
        def callback(user_data):
            self.assertEqual(user_data, ud)
650
            TestCallbacks.called = True
651 652 653 654
            return 44

        ud_refcount = sys.getrefcount(ud)
        callback_refcount = sys.getrefcount(callback)
655

656 657 658 659 660 661 662 663 664
        self.assertEqual(Everything.test_callback_async(callback, ud), None)
        # Callback should not have run and the ref count is increased by 1
        self.assertEqual(TestCallbacks.called, False)
        self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
        self.assertEqual(sys.getrefcount(ud), ud_refcount + 1)

        # test_callback_thaw_async will run the callback previously supplied.
        # references should be auto decremented after this call.
        self.assertEqual(Everything.test_callback_thaw_async(), 44)
665
        self.assertTrue(TestCallbacks.called)
666

667 668 669 670 671 672 673
        # Make sure refcounts are returned to normal
        self.assertEqual(sys.getrefcount(callback), callback_refcount)
        self.assertEqual(sys.getrefcount(ud), ud_refcount)

    def test_callback_scope_call_multi(self):
        # This tests a callback that gets called multiple times from a
        # single scope call in python.
674
        TestCallbacks.called = 0
675

676 677
        def callback():
            TestCallbacks.called += 1
678
            return TestCallbacks.called
679

680
        refcount = sys.getrefcount(callback)
681 682 683
        result = Everything.test_multi_callback(callback)
        # first callback should give 1, second 2, and the function sums them up
        self.assertEqual(result, 3)
684
        self.assertEqual(TestCallbacks.called, 2)
685
        self.assertEqual(sys.getrefcount(callback), refcount)
686

687 688 689 690 691
    def test_callback_scope_call_array(self):
        # This tests a callback that gets called multiple times from a
        # single scope call in python with array arguments
        TestCallbacks.callargs = []

692 693 694
        # FIXME: would be cleaner without the explicit length args:
        # def callback(one, two):
        def callback(one, one_length, two, two_length):
695 696 697 698 699 700 701 702 703 704 705
            TestCallbacks.callargs.append((one, two))
            return len(TestCallbacks.callargs)

        refcount = sys.getrefcount(callback)
        result = Everything.test_array_callback(callback)
        # first callback should give 1, second 2, and the function sums them up
        self.assertEqual(result, 3)
        self.assertEqual(TestCallbacks.callargs,
                         [([-1, 0, 1, 2], ['one', 'two', 'three'])] * 2)
        self.assertEqual(sys.getrefcount(callback), refcount)

706
    def test_callback_userdata(self):
707
        TestCallbacks.called = 0
708

709
        def callback(userdata):
710
            self.assertEqual(userdata, "Test%d" % TestCallbacks.called)
711 712
            TestCallbacks.called += 1
            return TestCallbacks.called
713

714 715
        for i in range(100):
            val = Everything.test_callback_user_data(callback, "Test%d" % i)
716
            self.assertEqual(val, i + 1)
717

718
        self.assertEqual(TestCallbacks.called, 100)
Tomeu Vizoso's avatar
Tomeu Vizoso committed
719

720
    def test_callback_userdata_no_user_data(self):
721 722
        TestCallbacks.called = 0

723
        def callback():
724 725 726 727 728 729 730 731 732
            TestCallbacks.called += 1
            return TestCallbacks.called

        for i in range(100):
            val = Everything.test_callback_user_data(callback)
            self.assertEqual(val, i + 1)

        self.assertEqual(TestCallbacks.called, 100)

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
    def test_callback_userdata_varargs(self):
        TestCallbacks.called = 0
        collected_user_data = []

        def callback(a, b):
            collected_user_data.extend([a, b])
            TestCallbacks.called += 1
            return TestCallbacks.called

        for i in range(10):
            val = Everything.test_callback_user_data(callback, 1, 2)
            self.assertEqual(val, i + 1)

        self.assertEqual(TestCallbacks.called, 10)
        self.assertSequenceEqual(collected_user_data, [1, 2] * 10)

    def test_callback_userdata_as_kwarg_tuple(self):
        TestCallbacks.called = 0
        collected_user_data = []

        def callback(user_data):
            collected_user_data.extend(user_data)
            TestCallbacks.called += 1
            return TestCallbacks.called

        for i in range(10):
            val = Everything.test_callback_user_data(callback, user_data=(1, 2))
            self.assertEqual(val, i + 1)

        self.assertEqual(TestCallbacks.called, 10)
        self.assertSequenceEqual(collected_user_data, [1, 2] * 10)

765
    def test_async_ready_callback(self):
Tomeu Vizoso's avatar
Tomeu Vizoso committed
766
        TestCallbacks.called = False
767
        TestCallbacks.main_loop = GLib.MainLoop()
Tomeu Vizoso's avatar
Tomeu Vizoso committed
768 769 770 771 772 773 774 775 776 777

        def callback(obj, result, user_data):
            TestCallbacks.main_loop.quit()
            TestCallbacks.called = True

        Everything.test_async_ready_callback(callback)

        TestCallbacks.main_loop.run()

        self.assertTrue(TestCallbacks.called)
Tomeu Vizoso's avatar
Tomeu Vizoso committed
778

779 780 781 782
    def test_callback_scope_notified_with_destroy(self):
        TestCallbacks.called = 0
        ud = 'Test scope notified data 33'

Tomeu Vizoso's avatar
Tomeu Vizoso committed
783
        def callback(user_data):
784 785 786
            self.assertEqual(user_data, ud)
            TestCallbacks.called += 1
            return 33
Tomeu Vizoso's avatar
Tomeu Vizoso committed
787

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
        value_refcount = sys.getrefcount(ud)
        callback_refcount = sys.getrefcount(callback)

        # Callback is immediately called.
        for i in range(100):
            res = Everything.test_callback_destroy_notify(callback, ud)
            self.assertEqual(res, 33)

        self.assertEqual(TestCallbacks.called, 100)
        self.assertEqual(sys.getrefcount(callback), callback_refcount + 100)
        self.assertEqual(sys.getrefcount(ud), value_refcount + 100)

        # thaw will call the callback again, this time resources should be freed
        self.assertEqual(Everything.test_callback_thaw_notifications(), 33 * 100)
        self.assertEqual(TestCallbacks.called, 200)
        self.assertEqual(sys.getrefcount(callback), callback_refcount)
        self.assertEqual(sys.getrefcount(ud), value_refcount)

    def test_callback_scope_notified_with_destroy_no_user_data(self):
        TestCallbacks.called = 0

        def callback(user_data):
            self.assertEqual(user_data, None)
            TestCallbacks.called += 1
            return 34

        callback_refcount = sys.getrefcount(callback)

        # Run with warning as exception
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("error")
            self.assertRaises(RuntimeWarning,
                              Everything.test_callback_destroy_notify_no_user_data,
                              callback)

        self.assertEqual(TestCallbacks.called, 0)
        self.assertEqual(sys.getrefcount(callback), callback_refcount)

        # Run with warning as warning
        with warnings.catch_warnings(record=True) as w:
            # Cause all warnings to always be triggered.
            warnings.simplefilter("default")
            # Trigger a warning.
            res = Everything.test_callback_destroy_notify_no_user_data(callback)
            # Verify some things
            self.assertEqual(len(w), 1)
            self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
            self.assertTrue('Callables passed to' in str(w[-1].message))

        self.assertEqual(res, 34)
        self.assertEqual(TestCallbacks.called, 1)
        self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)

        # thaw will call the callback again,
        # refcount will not go down without user_data parameter
        self.assertEqual(Everything.test_callback_thaw_notifications(), 34)
        self.assertEqual(TestCallbacks.called, 2)
        self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
846

847
    def test_callback_in_methods(self):
848 849 850 851
        object_ = Everything.TestObj()

        def callback():
            TestCallbacks.called = True
852
            return 42
853 854 855 856 857 858 859 860 861 862

        TestCallbacks.called = False
        object_.instance_method_callback(callback)
        self.assertTrue(TestCallbacks.called)

        TestCallbacks.called = False
        Everything.TestObj.static_method_callback(callback)
        self.assertTrue(TestCallbacks.called)

        def callbackWithUserData(user_data):
863
            TestCallbacks.called += 1
864
            return 42
865

866
        TestCallbacks.called = 0
867
        Everything.TestObj.new_callback(callbackWithUserData, None)
868 869 870 871 872 873
        self.assertEqual(TestCallbacks.called, 1)
        # Note: using "new_callback" adds the notification to the same global
        # list as Everything.test_callback_destroy_notify, so thaw the list
        # so we don't get confusion between tests.
        self.assertEqual(Everything.test_callback_thaw_notifications(), 42)
        self.assertEqual(TestCallbacks.called, 2)
874

875
    def test_callback_none(self):
876
        # make sure this doesn't assert or crash
877
        Everything.test_simple_callback(None)
878

879
    def test_callback_gerror(self):
880 881 882 883 884 885 886 887 888 889
        def callback(error):
            self.assertEqual(error.message, 'regression test error')
            self.assertTrue('g-io' in error.domain)
            self.assertEqual(error.code, Gio.IOErrorEnum.NOT_SUPPORTED)
            TestCallbacks.called = True

        TestCallbacks.called = False
        Everything.test_gerror_callback(callback)
        self.assertTrue(TestCallbacks.called)

890 891 892 893 894 895 896 897 898
    def test_callback_null_gerror(self):
        def callback(error):
            self.assertEqual(error, None)
            TestCallbacks.called = True

        TestCallbacks.called = False
        Everything.test_null_gerror_callback(callback)
        self.assertTrue(TestCallbacks.called)

899
    def test_callback_owned_gerror(self):
900 901 902 903 904 905 906 907 908 909
        def callback(error):
            self.assertEqual(error.message, 'regression test owned error')
            self.assertTrue('g-io' in error.domain)
            self.assertEqual(error.code, Gio.IOErrorEnum.PERMISSION_DENIED)
            TestCallbacks.called = True

        TestCallbacks.called = False
        Everything.test_owned_gerror_callback(callback)
        self.assertTrue(TestCallbacks.called)

910
    def test_callback_hashtable(self):
911 912 913 914 915
        def callback(data):
            self.assertEqual(data, mydict)
            mydict['new'] = 42
            TestCallbacks.called = True

916
        mydict = {'foo': 1, 'bar': 2}
917 918 919
        TestCallbacks.called = False
        Everything.test_hash_table_callback(mydict, callback)
        self.assertTrue(TestCallbacks.called)
920 921
        self.assertEqual(mydict, {'foo': 1, 'bar': 2, 'new': 42})

922

923
@unittest.skipUnless(has_cairo, 'built without cairo support')
Martin Pitt's avatar
Martin Pitt committed
924
class TestClosures(unittest.TestCase):
925 926 927 928 929 930 931 932 933 934
    def test_no_arg(self):
        def callback():
            self.called = True
            return 42

        self.called = False
        result = Everything.test_closure(callback)
        self.assertTrue(self.called)
        self.assertEqual(result, 42)

Martin Pitt's avatar
Martin Pitt committed
935 936 937
    def test_int_arg(self):
        def callback(num):
            self.called = True
938
            return num + 1
Martin Pitt's avatar
Martin Pitt committed
939 940 941 942 943 944 945 946 947

        self.called = False
        result = Everything.test_closure_one_arg(callback, 42)
        self.assertTrue(self.called)
        self.assertEqual(result, 43)

    def test_variant(self):
        def callback(variant):
            self.called = True
948 949 950
            if variant is None:
                return None
            self.assertEqual(variant.get_type_string(), 'i')
Martin Pitt's avatar
Martin Pitt committed
951 952 953 954 955 956 957
            return GLib.Variant('i', variant.get_int32() + 1)

        self.called = False
        result = Everything.test_closure_variant(callback, GLib.Variant('i', 42))
        self.assertTrue(self.called)
        self.assertEqual(result.get_type_string(), 'i')
        self.assertEqual(result.get_int32(), 43)
958

959 960 961 962 963 964 965 966 967
        self.called = False
        result = Everything.test_closure_variant(callback, None)
        self.assertTrue(self.called)
        self.assertEqual(result, None)

        self.called = False
        self.assertRaises(TypeError, Everything.test_closure_variant, callback, 'foo')
        self.assertFalse(self.called)

968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
    def test_variant_wrong_return_type(self):
        def callback(variant):
            return 'no_variant'

        # reset last error
        sys.last_type = None

        # this does not directly raise an exception (see
        # https://bugzilla.gnome.org/show_bug.cgi?id=616279)
        result = Everything.test_closure_variant(callback, GLib.Variant('i', 42))
        # ... but the result shouldn't be a string
        self.assertEqual(result, None)
        # and the error should be shown
        self.assertEqual(sys.last_type, TypeError)
        self.assertTrue('return value' in str(sys.last_value), sys.last_value)

984

985
@unittest.skipUnless(has_cairo, 'built without cairo support')
986 987
class TestProperties(unittest.TestCase):

988 989 990
    def test_basic(self):
        object_ = Everything.TestObj()

991
        self.assertEqual(object_.props.int, 0)
992 993
        object_.props.int = 42
        self.assertTrue(isinstance(object_.props.int, int))
994
        self.assertEqual(object_.props.int, 42)
995

996
        self.assertEqual(object_.props.float, 0.0)
997 998
        object_.props.float = 42.42
        self.assertTrue(isinstance(object_.props.float, float))
Martin Pitt's avatar