diff options
Diffstat (limited to 'test/-ext-')
| -rw-r--r-- | test/-ext-/box/test_load_ext.rb | 97 | ||||
| -rw-r--r-- | test/-ext-/bug_reporter/test_bug_reporter.rb | 8 | ||||
| -rw-r--r-- | test/-ext-/debug/test_debug.rb | 54 | ||||
| -rw-r--r-- | test/-ext-/gvl/test_last_thread.rb | 3 | ||||
| -rw-r--r-- | test/-ext-/postponed_job/test_postponed_job.rb | 35 | ||||
| -rw-r--r-- | test/-ext-/scheduler/test_interrupt_with_scheduler.rb | 54 | ||||
| -rw-r--r-- | test/-ext-/stack/test_stack_overflow.rb | 55 | ||||
| -rw-r--r-- | test/-ext-/string/test_capacity.rb | 13 | ||||
| -rw-r--r-- | test/-ext-/string/test_interned_str.rb | 5 | ||||
| -rw-r--r-- | test/-ext-/string/test_set_len.rb | 2 | ||||
| -rw-r--r-- | test/-ext-/symbol/test_type.rb | 16 | ||||
| -rw-r--r-- | test/-ext-/test_abi.rb | 12 | ||||
| -rw-r--r-- | test/-ext-/thread/test_instrumentation_api.rb | 4 | ||||
| -rw-r--r-- | test/-ext-/thread/test_lock_native_thread.rb | 4 | ||||
| -rw-r--r-- | test/-ext-/thread_fd/test_thread_fd_close.rb | 24 | ||||
| -rw-r--r-- | test/-ext-/tracepoint/test_tracepoint.rb | 2 |
16 files changed, 307 insertions, 81 deletions
diff --git a/test/-ext-/box/test_load_ext.rb b/test/-ext-/box/test_load_ext.rb new file mode 100644 index 0000000000..ea3744375e --- /dev/null +++ b/test/-ext-/box/test_load_ext.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true +require 'test/unit' + +class Test_Load_Extensions < Test::Unit::TestCase + ENV_ENABLE_BOX = {'RUBY_BOX' => '1'} + + def test_load_extension + pend + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + require '-test-/box/yay1' + assert_equal "1.0.0", Yay.version + assert_equal "yay", Yay.yay + end; + end + + def test_extension_contamination_in_global + pend + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true) + begin; + require '-test-/box/yay1' + yay1 = Yay + assert_equal "1.0.0", Yay.version + assert_equal "yay", Yay.yay + + require '-test-/box/yay2' + assert_equal "2.0.0", Yay.version + v = Yay.yay + assert(v == "yay" || v == "yaaay") # "yay" on Linux, "yaaay" on macOS, Win32 + end; + end + + def test_load_extension_in_box + pend + assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + ns = Ruby::Box.new + ns.require '-test-/box/yay1' + assert_equal "1.0.0", ns::Yay.version + assert_raise(NameError) { Yay } + end; + end + + def test_different_version_extensions + pend + assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + ns1 = Ruby::Box.new + ns2 = Ruby::Box.new + ns1.require('-test-/box/yay1') + ns2.require('-test-/box/yay2') + + assert_raise(NameError) { Yay } + assert_not_nil ns1::Yay + assert_not_nil ns2::Yay + assert_equal "1.0.0", ns1::Yay::VERSION + assert_equal "2.0.0", ns2::Yay::VERSION + assert_equal "1.0.0", ns1::Yay.version + assert_equal "2.0.0", ns2::Yay.version + end; + end + + def test_loading_extensions_from_global_to_local + pend + assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + require '-test-/box/yay1' + assert_equal "1.0.0", Yay.version + assert_equal "yay", Yay.yay + + ns = Ruby::Box.new + ns.require '-test-/box/yay2' + assert_equal "2.0.0", ns::Yay.version + assert_equal "yaaay", ns::Yay.yay + + assert_equal "yay", Yay.yay + end; + end + + def test_loading_extensions_from_local_to_global + pend + assert_separately([ENV_ENABLE_BOX], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + ns = Ruby::Box.new + ns.require '-test-/box/yay1' + assert_equal "1.0.0", ns::Yay.version + assert_equal "yay", ns::Yay.yay + + + require '-test-/box/yay2' + assert_equal "2.0.0", Yay.version + assert_equal "yaaay", Yay.yay + + assert_equal "yay", ns::Yay.yay + end; + end +end diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_reporter/test_bug_reporter.rb index 8293408518..83fdba2282 100644 --- a/test/-ext-/bug_reporter/test_bug_reporter.rb +++ b/test/-ext-/bug_reporter/test_bug_reporter.rb @@ -6,8 +6,6 @@ require_relative '../../lib/parser_support' class TestBugReporter < Test::Unit::TestCase def test_bug_reporter_add - pend "macOS 15 is not working with this test" if macos?(15) - description = RUBY_DESCRIPTION description = description.sub(/\+PRISM /, '') unless ParserSupport.prism_enabled_in_subprocess? expected_stderr = [ @@ -22,8 +20,10 @@ class TestBugReporter < Test::Unit::TestCase no_core = "Process.setrlimit(Process::RLIMIT_CORE, 0); " if defined?(Process.setrlimit) && defined?(Process::RLIMIT_CORE) args = ["-r-test-/bug_reporter", "-C", tmpdir] - args.push("--yjit") if JITSupport.yjit_enabled? # We want the printed description to match this process's RUBY_DESCRIPTION - args.unshift({"RUBY_ON_BUG" => nil}) + # We want the printed description to match this process's RUBY_DESCRIPTION + args.push("--yjit") if JITSupport.yjit_enabled? + args.push("--zjit") if JITSupport.zjit_enabled? + args.unshift({"RUBY_ON_BUG" => nil, "RUBY_CRASH_REPORT" => nil}) stdin = "#{no_core}register_sample_bug_reporter(12345); Process.kill :SEGV, $$" assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT") ensure diff --git a/test/-ext-/debug/test_debug.rb b/test/-ext-/debug/test_debug.rb index 98e178e34f..c9263d76fa 100644 --- a/test/-ext-/debug/test_debug.rb +++ b/test/-ext-/debug/test_debug.rb @@ -76,3 +76,57 @@ class TestDebug < Test::Unit::TestCase assert_equal true, x, '[Bug #15105]' end end + +# This is a YJIT test, but we can't test this without a C extension that calls +# rb_debug_inspector_open(), so we're testing it using "-test-/debug" here. +class TestDebugWithYJIT < Test::Unit::TestCase + class LocalSetArray + def to_a + Bug::Debug.inspector.each do |_, binding,| + binding.local_variable_set(:local, :ok) if binding + end + [:ok] + end + end + + class DebugArray + def to_a + Bug::Debug.inspector + [:ok] + end + end + + def test_yjit_invalidates_getlocal_after_splatarray + val = getlocal_after_splatarray(LocalSetArray.new) + assert_equal [:ok, :ok], val + end + + def test_yjit_invalidates_setlocal_after_splatarray + val = setlocal_after_splatarray(DebugArray.new) + assert_equal [:ok], val + end + + def test_yjit_invalidates_setlocal_after_proc_call + val = setlocal_after_proc_call(proc { Bug::Debug.inspector; :ok }) + assert_equal :ok, val + end + + private + + def getlocal_after_splatarray(array) + local = 1 + [*array, local] + end + + def setlocal_after_splatarray(array) + local = *array # setlocal followed by splatarray + itself # split a block using a C call + local # getlocal + end + + def setlocal_after_proc_call(block) + local = block.call # setlocal followed by OPTIMIZED_METHOD_TYPE_CALL + itself # split a block using a C call + local # getlocal + end +end if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? diff --git a/test/-ext-/gvl/test_last_thread.rb b/test/-ext-/gvl/test_last_thread.rb index f1bebafeea..bcda0e3385 100644 --- a/test/-ext-/gvl/test_last_thread.rb +++ b/test/-ext-/gvl/test_last_thread.rb @@ -15,8 +15,7 @@ class TestLastThread < Test::Unit::TestCase t1 = Time.now t = t1 - t0 - assert_in_delta(1.0, t, 0.16) + assert_in_delta(1.0, t, 0.8) end; end end - diff --git a/test/-ext-/postponed_job/test_postponed_job.rb b/test/-ext-/postponed_job/test_postponed_job.rb index 8c2b3e95d1..01d6015de1 100644 --- a/test/-ext-/postponed_job/test_postponed_job.rb +++ b/test/-ext-/postponed_job/test_postponed_job.rb @@ -33,39 +33,4 @@ class TestPostponed_job < Test::Unit::TestCase assert_equal [3, 4], values RUBY end - - def test_legacy_register - assert_separately([], __FILE__, __LINE__, <<-'RUBY') - require '-test-/postponed_job' - direct, registered = [], [] - - Bug.postponed_job_call_direct(direct) - Bug.postponed_job_register(registered) - - assert_equal([0], direct) - assert_equal([3], registered) - - Bug.postponed_job_register_one(ary = []) - assert_equal [1], ary - RUBY - end - - def test_legacy_register_one_same - assert_separately([], __FILE__, __LINE__, <<-'RUBY') - require '-test-/postponed_job' - # Registering the same job three times should result in three of the same handle - handles = Bug.postponed_job_register_one_same - assert_equal [handles[0]], handles.uniq - RUBY - end - - if Bug.respond_to?(:postponed_job_register_in_c_thread) - def test_legacy_register_in_c_thread - assert_separately([], __FILE__, __LINE__, <<-'RUBY') - require '-test-/postponed_job' - assert Bug.postponed_job_register_in_c_thread(ary = []) - assert_equal [1], ary - RUBY - end - end end diff --git a/test/-ext-/scheduler/test_interrupt_with_scheduler.rb b/test/-ext-/scheduler/test_interrupt_with_scheduler.rb new file mode 100644 index 0000000000..eb7a0647e5 --- /dev/null +++ b/test/-ext-/scheduler/test_interrupt_with_scheduler.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true +require 'test/unit' +require 'timeout' +require_relative '../../fiber/scheduler' + +class TestSchedulerInterruptHandling < Test::Unit::TestCase + def setup + pend("No fork support") unless Process.respond_to?(:fork) + require '-test-/scheduler' + end + + # Test without Thread.handle_interrupt - should work regardless of fix + def test_without_handle_interrupt_signal_works + IO.pipe do |input, output| + pid = fork do + STDERR.reopen(output) + + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + Signal.trap(:INT) do + ::Thread.current.raise(Interrupt) + end + + Fiber.schedule do + # Yield to the scheduler: + sleep(0) + + Bug::Scheduler.blocking_loop(output) + end + end + + output.close + assert_equal "x", input.read(1) + + Process.kill(:INT, pid) + + reaper = Thread.new do + Process.waitpid2(pid) + end + + unless reaper.join(10) + Process.kill(:KILL, pid) + end + + _, status = reaper.value + + # It should be interrupted (not killed): + assert_not_equal 0, status.exitstatus + assert_equal true, status.signaled? + assert_equal Signal.list["INT"], status.termsig + end + end +end diff --git a/test/-ext-/stack/test_stack_overflow.rb b/test/-ext-/stack/test_stack_overflow.rb new file mode 100644 index 0000000000..3d7f00331d --- /dev/null +++ b/test/-ext-/stack/test_stack_overflow.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true +require 'test/unit' + +class Test_StackOverflow < Test::Unit::TestCase + def setup + omit "Stack overflow tests are not supported on this platform: #{RUBY_PLATFORM.inspect}" unless RUBY_PLATFORM =~ /x86_64-linux|darwin/ + + require '-test-/stack' + + omit "Stack overflow tests are not supported with ASAN" if Thread.asan? + end + + def test_overflow + assert_separately([], <<~RUBY) + # GC may try to scan the top of the stack and cause a SEGV. + GC.disable + require '-test-/stack' + + assert_raise(SystemStackError) do + Thread.stack_overflow + end + RUBY + end + + def test_thread_stack_overflow + assert_separately([], <<~RUBY) + require '-test-/stack' + GC.disable + + thread = Thread.new do + Thread.current.report_on_exception = false + Thread.stack_overflow + end + + assert_raise(SystemStackError) do + thread.join + end + RUBY + end + + def test_fiber_stack_overflow + assert_separately([], <<~RUBY) + require '-test-/stack' + GC.disable + + fiber = Fiber.new do + Thread.stack_overflow + end + + assert_raise(SystemStackError) do + fiber.resume + end + RUBY + end +end diff --git a/test/-ext-/string/test_capacity.rb b/test/-ext-/string/test_capacity.rb index bcca64d85a..a23892142a 100644 --- a/test/-ext-/string/test_capacity.rb +++ b/test/-ext-/string/test_capacity.rb @@ -2,16 +2,17 @@ require 'test/unit' require '-test-/string' require 'rbconfig/sizeof' +require 'objspace' class Test_StringCapacity < Test::Unit::TestCase def test_capacity_embedded - assert_equal GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] - embed_header_size - 1, capa('foo') + assert_equal pool_slot_size(0) - embed_header_size - 1, capa('foo') assert_equal max_embed_len, capa('1' * max_embed_len) assert_equal max_embed_len, capa('1' * (max_embed_len - 1)) end def test_capacity_shared - sym = ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).to_sym + sym = ("a" * pool_slot_size(0)).to_sym assert_equal 0, capa(sym.to_s) end @@ -47,7 +48,7 @@ class Test_StringCapacity < Test::Unit::TestCase def test_capacity_frozen s = String.new("I am testing", capacity: 1000) - s << "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] + s << "a" * pool_slot_size(0) s.freeze assert_equal(s.length, capa(s)) end @@ -66,7 +67,11 @@ class Test_StringCapacity < Test::Unit::TestCase end def embed_header_size - 3 * RbConfig::SIZEOF['void*'] + GC::INTERNAL_CONSTANTS[:RBASIC_SIZE] + RbConfig::SIZEOF['void*'] + end + + def pool_slot_size(_idx = 0) + Integer(ObjectSpace.dump("")[/"slot_size":(\d+)/, 1]) end def max_embed_len diff --git a/test/-ext-/string/test_interned_str.rb b/test/-ext-/string/test_interned_str.rb index 340dba41e8..a81cb59aa5 100644 --- a/test/-ext-/string/test_interned_str.rb +++ b/test/-ext-/string/test_interned_str.rb @@ -9,4 +9,9 @@ class Test_RbInternedStr < Test::Unit::TestCase src << "b" * 20 assert_equal "a" * 20, interned_str end + + def test_interned_str_encoding + src = :ascii.name + assert_equal Encoding::US_ASCII, Bug::String.rb_interned_str_dup(src).encoding + end end diff --git a/test/-ext-/string/test_set_len.rb b/test/-ext-/string/test_set_len.rb index 1531d76167..41e14a293a 100644 --- a/test/-ext-/string/test_set_len.rb +++ b/test/-ext-/string/test_set_len.rb @@ -5,7 +5,7 @@ require "-test-/string" class Test_StrSetLen < Test::Unit::TestCase def setup # Make string long enough so that it is not embedded - @range_end = ("0".ord + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).chr + @range_end = ("0".ord + GC.stat_heap(0, :slot_size)).chr @s0 = [*"0"..@range_end].join("").freeze @s1 = Bug::String.new(@s0) end diff --git a/test/-ext-/symbol/test_type.rb b/test/-ext-/symbol/test_type.rb index 2b0fbe5b79..ed019062fa 100644 --- a/test/-ext-/symbol/test_type.rb +++ b/test/-ext-/symbol/test_type.rb @@ -123,16 +123,20 @@ module Test_Symbol def test_check_id_invalid_type cx = EnvUtil.labeled_class("X\u{1f431}") - assert_raise_with_message(TypeError, /X\u{1F431}/) { - Bug::Symbol.pinneddown?(cx) - } + EnvUtil.with_default_internal(Encoding::UTF_8) do + assert_raise_with_message(TypeError, /X\u{1F431}/) { + Bug::Symbol.pinneddown?(cx) + } + end end def test_check_symbol_invalid_type cx = EnvUtil.labeled_class("X\u{1f431}") - assert_raise_with_message(TypeError, /X\u{1F431}/) { - Bug::Symbol.find(cx) - } + EnvUtil.with_default_internal(Encoding::UTF_8) do + assert_raise_with_message(TypeError, /X\u{1F431}/) { + Bug::Symbol.find(cx) + } + end end def test_const_name_type diff --git a/test/-ext-/test_abi.rb b/test/-ext-/test_abi.rb index d3ea6bb9b1..7f30feb944 100644 --- a/test/-ext-/test_abi.rb +++ b/test/-ext-/test_abi.rb @@ -9,7 +9,11 @@ class TestABI < Test::Unit::TestCase assert_separately [], <<~RUBY err = assert_raise(LoadError) { require "-test-/abi" } assert_match(/incompatible ABI version/, err.message) - assert_include err.message, "/-test-/abi." + if Ruby::Box.enabled? + assert_include err.message, "_-test-+abi." + else + assert_include err.message, "/-test-/abi." + end RUBY end @@ -27,7 +31,11 @@ class TestABI < Test::Unit::TestCase assert_separately [{ "RUBY_ABI_CHECK" => "1" }], <<~RUBY err = assert_raise(LoadError) { require "-test-/abi" } assert_match(/incompatible ABI version/, err.message) - assert_include err.message, "/-test-/abi." + if Ruby::Box.enabled? + assert_include err.message, "_-test-+abi." + else + assert_include err.message, "/-test-/abi." + end RUBY end diff --git a/test/-ext-/thread/test_instrumentation_api.rb b/test/-ext-/thread/test_instrumentation_api.rb index c0fad14908..ba41069304 100644 --- a/test/-ext-/thread/test_instrumentation_api.rb +++ b/test/-ext-/thread/test_instrumentation_api.rb @@ -151,7 +151,7 @@ class TestThreadInstrumentation < Test::Unit::TestCase end full_timeline = record do - ractor.take + ractor.value end timeline = timeline_for(Thread.current, full_timeline) @@ -172,7 +172,7 @@ class TestThreadInstrumentation < Test::Unit::TestCase thread = Ractor.new{ sleep 0.1 Thread.current - }.take + }.value sleep 0.1 end diff --git a/test/-ext-/thread/test_lock_native_thread.rb b/test/-ext-/thread/test_lock_native_thread.rb index 8a5ba78838..b4044b2b93 100644 --- a/test/-ext-/thread/test_lock_native_thread.rb +++ b/test/-ext-/thread/test_lock_native_thread.rb @@ -15,6 +15,8 @@ end class TestThreadLockNativeThread < Test::Unit::TestCase def test_lock_native_thread + omit "LSAN reports memory leak because NT is not freed for MN thread" if Test::Sanitizers.lsan_enabled? + assert_separately([{'RUBY_MN_THREADS' => '1'}], <<-RUBY) require '-test-/thread/lock_native_thread' @@ -28,6 +30,8 @@ class TestThreadLockNativeThread < Test::Unit::TestCase end def test_lock_native_thread_tls + omit "LSAN reports memory leak because NT is not freed for MN thread" if Test::Sanitizers.lsan_enabled? + assert_separately([{'RUBY_MN_THREADS' => '1'}], <<-RUBY) require '-test-/thread/lock_native_thread' tn = 10 diff --git a/test/-ext-/thread_fd/test_thread_fd_close.rb b/test/-ext-/thread_fd/test_thread_fd_close.rb deleted file mode 100644 index 1d2ef63635..0000000000 --- a/test/-ext-/thread_fd/test_thread_fd_close.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true -require 'test/unit' -require '-test-/thread_fd' - -class TestThreadFdClose < Test::Unit::TestCase - - def test_thread_fd_close - IO.pipe do |r, w| - th = Thread.new do - begin - assert_raise(IOError) { - r.read(4) - } - ensure - w.syswrite('done') - end - end - Thread.pass until th.stop? - IO.thread_fd_close(r.fileno) - assert_equal 'done', r.read(4) - th.join - end - end -end diff --git a/test/-ext-/tracepoint/test_tracepoint.rb b/test/-ext-/tracepoint/test_tracepoint.rb index bf66d8f105..603fd01fd5 100644 --- a/test/-ext-/tracepoint/test_tracepoint.rb +++ b/test/-ext-/tracepoint/test_tracepoint.rb @@ -83,7 +83,7 @@ class TestTracepointObj < Test::Unit::TestCase end def test_teardown_with_active_GC_end_hook - assert_separately([], 'require("-test-/tracepoint"); Bug.after_gc_exit_hook = proc {}') + assert_ruby_status([], 'require("-test-/tracepoint"); Bug.after_gc_exit_hook = proc {}; GC.start') end end |
