From 4b8903421828cb9d4de139180563ae8d8f04e1ab Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Fri, 2 Jul 2021 22:41:16 +1200 Subject: IO::Buffer for scheduler interface. --- test/ruby/test_io_buffer.rb | 131 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 test/ruby/test_io_buffer.rb (limited to 'test/ruby') diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb new file mode 100644 index 0000000000..ec10d2e1e6 --- /dev/null +++ b/test/ruby/test_io_buffer.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: false + +class TestIOBuffer < Test::Unit::TestCase + def assert_negative(value) + assert(value < 0, "Expected #{value} to be negative!") + end + + def assert_positive(value) + assert(value > 0, "Expected #{value} to be positive!") + end + + def test_flags + assert_equal 0, IO::Buffer::EXTERNAL + assert_equal 1, IO::Buffer::INTERNAL + assert_equal 2, IO::Buffer::MAPPED + + assert_equal 16, IO::Buffer::LOCKED + assert_equal 32, IO::Buffer::PRIVATE + + assert_equal 64, IO::Buffer::IMMUTABLE + end + + def test_endian + assert_equal 4, IO::Buffer::LITTLE_ENDIAN + assert_equal 8, IO::Buffer::BIG_ENDIAN + assert_equal 8, IO::Buffer::NETWORK_ENDIAN + + assert_include [IO::Buffer::LITTLE_ENDIAN, IO::Buffer::BIG_ENDIAN], IO::Buffer::HOST_ENDIAN + end + + def test_new_internal + buffer = IO::Buffer.new(1024, IO::Buffer::INTERNAL) + assert_equal 1024, buffer.size + refute buffer.external? + assert buffer.internal? + refute buffer.mapped? + end + + def test_new_mapped + buffer = IO::Buffer.new(1024, IO::Buffer::MAPPED) + assert_equal 1024, buffer.size + refute buffer.external? + refute buffer.internal? + assert buffer.mapped? + end + + def test_file_mapped + buffer = File.open(__FILE__) {|file| IO::Buffer.map(file)} + assert_include buffer.to_str, "Hello World" + end + + def test_resize + buffer = IO::Buffer.new(1024, IO::Buffer::MAPPED) + buffer.resize(2048, 0) + assert_equal 2048, buffer.size + end + + def test_resize_preserve + message = "Hello World" + buffer = IO::Buffer.new(1024, IO::Buffer::MAPPED) + buffer.copy(message, 0) + buffer.resize(2048, 1024) + assert_equal message, buffer.to_str(0, message.bytesize) + end + + def test_compare_same_size + buffer1 = IO::Buffer.new(1) + assert_equal buffer1, buffer1 + + buffer2 = IO::Buffer.new(1) + buffer1.set(:U8, 0, 0x10) + buffer2.set(:U8, 0, 0x20) + + assert_negative buffer1 <=> buffer2 + assert_positive buffer2 <=> buffer1 + end + + def test_compare_different_size + buffer1 = IO::Buffer.new(3) + buffer2 = IO::Buffer.new(5) + + assert_negative buffer1 <=> buffer2 + assert_positive buffer2 <=> buffer1 + end + + def test_slice + buffer = IO::Buffer.new(128) + slice = buffer.slice(8, 32) + slice.copy("Hello World", 0) + assert_equal("Hello World", buffer.to_str(8, 11)) + end + + def test_slice_bounds + buffer = IO::Buffer.new(128) + + # What is best exception class? + assert_raise RuntimeError do + buffer.slice(128, 10) + end + + # assert_raise RuntimeError do + # pp buffer.slice(-10, 10) + # end + end + + def test_invalidation + input, output = IO.pipe + + # (1) rb_write_internal creates IO::Buffer object, + buffer = IO::Buffer.new(128) + + # (2) it is passed to (malicious) scheduler + # (3) scheduler starts a thread which call system call with the buffer object + thread = Thread.new{buffer.locked{input.read}} + + Thread.pass until thread.stop? + + # (4) scheduler returns + # (5) rb_write_internal invalidate the buffer object + assert_raise RuntimeError do + buffer.free + end + + # (6) the system call access the memory area after invalidation + output.write("Hello World") + output.close + thread.join + + input.close + end +end -- cgit v1.2.3