1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
# frozen_string_literal: true
begin
require_relative 'helper'
rescue LoadError
end
module Fiddle
class TestClosure < Fiddle::TestCase
def teardown
super
# We can't use ObjectSpace with JRuby.
return if RUBY_ENGINE == "jruby"
# Ensure freeing all closures.
# See https://github.com/ruby/fiddle/issues/102#issuecomment-1241763091 .
not_freed_closures = []
ObjectSpace.each_object(Fiddle::Closure) do |closure|
not_freed_closures << closure unless closure.freed?
end
assert_equal([], not_freed_closures)
end
def test_argument_errors
assert_raise(TypeError) do
Closure.new(TYPE_INT, TYPE_INT)
end
assert_raise(TypeError) do
Closure.new('foo', [TYPE_INT])
end
assert_raise(TypeError) do
Closure.new(TYPE_INT, ['meow!'])
end
end
def test_call
closure_class = Class.new(Closure) do
def call
10
end
end
closure_class.create(TYPE_INT, []) do |closure|
func = Function.new(closure, [], TYPE_INT)
assert_equal 10, func.call
end
end
def test_returner
closure_class = Class.new(Closure) do
def call thing
thing
end
end
closure_class.create(TYPE_INT, [TYPE_INT]) do |closure|
func = Function.new(closure, [TYPE_INT], TYPE_INT)
assert_equal 10, func.call(10)
end
end
def test_const_string
if ffi_backend?
omit("Closure with :const_string works but " +
"Function with :const_string doesn't work with FFI backend")
end
closure_class = Class.new(Closure) do
def call(string)
@return_string = "Hello! #{string}"
@return_string
end
end
closure_class.create(:const_string, [:const_string]) do |closure|
func = Function.new(closure, [:const_string], :const_string)
assert_equal("Hello! World!", func.call("World!"))
end
end
def test_bool
closure_class = Class.new(Closure) do
def call(bool)
not bool
end
end
closure_class.create(:bool, [:bool]) do |closure|
func = Function.new(closure, [:bool], :bool)
assert_equal(false, func.call(true))
end
end
def test_free
closure_class = Class.new(Closure) do
def call
10
end
end
closure_class.create(:int, [:void]) do |closure|
assert(!closure.freed?)
closure.free
assert(closure.freed?)
closure.free
end
end
def test_block_caller
cb = Closure::BlockCaller.new(TYPE_INT, [TYPE_INT]) do |one|
one
end
begin
func = Function.new(cb, [TYPE_INT], TYPE_INT)
assert_equal 11, func.call(11)
ensure
cb.free
end
end
def test_memsize_ruby_dev_42480
if RUBY_ENGINE == "jruby"
omit("We can't use ObjectSpace with JRuby")
end
require 'objspace'
closure_class = Class.new(Closure) do
def call
10
end
end
n = 10000
n.times do
closure_class.create(:int, [:void]) do |closure|
ObjectSpace.memsize_of(closure)
end
end
end
%w[INT SHORT CHAR LONG LONG_LONG].each do |name|
type = Fiddle.const_get("TYPE_#{name}") rescue next
size = Fiddle.const_get("SIZEOF_#{name}")
[[type, size-1, name], [-type, size, "unsigned_"+name]].each do |t, s, n|
define_method("test_conversion_#{n.downcase}") do
arg = nil
closure_class = Class.new(Closure) do
define_method(:call) {|x| arg = x}
end
closure_class.create(t, [t]) do |closure|
v = ~(~0 << (8*s))
arg = nil
assert_equal(v, closure.call(v))
assert_equal(arg, v, n)
arg = nil
func = Function.new(closure, [t], t)
assert_equal(v, func.call(v))
assert_equal(arg, v, n)
end
end
end
end
def test_ractor_shareable
omit("Need Ractor") unless defined?(Ractor)
closure_class = Class.new(Closure) do
def call
0
end
end
closure_class.create(:int, [:void]) do |c|
assert_ractor_shareable(c)
end
end
end
end if defined?(Fiddle)
|