gir_ffi 0.10.2 → 0.11.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +13 -0
  3. data/Gemfile +9 -4
  4. data/README.md +3 -2
  5. data/Rakefile +2 -1
  6. data/lib/ffi-glib/byte_array.rb +1 -1
  7. data/lib/ffi-glib/main_loop.rb +2 -1
  8. data/lib/ffi-glib/strv.rb +5 -2
  9. data/lib/ffi-glib/variant.rb +3 -5
  10. data/lib/ffi-glib.rb +4 -0
  11. data/lib/ffi-gobject/closure.rb +8 -10
  12. data/lib/ffi-gobject/object.rb +9 -6
  13. data/lib/ffi-gobject/param_spec.rb +4 -0
  14. data/lib/ffi-gobject/value.rb +13 -16
  15. data/lib/ffi-gobject_introspection/gobject_type_init.rb +18 -0
  16. data/lib/ffi-gobject_introspection/i_callable_info.rb +1 -5
  17. data/lib/ffi-gobject_introspection/i_constant_info.rb +3 -3
  18. data/lib/ffi-gobject_introspection/i_repository.rb +3 -47
  19. data/lib/ffi-gobject_introspection/i_vfunc_info.rb +3 -11
  20. data/lib/ffi-gobject_introspection/lib.rb +8 -31
  21. data/lib/{gir_ffi-base/glib → ffi-gobject_introspection}/strv.rb +9 -13
  22. data/lib/ffi-gobject_introspection.rb +47 -2
  23. data/lib/gir_ffi/allocation_helper.rb +1 -19
  24. data/lib/gir_ffi/arg_helper.rb +36 -26
  25. data/lib/{gir_ffi-base/glib → gir_ffi}/boolean.rb +7 -5
  26. data/lib/gir_ffi/boxed_base.rb +5 -23
  27. data/lib/gir_ffi/builder.rb +3 -3
  28. data/lib/gir_ffi/builders/argument_builder.rb +7 -8
  29. data/lib/gir_ffi/builders/base_argument_builder.rb +0 -1
  30. data/lib/gir_ffi/builders/callback_argument_builder.rb +2 -2
  31. data/lib/gir_ffi/builders/callback_return_value_builder.rb +21 -13
  32. data/lib/gir_ffi/builders/field_builder.rb +4 -10
  33. data/lib/gir_ffi/builders/module_builder.rb +6 -4
  34. data/lib/gir_ffi/builders/object_builder.rb +16 -16
  35. data/lib/gir_ffi/builders/struct_builder.rb +4 -6
  36. data/lib/gir_ffi/builders/struct_like.rb +1 -1
  37. data/lib/gir_ffi/builders/user_defined_builder.rb +83 -23
  38. data/lib/gir_ffi/builders/vfunc_argument_builder.rb +12 -17
  39. data/lib/gir_ffi/class_base.rb +0 -4
  40. data/lib/gir_ffi/core.rb +16 -13
  41. data/lib/gir_ffi/enum_base.rb +2 -41
  42. data/lib/gir_ffi/enum_like_base.rb +48 -0
  43. data/lib/gir_ffi/ffi_ext/pointer.rb +1 -1
  44. data/lib/gir_ffi/flags_base.rb +2 -41
  45. data/lib/gir_ffi/in_out_pointer.rb +1 -1
  46. data/lib/gir_ffi/in_pointer.rb +4 -4
  47. data/lib/gir_ffi/info_ext/i_type_info.rb +14 -5
  48. data/lib/gir_ffi/info_ext/i_vfunc_info.rb +8 -0
  49. data/lib/gir_ffi/module_base.rb +4 -0
  50. data/lib/gir_ffi/receiver_argument_info.rb +1 -1
  51. data/lib/gir_ffi/sized_array.rb +6 -6
  52. data/lib/gir_ffi/struct_base.rb +1 -6
  53. data/lib/gir_ffi/struct_like_base.rb +54 -45
  54. data/lib/gir_ffi/type_map.rb +6 -7
  55. data/lib/gir_ffi/union_base.rb +1 -1
  56. data/lib/gir_ffi/{user_defined_type_info.rb → user_defined_object_info.rb} +1 -2
  57. data/lib/gir_ffi/user_defined_property_info.rb +80 -2
  58. data/lib/gir_ffi/version.rb +1 -1
  59. data/lib/gir_ffi-base/gobject/lib.rb +0 -1
  60. data/lib/gir_ffi-base/gobject.rb +3 -5
  61. data/lib/gir_ffi-base.rb +3 -8
  62. data/tasks/test.rake +17 -3
  63. data/test/base_test_helper.rb +39 -23
  64. data/test/ffi-glib/closure_test.rb +37 -0
  65. data/test/ffi-glib/main_loop_test.rb +24 -0
  66. data/test/ffi-glib/ruby_closure_test.rb +0 -5
  67. data/test/ffi-gobject/object_test.rb +6 -10
  68. data/test/ffi-gobject/param_spec_test.rb +17 -5
  69. data/test/ffi-gobject/value_test.rb +15 -6
  70. data/test/ffi-gobject_introspection/gobject_type_init_test.rb +25 -0
  71. data/test/ffi-gobject_introspection/i_base_info_test.rb +1 -1
  72. data/test/ffi-gobject_introspection/i_repository_test.rb +18 -0
  73. data/test/ffi-gobject_introspection/i_vfunc_info_test.rb +40 -0
  74. data/test/{gir_ffi-base/glib → ffi-gobject_introspection}/strv_test.rb +8 -8
  75. data/test/gir_ffi/allocation_helper_test.rb +35 -0
  76. data/test/gir_ffi/arg_helper_test.rb +102 -7
  77. data/test/gir_ffi/boolean_test.rb +34 -0
  78. data/test/gir_ffi/boxed_base_test.rb +46 -6
  79. data/test/gir_ffi/builder_test.rb +88 -29
  80. data/test/gir_ffi/builders/argument_builder_test.rb +19 -0
  81. data/test/gir_ffi/builders/callback_argument_builder_test.rb +17 -0
  82. data/test/gir_ffi/builders/callback_return_value_builder_test.rb +1 -1
  83. data/test/gir_ffi/builders/field_builder_test.rb +2 -1
  84. data/test/gir_ffi/builders/struct_builder_test.rb +42 -25
  85. data/test/gir_ffi/builders/user_defined_builder_test.rb +365 -17
  86. data/test/gir_ffi/builders/vfunc_argument_builder_test.rb +100 -0
  87. data/test/gir_ffi/builders/vfunc_builder_test.rb +5 -3
  88. data/test/{gir_ffi_test.rb → gir_ffi/core_test.rb} +8 -6
  89. data/test/gir_ffi/in_out_pointer_test.rb +1 -1
  90. data/test/gir_ffi/receiver_argument_info_test.rb +32 -0
  91. data/test/gir_ffi/sized_array_test.rb +34 -0
  92. data/test/gir_ffi/struct_base_test.rb +4 -32
  93. data/test/gir_ffi/struct_like_base_test.rb +164 -0
  94. data/test/gir_ffi/union_base_test.rb +4 -20
  95. data/test/gir_ffi/{user_defined_type_info_test.rb → user_defined_object_info_test.rb} +10 -10
  96. data/test/gir_ffi/user_defined_property_info_test.rb +22 -5
  97. data/test/gir_ffi/version_test.rb +1 -1
  98. data/test/integration/callback_exceptions_test.rb +2 -0
  99. data/test/integration/derived_classes_test.rb +2 -0
  100. data/test/integration/generated_everything_test.rb +22 -0
  101. data/test/integration/generated_gimarshallingtests_test.rb +23 -21
  102. data/test/integration/generated_gio_test.rb +2 -0
  103. data/test/integration/generated_glib_test.rb +2 -0
  104. data/test/integration/generated_gst_test.rb +2 -0
  105. data/test/integration/generated_gtop_test.rb +2 -0
  106. data/test/integration/generated_regress_test.rb +113 -29
  107. data/test/integration/generated_secret_test.rb +2 -0
  108. data/test/integration/generated_warnlib_test.rb +2 -0
  109. data/test/integration/method_lookup_test.rb +2 -0
  110. data/test/introspection_test_helper.rb +15 -0
  111. metadata +21 -27
  112. data/lib/gir_ffi-base/glib.rb +0 -8
  113. data/test/gir_ffi-base/glib/boolean_test.rb +0 -34
@@ -7,7 +7,6 @@ module GObject
7
7
  extend FFI::Library
8
8
  extend FFI::BitMasks
9
9
  ffi_lib 'gobject-2.0'
10
- attach_function :g_type_init, [], :void
11
10
  attach_function :g_type_from_name, [:string], :size_t
12
11
  attach_function :g_type_fundamental, [:size_t], :size_t
13
12
  end
@@ -5,12 +5,10 @@ raise 'The module GObject was already defined elsewhere' if Kernel.const_defined
5
5
 
6
6
  require 'gir_ffi-base/gobject/lib'
7
7
 
8
- # The part of the GObject namespace that is needed by GObjectIntrospection.
8
+ # The part of the GObject namespace that is needed by GirFFI.
9
+ #
10
+ # :reek:TooManyConstants: because it needs to hold the type constants.
9
11
  module GObject
10
- def self.type_init
11
- Lib.g_type_init
12
- end
13
-
14
12
  def self.type_from_name(name)
15
13
  Lib.g_type_from_name name
16
14
  end
data/lib/gir_ffi-base.rb CHANGED
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  #
3
- # This section contains code that is needed by GObjectIntrospection and GirFFI,
4
- # but belongs in modules that can only be created fully once GirFFI is fully
5
- # loaded.
3
+ # This section contains code that is needed by GirFFI, but belongs in modules
4
+ # that can only be created fully once GirFFI is fully loaded.
6
5
 
7
- # GLib::Strv and GObject.type_init are needed by GObjectIntrospection
8
- require 'gir_ffi-base/glib/strv'
6
+ # Some base GObject functions and constants are needed by GirFFI.
9
7
  require 'gir_ffi-base/gobject'
10
-
11
- # GLib::Boolean is needed by GirFFI.
12
- require 'gir_ffi-base/glib/boolean'
data/tasks/test.rake CHANGED
@@ -132,8 +132,7 @@ namespace :test do
132
132
  end
133
133
 
134
134
  define_test_task(:main) do |t|
135
- t.test_files = FileList['test/gir_ffi_test.rb',
136
- 'test/gir_ffi/**/*_test.rb']
135
+ t.test_files = FileList['test/gir_ffi/**/*_test.rb']
137
136
  end
138
137
 
139
138
  define_test_task(:overrides) do |t|
@@ -190,6 +189,22 @@ namespace :test do
190
189
  Cucumber::Rake::Task.new(:features) do |t|
191
190
  t.cucumber_opts = 'features --format pretty'
192
191
  end
192
+
193
+ desc 'Run mutant'
194
+
195
+ task mutant: :lib do
196
+ command = <<-EOS
197
+ RUBY_THREAD_VM_STACK_SIZE=64000 \
198
+ bundle exec mutant \
199
+ --include lib \
200
+ --include test \
201
+ --use minitest \
202
+ --since master \
203
+ --jobs 4 \
204
+ "GirFFI*" "GObject*" "GObjectIntrospection*" "GLib*"
205
+ EOS
206
+ system command
207
+ end
193
208
  end
194
209
 
195
210
  file "test/lib/Makefile" => "test/lib/configure" do
@@ -201,4 +216,3 @@ file "test/lib/configure" => ["test/lib/autogen.sh", "test/lib/configure.ac"] do
201
216
  end
202
217
 
203
218
  task test: 'test:all'
204
- task test: 'test:features'
@@ -15,29 +15,8 @@ begin
15
15
  rescue LoadError
16
16
  end
17
17
 
18
- require 'minitest/rspec_mocks'
19
18
  require 'minitest/autorun'
20
-
21
- require 'gir_ffi-base'
22
- require 'ffi-gobject_introspection'
23
-
24
- GObjectIntrospection::IRepository.prepend_search_path File.join(File.dirname(__FILE__), 'lib')
25
-
26
- module GObjectIntrospection
27
- class IRepository
28
- def shared_library_with_regress(namespace)
29
- case namespace
30
- when 'Everything', 'GIMarshallingTests', 'Regress', 'Utility', 'WarnLib'
31
- return File.join(File.dirname(__FILE__), 'lib', "lib#{namespace.downcase}.so")
32
- else
33
- return shared_library_without_regress namespace
34
- end
35
- end
36
-
37
- alias_method :shared_library_without_regress, :shared_library
38
- alias_method :shared_library, :shared_library_with_regress
39
- end
40
- end
19
+ require 'rspec/mocks/minitest_integration'
41
20
 
42
21
  Thread.abort_on_exception = true
43
22
 
@@ -82,4 +61,41 @@ module BaseTestExtensions
82
61
  end
83
62
 
84
63
  Minitest::Test.send :include, BaseTestExtensions
85
- Minitest::Test.send :include, Minitest::RSpecMocks
64
+
65
+ # Provide methods needed for integration with mutant
66
+ module ForMutant
67
+ # Mark the current test class as covering the given expression.
68
+ def cover(expression)
69
+ @expression = expression
70
+ end
71
+
72
+ # Return the currently set covering expression.
73
+ def covering
74
+ defined?(@expression) && @expression
75
+ end
76
+
77
+ # Return the cover expression, but raise an exception if it is not defined.
78
+ # This is the method used by mutant to fetch the coverage information.
79
+ def cover_expression
80
+ raise "Cover expression for #{self} is not specified" unless @expression
81
+ @expression
82
+ end
83
+ end
84
+
85
+ Minitest::Test.send :extend, ForMutant
86
+
87
+ def cover_expression_for(cls)
88
+ full_stack = cls.describe_stack.dup << cls
89
+ full_stack.reverse_each do |level|
90
+ return level.covering if level.covering
91
+ return level.desc.to_s if level.desc.is_a? Module
92
+ end
93
+ full_stack.first.desc.to_s
94
+ end
95
+
96
+ # Override describe to automatically set cover information
97
+ def describe(desc, *additional_desc, &block)
98
+ super.tap do |cls|
99
+ cls.cover cover_expression_for(cls) unless cls.covering
100
+ end
101
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ require 'gir_ffi_test_helper'
3
+
4
+ describe GObject::Closure do
5
+ describe '.new' do
6
+ it 'updates the ref_count of the created object' do
7
+ # Tested on a subclass ...
8
+ c = GObject::RubyClosure.new {}
9
+ c.ref_count.must_equal 1
10
+ end
11
+ end
12
+
13
+ describe '#invoke' do
14
+ it 'invokes the closure' do
15
+ a = 0
16
+ c = GObject::RubyClosure.new { a = 2 }
17
+ c2 = GObject::Closure.wrap(c.to_ptr)
18
+ c2.invoke nil, []
19
+ a.must_equal 2
20
+ end
21
+
22
+ it 'returns the closure result' do
23
+ c = GObject::RubyClosure.new { 3 }
24
+ c2 = GObject::Closure.wrap(c.to_ptr)
25
+ result = c2.invoke GObject::Value.for_gtype(GObject::TYPE_INT), []
26
+ result.must_equal 3
27
+ end
28
+
29
+ it 'passes arguments' do
30
+ a = 0
31
+ c = GObject::RubyClosure.new { |val| a = val }
32
+ c2 = GObject::Closure.wrap(c.to_ptr)
33
+ c2.invoke nil, [5]
34
+ a.must_equal 5
35
+ end
36
+ end
37
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  require 'gir_ffi_test_helper'
3
3
 
4
+ class MainLoopTestException < RuntimeError; end
5
+
4
6
  describe GLib::MainLoop do
5
7
  describe '#run' do
6
8
  it 'allows other threads to run' do
@@ -24,5 +26,27 @@ describe GLib::MainLoop do
24
26
 
25
27
  a.must_equal ['Before run', 'During run', 'After run']
26
28
  end
29
+
30
+ it 'raises and quits on exceptions in callbacks' do
31
+ main_loop = GLib::MainLoop.new nil, false
32
+
33
+ a = 'expected'
34
+
35
+ # This timeout shouldn't get called
36
+ guard = GLib.timeout_add GLib::PRIORITY_DEFAULT, 150 do
37
+ a = 'unexpected'
38
+ main_loop.quit
39
+ end
40
+
41
+ GLib.timeout_add GLib::PRIORITY_DEFAULT, 10 do
42
+ raise MainLoopTestException
43
+ end
44
+
45
+ -> { main_loop.run }.must_raise MainLoopTestException
46
+ a.must_equal 'expected'
47
+
48
+ # Clean up uncalled timeout
49
+ GLib.source_remove guard
50
+ end
27
51
  end
28
52
  end
@@ -13,11 +13,6 @@ describe GObject::RubyClosure do
13
13
  c = GObject::RubyClosure.new {}
14
14
  assert_kind_of GObject::Closure, c
15
15
  end
16
-
17
- it 'updates the ref_count of the created object' do
18
- c = GObject::RubyClosure.new {}
19
- c.ref_count.must_equal 1
20
- end
21
16
  end
22
17
 
23
18
  describe '.wrap' do
@@ -119,23 +119,19 @@ describe GObject::Object do
119
119
  end
120
120
 
121
121
  describe 'upon garbage collection' do
122
- # FIXME: Test this some other way
123
122
  it 'lowers the reference count' do
124
- if defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE)
123
+ if jruby? || rubinius?
125
124
  skip 'cannot be reliably tested on JRuby and Rubinius'
126
125
  end
127
- if RUBY_VERSION >= '2.3.0'
128
- skip 'cannot be reliably tested on CRuby >= 2.3'
129
- end
130
126
 
131
- object = GObject::Object.new
132
- ptr = object.to_ptr
127
+ ptr = GObject::Object.new.to_ptr
133
128
  ref_count(ptr).must_equal 1
134
129
 
135
- # Lose reference to object to allow garbage collection
136
- object = nil # rubocop:disable Lint/UselessAssignment
137
-
138
130
  GC.start
131
+ # Creating a new object is sometimes needed to trigger enough garbage collection.
132
+ GObject::Object.new
133
+ sleep 1
134
+
139
135
  GC.start
140
136
  GC.start
141
137
 
@@ -3,16 +3,28 @@ require 'gir_ffi_test_helper'
3
3
 
4
4
  require 'ffi-gobject'
5
5
  describe GObject::ParamSpec do
6
+ let(:pspec) do
7
+ GObject.param_spec_int('foo-bar', 'foo bar',
8
+ 'Foo Bar',
9
+ 1, 3, 2,
10
+ readable: true, writable: true)
11
+ end
12
+
6
13
  describe '#ref' do
7
14
  it 'increases the ref count' do
8
- pspec = GObject.param_spec_boolean('foo', 'foo bar',
9
- 'Boolean Foo Bar',
10
- false,
11
- readable: true, writable: true)
12
-
13
15
  old = pspec.ref_count
14
16
  pspec.ref
15
17
  pspec.ref_count.must_equal old + 1
16
18
  end
17
19
  end
20
+
21
+ describe '#accessor_name' do
22
+ it 'returns a safe ruby method name' do
23
+ pspec.accessor_name.must_equal 'foo_bar'
24
+ end
25
+ end
26
+
27
+ it 'cannot be instantiated directly' do
28
+ proc { GObject::ParamSpec.new }.must_raise NoMethodError
29
+ end
18
30
  end
@@ -256,7 +256,7 @@ describe GObject::Value do
256
256
  gv.get_value.must_equal value
257
257
  end
258
258
 
259
- it 'unwraps a ulong' do
259
+ it 'unwraps an ulong' do
260
260
  value = FFI.type_size(:long) == 8 ? 0x1234_5678_9012_3456 : 0x1234_5678
261
261
  gv = GObject::Value.for_gtype GObject::TYPE_ULONG
262
262
  gv.set_ulong value
@@ -291,6 +291,17 @@ describe GObject::Value do
291
291
  result.must_be_kind_of GLib::Array
292
292
  result.reset_typespec(:uint).to_a.must_equal [1, 2, 3]
293
293
  end
294
+
295
+ it 'unwraps a Strv' do
296
+ strv = GLib::Strv.from %w(foo bar)
297
+ val = GObject::Value.for_gtype GObject::TYPE_STRV
298
+ val.set_boxed strv
299
+
300
+ result = val.get_value
301
+
302
+ result.must_be_kind_of GLib::Strv
303
+ result.to_a.must_equal %w(foo bar)
304
+ end
294
305
  end
295
306
 
296
307
  describe '::from' do
@@ -334,12 +345,8 @@ describe GObject::Value do
334
345
  end
335
346
 
336
347
  describe 'upon garbage collection' do
337
- before do
338
- GirFFI.setup :GIMarshallingTests
339
- end
340
-
341
348
  it 'restores the underlying GValue to its pristine state' do
342
- if defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE)
349
+ if jruby? || rubinius?
343
350
  skip 'cannot be reliably tested on JRuby and Rubinius'
344
351
  end
345
352
 
@@ -350,6 +357,8 @@ describe GObject::Value do
350
357
  value.current_gtype_name.must_equal 'gint'
351
358
 
352
359
  GC.start
360
+ # Creating a new object is sometimes needed to trigger enough garbage collection.
361
+ GObject::Value.new
353
362
  sleep 1
354
363
  GC.start
355
364
  GC.start
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require 'introspection_test_helper'
3
+
4
+ describe GObjectIntrospection::GObjectTypeInit do
5
+ describe 'Lib' do
6
+ it 'represents the gobject-2.0 library' do
7
+ GObjectIntrospection::GObjectTypeInit::Lib.ffi_libraries.first.name.
8
+ must_match(/gobject-2\.0/)
9
+ end
10
+
11
+ it 'provides the g_type_init function' do
12
+ GObjectIntrospection::GObjectTypeInit::Lib.must_respond_to :g_type_init
13
+ end
14
+ end
15
+
16
+ describe '.type_init' do
17
+ it 'calls the g_type_init function from the gobject-2.0 library' do
18
+ allow(GObjectIntrospection::GObjectTypeInit::Lib).to receive(:g_type_init)
19
+
20
+ GObjectIntrospection::GObjectTypeInit.type_init
21
+
22
+ expect(GObjectIntrospection::GObjectTypeInit::Lib).to have_received(:g_type_init)
23
+ end
24
+ end
25
+ end
@@ -32,7 +32,7 @@ describe GObjectIntrospection::IBaseInfo do
32
32
 
33
33
  describe 'upon garbage collection' do
34
34
  it 'calls g_base_info_unref' do
35
- if defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE)
35
+ if jruby? || rubinius?
36
36
  skip 'cannot be reliably tested on JRuby and Rubinius'
37
37
  end
38
38
 
@@ -58,4 +58,22 @@ describe GObjectIntrospection::IRepository do
58
58
  assert_kind_of GObjectIntrospection::IBaseInfo, gir.info('GObject', 0)
59
59
  end
60
60
  end
61
+
62
+ describe '#dependencies' do
63
+ it 'returns a list of dependencies of the given namespace' do
64
+ result = gir.dependencies('GObject')
65
+ result.must_equal ['GLib-2.0']
66
+ end
67
+
68
+ it 'passes its struct pointer to the c function just in case' do
69
+ ptr = gir.instance_variable_get(:@gobj)
70
+ allow(GObjectIntrospection::Lib).to receive(:g_irepository_get_dependencies).
71
+ and_call_original
72
+
73
+ gir.dependencies('GObject')
74
+
75
+ expect(GObjectIntrospection::Lib).to have_received(:g_irepository_get_dependencies).
76
+ with(ptr, 'GObject')
77
+ end
78
+ end
61
79
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ require 'introspection_test_helper'
3
+
4
+ describe GObjectIntrospection::IVFuncInfo do
5
+ let(:vfunc_info) do
6
+ get_vfunc_introspection_data 'GIMarshallingTests', 'Object', 'method_int8_in'
7
+ end
8
+
9
+ let(:throwing_vfunc_info) do
10
+ get_vfunc_introspection_data 'GIMarshallingTests', 'Object', 'vfunc_meth_with_err'
11
+ end
12
+
13
+ let(:vfunc_info_with_different_invoker) do
14
+ get_vfunc_introspection_data 'Regress', 'TestObj', 'matrix'
15
+ end
16
+
17
+ describe '#throws?' do
18
+ it 'returns false if there is no error argument' do
19
+ vfunc_info.wont_be :throws?
20
+ end
21
+
22
+ it 'returns true if there is and error argument' do
23
+ throwing_vfunc_info.must_be :throws?
24
+ end
25
+ end
26
+
27
+ describe '#invoker' do
28
+ it 'returns nil if no invoker method is present' do
29
+ throwing_vfunc_info.invoker.must_be_nil
30
+ end
31
+
32
+ it 'returns info for the invoker method if present' do
33
+ vfunc_info.invoker.name.must_equal 'method_int8_in'
34
+ end
35
+
36
+ it 'returns the correct invoker even if named differently' do
37
+ vfunc_info_with_different_invoker.invoker.name.must_equal 'do_matrix'
38
+ end
39
+ end
40
+ end
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
  require 'base_test_helper'
3
3
 
4
- describe GLib::Strv do
4
+ describe GObjectIntrospection::Strv do
5
5
  it 'wraps a pointer' do
6
- strv = GLib::Strv.new :some_pointer
6
+ strv = GObjectIntrospection::Strv.new :some_pointer
7
7
  assert_equal :some_pointer, strv.to_ptr
8
8
  end
9
9
 
10
10
  describe '::wrap' do
11
- it 'takes a pointer and returns a GLib::Strv wrapping it' do
12
- strv = GLib::Strv.wrap :some_pointer
13
- assert_instance_of GLib::Strv, strv
11
+ it 'takes a pointer and returns a GObjectIntrospection::Strv wrapping it' do
12
+ strv = GObjectIntrospection::Strv.wrap :some_pointer
13
+ assert_instance_of GObjectIntrospection::Strv, strv
14
14
  assert_equal :some_pointer, strv.to_ptr
15
15
  end
16
16
  end
@@ -23,7 +23,7 @@ describe GLib::Strv do
23
23
  block = FFI::MemoryPointer.new(:pointer, ptrs.length)
24
24
  block.write_array_of_pointer ptrs
25
25
 
26
- strv = GLib::Strv.new block
26
+ strv = GObjectIntrospection::Strv.new block
27
27
  arr = []
28
28
  strv.each do |str|
29
29
  arr << str
@@ -32,7 +32,7 @@ describe GLib::Strv do
32
32
  end
33
33
 
34
34
  it 'yields zero times for a Strv wrapping a null pointer' do
35
- strv = GLib::Strv.new FFI::Pointer.new(0)
35
+ strv = GObjectIntrospection::Strv.new FFI::Pointer.new(0)
36
36
  strv.each do |_str|
37
37
  flunk
38
38
  end
@@ -40,6 +40,6 @@ describe GLib::Strv do
40
40
  end
41
41
 
42
42
  it 'includes Enumerable' do
43
- GLib::Strv.must_include Enumerable
43
+ GObjectIntrospection::Strv.must_include Enumerable
44
44
  end
45
45
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ require 'gir_ffi_test_helper'
3
+
4
+ describe GirFFI::AllocationHelper do
5
+ describe '.free_after' do
6
+ before do
7
+ allow(GirFFI::LibC).to receive(:free)
8
+ end
9
+
10
+ it 'frees the passed-in pointer' do
11
+ ptr = double('pointer', null?: false)
12
+ GirFFI::AllocationHelper.free_after(ptr) {}
13
+ expect(GirFFI::LibC).to have_received(:free).with(ptr)
14
+ end
15
+
16
+ it 'does not free a passed-in null pointer' do
17
+ ptr = double('pointer', null?: true)
18
+ GirFFI::AllocationHelper.free_after(ptr) {}
19
+ expect(GirFFI::LibC).not_to have_received(:free)
20
+ end
21
+
22
+ it 'yields ptr to the block' do
23
+ ptr = double('pointer', null?: false)
24
+ foo = nil
25
+ GirFFI::AllocationHelper.free_after(ptr) { |it| foo = it }
26
+ foo.must_equal ptr
27
+ end
28
+
29
+ it 'returns the result of the block' do
30
+ ptr = double('pointer', null?: false)
31
+ result = GirFFI::AllocationHelper.free_after(ptr) { 'bar' }
32
+ result.must_equal 'bar'
33
+ end
34
+ end
35
+ end
@@ -9,20 +9,87 @@ describe GirFFI::ArgHelper do
9
9
  GirFFI::ArgHelper.cast_from_pointer(klass, :pointer_value).must_equal :wrapped_value
10
10
  end
11
11
 
12
- it 'handles negative :gint8' do
13
- ptr = FFI::Pointer.new(-127)
14
- GirFFI::ArgHelper.cast_from_pointer(:gint8, ptr).must_equal(-127)
15
- end
12
+ describe 'for :gint8' do
13
+ it 'handles negative :gint8' do
14
+ ptr = FFI::Pointer.new(-127)
15
+ GirFFI::ArgHelper.cast_from_pointer(:gint8, ptr).must_equal(-127)
16
+ end
16
17
 
17
- it 'handles positive :gint8' do
18
- ptr = FFI::Pointer.new(128)
19
- GirFFI::ArgHelper.cast_from_pointer(:gint8, ptr).must_equal(128)
18
+ it 'handles positive :gint8' do
19
+ ptr = FFI::Pointer.new(128)
20
+ GirFFI::ArgHelper.cast_from_pointer(:gint8, ptr).must_equal(128)
21
+ end
20
22
  end
21
23
 
22
24
  it 'handles :guint32' do
23
25
  ptr = FFI::Pointer.new(0xffffffff)
24
26
  GirFFI::ArgHelper.cast_from_pointer(:guint32, ptr).must_equal(0xffffffff)
25
27
  end
28
+
29
+ describe 'for :gint32' do
30
+ it 'handles positive :gint32' do
31
+ ptr = FFI::Pointer.new(1)
32
+ GirFFI::ArgHelper.cast_from_pointer(:gint32, ptr).must_equal(1)
33
+ end
34
+
35
+ it 'handles negative :gint32' do
36
+ ptr = FFI::Pointer.new(0xffffffff)
37
+ GirFFI::ArgHelper.cast_from_pointer(:gint32, ptr).must_equal(-1)
38
+ end
39
+
40
+ it 'handles largest negative :gint32' do
41
+ ptr = FFI::Pointer.new(0x80000000)
42
+ GirFFI::ArgHelper.cast_from_pointer(:gint32, ptr).must_equal(-0x80000000)
43
+ end
44
+
45
+ it 'handles largest positive :gint32' do
46
+ ptr = FFI::Pointer.new(0x7fffffff)
47
+ GirFFI::ArgHelper.cast_from_pointer(:gint32, ptr).must_equal(0x7fffffff)
48
+ end
49
+ end
50
+
51
+ it 'handles :utf8' do
52
+ ptr = FFI::MemoryPointer.from_string 'foo'
53
+ GirFFI::ArgHelper.cast_from_pointer(:utf8, ptr).must_equal 'foo'
54
+ end
55
+
56
+ it 'handles :filename' do
57
+ ptr = FFI::MemoryPointer.from_string 'foo'
58
+ GirFFI::ArgHelper.cast_from_pointer(:filename, ptr).must_equal 'foo'
59
+ end
60
+
61
+ it 'handles GHashTable' do
62
+ hash = GLib::HashTable.from [:utf8, :gint32], 'foo' => 1, 'bar' => 2
63
+ ptr = hash.to_ptr
64
+ result = GirFFI::ArgHelper.cast_from_pointer([:pointer, [:ghash, :utf8, :gint32]], ptr)
65
+ result.to_hash.must_equal hash.to_hash
66
+ end
67
+
68
+ describe 'when passing a broken typespec' do
69
+ it 'raises on unknown symbol' do
70
+ ptr = FFI::Pointer.new(0xffffffff)
71
+ exception = -> { GirFFI::ArgHelper.cast_from_pointer(:foo, ptr) }.must_raise
72
+ exception.message.must_equal "Don't know how to cast foo"
73
+ end
74
+
75
+ it 'raises on unexpected main type for complex type' do
76
+ ptr = FFI::Pointer.new(0xffffffff)
77
+ exception = -> { GirFFI::ArgHelper.cast_from_pointer([:utf8], ptr) }.must_raise
78
+ exception.message.must_equal "Don't know how to cast [:utf8]"
79
+ end
80
+
81
+ it 'raises on unexpected sub type for complex type' do
82
+ ptr = FFI::Pointer.new(0xffffffff)
83
+ exception = -> { GirFFI::ArgHelper.cast_from_pointer([:pointer, :utf8], ptr) }.must_raise
84
+ exception.message.must_equal "Don't know how to cast [:pointer, :utf8]"
85
+ end
86
+
87
+ it 'raises on unexpected container type for complex type' do
88
+ ptr = FFI::Pointer.new(0xffffffff)
89
+ exception = -> { GirFFI::ArgHelper.cast_from_pointer([:pointer, [:gint32]], ptr) }.must_raise
90
+ exception.message.must_equal "Don't know how to cast [:pointer, [:gint32]]"
91
+ end
92
+ end
26
93
  end
27
94
 
28
95
  describe '.store' do
@@ -41,4 +108,32 @@ describe GirFFI::ArgHelper do
41
108
  end
42
109
  end
43
110
  end
111
+
112
+ describe '.check_fixed_array_size' do
113
+ it 'passes if array has the correct size' do
114
+ GirFFI::ArgHelper.check_fixed_array_size(3, [1, 2, 3], 'foo')
115
+ pass
116
+ end
117
+
118
+ it 'raises if array does not have the correct size' do
119
+ result = lambda do
120
+ GirFFI::ArgHelper.check_fixed_array_size(3, [1, 2], 'foo')
121
+ end.must_raise ArgumentError
122
+ result.message.must_equal 'foo should have size 3'
123
+ end
124
+ end
125
+
126
+ describe '.check_error' do
127
+ it 'does nothing if there is no error' do
128
+ err_ptr = double('err_ptr', read_pointer: nil)
129
+ GirFFI::ArgHelper.check_error err_ptr
130
+ pass
131
+ end
132
+
133
+ it 'raises an exception if there is an error' do
134
+ err = GLib::Error.new
135
+ err_ptr = double('err_ptr', read_pointer: err.to_ptr)
136
+ -> { GirFFI::ArgHelper.check_error err_ptr }.must_raise GirFFI::GLibError
137
+ end
138
+ end
44
139
  end