mirror of
https://github.com/ruby/ruby.git
synced 2025-08-28 07:26:00 +02:00

Fix GH-104 lib/fiddle/jruby.rb is based on https://github.com/jruby/jruby/blob/master/lib/ruby/stdlib/fiddle/jruby.rb . Here are changes for it: * Move `Fiddle::TYPE_*` to `Fiddle::Types::*` * Add `Fiddle::Types::VARIADIC` * Add `Fiddle::Types::CONST_STRING` * Add `Fiddle::Types::BOOL` * Add `Fiddle::Types::INT8_T` * Add `Fiddle::Types::UINT8_T` * Add `Fiddle::Types::INT16_T` * Add `Fiddle::Types::UINT16_T` * Add `Fiddle::Types::INT32_T` * Add `Fiddle::Types::UINT32_T` * Add `Fiddle::Types::INT64_T` * Add `Fiddle::Types::UINT64_T` * Add more `Fiddle::ALIGN_*` for the above new `Fiddle::Types::*` * Add more `Fiddle::SIZEOF_*` for the above new `Fiddle::Types::*` * Add support for specifying type as not only `Fiddle::Types::*` but also `Symbol` like `:int` * Add support for variable size arguments in `Fiddle::Function` * Add `Fiddle::Closure#free` * Add `Fiddle::Closure#freed?` * Add `Fiddle::Error` as base the error class * Add `Fiddle::Pointer#call_free` and stop using `FFI::AutoPointer` in `Fiddle::Pointer` * Add support for `Fiddle::Pointer.malloc {}` `Fiddle::Pointer` * Add support for `Fiddle::Pointer#free=` * Add `Fiddle::Pointer#freed?` * Use binary string not C string for `Fiddle::Pointer#[]` * Add `Fiddle::Handle.sym_defined?` * Add `Fiddle::Handle#sym_defined?` * Add `Fiddle::Handle::DEFAULT` * Add `Fiddle::ClearedReferenceError` * Add no-op `Fiddle::Pinned` Some features are still "not implemented". So there are some "omit"s for JRuby in tests.
309 lines
7.6 KiB
Ruby
309 lines
7.6 KiB
Ruby
# frozen_string_literal: true
|
|
begin
|
|
require_relative 'helper'
|
|
rescue LoadError
|
|
end
|
|
|
|
module Fiddle
|
|
class TestPointer < TestCase
|
|
def dlwrap arg
|
|
Fiddle.dlwrap arg
|
|
end
|
|
|
|
def test_can_read_write_memory
|
|
if RUBY_ENGINE == "jruby"
|
|
omit("Fiddle::Pointer.{read,write} don't exist in JRuby")
|
|
end
|
|
|
|
# Allocate some memory
|
|
Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |pointer|
|
|
address = pointer.to_i
|
|
bytes_to_write = Fiddle::SIZEOF_VOIDP.times.to_a.pack("C*")
|
|
|
|
# Write to the memory
|
|
Fiddle::Pointer.write(address, bytes_to_write)
|
|
|
|
# Read the bytes out again
|
|
bytes = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP)
|
|
assert_equal bytes_to_write, bytes
|
|
end
|
|
end
|
|
|
|
def test_cptr_to_int
|
|
null = Fiddle::NULL
|
|
assert_equal(null.to_i, null.to_int)
|
|
end
|
|
|
|
def test_malloc_free_func_int
|
|
free = Fiddle::Function.new(Fiddle::RUBY_FREE, [TYPE_VOIDP], TYPE_VOID)
|
|
assert_equal free.to_i, Fiddle::RUBY_FREE.to_i
|
|
|
|
ptr = Pointer.malloc(10, free.to_i)
|
|
assert_equal 10, ptr.size
|
|
assert_equal free.to_i, ptr.free.to_i
|
|
end
|
|
|
|
def test_malloc_free_func
|
|
free = Fiddle::Function.new(Fiddle::RUBY_FREE, [TYPE_VOIDP], TYPE_VOID)
|
|
|
|
ptr = Pointer.malloc(10, free)
|
|
assert_equal 10, ptr.size
|
|
assert_equal free.to_i, ptr.free.to_i
|
|
end
|
|
|
|
def test_malloc_block
|
|
escaped_ptr = nil
|
|
returned = Pointer.malloc(10, Fiddle::RUBY_FREE) do |ptr|
|
|
assert_equal 10, ptr.size
|
|
assert_equal Fiddle::RUBY_FREE, ptr.free.to_i
|
|
escaped_ptr = ptr
|
|
:returned
|
|
end
|
|
assert_equal :returned, returned
|
|
assert escaped_ptr.freed?
|
|
end
|
|
|
|
def test_malloc_block_no_free
|
|
assert_raise ArgumentError do
|
|
Pointer.malloc(10) { |ptr| }
|
|
end
|
|
end
|
|
|
|
def test_malloc_subclass
|
|
subclass = Class.new(Pointer)
|
|
subclass.malloc(10, Fiddle::RUBY_FREE) do |ptr|
|
|
assert ptr.is_a?(subclass)
|
|
end
|
|
end
|
|
|
|
def test_to_str
|
|
str = Marshal.load(Marshal.dump("hello world"))
|
|
ptr = Pointer[str]
|
|
|
|
assert_equal 3, ptr.to_str(3).length
|
|
assert_equal str, ptr.to_str
|
|
|
|
ptr[5] = 0
|
|
assert_equal "hello\0world", ptr.to_str
|
|
end
|
|
|
|
def test_to_s
|
|
str = Marshal.load(Marshal.dump("hello world"))
|
|
ptr = Pointer[str]
|
|
|
|
assert_equal 3, ptr.to_s(3).length
|
|
assert_equal str, ptr.to_s
|
|
|
|
ptr[5] = 0
|
|
assert_equal 'hello', ptr.to_s
|
|
end
|
|
|
|
def test_minus
|
|
str = "hello world"
|
|
ptr = Pointer[str]
|
|
assert_equal ptr.to_s, (ptr + 3 - 3).to_s
|
|
end
|
|
|
|
# TODO: what if the pointer size is 0? raise an exception? do we care?
|
|
def test_plus
|
|
str = "hello world"
|
|
ptr = Pointer[str]
|
|
new_str = ptr + 3
|
|
assert_equal 'lo world', new_str.to_s
|
|
end
|
|
|
|
def test_inspect
|
|
if RUBY_ENGINE == "jruby"
|
|
omit("Fiddle::Pointer#inspect is incompatible on JRuby")
|
|
end
|
|
|
|
ptr = Pointer.new(0)
|
|
inspect = ptr.inspect
|
|
assert_match(/size=#{ptr.size}/, inspect)
|
|
assert_match(/free=#{sprintf("%#x", ptr.free.to_i)}/, inspect)
|
|
assert_match(/ptr=#{sprintf("%#x", ptr.to_i)}/, inspect)
|
|
end
|
|
|
|
def test_to_ptr_string
|
|
str = "hello world"
|
|
ptr = Pointer[str]
|
|
assert_equal str.length, ptr.size
|
|
assert_equal 'hello', ptr[0,5]
|
|
end
|
|
|
|
def test_to_ptr_io
|
|
if RUBY_ENGINE == "jruby"
|
|
omit("Fiddle::Pointer.to_ptr(IO) isn't supported with JRuby")
|
|
end
|
|
|
|
Pointer.malloc(10, Fiddle::RUBY_FREE) do |buf|
|
|
File.open(__FILE__, 'r') do |f|
|
|
ptr = Pointer.to_ptr f
|
|
fread = Function.new(@libc['fread'],
|
|
[TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP],
|
|
TYPE_INT)
|
|
fread.call(buf.to_i, Fiddle::SIZEOF_CHAR, buf.size - 1, ptr.to_i)
|
|
end
|
|
|
|
File.open(__FILE__, 'r') do |f|
|
|
assert_equal f.read(9), buf.to_s
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_to_ptr_with_ptr
|
|
ptr = Pointer.new 0
|
|
ptr2 = Pointer.to_ptr Struct.new(:to_ptr).new(ptr)
|
|
assert_equal ptr, ptr2
|
|
|
|
assert_raise(Fiddle::DLError) do
|
|
Pointer.to_ptr Struct.new(:to_ptr).new(nil)
|
|
end
|
|
end
|
|
|
|
def test_to_ptr_with_num
|
|
ptr = Pointer.new 0
|
|
assert_equal ptr, Pointer[0]
|
|
end
|
|
|
|
def test_equals
|
|
ptr = Pointer.new 0
|
|
ptr2 = Pointer.new 0
|
|
assert_equal ptr2, ptr
|
|
end
|
|
|
|
def test_not_equals
|
|
ptr = Pointer.new 0
|
|
refute_equal 10, ptr, '10 should not equal the pointer'
|
|
end
|
|
|
|
def test_cmp
|
|
ptr = Pointer.new 0
|
|
assert_nil(ptr <=> 10, '10 should not be comparable')
|
|
end
|
|
|
|
def test_ref_ptr
|
|
if RUBY_ENGINE == "jruby"
|
|
omit("Fiddle.dlwrap([]) isn't supported with JRuby")
|
|
end
|
|
|
|
ary = [0,1,2,4,5]
|
|
addr = Pointer.new(dlwrap(ary))
|
|
assert_equal addr.to_i, addr.ref.ptr.to_i
|
|
|
|
assert_equal addr.to_i, (+ (- addr)).to_i
|
|
end
|
|
|
|
def test_to_value
|
|
if RUBY_ENGINE == "jruby"
|
|
omit("Fiddle.dlwrap([]) isn't supported with JRuby")
|
|
end
|
|
|
|
ary = [0,1,2,4,5]
|
|
addr = Pointer.new(dlwrap(ary))
|
|
assert_equal ary, addr.to_value
|
|
end
|
|
|
|
def test_free
|
|
ptr = Pointer.malloc(4)
|
|
begin
|
|
assert_nil ptr.free
|
|
ensure
|
|
Fiddle.free ptr
|
|
end
|
|
end
|
|
|
|
def test_free=
|
|
free = Function.new(Fiddle::RUBY_FREE, [TYPE_VOIDP], TYPE_VOID)
|
|
ptr = Pointer.malloc(4)
|
|
ptr.free = free
|
|
|
|
assert_equal free.ptr, ptr.free.ptr
|
|
end
|
|
|
|
def test_free_with_func
|
|
ptr = Pointer.malloc(4, Fiddle::RUBY_FREE)
|
|
refute ptr.freed?
|
|
ptr.call_free
|
|
assert ptr.freed?
|
|
ptr.call_free # you can safely run it again
|
|
assert ptr.freed?
|
|
GC.start # you can safely run the GC routine
|
|
assert ptr.freed?
|
|
end
|
|
|
|
def test_free_with_no_func
|
|
ptr = Pointer.malloc(4)
|
|
refute ptr.freed?
|
|
ptr.call_free
|
|
refute ptr.freed?
|
|
ptr.call_free # you can safely run it again
|
|
refute ptr.freed?
|
|
end
|
|
|
|
def test_freed?
|
|
ptr = Pointer.malloc(4, Fiddle::RUBY_FREE)
|
|
refute ptr.freed?
|
|
ptr.call_free
|
|
assert ptr.freed?
|
|
end
|
|
|
|
def test_null?
|
|
ptr = Pointer.new(0)
|
|
assert ptr.null?
|
|
end
|
|
|
|
def test_size
|
|
Pointer.malloc(4, Fiddle::RUBY_FREE) do |ptr|
|
|
assert_equal 4, ptr.size
|
|
end
|
|
end
|
|
|
|
def test_size=
|
|
Pointer.malloc(4, Fiddle::RUBY_FREE) do |ptr|
|
|
ptr.size = 10
|
|
assert_equal 10, ptr.size
|
|
end
|
|
end
|
|
|
|
def test_aref_aset
|
|
check = Proc.new{|str,ptr|
|
|
assert_equal(str.size(), ptr.size())
|
|
assert_equal(str, ptr.to_s())
|
|
assert_equal(str[0,2], ptr.to_s(2))
|
|
assert_equal(str[0,2], ptr[0,2])
|
|
assert_equal(str[1,2], ptr[1,2])
|
|
assert_equal(str[1,0], ptr[1,0])
|
|
assert_equal(str[0].ord, ptr[0])
|
|
assert_equal(str[1].ord, ptr[1])
|
|
}
|
|
str = Marshal.load(Marshal.dump('abc'))
|
|
ptr = Pointer[str]
|
|
check.call(str, ptr)
|
|
|
|
str[0] = "c"
|
|
assert_equal 'c'.ord, ptr[0] = "c".ord
|
|
check.call(str, ptr)
|
|
|
|
str[0,2] = "aa"
|
|
assert_equal 'aa', ptr[0,2] = "aa"
|
|
check.call(str, ptr)
|
|
|
|
ptr2 = Pointer['cdeeee']
|
|
str[0,2] = "cd"
|
|
assert_equal ptr2, ptr[0,2] = ptr2
|
|
check.call(str, ptr)
|
|
|
|
ptr3 = Pointer['vvvv']
|
|
str[0,2] = "vv"
|
|
assert_equal ptr3.to_i, ptr[0,2] = ptr3.to_i
|
|
check.call(str, ptr)
|
|
end
|
|
|
|
def test_null_pointer
|
|
nullpo = Pointer.new(0)
|
|
assert_raise(DLError) {nullpo[0]}
|
|
assert_raise(DLError) {nullpo[0] = 1}
|
|
end
|
|
end
|
|
end if defined?(Fiddle)
|