diff options
Diffstat (limited to 'test/-ext-')
22 files changed, 421 insertions, 144 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 76f913c275..83fdba2282 100644 --- a/test/-ext-/bug_reporter/test_bug_reporter.rb +++ b/test/-ext-/bug_reporter/test_bug_reporter.rb @@ -2,12 +2,12 @@ require 'test/unit' require 'tmpdir' require_relative '../../lib/jit_support' +require_relative '../../lib/parser_support' class TestBugReporter < Test::Unit::TestCase def test_bug_reporter_add - omit "flaky with RJIT" if JITSupport.rjit_enabled? - description = RUBY_DESCRIPTION.sub(/\+PRISM /, '') - description = description.sub(/\+RJIT /, '') unless JITSupport.rjit_force_enabled? + description = RUBY_DESCRIPTION + description = description.sub(/\+PRISM /, '') unless ParserSupport.prism_enabled_in_subprocess? expected_stderr = [ :*, /\[BUG\]\sSegmentation\sfault.*\n/, @@ -20,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 b244eb41ea..c9263d76fa 100644 --- a/test/-ext-/debug/test_debug.rb +++ b/test/-ext-/debug/test_debug.rb @@ -26,11 +26,14 @@ class TestDebug < Test::Unit::TestCase count[:iseq] += 1 assert_instance_of(RubyVM::InstructionSequence, iseq, msg) - # check same location - assert_equal(loc.path, iseq.path, msg) - assert_equal(loc.absolute_path, iseq.absolute_path, msg) - #assert_equal(loc.label, iseq.label, msg) - assert_operator(loc.lineno, :>=, iseq.first_lineno, msg) + # Backtraces and source locations don't match for :c_trace methods + unless iseq.disasm.include?('C_TRACE') + # check same location + assert_equal(loc.path, iseq.path, msg) + assert_equal(loc.absolute_path, iseq.absolute_path, msg) + #assert_equal(loc.label, iseq.label, msg) + assert_operator(loc.lineno, :>=, iseq.first_lineno, msg) + end end assert_instance_of(Thread::Backtrace::Location, loc, msg) @@ -73,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-/debug/test_profile_frames.rb b/test/-ext-/debug/test_profile_frames.rb index bd819266df..d79c94c468 100644 --- a/test/-ext-/debug/test_profile_frames.rb +++ b/test/-ext-/debug/test_profile_frames.rb @@ -209,8 +209,9 @@ class TestProfileFrames < Test::Unit::TestCase profile_frames.shift # The rest of the stack is expected to look the same... - backtrace_locations.zip(profile_frames).each.with_index do |(location, (path, absolute_path, _, base_label, _, _, _, _, _, _, lineno)), i| + backtrace_locations.zip(profile_frames).each.with_index do |(location, (path, absolute_path, _, base_label, label, _, _, _, _, _, lineno)), i| next if absolute_path == "<cfunc>" # ...except for cfunc frames + next if label in "Array#each" | "Array#map" # ...except for :c_trace method frames err_msg = "#{i}th frame" assert_equal(location.absolute_path, absolute_path, err_msg) 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-/integer/test_my_integer.rb b/test/-ext-/integer/test_my_integer.rb index 1b6f8489f8..0dfa234921 100644 --- a/test/-ext-/integer/test_my_integer.rb +++ b/test/-ext-/integer/test_my_integer.rb @@ -8,19 +8,13 @@ class Test_MyInteger < Test::Unit::TestCase Bug::Integer::MyInteger.new.to_f end - begin - Bug::Integer::MyInteger.class_eval do - def to_f - end + int = Class.new(Bug::Integer::MyInteger) do + def to_f end + end - assert_nothing_raised do - Bug::Integer::MyInteger.new.to_f - end - ensure - Bug::Integer::MyInteger.class_eval do - remove_method :to_f - end + assert_nothing_raised do + int.new.to_f end end @@ -29,20 +23,14 @@ class Test_MyInteger < Test::Unit::TestCase Bug::Integer::MyInteger.new <=> 0 end - begin - Bug::Integer::MyInteger.class_eval do - def <=>(other) - 0 - end + int = Class.new(Bug::Integer::MyInteger) do + def <=>(other) + 0 end + end - assert_nothing_raised do - Bug::Integer::MyInteger.new <=> 0 - end - ensure - Bug::Integer::MyInteger.class_eval do - remove_method :<=> - end + assert_nothing_raised do + int.new <=> 0 end end end diff --git a/test/-ext-/marshal/test_internal_ivar.rb b/test/-ext-/marshal/test_internal_ivar.rb index faabe14ab2..8b4667fdf9 100644 --- a/test/-ext-/marshal/test_internal_ivar.rb +++ b/test/-ext-/marshal/test_internal_ivar.rb @@ -7,11 +7,16 @@ module Bug end module Bug::Marshal class TestInternalIVar < Test::Unit::TestCase def test_marshal - v = InternalIVar.new("hello", "world", "bye") + v = InternalIVar.new("hello", "world", "bye", "hi") assert_equal("hello", v.normal) assert_equal("world", v.internal) assert_equal("bye", v.encoding_short) - dump = assert_warn(/instance variable 'E' on class \S+ is not dumped/) { + assert_equal("hi", v.encoding_long) + warnings = ->(s) { + w = s.scan(/instance variable '(.+?)' on class \S+ is not dumped/) + assert_equal(%w[E K encoding], w.flatten.sort) + } + dump = assert_warn(warnings) { ::Marshal.dump(v) } v = assert_nothing_raised {break ::Marshal.load(dump)} @@ -19,6 +24,7 @@ module Bug::Marshal assert_equal("hello", v.normal) assert_nil(v.internal) assert_nil(v.encoding_short) + assert_nil(v.encoding_long) 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-/required.rb b/test/-ext-/required.rb new file mode 100644 index 0000000000..70514355ff --- /dev/null +++ b/test/-ext-/required.rb @@ -0,0 +1,10 @@ +require 'continuation' +cont = nil +a = [*1..10].reject do |i| + callcc {|c| cont = c} if !cont and i == 10 + false +end +if a.size < 1000 + a.unshift(:x) + cont.call +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 2c6c51fdda..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 @@ -23,7 +24,7 @@ class Test_StringCapacity < Test::Unit::TestCase def test_s_new_capacity assert_equal("", String.new(capacity: 1000)) assert_equal(String, String.new(capacity: 1000).class) - assert_equal(10_000 - 1, capa(String.new(capacity: 10_000))) # Real capa doesn't account for termlen + assert_equal(10_000, capa(String.new(capacity: 10_000))) assert_equal("", String.new(capacity: -1000)) assert_equal(capa(String.new(capacity: -10000)), capa(String.new(capacity: -1000))) @@ -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_chilled.rb b/test/-ext-/string/test_chilled.rb deleted file mode 100644 index dccab61ced..0000000000 --- a/test/-ext-/string/test_chilled.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'test/unit' -require '-test-/string' - -class Test_String_ChilledString < Test::Unit::TestCase - def test_rb_str_chilled_p - str = "" - assert_equal true, Bug::String.rb_str_chilled_p(str) - end - - def test_rb_str_chilled_p_frozen - str = "".freeze - assert_equal false, Bug::String.rb_str_chilled_p(str) - end - - def test_rb_str_chilled_p_mutable - str = "".dup - assert_equal false, Bug::String.rb_str_chilled_p(str) - end -end 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 e3eff75d9b..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 @@ -63,4 +63,22 @@ class Test_StrSetLen < Test::Unit::TestCase assert_not_predicate str, :ascii_only? assert_equal u, str end + + def test_valid_encoding_after_resized + s = "\0\0".force_encoding(Encoding::UTF_16BE) + str = Bug::String.new(s) + assert_predicate str, :valid_encoding? + str.resize(1) + assert_not_predicate str, :valid_encoding? + str.resize(2) + assert_predicate str, :valid_encoding? + str.resize(3) + assert_not_predicate str, :valid_encoding? + + s = "\xDB\x00\xDC\x00".force_encoding(Encoding::UTF_16BE) + str = Bug::String.new(s) + assert_predicate str, :valid_encoding? + str.resize(2) + assert_not_predicate str, :valid_encoding? + end 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-/test_ensure_and_callcc.rb b/test/-ext-/test_ensure_and_callcc.rb new file mode 100644 index 0000000000..9303a094ea --- /dev/null +++ b/test/-ext-/test_ensure_and_callcc.rb @@ -0,0 +1,40 @@ +# -*- coding: us-ascii -*- +# frozen_string_literal: false +require 'test/unit' + +class TestEnsureAndCallcc < Test::Unit::TestCase + def test_bug20655_dir_chdir_using_rb_ensure + require 'tmpdir' + need_continuation + called = 0 + tmp = nil + Dir.mktmpdir do |tmpdir| + Dir.chdir(tmpdir) do + tmp = Dir.pwd + cont = nil + callcc{|c| cont = c} + assert_equal(tmp, Dir.pwd, "BUG #20655: ensure called and pwd was changed unexpectedly") + called += 1 + cont.call if called < 10 + end + end + end + + def test_bug20655_extension_using_rb_ensure + need_continuation + require '-test-/ensure_and_callcc' + EnsureAndCallcc.reset + assert_equal(0, EnsureAndCallcc.ensure_called) + EnsureAndCallcc.require_with_ensure(File.join(__dir__, 'required')) + assert_equal(1, EnsureAndCallcc.ensure_called, + "BUG #20655: ensure called unexpectedly in the required script even without exceptions") + end + + private + def need_continuation + unless respond_to?(:callcc, true) + EnvUtil.suppress_warning {require 'continuation'} + end + omit 'requires callcc support' unless respond_to?(:callcc, true) + end +end diff --git a/test/-ext-/thread/test_instrumentation_api.rb b/test/-ext-/thread/test_instrumentation_api.rb index 9a3b67fa10..ba41069304 100644 --- a/test/-ext-/thread/test_instrumentation_api.rb +++ b/test/-ext-/thread/test_instrumentation_api.rb @@ -54,7 +54,7 @@ class TestThreadInstrumentation < Test::Unit::TestCase thread&.join end - def test_muti_thread_timeline + def test_multi_thread_timeline threads = nil full_timeline = record do threads = threaded_cpu_bound_work(1.0) @@ -68,7 +68,7 @@ class TestThreadInstrumentation < Test::Unit::TestCase threads.each do |thread| timeline = timeline_for(thread, full_timeline) assert_consistent_timeline(timeline) - assert timeline.count(:suspended) > 1, "Expected threads to yield suspended at least once: #{timeline.inspect}" + assert_operator timeline.count(:suspended), :>=, 1, "Expected threads to yield suspended at least once: #{timeline.inspect}" end timeline = timeline_for(Thread.current, full_timeline) @@ -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) @@ -161,6 +161,8 @@ class TestThreadInstrumentation < Test::Unit::TestCase end def test_sleeping_inside_ractor + omit "This test is flaky and intermittently failing now on ModGC workflow" if ENV['GITHUB_WORKFLOW'] == 'ModGC' + assert_ractor(<<-"RUBY", require_relative: "helper", require: "-test-/thread/instrumentation") include ThreadInstrumentation::TestHelper @@ -170,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 48ffe2605c..603fd01fd5 100644 --- a/test/-ext-/tracepoint/test_tracepoint.rb +++ b/test/-ext-/tracepoint/test_tracepoint.rb @@ -66,15 +66,15 @@ class TestTracepointObj < Test::Unit::TestCase count = 0 hook = proc {count += 1} def run(hook) - stress, GC.stress = GC.stress, false - Bug.after_gc_start_hook = hook - begin - GC.stress = true - 3.times {Object.new} - ensure - GC.stress = stress - Bug.after_gc_start_hook = nil - end + stress, GC.stress = GC.stress, false + Bug.after_gc_start_hook = hook + begin + GC.stress = true + 3.times {Object.new} + ensure + GC.stress = stress + Bug.after_gc_start_hook = nil + end end run(hook) puts count @@ -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 |
