gir_ffi 0.10.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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