blob: bc9b55a8c7806e059531508c7b76e2b6f5d39fda [file] [log] [blame]
#
# This file is part of ruby-ffi.
# For licensing, see LICENSE.SPECS
#
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
describe "Callback" do
# module LibC
# extend FFI::Library
# callback :qsort_cmp, [ :pointer, :pointer ], :int
# attach_function :qsort, [ :pointer, :int, :int, :qsort_cmp ], :int
# end
# it "arguments get passed correctly" do
# p = MemoryPointer.new(:int, 2)
# p.put_array_of_int32(0, [ 1 , 2 ])
# args = []
# cmp = proc do |p1, p2| args.push(p1.get_int(0)); args.push(p2.get_int(0)); 0; end
# # this is a bit dodgey, as it relies on qsort passing the args in order
# LibC.qsort(p, 2, 4, cmp)
# args.should == [ 1, 2 ]
# end
#
# it "Block can be substituted for Callback as last argument" do
# p = MemoryPointer.new(:int, 2)
# p.put_array_of_int32(0, [ 1 , 2 ])
# args = []
# # this is a bit dodgey, as it relies on qsort passing the args in order
# LibC.qsort(p, 2, 4) do |p1, p2|
# args.push(p1.get_int(0))
# args.push(p2.get_int(0))
# 0
# end
# args.should == [ 1, 2 ]
# end
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
class S8F32S32 < FFI::Struct
layout :s8, :char, :f32, :float, :s32, :int
end
callback :cbVrS8, [ ], :char
callback :cbVrU8, [ ], :uchar
callback :cbVrS16, [ ], :short
callback :cbVrU16, [ ], :ushort
callback :cbVrS32, [ ], :int
callback :cbVrU32, [ ], :uint
callback :cbVrL, [ ], :long
callback :cbVrUL, [ ], :ulong
callback :cbVrS64, [ ], :long_long
callback :cbVrU64, [ ], :ulong_long
callback :cbVrP, [], :pointer
callback :cbVrZ, [], :bool
callback :cbCrV, [ :char ], :void
callback :cbSrV, [ :short ], :void
callback :cbIrV, [ :int ], :void
callback :cbLrV, [ :long ], :void
callback :cbULrV, [ :ulong ], :void
callback :cbLrV, [ :long_long ], :void
callback :cbVrT, [ ], S8F32S32.by_value
callback :cbTrV, [ S8F32S32.by_value ], :void
callback :cbYrV, [ S8F32S32.ptr ], :void
callback :cbVrY, [ ], S8F32S32.ptr
attach_function :testCallbackVrS8, :testClosureVrB, [ :cbVrS8 ], :char
attach_function :testCallbackVrU8, :testClosureVrB, [ :cbVrU8 ], :uchar
attach_function :testCallbackVrS16, :testClosureVrS, [ :cbVrS16 ], :short
attach_function :testCallbackVrU16, :testClosureVrS, [ :cbVrU16 ], :ushort
attach_function :testCallbackVrS32, :testClosureVrI, [ :cbVrS32 ], :int
attach_function :testCallbackVrU32, :testClosureVrI, [ :cbVrU32 ], :uint
attach_function :testCallbackVrL, :testClosureVrL, [ :cbVrL ], :long
attach_function :testCallbackVrZ, :testClosureVrZ, [ :cbVrZ ], :bool
attach_function :testCallbackVrUL, :testClosureVrL, [ :cbVrUL ], :ulong
attach_function :testCallbackVrS64, :testClosureVrLL, [ :cbVrS64 ], :long_long
attach_function :testCallbackVrU64, :testClosureVrLL, [ :cbVrU64 ], :ulong_long
attach_function :testCallbackVrP, :testClosureVrP, [ :cbVrP ], :pointer
attach_function :testCallbackVrY, :testClosureVrP, [ :cbVrY ], S8F32S32.ptr
attach_function :testCallbackVrT, :testClosureVrT, [ :cbVrT ], S8F32S32.by_value
attach_function :testCallbackTrV, :testClosureTrV, [ :cbTrV, S8F32S32.ptr ], :void
attach_variable :cbVrS8, :gvar_pointer, :cbVrS8
attach_variable :pVrS8, :gvar_pointer, :pointer
attach_function :testGVarCallbackVrS8, :testClosureVrB, [ :pointer ], :char
attach_function :testOptionalCallbackCrV, :testOptionalClosureBrV, [ :cbCrV, :char ], :void
end
it "returning :char (0)" do
expect(LibTest.testCallbackVrS8 { 0 }).to eq(0)
end
it "returning :char (127)" do
expect(LibTest.testCallbackVrS8 { 127 }).to eq(127)
end
it "returning :char (-128)" do
expect(LibTest.testCallbackVrS8 { -128 }).to eq(-128)
end
# test wrap around
it "returning :char (128)" do
expect(LibTest.testCallbackVrS8 { 128 }).to eq(-128)
end
it "returning :char (255)" do
expect(LibTest.testCallbackVrS8 { 0xff }).to eq(-1)
end
it "returning :uchar (0)" do
expect(LibTest.testCallbackVrU8 { 0 }).to eq(0)
end
it "returning :uchar (0xff)" do
expect(LibTest.testCallbackVrU8 { 0xff }).to eq(0xff)
end
it "returning :uchar (-1)" do
expect(LibTest.testCallbackVrU8 { -1 }).to eq(0xff)
end
it "returning :uchar (128)" do
expect(LibTest.testCallbackVrU8 { 128 }).to eq(128)
end
it "returning :uchar (-128)" do
expect(LibTest.testCallbackVrU8 { -128 }).to eq(128)
end
it "returning :short (0)" do
expect(LibTest.testCallbackVrS16 { 0 }).to eq(0)
end
it "returning :short (0x7fff)" do
expect(LibTest.testCallbackVrS16 { 0x7fff }).to eq(0x7fff)
end
# test wrap around
it "returning :short (0x8000)" do
expect(LibTest.testCallbackVrS16 { 0x8000 }).to eq(-0x8000)
end
it "returning :short (0xffff)" do
expect(LibTest.testCallbackVrS16 { 0xffff }).to eq(-1)
end
it "returning :ushort (0)" do
expect(LibTest.testCallbackVrU16 { 0 }).to eq(0)
end
it "returning :ushort (0x7fff)" do
expect(LibTest.testCallbackVrU16 { 0x7fff }).to eq(0x7fff)
end
it "returning :ushort (0x8000)" do
expect(LibTest.testCallbackVrU16 { 0x8000 }).to eq(0x8000)
end
it "returning :ushort (0xffff)" do
expect(LibTest.testCallbackVrU16 { 0xffff }).to eq(0xffff)
end
it "returning :ushort (-1)" do
expect(LibTest.testCallbackVrU16 { -1 }).to eq(0xffff)
end
it "returning :int (0)" do
expect(LibTest.testCallbackVrS32 { 0 }).to eq(0)
end
it "returning :int (0x7fffffff)" do
expect(LibTest.testCallbackVrS32 { 0x7fffffff }).to eq(0x7fffffff)
end
# test wrap around
it "returning :int (-0x80000000)" do
expect(LibTest.testCallbackVrS32 { -0x80000000 }).to eq(-0x80000000)
end
it "returning :int (-1)" do
expect(LibTest.testCallbackVrS32 { -1 }).to eq(-1)
end
it "returning :uint (0)" do
expect(LibTest.testCallbackVrU32 { 0 }).to eq(0)
end
it "returning :uint (0x7fffffff)" do
expect(LibTest.testCallbackVrU32 { 0x7fffffff }).to eq(0x7fffffff)
end
# test wrap around
it "returning :uint (0x80000000)" do
expect(LibTest.testCallbackVrU32 { 0x80000000 }).to eq(0x80000000)
end
it "returning :uint (0xffffffff)" do
expect(LibTest.testCallbackVrU32 { 0xffffffff }).to eq(0xffffffff)
end
it "returning :uint (-1)" do
expect(LibTest.testCallbackVrU32 { -1 }).to eq(0xffffffff)
end
it "returning :long (0)" do
expect(LibTest.testCallbackVrL { 0 }).to eq(0)
end
it "returning :long (0x7fffffff)" do
expect(LibTest.testCallbackVrL { 0x7fffffff }).to eq(0x7fffffff)
end
# test wrap around
it "returning :long (-0x80000000)" do
expect(LibTest.testCallbackVrL { -0x80000000 }).to eq(-0x80000000)
end
it "returning :long (-1)" do
expect(LibTest.testCallbackVrL { -1 }).to eq(-1)
end
it "returning :ulong (0)" do
expect(LibTest.testCallbackVrUL { 0 }).to eq(0)
end
it "returning :ulong (0x7fffffff)" do
expect(LibTest.testCallbackVrUL { 0x7fffffff }).to eq(0x7fffffff)
end
# test wrap around
it "returning :ulong (0x80000000)" do
expect(LibTest.testCallbackVrUL { 0x80000000 }).to eq(0x80000000)
end
it "returning :ulong (0xffffffff)" do
expect(LibTest.testCallbackVrUL { 0xffffffff }).to eq(0xffffffff)
end
it "Callback returning :ulong (-1)" do
if FFI::Platform::LONG_SIZE == 32
expect(LibTest.testCallbackVrUL { -1 }).to eq(0xffffffff)
else
expect(LibTest.testCallbackVrUL { -1 }).to eq(0xffffffffffffffff)
end
end
it "returning :long_long (0)" do
expect(LibTest.testCallbackVrS64 { 0 }).to eq(0)
end
it "returning :long_long (0x7fffffffffffffff)" do
expect(LibTest.testCallbackVrS64 { 0x7fffffffffffffff }).to eq(0x7fffffffffffffff)
end
# test wrap around
it "returning :long_long (-0x8000000000000000)" do
expect(LibTest.testCallbackVrS64 { -0x8000000000000000 }).to eq(-0x8000000000000000)
end
it "returning :long_long (-1)" do
expect(LibTest.testCallbackVrS64 { -1 }).to eq(-1)
end
it "returning bool" do
expect(LibTest.testCallbackVrZ { true }).to be true
end
it "returning :pointer (nil)" do
expect(LibTest.testCallbackVrP { nil }).to be_null
end
it "returning :pointer (MemoryPointer)" do
p = FFI::MemoryPointer.new :long
expect(LibTest.testCallbackVrP { p }).to eq(p)
end
it "returning struct by value" do
s = LibTest::S8F32S32.new
s[:s8] = 0x12
s[:s32] = 0x1eefbeef
s[:f32] = 1.234567
ret = LibTest.testCallbackVrT { s }
expect(ret[:s8]).to eq(s[:s8])
expect(ret[:f32]).to eq(s[:f32])
expect(ret[:s32]).to eq(s[:s32])
end
it "struct by value parameter" do
s = LibTest::S8F32S32.new
s[:s8] = 0x12
s[:s32] = 0x1eefbeef
s[:f32] = 1.234567
s2 = LibTest::S8F32S32.new
LibTest.testCallbackTrV(s) do |struct|
s2[:s8] = struct[:s8]
s2[:f32] = struct[:f32]
s2[:s32] = struct[:s32]
end
expect(s2[:s8]).to eql 0x12
expect(s2[:s32]).to eql 0x1eefbeef
expect(s2[:f32]).to be_within(0.0000001).of 1.234567
end
it "global variable" do
proc = Proc.new { 0x1e }
LibTest.cbVrS8 = proc
expect(LibTest.testGVarCallbackVrS8(LibTest.pVrS8)).to eq(0x1e)
end
describe "When the callback is considered optional by the underlying library" do
it "should handle receiving 'nil' in place of the closure" do
expect(LibTest.testOptionalCallbackCrV(nil, 13)).to be_nil
end
end
describe 'when inlined' do
it 'could be anonymous' do
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
attach_function :testAnonymousCallbackVrS8, :testClosureVrB, [ callback([ ], :char) ], :char
end
expect(LibTest.testAnonymousCallbackVrS8 { 0 }).to eq(0)
end
end
describe "as return value" do
it "should not blow up when a callback is defined that returns a callback" do
expect(module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :cb_return_type_1, [ :short ], :short
callback :cb_lookup_1, [ :short ], :cb_return_type_1
attach_function :testReturnsCallback_1, :testReturnsClosure, [ :cb_lookup_1, :short ], :cb_return_type_1
end).to be_an_instance_of FFI::Function
end
it "should return a callback" do
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :cb_return_type, [ :int ], :int
callback :cb_lookup, [ ], :cb_return_type
attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
end
lookup_proc_called = false
return_proc_called = false
return_proc = Proc.new do |a|
return_proc_called = true
a * 2
end
lookup_proc = Proc.new do
lookup_proc_called = true
return_proc
end
val = LibTest.testReturnsCallback(lookup_proc, 0x1234)
expect(val).to eq(0x1234 * 2)
expect(lookup_proc_called).to be true
expect(return_proc_called).to be true
end
it "should return a method callback" do
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :cb_return_type, [ :int ], :int
callback :cb_lookup, [ ], :cb_return_type
attach_function :testReturnsCallback_2, :testReturnsClosure, [ :cb_lookup, :int ], :int
end
module MethodCallback
def self.lookup
method(:perform)
end
def self.perform num
num * 2
end
end
expect(LibTest.testReturnsCallback_2(MethodCallback.method(:lookup), 0x1234)).to eq(0x2468)
end
it 'should not blow up when a callback takes a callback as argument' do
expect(module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :cb_argument, [ :int ], :int
callback :cb_with_cb_argument, [ :cb_argument, :int ], :int
attach_function :testCallbackAsArgument_2, :testArgumentClosure, [ :cb_with_cb_argument, :int ], :int
end).to be_an_instance_of FFI::Function
end
it 'should be able to use the callback argument' do
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :cb_argument, [ :int ], :int
callback :cb_with_cb_argument, [ :cb_argument, :int ], :int
attach_function :testCallbackAsArgument, :testArgumentClosure, [ :cb_with_cb_argument, :cb_argument, :int ], :int
end
callback_arg_called = false
callback_with_callback_arg_called = false
callback_arg = Proc.new do |val|
callback_arg_called = true
val * 2
end
callback_with_callback_arg = Proc.new do |cb, val|
callback_with_callback_arg_called = true
cb.call(val)
end
val = LibTest.testCallbackAsArgument(callback_with_callback_arg, callback_arg, 0xff1)
expect(val).to eq(0xff1 * 2)
expect(callback_arg_called).to be true
expect(callback_with_callback_arg_called).to be true
end
it 'function returns callable object' do
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :funcptr, [ :int ], :int
attach_function :testReturnsFunctionPointer, [ ], :funcptr
end
f = LibTest.testReturnsFunctionPointer
expect(f.call(3)).to eq(6)
end
end
end
describe "Callback with " do
#
# Test callbacks that take an argument, returning void
#
module LibTest
extend FFI::Library
ffi_lib TestLibrary::PATH
class S8F32S32 < FFI::Struct
layout :s8, :char, :f32, :float, :s32, :int
end
callback :cbS8rV, [ :char ], :void
callback :cbU8rV, [ :uchar ], :void
callback :cbS16rV, [ :short ], :void
callback :cbU16rV, [ :ushort ], :void
callback :cbZrV, [ :bool ], :void
callback :cbS32rV, [ :int ], :void
callback :cbU32rV, [ :uint ], :void
callback :cbLrV, [ :long ], :void
callback :cbULrV, [ :ulong ], :void
callback :cbArV, [ :string ], :void
callback :cbPrV, [ :pointer], :void
callback :cbYrV, [ S8F32S32.ptr ], :void
callback :cbS64rV, [ :long_long ], :void
attach_function :testCallbackCrV, :testClosureBrV, [ :cbS8rV, :char ], :void
attach_function :testCallbackU8rV, :testClosureBrV, [ :cbU8rV, :uchar ], :void
attach_function :testCallbackSrV, :testClosureSrV, [ :cbS16rV, :short ], :void
attach_function :testCallbackU16rV, :testClosureSrV, [ :cbU16rV, :ushort ], :void
attach_function :testCallbackZrV, :testClosureZrV, [ :cbZrV, :bool ], :void
attach_function :testCallbackIrV, :testClosureIrV, [ :cbS32rV, :int ], :void
attach_function :testCallbackU32rV, :testClosureIrV, [ :cbU32rV, :uint ], :void
attach_function :testCallbackLrV, :testClosureLrV, [ :cbLrV, :long ], :void
attach_function :testCallbackULrV, :testClosureULrV, [ :cbULrV, :ulong ], :void
attach_function :testCallbackLLrV, :testClosureLLrV, [ :cbS64rV, :long_long ], :void
attach_function :testCallbackArV, :testClosurePrV, [ :cbArV, :string ], :void
attach_function :testCallbackPrV, :testClosurePrV, [ :cbPrV, :pointer], :void
attach_function :testCallbackYrV, :testClosurePrV, [ :cbYrV, S8F32S32.in ], :void
end
it "function with Callback plus another arg should raise error if no arg given" do
expect { LibTest.testCallbackCrV { |*a| }}.to raise_error
end
it ":char (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackCrV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":char (127) argument" do
v = 0xdeadbeef
LibTest.testCallbackCrV(127) { |i| v = i }
expect(v).to eq(127)
end
it ":char (-128) argument" do
v = 0xdeadbeef
LibTest.testCallbackCrV(-128) { |i| v = i }
expect(v).to eq(-128)
end
it ":char (-1) argument" do
v = 0xdeadbeef
LibTest.testCallbackCrV(-1) { |i| v = i }
expect(v).to eq(-1)
end
it ":uchar (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackU8rV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":uchar (127) argument" do
v = 0xdeadbeef
LibTest.testCallbackU8rV(127) { |i| v = i }
expect(v).to eq(127)
end
it ":uchar (128) argument" do
v = 0xdeadbeef
LibTest.testCallbackU8rV(128) { |i| v = i }
expect(v).to eq(128)
end
it ":uchar (255) argument" do
v = 0xdeadbeef
LibTest.testCallbackU8rV(255) { |i| v = i }
expect(v).to eq(255)
end
it ":short (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackSrV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":short (0x7fff) argument" do
v = 0xdeadbeef
LibTest.testCallbackSrV(0x7fff) { |i| v = i }
expect(v).to eq(0x7fff)
end
it ":short (-0x8000) argument" do
v = 0xdeadbeef
LibTest.testCallbackSrV(-0x8000) { |i| v = i }
expect(v).to eq(-0x8000)
end
it ":short (-1) argument" do
v = 0xdeadbeef
LibTest.testCallbackSrV(-1) { |i| v = i }
expect(v).to eq(-1)
end
it ":ushort (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackU16rV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":ushort (0x7fff) argument" do
v = 0xdeadbeef
LibTest.testCallbackU16rV(0x7fff) { |i| v = i }
expect(v).to eq(0x7fff)
end
it ":ushort (0x8000) argument" do
v = 0xdeadbeef
LibTest.testCallbackU16rV(0x8000) { |i| v = i }
expect(v).to eq(0x8000)
end
it ":ushort (0xffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackU16rV(0xffff) { |i| v = i }
expect(v).to eq(0xffff)
end
it ":bool (true) argument" do
v = false
LibTest.testCallbackZrV(true) { |i| v = i }
expect(v).to be true
end
it ":int (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackIrV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":int (0x7fffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackIrV(0x7fffffff) { |i| v = i }
expect(v).to eq(0x7fffffff)
end
it ":int (-0x80000000) argument" do
v = 0xdeadbeef
LibTest.testCallbackIrV(-0x80000000) { |i| v = i }
expect(v).to eq(-0x80000000)
end
it ":int (-1) argument" do
v = 0xdeadbeef
LibTest.testCallbackIrV(-1) { |i| v = i }
expect(v).to eq(-1)
end
it ":uint (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackU32rV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":uint (0x7fffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackU32rV(0x7fffffff) { |i| v = i }
expect(v).to eq(0x7fffffff)
end
it ":uint (0x80000000) argument" do
v = 0xdeadbeef
LibTest.testCallbackU32rV(0x80000000) { |i| v = i }
expect(v).to eq(0x80000000)
end
it ":uint (0xffffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackU32rV(0xffffffff) { |i| v = i }
expect(v).to eq(0xffffffff)
end
it ":long (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackLrV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":long (0x7fffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackLrV(0x7fffffff) { |i| v = i }
expect(v).to eq(0x7fffffff)
end
it ":long (-0x80000000) argument" do
v = 0xdeadbeef
LibTest.testCallbackLrV(-0x80000000) { |i| v = i }
expect(v).to eq(-0x80000000)
end
it ":long (-1) argument" do
v = 0xdeadbeef
LibTest.testCallbackLrV(-1) { |i| v = i }
expect(v).to eq(-1)
end
it ":ulong (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackULrV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":ulong (0x7fffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackULrV(0x7fffffff) { |i| v = i }
expect(v).to eq(0x7fffffff)
end
it ":ulong (0x80000000) argument" do
v = 0xdeadbeef
LibTest.testCallbackULrV(0x80000000) { |i| v = i }
expect(v).to eq(0x80000000)
end
it ":ulong (0xffffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackULrV(0xffffffff) { |i| v = i }
expect(v).to eq(0xffffffff)
end
it ":long_long (0) argument" do
v = 0xdeadbeef
LibTest.testCallbackLLrV(0) { |i| v = i }
expect(v).to eq(0)
end
it ":long_long (0x7fffffffffffffff) argument" do
v = 0xdeadbeef
LibTest.testCallbackLLrV(0x7fffffffffffffff) { |i| v = i }
expect(v).to eq(0x7fffffffffffffff)
end
it ":long_long (-0x8000000000000000) argument" do
v = 0xdeadbeef
LibTest.testCallbackLLrV(-0x8000000000000000) { |i| v = i }
expect(v).to eq(-0x8000000000000000)
end
it ":long_long (-1) argument" do
v = 0xdeadbeef
LibTest.testCallbackLLrV(-1) { |i| v = i }
expect(v).to eq(-1)
end
it ":string argument" do
v = nil
LibTest.testCallbackArV("Hello, World") { |i| v = i }
expect(v).to eq("Hello, World")
end
it ":string (nil) argument" do
v = "Hello, World"
LibTest.testCallbackArV(nil) { |i| v = i }
expect(v).to be_nil
end
it ":pointer argument" do
v = nil
magic = FFI::Pointer.new(0xdeadbeef)
LibTest.testCallbackPrV(magic) { |i| v = i }
expect(v).to eq(magic)
end
it ":pointer (nil) argument" do
v = "Hello, World"
LibTest.testCallbackPrV(nil) { |i| v = i }
expect(v).to eq(FFI::Pointer::NULL)
end
it "struct by reference argument" do
v = nil
magic = LibTest::S8F32S32.new
LibTest.testCallbackYrV(magic) { |i| v = i }
expect(v.class).to eq(magic.class)
expect(v.pointer).to eq(magic.pointer)
end
it "struct by reference argument with nil value" do
v = LibTest::S8F32S32.new
LibTest.testCallbackYrV(nil) { |i| v = i }
expect(v.is_a?(FFI::Struct)).to be true
expect(v.pointer).to eq(FFI::Pointer::NULL)
end
it "varargs parameters are rejected" do
expect {
Module.new do
extend FFI::Library
ffi_lib TestLibrary::PATH
callback :cbVrL, [ :varargs ], :long
end
}.to raise_error(ArgumentError)
end
#
# Test stdcall convention with function and callback.
# This is Windows 32-bit only.
#
if FFI::Platform::OS =~ /windows|cygwin/ && FFI::Platform::ARCH == 'i386'
module LibTestStdcall
extend FFI::Library
ffi_lib TestLibrary::PATH
ffi_convention :stdcall
callback :cbStdcall, [ :pointer, :long ], :void
attach_function :testCallbackStdcall, 'testClosureStdcall', [ :pointer, :cbStdcall, :long ], :bool
end
it "stdcall convention" do
v = 0xdeadbeef
po = FFI::MemoryPointer.new :long
pr = proc{|a,i| v = a,i; i }
res = LibTestStdcall.testCallbackStdcall(po, pr, 0x7fffffff)
expect(v).to eq([po, 0x7fffffff])
expect(res).to be true
end
end
end