gir_ffi 0.8.6 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +18 -0
  3. data/README.md +3 -4
  4. data/lib/ffi-glib.rb +1 -0
  5. data/lib/ffi-glib/container_class_methods.rb +12 -0
  6. data/lib/ffi-glib/destroy_notify.rb +15 -0
  7. data/lib/ffi-glib/main_loop.rb +23 -4
  8. data/lib/ffi-gobject.rb +4 -2
  9. data/lib/ffi-gobject/object.rb +31 -16
  10. data/lib/ffi-gobject/object_class.rb +4 -0
  11. data/lib/ffi-gobject/value.rb +3 -3
  12. data/lib/ffi-gobject_introspection/i_flags_info.rb +0 -1
  13. data/lib/gir_ffi-base/gobject/lib.rb +10 -0
  14. data/lib/gir_ffi/arg_helper.rb +1 -22
  15. data/lib/gir_ffi/boxed_base.rb +1 -0
  16. data/lib/gir_ffi/builder.rb +7 -1
  17. data/lib/gir_ffi/builders/argument_builder.rb +21 -9
  18. data/lib/gir_ffi/builders/argument_builder_collection.rb +28 -9
  19. data/lib/gir_ffi/builders/base_argument_builder.rb +36 -12
  20. data/lib/gir_ffi/builders/base_method_builder.rb +1 -1
  21. data/lib/gir_ffi/builders/callback_argument_builder.rb +4 -0
  22. data/lib/gir_ffi/builders/closure_to_pointer_convertor.rb +3 -2
  23. data/lib/gir_ffi/builders/constructor_builder.rb +1 -1
  24. data/lib/gir_ffi/builders/enum_builder.rb +4 -4
  25. data/lib/gir_ffi/builders/error_argument_builder.rb +4 -0
  26. data/lib/gir_ffi/builders/field_builder.rb +23 -9
  27. data/lib/gir_ffi/builders/flags_builder.rb +28 -0
  28. data/lib/gir_ffi/builders/full_c_to_ruby_convertor.rb +18 -0
  29. data/lib/gir_ffi/builders/module_builder.rb +1 -0
  30. data/lib/gir_ffi/builders/null_argument_builder.rb +9 -1
  31. data/lib/gir_ffi/builders/object_builder.rb +7 -4
  32. data/lib/gir_ffi/builders/property_builder.rb +2 -2
  33. data/lib/gir_ffi/builders/return_value_builder.rb +4 -4
  34. data/lib/gir_ffi/builders/struct_builder.rb +10 -2
  35. data/lib/gir_ffi/builders/type_builder.rb +12 -9
  36. data/lib/gir_ffi/builders/unintrospectable_boxed_builder.rb +26 -0
  37. data/lib/gir_ffi/builders/user_defined_builder.rb +2 -2
  38. data/lib/gir_ffi/builders/with_layout.rb +1 -1
  39. data/lib/gir_ffi/callback_base.rb +13 -5
  40. data/lib/gir_ffi/core.rb +1 -0
  41. data/lib/gir_ffi/error_argument_info.rb +4 -0
  42. data/lib/gir_ffi/flags_base.rb +63 -0
  43. data/lib/gir_ffi/in_pointer.rb +1 -3
  44. data/lib/gir_ffi/info_ext/i_type_info.rb +6 -0
  45. data/lib/gir_ffi/object_base.rb +9 -1
  46. data/lib/gir_ffi/object_store.rb +26 -0
  47. data/lib/gir_ffi/unintrospectable_boxed_info.rb +31 -0
  48. data/lib/gir_ffi/unintrospectable_type_info.rb +5 -0
  49. data/lib/gir_ffi/user_defined_type_info.rb +19 -0
  50. data/lib/gir_ffi/version.rb +1 -1
  51. data/test/ffi-glib/destroy_notify_test.rb +13 -0
  52. data/test/ffi-glib/main_loop_test.rb +3 -3
  53. data/test/ffi-gobject/object_class_test.rb +8 -0
  54. data/test/ffi-gobject/object_test.rb +23 -5
  55. data/test/ffi-gobject/value_test.rb +19 -5
  56. data/test/ffi-gobject_test.rb +2 -2
  57. data/test/gir_ffi/builders/argument_builder_test.rb +12 -2
  58. data/test/gir_ffi/builders/constructor_builder_test.rb +4 -4
  59. data/test/gir_ffi/builders/function_builder_test.rb +46 -3
  60. data/test/gir_ffi/builders/object_builder_test.rb +25 -0
  61. data/test/gir_ffi/builders/property_builder_test.rb +4 -4
  62. data/test/gir_ffi/builders/struct_builder_test.rb +15 -13
  63. data/test/gir_ffi/builders/unintrospectable_boxed_builder_test.rb +33 -0
  64. data/test/gir_ffi/builders/unintrospectable_builder_test.rb +6 -0
  65. data/test/gir_ffi/builders/user_defined_builder_test.rb +7 -1
  66. data/test/gir_ffi/callback_base_test.rb +12 -2
  67. data/test/gir_ffi/object_base_test.rb +14 -0
  68. data/test/integration/callback_exceptions_test.rb +61 -0
  69. data/test/integration/generated_gimarshallingtests_test.rb +70 -70
  70. data/test/integration/generated_gio_test.rb +1 -1
  71. data/test/integration/generated_gobject_test.rb +1 -1
  72. data/test/integration/generated_gtop_test.rb +5 -1
  73. data/test/integration/generated_regress_test.rb +83 -102
  74. data/test/integration/generated_warnlib_test.rb +2 -2
  75. metadata +42 -4
@@ -73,11 +73,18 @@ describe GObject::Value do
73
73
  end
74
74
 
75
75
  describe '#set_value' do
76
- it 'handles char values' do
76
+ it 'handles signed char values' do
77
77
  value = -83
78
78
  gv = GObject::Value.for_gtype GObject::TYPE_CHAR
79
79
  gv.set_value value
80
- gv.get_char.must_equal value
80
+ gv.get_schar.must_equal value
81
+ end
82
+
83
+ it 'handles unsigned char values' do
84
+ value = 174
85
+ gv = GObject::Value.for_gtype GObject::TYPE_UCHAR
86
+ gv.set_value value
87
+ gv.get_uchar.must_equal value
81
88
  end
82
89
 
83
90
  it 'handles enum values presented as symbols' do
@@ -178,10 +185,17 @@ describe GObject::Value do
178
185
  assert_equal true, result
179
186
  end
180
187
 
181
- it 'unwraps a char' do
182
- value = 3
188
+ it 'unwraps a signed char' do
189
+ value = -42
183
190
  gv = GObject::Value.for_gtype GObject::TYPE_CHAR
184
- gv.set_char value
191
+ gv.set_schar value
192
+ gv.get_value.must_equal value
193
+ end
194
+
195
+ it 'unwraps an unsigned char' do
196
+ value = 173
197
+ gv = GObject::Value.for_gtype GObject::TYPE_UCHAR
198
+ gv.set_uchar value
185
199
  gv.get_value.must_equal value
186
200
  end
187
201
 
@@ -23,7 +23,7 @@ describe GObject do
23
23
  callback = FFI::Function.new(:bool, argtypes) { |_a, _b, _c, _d| true }
24
24
  ::GObject::Lib.g_signal_connect_data s, 'incoming', callback, nil, nil, 0
25
25
  rv = GObject.signal_emit s, 'incoming'
26
- assert_equal true, rv.get_value
26
+ assert_equal true, rv
27
27
  end
28
28
 
29
29
  it 'passes in extra arguments' do
@@ -95,7 +95,7 @@ describe GObject do
95
95
  s = Gio::SocketService.new
96
96
  GObject.signal_connect(s, 'incoming') { true }
97
97
  rv = GObject.signal_emit s, 'incoming'
98
- assert_equal true, rv.get_value
98
+ assert_equal true, rv
99
99
  end
100
100
 
101
101
  it 'requires a block' do
@@ -42,6 +42,10 @@ describe GirFFI::Builders::ArgumentBuilder do
42
42
  builder.closure = false
43
43
  end
44
44
 
45
+ it 'has the correct value for method_argument_name' do
46
+ builder.method_argument_name.must_equal arg_info.name
47
+ end
48
+
45
49
  it 'has the correct value for #pre_conversion' do
46
50
  builder.pre_conversion.must_equal ['_v1 = GirFFI::InPointer.from(:void, user_data)']
47
51
  end
@@ -53,11 +57,17 @@ describe GirFFI::Builders::ArgumentBuilder do
53
57
 
54
58
  describe 'when it is a closure' do
55
59
  before do
56
- builder.closure = true
60
+ callback = Object.new
61
+ allow(callback).to receive(:call_argument_name).and_return 'foo'
62
+ builder.closure = callback
63
+ end
64
+
65
+ it 'has the correct value for method_argument_name' do
66
+ builder.method_argument_name.must_be_nil
57
67
  end
58
68
 
59
69
  it 'has the correct value for #pre_conversion' do
60
- builder.pre_conversion.must_equal ['_v1 = GirFFI::InPointer.from_closure_data(user_data)']
70
+ builder.pre_conversion.must_equal ['_v1 = GirFFI::InPointer.from_closure_data(foo.object_id)']
61
71
  end
62
72
 
63
73
  it 'has the correct value for #post_conversion' do
@@ -9,9 +9,9 @@ describe GirFFI::Builders::ConstructorBuilder do
9
9
  let(:function_info) { get_method_introspection_data 'Regress', 'TestObj', 'new' }
10
10
  it 'builds a constructor' do
11
11
  code.must_equal <<-CODE.reset_indentation
12
- def self.new(*args)
12
+ def self.new(*args, &block)
13
13
  obj = allocate
14
- obj.__send__ :initialize, *args
14
+ obj.__send__ :initialize, *args, &block
15
15
  obj
16
16
  end
17
17
  CODE
@@ -22,10 +22,10 @@ describe GirFFI::Builders::ConstructorBuilder do
22
22
  let(:function_info) { get_method_introspection_data 'Regress', 'TestObj', 'new_from_file' }
23
23
  it 'builds a custom constructor' do
24
24
  code.must_equal <<-CODE.reset_indentation
25
- def self.new_from_file(*args)
25
+ def self.new_from_file(*args, &block)
26
26
  raise NoMethodError unless self == Regress::TestObj
27
27
  obj = allocate
28
- obj.__send__ :initialize_from_file, *args
28
+ obj.__send__ :initialize_from_file, *args, &block
29
29
  obj
30
30
  end
31
31
  CODE
@@ -39,10 +39,10 @@ describe GirFFI::Builders::FunctionBuilder do
39
39
  let(:function_info) { get_introspection_data 'Regress', 'test_callback_destroy_notify' }
40
40
  it 'builds a correct definition' do
41
41
  code.must_equal <<-CODE.reset_indentation
42
- def self.test_callback_destroy_notify(callback, user_data, notify)
42
+ def self.test_callback_destroy_notify(&callback)
43
43
  _v1 = Regress::TestCallbackUserData.from(callback)
44
- _v2 = GirFFI::InPointer.from_closure_data(user_data)
45
- _v3 = GLib::DestroyNotify.from(notify)
44
+ _v2 = GirFFI::InPointer.from_closure_data(_v1.object_id)
45
+ _v3 = GLib::DestroyNotify.default
46
46
  _v4 = Regress::Lib.regress_test_callback_destroy_notify _v1, _v2, _v3
47
47
  return _v4
48
48
  end
@@ -62,6 +62,49 @@ describe GirFFI::Builders::FunctionBuilder do
62
62
  end
63
63
  end
64
64
 
65
+ describe 'for functions that return a GValue' do
66
+ let(:function_info) { get_introspection_data 'GIMarshallingTests', 'gvalue_return' }
67
+ it 'creates a call to #get_value' do
68
+ code.must_equal <<-CODE.reset_indentation
69
+ def self.gvalue_return
70
+ _v1 = GIMarshallingTests::Lib.gi_marshalling_tests_gvalue_return
71
+ _v2 = GObject::Value.wrap(_v1).get_value
72
+ return _v2
73
+ end
74
+ CODE
75
+ end
76
+ end
77
+
78
+ describe 'for functions that have a GValue out argument' do
79
+ let(:function_info) { get_introspection_data 'GIMarshallingTests', 'gvalue_out' }
80
+ it 'creates a call to #get_value' do
81
+ code.must_equal <<-CODE.reset_indentation
82
+ def self.gvalue_out
83
+ _v1 = GirFFI::InOutPointer.for [:pointer, GObject::Value]
84
+ GIMarshallingTests::Lib.gi_marshalling_tests_gvalue_out _v1
85
+ _v2 = GObject::Value.wrap(_v1.to_value).get_value
86
+ return _v2
87
+ end
88
+ CODE
89
+ end
90
+ end
91
+
92
+ describe 'for functions that have a caller-allocated GValue out argument' do
93
+ let(:function_info) { get_introspection_data 'GIMarshallingTests', 'gvalue_out_caller_allocates' }
94
+
95
+ it 'creates a call to #get_value' do
96
+ skip unless function_info
97
+ code.must_equal <<-CODE.reset_indentation
98
+ def self.gvalue_out_caller_allocates
99
+ _v1 = GObject::Value.new
100
+ GIMarshallingTests::Lib.gi_marshalling_tests_gvalue_out_caller_allocates _v1
101
+ _v2 = _v1.get_value
102
+ return _v2
103
+ end
104
+ CODE
105
+ end
106
+ end
107
+
65
108
  describe 'for functions with a nullable input array' do
66
109
  let(:function_info) { get_introspection_data 'Regress', 'test_array_int_null_in' }
67
110
  it 'builds correct definition' do
@@ -60,5 +60,30 @@ describe GirFFI::Builders::ObjectBuilder do
60
60
  it 'returns the class struct type' do
61
61
  obj_builder.object_class_struct.must_equal Regress::TestObjClass
62
62
  end
63
+
64
+ it 'returns the parent struct type for classes without their own struct' do
65
+ binding_info = get_introspection_data 'GObject', 'Binding'
66
+ builder = GirFFI::Builders::ObjectBuilder.new binding_info
67
+ builder.object_class_struct.must_equal GObject::ObjectClass
68
+ end
69
+ end
70
+
71
+ # TODO: Improve this spec to use less mocking
72
+ describe 'for a struct without defined fields' do
73
+ it 'uses a single field of the parent struct type as the default layout' do
74
+ @gir = GObjectIntrospection::IRepository.default
75
+ @gir.require 'GObject', nil
76
+
77
+ allow(info = Object.new).to receive(:parent).and_return @gir.find_by_name 'GObject', 'Object'
78
+ allow(info).to receive(:fields).and_return []
79
+ allow(info).to receive(:info_type).and_return :object
80
+ allow(info).to receive(:safe_name).and_return 'Bar'
81
+ allow(info).to receive(:namespace).and_return 'Foo'
82
+
83
+ @classbuilder = GirFFI::Builders::ObjectBuilder.new info
84
+
85
+ spec = @classbuilder.send :layout_specification
86
+ assert_equal [:parent, GObject::Object::Struct, 0], spec
87
+ end
63
88
  end
64
89
  end
@@ -8,7 +8,7 @@ describe GirFFI::Builders::PropertyBuilder do
8
8
  it 'generates the correct getter definition' do
9
9
  expected = <<-CODE.reset_indentation
10
10
  def list
11
- _v1 = get_property("list").get_value_plain
11
+ _v1 = get_property("list")
12
12
  _v2 = GLib::List.wrap(:utf8, _v1)
13
13
  _v2
14
14
  end
@@ -34,7 +34,7 @@ describe GirFFI::Builders::PropertyBuilder do
34
34
  it 'generates the correct getter definition' do
35
35
  expected = <<-CODE.reset_indentation
36
36
  def hash_table
37
- _v1 = get_property("hash-table").get_value_plain
37
+ _v1 = get_property("hash-table")
38
38
  _v2 = GLib::HashTable.wrap([:utf8, :gint8], _v1)
39
39
  _v2
40
40
  end
@@ -68,7 +68,7 @@ describe GirFFI::Builders::PropertyBuilder do
68
68
  it 'generates the correct getter definition' do
69
69
  expected = <<-CODE.reset_indentation
70
70
  def some_strv
71
- get_property("some-strv").get_value
71
+ get_property("some-strv")
72
72
  end
73
73
  CODE
74
74
 
@@ -92,7 +92,7 @@ describe GirFFI::Builders::PropertyBuilder do
92
92
  it 'generates the correct getter definition' do
93
93
  expected = <<-CODE.reset_indentation
94
94
  def string
95
- get_property("string").get_value
95
+ get_property("string")
96
96
  end
97
97
  CODE
98
98
 
@@ -46,21 +46,23 @@ describe GirFFI::Builders::StructBuilder do
46
46
  end
47
47
  end
48
48
 
49
- describe 'for a struct without defined fields' do
50
- it 'uses a single field of the parent struct type as the default layout' do
51
- @gir = GObjectIntrospection::IRepository.default
52
- @gir.require 'GObject', nil
53
-
54
- allow(info = Object.new).to receive(:parent).and_return @gir.find_by_name 'GObject', 'Object'
55
- allow(info).to receive(:fields).and_return []
56
- allow(info).to receive(:info_type).and_return :object
57
- allow(info).to receive(:safe_name).and_return 'Bar'
58
- allow(info).to receive(:namespace).and_return 'Foo'
49
+ describe '#superclass' do
50
+ it 'returns StructBase for a normal struct' do
51
+ info = get_introspection_data 'Regress', 'TestStructA'
52
+ builder = GirFFI::Builders::StructBuilder.new info
53
+ builder.superclass.must_equal GirFFI::StructBase
54
+ end
59
55
 
60
- @classbuilder = GirFFI::Builders::ObjectBuilder.new info
56
+ it 'returns the GObject parent class for a type class' do
57
+ info = get_introspection_data 'GIMarshallingTests', 'SubSubObjectClass'
58
+ builder = GirFFI::Builders::StructBuilder.new info
59
+ builder.superclass.must_equal GIMarshallingTests::SubObjectClass
60
+ end
61
61
 
62
- spec = @classbuilder.send :layout_specification
63
- assert_equal [:parent, GObject::Object::Struct, 0], spec
62
+ it 'returns ObjectClass for InitiallyUnownedClass' do
63
+ info = get_introspection_data 'GObject', 'InitiallyUnownedClass'
64
+ builder = GirFFI::Builders::StructBuilder.new info
65
+ builder.superclass.must_equal GObject::ObjectClass
64
66
  end
65
67
  end
66
68
  end
@@ -0,0 +1,33 @@
1
+ require 'gir_ffi_test_helper'
2
+
3
+ GirFFI.setup :GIMarshallingTests
4
+
5
+ describe GirFFI::Builders::UnintrospectableBoxedBuilder do
6
+ let(:instance) { GIMarshallingTests::PropertiesObject.new }
7
+ let(:property) { instance.object_class.find_property 'some-boxed-glist' }
8
+ let(:gtype) { property.value_type }
9
+ let(:info) { GirFFI::UnintrospectableBoxedInfo.new(gtype) }
10
+ let(:bldr) { GirFFI::Builders::UnintrospectableBoxedBuilder.new(info) }
11
+ let(:klass) { bldr.build_class }
12
+
13
+ before do
14
+ skip unless get_property_introspection_data('GIMarshallingTests',
15
+ 'PropertiesObject',
16
+ 'some-boxed-glist')
17
+ end
18
+
19
+ it 'builds a class' do
20
+ klass.must_be_instance_of Class
21
+ end
22
+
23
+ it 'builds a class derived from GirFFI::BoxedBase' do
24
+ klass.ancestors.must_include GirFFI::BoxedBase
25
+ end
26
+
27
+ it 'returns the same class when built again' do
28
+ other_bldr = GirFFI::Builders::UnintrospectableBoxedBuilder.new(info)
29
+ other_klass = other_bldr.build_class
30
+
31
+ other_klass.must_equal klass
32
+ end
33
+ end
@@ -52,5 +52,11 @@ describe GirFFI::Builders::UnintrospectableBuilder do
52
52
  signal.name.must_equal 'notify'
53
53
  end
54
54
  end
55
+
56
+ describe '#object_class_struct' do
57
+ it 'returns the parent class struct' do
58
+ @bldr.object_class_struct.must_equal GObject::ObjectClass
59
+ end
60
+ end
55
61
  end
56
62
  end
@@ -44,7 +44,7 @@ describe GirFFI::Builders::UserDefinedBuilder do
44
44
  it 'makes the property retrievable using #get_property' do
45
45
  obj = klass.new
46
46
  obj.foo = 13
47
- obj.get_property('foo').get_value.must_equal 13
47
+ obj.get_property('foo').must_equal 13
48
48
  end
49
49
 
50
50
  it 'makes the property settable using #set_property' do
@@ -121,4 +121,10 @@ describe GirFFI::Builders::UserDefinedBuilder do
121
121
  GObject.type_from_instance(obj).must_equal klass.gtype
122
122
  end
123
123
  end
124
+
125
+ describe '#object_class_struct' do
126
+ it 'returns the parent class struct' do
127
+ builder.object_class_struct.must_equal GIMarshallingTests::ObjectClass
128
+ end
129
+ end
124
130
  end
@@ -3,8 +3,18 @@ require 'gir_ffi_test_helper'
3
3
  describe GirFFI::CallbackBase do
4
4
  describe '.store_callback' do
5
5
  it 'stores the passed in proc in CALLBACKS' do
6
- GirFFI::CallbackBase.store_callback 'some-callback'
7
- GirFFI::CallbackBase::CALLBACKS.last.must_equal 'some-callback'
6
+ dummy_proc = 'some-callback'
7
+ GirFFI::CallbackBase.store_callback dummy_proc
8
+ GirFFI::CallbackBase::CALLBACKS[dummy_proc.object_id].must_equal dummy_proc
9
+ end
10
+ end
11
+
12
+ describe '.drop_callback' do
13
+ it 'removes the corresponding proc from CALLBACKS' do
14
+ dummy_proc = 'some-callback'
15
+ GirFFI::CallbackBase.store_callback dummy_proc
16
+ GirFFI::CallbackBase.drop_callback dummy_proc.object_id
17
+ GirFFI::CallbackBase::CALLBACKS[dummy_proc.object_id].must_be_nil
8
18
  end
9
19
  end
10
20
  end
@@ -1,5 +1,7 @@
1
1
  require 'gir_ffi_test_helper'
2
2
 
3
+ GirFFI.setup :Regress
4
+
3
5
  describe GirFFI::ObjectBase do
4
6
  let(:derived_class) { Class.new GirFFI::ObjectBase }
5
7
 
@@ -15,4 +17,16 @@ describe GirFFI::ObjectBase do
15
17
  derived_class.to_ffi_type.must_equal derived_class
16
18
  end
17
19
  end
20
+
21
+ describe '.object_class' do
22
+ it 'returns an object of the class struct type' do
23
+ Regress::TestObj.object_class.must_be_instance_of Regress::TestObjClass
24
+ end
25
+
26
+ it 'caches its result' do
27
+ first = Regress::TestObj.object_class
28
+ second = Regress::TestObj.object_class
29
+ second.must_be :eql?, first
30
+ end
31
+ end
18
32
  end
@@ -0,0 +1,61 @@
1
+ require 'gir_ffi_test_helper'
2
+
3
+ GirFFI.setup :Regress
4
+
5
+ class CallbackTestException < RuntimeError; end
6
+
7
+ describe 'An exception in a callback' do
8
+ describe 'for signals' do
9
+ let(:object) { Regress::TestSubObj.new }
10
+
11
+ before do
12
+ object.signal_connect 'test' do
13
+ raise CallbackTestException, 'Boom'
14
+ end
15
+ end
16
+
17
+ describe 'when the signal is emitted synchronously' do
18
+ it 'raises an error' do
19
+ proc { GObject.signal_emit object, 'test' }.must_raise CallbackTestException
20
+ end
21
+ end
22
+
23
+ describe 'when the signal is emitted during an event loop' do
24
+ it 'causes loop run to be terminated with an exception' do
25
+ main_loop = GLib::MainLoop.new nil, false
26
+
27
+ GLib.timeout_add GLib::PRIORITY_DEFAULT, 1 do
28
+ GObject.signal_emit object, 'test'
29
+ false
30
+ end
31
+ # Guard against runaway loop
32
+ GLib.timeout_add GLib::PRIORITY_DEFAULT, 500 do
33
+ main_loop.quit
34
+ end
35
+ proc do
36
+ main_loop.run
37
+ end.must_raise CallbackTestException
38
+ end
39
+ end
40
+ end
41
+
42
+ describe 'for other callbacks' do
43
+ describe 'when the callback occurs during an event loop' do
44
+ it 'causes loop run to be terminated with an exception' do
45
+ main_loop = GLib::MainLoop.new nil, false
46
+
47
+ GLib.timeout_add GLib::PRIORITY_DEFAULT, 1 do
48
+ raise CallbackTestException, 'Boom'
49
+ end
50
+ # Guard against runaway loop
51
+ GLib.timeout_add GLib::PRIORITY_DEFAULT, 500 do
52
+ main_loop.quit
53
+ end
54
+
55
+ proc do
56
+ main_loop.run
57
+ end.must_raise CallbackTestException
58
+ end
59
+ end
60
+ end
61
+ end