gir_ffi 0.8.6 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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