mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
8f752c95d2
https://github.com/ruby/fiddle/commit/e08c4c635e Co-authored-by: Sutou Kouhei <kou@clear-code.com>
287 lines
7 KiB
Ruby
287 lines
7 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_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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
|
|
def test_no_memory_leak
|
|
if respond_to?(:assert_nothing_leaked_memory)
|
|
n_tries = 100_000
|
|
assert_nothing_leaked_memory(SIZEOF_VOIDP * (n_tries / 100)) do
|
|
n_tries.times do
|
|
Fiddle::Pointer.allocate
|
|
end
|
|
end
|
|
else
|
|
assert_no_memory_leak(%w[-W0 -rfiddle.so], '', '100_000.times {Fiddle::Pointer.allocate}', rss: true)
|
|
end
|
|
end
|
|
end
|
|
end if defined?(Fiddle)
|