Skip to content

Commit b34002d

Browse files
committed
Update FFI specs to 1.11.1 + our exclusions
* eregon/ffi@563c06b
1 parent 5defdc8 commit b34002d

File tree

6 files changed

+161
-25
lines changed

6 files changed

+161
-25
lines changed

spec/ffi/callback_spec.rb

Lines changed: 110 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -510,40 +510,32 @@ class S8F32S32 < FFI::Struct
510510
expect(v).to eq(-1)
511511
end
512512

513-
def testCallbackU8rV(value, &block)
513+
def testCallbackU8rV(value)
514514
v1 = 0xdeadbeef
515-
LibTest.testCallbackU8rV(value) { |i| v1 = yield(i) }
515+
LibTest.testCallbackU8rV(value) { |i| v1 = i }
516+
expect(v1).to eq(value)
516517

518+
# Using a FFI::Function (v2) should be consistent with the direct callback (v1)
517519
v2 = 0xdeadbeef
518-
fun = FFI::Function.new(:void, [:uchar]) { |i| v2 = yield(i) }
520+
fun = FFI::Function.new(:void, [:uchar]) { |i| v2 = i }
519521
LibTest.testCallbackU8rV(fun, value)
520-
raise "FFI::Function (#{v2}) not consistent with direct callback (#{v1})" unless v1 == v2
521-
522-
v1
522+
expect(v2).to eq(value)
523523
end
524524

525525
it ":uchar (0) argument" do
526-
v = 0xdeadbeef
527-
testCallbackU8rV(0) { |i| v = i }
528-
expect(v).to eq(0)
526+
testCallbackU8rV(0)
529527
end
530528

531529
it ":uchar (127) argument" do
532-
v = 0xdeadbeef
533-
testCallbackU8rV(127) { |i| v = i }
534-
expect(v).to eq(127)
530+
testCallbackU8rV(127)
535531
end
536532

537533
it ":uchar (128) argument" do
538-
v = 0xdeadbeef
539-
testCallbackU8rV(128) { |i| v = i }
540-
expect(v).to eq(128)
534+
testCallbackU8rV(128)
541535
end
542536

543537
it ":uchar (255) argument" do
544-
v = 0xdeadbeef
545-
testCallbackU8rV(255) { |i| v = i }
546-
expect(v).to eq(255)
538+
testCallbackU8rV(255)
547539
end
548540

549541
it ":short (0) argument" do
@@ -794,3 +786,103 @@ module LibTestStdcall
794786
end
795787
end
796788
end
789+
790+
describe "Callback interop" do
791+
# require 'fiddle'
792+
# require 'fiddle/import'
793+
require 'timeout'
794+
795+
module LibTestFFI
796+
extend FFI::Library
797+
ffi_lib TestLibrary::PATH
798+
attach_function :testCallbackVrV, :testClosureVrV, [ :pointer ], :void
799+
attach_function :testCallbackVrV_blocking, :testClosureVrV, [ :pointer ], :void, blocking: true
800+
end
801+
802+
# module LibTestFiddle
803+
# extend Fiddle::Importer
804+
# dlload TestLibrary::PATH
805+
# extern 'void testClosureVrV(void *fp)'
806+
# end
807+
808+
def assert_callback_in_same_thread_called_once
809+
called = 0
810+
thread = nil
811+
yield proc {
812+
called += 1
813+
thread = Thread.current
814+
}
815+
expect(called).to eq(1)
816+
expect(thread).to eq(Thread.current)
817+
end
818+
819+
it "from ffi to ffi" do
820+
assert_callback_in_same_thread_called_once do |block|
821+
func = FFI::Function.new(:void, [:pointer], &block)
822+
LibTestFFI.testCallbackVrV(FFI::Pointer.new(func.to_i))
823+
end
824+
end
825+
826+
it "from ffi to ffi with blocking:true" do
827+
assert_callback_in_same_thread_called_once do |block|
828+
func = FFI::Function.new(:void, [:pointer], &block)
829+
LibTestFFI.testCallbackVrV_blocking(FFI::Pointer.new(func.to_i))
830+
end
831+
end
832+
833+
# https://github.com/ffi/ffi/issues/527
834+
if RUBY_VERSION.split('.').map(&:to_i).pack("C*") >= [2,3,0].pack("C*") || RUBY_PLATFORM =~ /java/
835+
it "from fiddle to ffi" do
836+
next # Fiddle
837+
assert_callback_in_same_thread_called_once do |block|
838+
func = FFI::Function.new(:void, [:pointer], &block)
839+
LibTestFiddle.testClosureVrV(Fiddle::Pointer[func.to_i])
840+
end
841+
end
842+
end
843+
844+
it "from ffi to fiddle" do
845+
next # Fiddle
846+
assert_callback_in_same_thread_called_once do |block|
847+
func = LibTestFiddle.bind_function(:cbVrV, Fiddle::TYPE_VOID, [], &block)
848+
LibTestFFI.testCallbackVrV(FFI::Pointer.new(func.to_i))
849+
end
850+
end
851+
852+
it "from ffi to fiddle with blocking:true" do
853+
next # Fiddle
854+
assert_callback_in_same_thread_called_once do |block|
855+
func = LibTestFiddle.bind_function(:cbVrV, Fiddle::TYPE_VOID, [], &block)
856+
LibTestFFI.testCallbackVrV_blocking(FFI::Pointer.new(func.to_i))
857+
end
858+
end
859+
860+
it "from fiddle to fiddle" do
861+
next # Fiddle
862+
assert_callback_in_same_thread_called_once do |block|
863+
func = LibTestFiddle.bind_function(:cbVrV, Fiddle::TYPE_VOID, [], &block)
864+
LibTestFiddle.testClosureVrV(Fiddle::Pointer[func.to_i])
865+
end
866+
end
867+
868+
# https://github.com/ffi/ffi/issues/527
869+
if RUBY_ENGINE == 'ruby' && RUBY_VERSION.split('.').map(&:to_i).pack("C*") >= [2,3,0].pack("C*")
870+
it "C outside ffi call stack does not deadlock [#527]" do
871+
next # takes a while, fails on MRI
872+
path = File.join(File.dirname(__FILE__), "embed-test/embed-test.rb")
873+
pid = spawn(RbConfig.ruby, "-Ilib", path, { [:out, :err] => "embed-test.log" })
874+
begin
875+
Timeout.timeout(10){ Process.wait(pid) }
876+
rescue Timeout::Error
877+
Process.kill(9, pid)
878+
raise
879+
else
880+
if $?.exitstatus != 0
881+
raise "external process failed:\n#{ File.read("embed-test.log") }"
882+
end
883+
end
884+
885+
expect(File.read("embed-test.log")).to match(/callback called with \["hello", 5, 0\]/)
886+
end
887+
end
888+
end

spec/ffi/errno_spec.rb

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,28 @@ module LibTest
1010
extend FFI::Library
1111
ffi_lib TestLibrary::PATH
1212
attach_function :setLastError, [ :int ], :void
13+
attach_function :setErrno, [ :int ], :void
1314
end
1415

15-
it "FFI.errno contains errno from last function" do
16+
it "FFI.errno contains errno from last function, FFI::LastError.winapi_error works differently per OS" do
17+
# setup
18+
LibTest.setErrno(0)
1619
LibTest.setLastError(0)
1720
LibTest.setLastError(0x12345678)
18-
expect(FFI.errno).to eq(0x12345678)
21+
# cases
22+
case FFI::Platform::OS
23+
when "cygwin"
24+
expect(FFI::LastError.winapi_error).to eq(0x12345678)
25+
LibTest.setErrno(0x2A)
26+
expect(FFI.errno).to eq(0x2A)
27+
when "windows"
28+
expect(FFI::LastError.winapi_error).to eq(0x12345678)
29+
expect(FFI.errno).to eq(0x12345678)
30+
else
31+
# Linux, and else
32+
expect {FFI::LastError.winapi_error}.to raise_exception(NoMethodError)
33+
expect {FFI::LastError.winapi_error = 0}.to raise_exception(NoMethodError)
34+
expect(FFI.errno).to eq(0x12345678)
35+
end
1936
end
2037
end

spec/ffi/fixtures/GNUmakefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ PREFIX = lib
2323
LIBEXT ?= so
2424
LIBNAME = $(PREFIX)test.$(LIBEXT)
2525

26+
export MACOSX_DEPLOYMENT_TARGET=10.4
27+
2628
CCACHE := $(strip $(realpath $(shell which ccache 2> /dev/null)))
2729

2830
TEST_SRCS = $(wildcard $(SRC_DIR)/*.c)
@@ -33,7 +35,7 @@ TEST_OBJS := $(patsubst $(SRC_DIR)/%.c, $(TEST_BUILD_DIR)/%.o, $(TEST_SRCS))
3335
# http://weblogs.java.net/blog/kellyohair/archive/2006/01/compilation_of_1.html
3436
JFLAGS = -fno-omit-frame-pointer -fno-strict-aliasing
3537
OFLAGS = -O2 $(JFLAGS)
36-
WFLAGS = -W -Wall -Wno-unused -Wno-unused-parameter -Wno-parentheses
38+
WFLAGS = -W -Wall -Wno-unused -Wno-parentheses
3739
PICFLAGS = -fPIC
3840
SOFLAGS = -shared
3941
LDFLAGS += $(SOFLAGS)
@@ -56,6 +58,9 @@ ifeq ($(OS), darwin)
5658
ifneq ($(findstring $(CPU),ppc),)
5759
ARCHFLAGS += -arch ppc
5860
endif
61+
ifneq ($(findstring $(CPU),i386 x86_64),)
62+
ARCHFLAGS += -arch i386 -arch x86_64
63+
endif
5964
CFLAGS += $(ARCHFLAGS) -DTARGET_RT_MAC_CFM=0
6065
CFLAGS += -fno-common
6166
LDFLAGS = $(ARCHFLAGS) -dynamiclib

spec/ffi/fixtures/LastErrorTest.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
# include <errno.h>
1111
#endif
1212

13-
int setLastError(int error) {
14-
#if defined(_WIN32) || defined(__WIN32__)
13+
void setLastError(int error) {
14+
#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
1515
SetLastError(error);
1616
#else
1717
errno = error;
1818
#endif
19-
return -1;
2019
}
2120

21+
void setErrno(int error) {
22+
errno = error;
23+
}

spec/ffi/fixtures/PipeHelperWindows.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#ifdef _WIN32
88
#include <windows.h>
9+
#include <stdio.h>
910
#include "PipeHelper.h"
1011

1112
int pipeHelperCreatePipe(FD_TYPE pipefd[2])

spec/ffi/pointer_spec.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,26 @@ def to_ptr
9494
expect(array[j].address).to eq(address)
9595
end
9696
end
97-
97+
98+
it "#write_array_of_type for uint8" do
99+
values = [10, 227, 32]
100+
memory = FFI::MemoryPointer.new FFI::TYPE_UINT8, values.size
101+
memory.write_array_of_type(FFI::TYPE_UINT8, :put_uint8, values)
102+
array = memory.read_array_of_type(FFI::TYPE_UINT8, :read_uint8, values.size)
103+
values.each_with_index do |val, j|
104+
expect(array[j]).to eq(val)
105+
end
106+
end
107+
108+
it "#write_array_of_type for uint32" do
109+
values = [10, 227, 32]
110+
memory = FFI::MemoryPointer.new FFI::TYPE_UINT32, values.size
111+
memory.write_array_of_type(FFI::TYPE_UINT32, :put_uint32, values)
112+
array = memory.read_array_of_type(FFI::TYPE_UINT32, :read_uint32, values.size)
113+
values.each_with_index do |val, j|
114+
expect(array[j]).to eq(val)
115+
end
116+
end
98117
end
99118

100119
describe 'NULL' do

0 commit comments

Comments
 (0)